android - 使用 Canvas 在游戏中显示对话框

标签 android multithreading dialog surfaceview

在发现开始一个新的 intent 可能不是通知用户 GameOver 的正确方式后,我现在正在为 runOnUiThread、Runnable 和对话框而苦苦挣扎..

问题:我将如何以及在何处实现 Dialog.show() 来通知用户游戏已结束?在我的日志中,一切正常(所以我设法在游戏结束时收到消息)。在某些时候,boolean GameManger.LevelEnded 切换为 true。当发生这种情况时,我想显示对话框..

我试验过 runOnUiThread、Runnable 和 Async 线程。想不通。

我有一个游戏。 Activity AppelzActivity:

public class AppelzActivity extends Activity {
    /** Called when the activity is first created. */

    private static final String TAG = AppelzActivity.class.getSimpleName();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(null);

        // requesting to turn the title OFF
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        // making it full screen
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        // set our MainGamePanel as the View
        setContentView(new MainGamePanel(this));
        Log.d(TAG, "View added");
    }
}

我的 MainGamePanel 类:

public class MainGamePanel extends SurfaceView implements
SurfaceHolder.Callback {

// DECLARING VARS (REMOVED FOR READABILITY)

    public MainGamePanel(Context context) {
        super(context);
        getHolder().addCallback(this);
        Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
        .getDefaultDisplay();
        GameManager.panel = this;

        width = display.getWidth();
        height = display.getHeight();
        RectScreen.set(0,0,width,height);

        // CREATING CONTROLS, MISSION AND VISIBLE OBJECTS (REMOVED FOR READABILITY)

        thread = new MainThread(getHolder(), this);
        setFocusable(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread.setRunning(true);
    }

        // HANDELING ON TOUCH EVENTS AND SUCH (REMOVED FOR READABILITY)


    @Override
    protected void onDraw(Canvas canvas) {
        // fills the canvas with black
        canvas.drawColor(Color.BLACK);
        backGnd.draw(canvas);

        basket.draw(canvas);
        for (int i = 0; i < AppleList.size();i++){
            AppleList.get(i).draw(canvas);
        }
        btnMoreFruit.draw(canvas);
        btnLessFruit.draw(canvas);

        if (GameManager.count){

            glyphsCount.drawString(MainThread.canvas, Integer.toString(GameManager.i), (width/2-120), (height/2-120));

        }

    }
}

最后是 MainThread 类:

public class MainThread extends Thread {

    private static final String TAG = MainThread.class.getSimpleName();

    private SurfaceHolder surfaceHolder;
    private MainGamePanel gamePanel;
    private DialogManager dialogManager;
    public static boolean running;
    public static Canvas canvas;

    public void setRunning(boolean running) {
        MainThread.running = running;
    }

    public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
        super();
        this.surfaceHolder = surfaceHolder;
        this.gamePanel = gamePanel;
        this.dialogManager = dialogManager;
    }

    @Override
    public void run() {
        // Canvas canvas;
        Log.d(TAG, "Starting game loop");
        while (running) {
            MainThread.canvas = null;
            // try locking the canvas for exclusive pixel editing on the surface

            try {
                MainThread.canvas = this.surfaceHolder.lockCanvas();
                synchronized (surfaceHolder) {
                    // update game state
                    this.gamePanel.update();

                    // render state to the screen
                    // draws the canvas on the panel
                    this.gamePanel.onDraw(MainThread.canvas);

                }
            } finally {
                // in case of an exception the surface is not left in
                // an inconsistent state
                if (MainThread.canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(MainThread.canvas);
                }
            } // end finally
        }
    }
}

Basket.java - 这是游戏中的一个对象。如您所见,如果它处于某个位置,我将开始倒计时:

public class basket {

 private Bitmap bitmap; // the actual bitmap
 private int x;   // the X coordinate
 private int y;   // the Y coordinate'
 public static int width;
 public static int height;
 public float X = 100;
 public float Y = 100;

 private boolean touched; // if droid is touched/picked up

 public basket(Bitmap bitmap, int x, int y) {
  this.bitmap = bitmap;

  width = bitmap.getWidth(); 
  height = bitmap.getHeight(); 
 }

 public Bitmap getBitmap() {
  return bitmap;
 }
 public void setBitmap(Bitmap bitmap) {
  this.bitmap = bitmap;
 }

 public int getWidth(){
      return bitmap.getWidth();
     }

     public int getHeight(){
      return bitmap.getHeight();
     }

 public int getX() {
  return x;
 }



 public void setX(float x) {

    // if basket is further than slotmargin 
     if (x + width/2 > SlotManager.SlotmarginX) {
        // if basket is NOT in CheckOut area    
         if (this.Y < MainGamePanel.height - 80 - height/2){
            x = SlotManager.SlotmarginX - width/2;

        } else {
            // if basket IS in CheckOut area
            x = MainGamePanel.width - width/2;

            // Start the countdown timer if not already running
            if (!GameManager.count){
                GameManager.count=true;
// --- HERE I START COUNTDOWN
                GameManager.handler.postDelayed(GameManager.runnable, 0);                               
            }

        }
    } else {

        // Basket is NOT in CheckOut area; stop countdown timer
        GameManager.count=false;
    }

     this.X = x;
 }


