简体   繁体   中英

Custom GUI won't show up the first time when app is started

I am trying to build a GUI with a joystick (d-pad) for android. And I have it working for the most part. There is one big problem: The GUI won't load the first time I open it on any android device. I have tracked down the problem, but it's not clear to me what is causing it.

Within the JoystickGui class I create a joystick object in the constrctor. Later on the drawJoystickGUI() is called by the class that extends Activity and it will draw bitmaps on to the canvas. Every time I start the app for the first time (or emptied the RAM manually) I managed to find out that the reference to the joystick-object is null, even though it is created in the constructor.

In the method drawJoystickGUI() I have used a System.Out.println to see whether the joystick object actually exitst and it returns . I had to use a try and catch to prevent the app from crashing on startup.

I really hope someone can explain to me what is causing this problem.

Here is my code:

public class JoystickGUI implements OnTouchListener {

// Screen size for positioning purposes
private float screenWidth, screenHeight;

// Used to determine if the Joystick Graphical User Interface is actually
public static boolean use;

private boolean useButtons = true;

// Will hold all non-Joystick objects
private ArrayList<Button> buttons = new ArrayList<Button>();

// Joystick object
private Joystick joystick;

Display display;

// Touch input identification
private int jsPointerID;
final private int INVALID_POINTER_ID = -1;

@SuppressWarnings("deprecation")
public JoystickGUI() {
    if(use){

        display = ((WindowManager) GameEngine.getAppContext().getSystemService(
            Context.WINDOW_SERVICE)).getDefaultDisplay();

        screenWidth = display.getWidth();
        screenHeight = display.getHeight();

        System.out.println("ScreenWidth: " + screenWidth + ". ScreenHeight: "
                + screenHeight + ".");

        joystick = new Joystick(100, screenHeight - 100);

        if (useButtons) {

            Sprite buttonA = new Sprite("buttonajoystickgui");
            buttons.add(new RoundButton(buttonA, screenWidth - 125,
                    screenHeight - 75));
            Sprite buttonB = new Sprite("buttonbjoystickgui");
            buttons.add(new RoundButton(buttonB, screenWidth - 75,
                    screenHeight - 125));

        }

        setTransparency(150);

        Log.d("JoystickGUI", "Initialized");
    }

}

/**
 * The following methods are used for handling the touch input
 */

public boolean onTouch(View v, MotionEvent event) {

        switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            buttonPressed(event);
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            buttonPressed(event);
            break;
        case MotionEvent.ACTION_MOVE:
            buttonMoved(event);
            break;
        case MotionEvent.ACTION_UP:
            buttonReleased(event, 0);
            break;
        case MotionEvent.ACTION_POINTER_UP:
            buttonReleased(event, event.getActionIndex());
            break;
        default:
            break;

    }
    return true;
}

public void buttonPressed(MotionEvent e) {

    for (int p = 0; p < e.getPointerCount(); p++) {
        if (joystick.isWithinJoystick(e, p) && !Joystick.isActive) {
            Joystick.isActive = true;
            jsPointerID = e.getActionIndex();
        }
        for (int i = 0; i < buttons.size(); i++) {
            if (buttons.get(i).isPressed(e, p) && !buttons.get(i).isActive) {
                buttons.get(i).setActive(true);
                buttons.get(i).setPointerID(e.getActionIndex());
                Log.d("JoystickGUI", "Button #" + i + " pressed.");
            }
        }
    }

}

public void buttonMoved(MotionEvent e) {

    for (int p = 0; p < e.getPointerCount(); p++) {
        if (Joystick.isActive && e.getPointerId(p) == jsPointerID) {
            joystick.updateButtonPos(e, p);
        }

    }

}

public void buttonReleased(MotionEvent e, int pointerIndex) {
    if (Joystick.isActive && e.getPointerId(pointerIndex) == jsPointerID) {
        Joystick.isActive = false;
        joystick.resetJoystick();
        jsPointerID = INVALID_POINTER_ID;

    }

    for (int i = 0; i < buttons.size(); i++) {
        if (buttons.get(i).isActive
                && e.getPointerId(pointerIndex) == buttons.get(i)
                        .getPointerID()) {
            buttons.get(i).setActive(false);
            buttons.get(i).resetPointerID();
        }
    }

}

