我正在尝试为 android 构建一个带有操纵杆(d-pad)的 GUI。而且我大部分时间都在工作。有一个大问题:当我第一次在任何安卓设备上打开它时,GUI 不会加载。我已经找到了问题所在,但我不清楚是什么原因造成的。
在JoystickGui
类中,我在构造函数中创建了一个joystick
对象。稍后drawJoystickGUI()
由扩展 Activity 的类调用,它将在画布上绘制位图。每次我第一次启动应用程序(或手动清空 RAM)时,我都设法发现对操纵杆对象的引用为空,即使它是在构造函数中创建的。
在该方法drawJoystickGUI()
中,我使用 aSystem.Out.println
查看joystick
对象是否实际存在并返回null。我必须使用try
andcatch
来防止应用程序在启动时崩溃。
我真的希望有人可以向我解释导致这个问题的原因。
这是我的代码:
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();
}
}
应该正确运行游戏的引擎,我把所有非必要的东西都拿出来了。在 GameLoop 中调用 InitializeTouch。
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);
}
}
编辑:
我通过初始化绘图函数中的“操纵杆”和“按钮”对象解决了这个问题,并使用一个简单的布尔值来防止不必要的 cpu 使用。但我仍然愿意接受实际的解决方案,而不是变通办法。