 public int getY() {
  return y;
 }
 public void setY(int y) {
        if (y + height/2 > MainGamePanel.height - 80){
            y = MainGamePanel.height - 80 - height/2;
        }


  this.Y = y;
 }


 public boolean isTouched() {
  return touched;
 }

 public void setTouched(boolean touched) {
  this.touched = touched;
 }

 public void draw(Canvas canvas) {
      canvas.drawBitmap(bitmap, X - width/2, Y - height/2, null);
 }

 public void handleActionDown(int eventX, int eventY) {
  if (eventX >= (X - width/ 2) && (eventX <= (X + width/2))) {
   if (eventY >= (Y - height/ 2) && (eventY <= (Y + height/ 2))) {
    // basket touched
    setTouched(true);
   } else {
    setTouched(false);
   }
  } else {
   setTouched(false);
  }

 }
}

GameManager 中的 CountDown 是:

        @Override
        public void run()
        {
            if (SlotManager.alSlottedFruitList.size() > 0){
            //TODO Create Full screen countdown timer
                Log.d("", "Countdown Timer in GameManager " + i);

                i--;
                if (count && i > -1) // stop timer when count is false
                {
                    handler.postDelayed(runnable, 1000);
                } else {
                    if (i == -1){
                        Log.d("", "RoundUp the Level");

// --- HERE I WANT TO DO A LEVEL END AND SHOW THE DIALOG                        

                    }
                    // reset Countdown (if basket outside checkout)
                    i = 6;
                }
            } else {
                // reset Countdown (if slot has no fruits)
                i = 6;
            }
        }
    };

    public static void startCountDown() {
        handler.postDelayed(GameManager.runnable, 0);
    }

    public static void finishRound() {
        listener.onRoundFinished();
    }



    public static List<Integer> missionlist;

    public static void CreateMission(){
        int maxtotalitems = 6;
        missionlist = new ArrayList<Integer>();
        Random Rnd = new Random();

        for (int FruitType = 0; FruitType < FruitManager.fruitResources.size();FruitType++){
            for (int x = 0; x < Rnd.nextInt(maxtotalitems); x++){
                missionlist.add(FruitType); 
            }}

// --- HERE I WANT TO SHOW A DIALOG CONTAINING THE MISSION


        for (int x = 0; x < FruitManager.fruitResources.size();x++){
            Log.d("MISSION", "Mission for " + x + " : " + Collections.frequency(missionlist, x));
        }

// Let's show the Dialog containing the mission 

    }

    public void LevelEnd(){
        // First, count the Fruits in the slot
        SlotManager.countSlotInv();
        List<Integer> list = new ArrayList<Integer>();      
        // Fill itemIds with the types of fruits
        for (apple a : SlotManager.alSlottedFruitList){
            Integer itemId = Integer.valueOf(a.FruitType);
            list.add(itemId);
        }


            for (int key = 0; key < 3 ; key++) {
                boolean succeed = CheckMissionComplete(key, Collections.frequency(list, key));

                System.out.println(key + " : " + Collections.frequency(list, key));
                    Log.d("MISSION", "Number : " + key + " : succeed = " + succeed );                   
            }
            listener.onRoundFinished();
    }

    public boolean CheckMissionComplete(int key, int amount) {

        //CheckMission
        if (amount == Collections.frequency(missionlist, key)){
            return true;            
        } else {
        return false;
        }
    }

    public GameManager(GameListener listener) {
        this.listener = listener;
    }





}

最佳答案

我觉得,最简单的方法就是通过listeners引入回调机制。为此,添加一个监听器接口(interface)(例如,GameListener.java),保留对此接口(interface)实例的引用并在类中调用其方法,所有游戏逻辑都出现在类中(比方说 Game.java).然后,让您的 AppelzActivity 实现此接口(interface)并在调用适当的回调时显示对话框:

GameListener.java:

public interface GameListener {
    /** 
    * ...
    * NOTE: may be called on any thread
    */
    public void onRoundFinished();
    ...
}

Game.java:

public class Game {
    private GameListener listener;

    public Game(GameListener listener) {
        this.listener = listener;
    }

    ...

    //Let's say, round finishes here
    public void finishRound() {
        ...

        listener.onRoundFinished();
    }
}

AppelzActivity.java:

public class AppelzActivity extends Activity implements GameListener {

    private static final int DLG_ROUND_FINISHED = 1;

    ...

    @Override
    public void onRoundFinished() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                showDialog(DLG_ROUND_FINISHED);
            }
        });
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        Dialog dialog = null;
        switch (id) {
        case DLG_ROUND_FINISHED:
            AlertDialog.Builder builder = new AlertDialog.Builder(this);

            ... // init your dialog here

            dialog = builder.create();
            break;
        }
        return dialog;
    }
}

关于android - 使用 Canvas 在游戏中显示对话框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10268422/

相关文章:

javascript - React Native Geolocation GetCurrentPosition EnableHighAccuracy

android - 在 Android 上注入(inject)新的 SMS 事件

c++ - 互斥锁和 block 作用域

安卓谷歌日历 "Unable to launch event"

java - 从 SQLite Column 中获取所有数字字符串并计算总和

c++ - 如何以线程安全的方式更改目录?

c - 为什么 Helgrind 显示 "lock order violated"错误消息?

dialog - Xpages 扩展库对话框位置

Android DialogFragment 文本颜色为白色而不是黑色

android - API 21 (Lollipop) Android 上的主题对话框