/**
 * The following methods are used for drawing all button-objects to the
 * canvas.
 * 
 * @param canvas
 */

public void drawJoystickGUI(Canvas canvas) {
    if(use){

        try {
            joystick.drawJoystick(canvas);
        } catch (Exception e) {
            System.out.println(joystick);
            Log.d("JoystickGUI", "Drawing joystick failed!");
        }

        for (int i = 0; i < buttons.size(); i++) {
            try {
                buttons.get(i).drawButton(canvas);
            } catch (Exception e) {
                Log.d("JoystickGUI", "Drawing Button " + i + " failed");
                System.out.println(buttons.get(i));
            }
        }
    }

}

private void setTransparency(int alpha) {

    joystick.setAlpha(alpha);
    for (int i = 0; i < buttons.size(); i++) {
        buttons.get(i).setAlpha(alpha);
    }

}

/**
 * The following (static) methods are used to get input.
 * 
 * @return
 */

public static boolean isJoystickActive() {
    return Joystick.isActive;
}

public static  double getJoystickAngle() {
    return Joystick.getAngle();
}

public static  float getPower() {
    return Joystick.getPower();
}
}

The engine that is supposed to run the game properly, i took al non-essential stuff out. InitializeTouch is called in the GameLoop.

public abstract class GameEngine extends Activity {

/**
 * Gameloop is a gameThread that handles the timing of the game
 */
private GameLoop gameloop;
/**
 * View deals with the proper rendering of the game
 */
private static GameView view;
/**
 * The width and height of the device
 */
private static int screenWidth, screenHeight;
/**
 * JoystickGUI handles input by touch via the joystick interface
 */
public JoystickGUI joystickGUI;

/**
 * A vectorlist that holds all the active GameObjects. Can be used if you
 * mannualy want to delete/change GameObjects. For instance, you could loop
 * through this list and remove health of every GameObject.
 */
public static Vector<GameObject> items;
/**
 * A vectorlist that holds all the newly created GameObjects during this
 * cycle of the game loop. At the end of the cycle, all items in this list
 * will be moved to the items-list and the object become active
 */
public static Vector<GameObject> newItems;
/**
 * A vectorlist that holds all the active alarms. Can be used if you
 * manually want to delete/change alarms.
 */
public static Vector<Alarm> gameAlarms;


/**
 * Holds context of the application
 */
private static Context appContext;
/**
 * The main thread of the gameloop
 */
private Thread gameThread;




@Override
protected final void onCreate(Bundle savedInstanceState) {

    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
    getWindow().setFlags(
            WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED,
            WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED);

    vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
    appContext = getApplicationContext();

    joystickGUI = new JoystickGUI(); // Added

    screenWidth = getWindow().getWindowManager().getDefaultDisplay()
            .getWidth();
    screenHeight = getWindow().getWindowManager().getDefaultDisplay()
            .getHeight();

    gameloop = new GameLoop(this);
    gameThread = new Thread(gameloop);
    gameThread.setPriority(7);

    view = new GameView(this, gameThread);
    gameloop.setView(view);

    setContentView(view);
    view.setKeepScreenOn(true);

    super.onCreate(savedInstanceState);

}


/**
 * Initialize the Listener for the screen (general touch OR screenButtons)
 */
protected void initializeTouch() {

    if (JoystickGUI.use) { // added
        Log.d("JoystickEnabled", "USING JOYSTICK");
            view.setOnTouchListener(joystickGUI);
        }
}

public final void drawInterface(Canvas canvas) {
    if(JoystickGUI.use){
        joystickGUI.drawJoystickGUI(canvas);
    } 
}

I have solved the problem by initializing the 'joystick' and 'buttons' objects inside the draw function, with a simple boolean to prevent unnecessary cpu usage. But i'm sill open for actual solutions instead of work-arounds.

I'm not sure what's wrong with your code.

Have you tried AndEngine ? It's free and open source. You can download its examples application from Google Play.

Its joystick example is analog. It's not as simple as your joystick code example, but if you can adapt your game to receive analog input, it's an example that works quite well out of the box.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM