簡體   English   中英

以編程方式在循環中從上到下移動 ImageView(s),在屏幕外開始和結束

[英]Programmatically move ImageView(s) from top to bottom in a loop, starting and ending outside of screen

我正在制作一個小型 Android 游戲,其中我需要兩個 ImageViews(障礙物)同時從屏幕頂部移動到屏幕底部; 開始和結束的屏幕之外 這樣做將是一個開始。

我有一個計時器,每次計時器結束時,它都會再次運行,我還希望其他兩個 ImageView(與前兩個相同)以上述相同的方式移動。

換句話說:

  • 一些隨機事件觸發計時器
  • 計時器達到閾值 -> 計時器重置並且兩個 ImageView 開始下降

我有一些作品,但有位圖和 Y 增量。 問題是,因為手機盡可能快地增加,游戲可能會變得遲鈍,並且兩個不同的手機上兩個圖像下降的速度不會相同。

我知道我必須使用動畫,但每次嘗試使用動畫時都無法得到我想要的東西。 他們通常不會從我想要的地方開始,而且會發生奇怪的事情。

以下是我已經訪問過的一些鏈接:

下面是一些代碼,向您展示我所擁有的:

游戲視圖

public class GameView extends SurfaceView implements SurfaceHolder.Callback {
    // [...]

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        // [...]
        this.obstacles = new ArrayList <> ();

        this.handleObstacleTimer = null;
        this.runnableObstacleTimer = null;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // [...]
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                this.startObstacleTimer();
                GameLogic.gameState = GameState.RUNNING;
                // [...]
        }

        return result;
    }


    @Override
    public void draw (Canvas canvas) {
        super.draw(canvas);

        if (canvas != null) {
            this.background.draw(canvas);
            if (! this.obstacles.isEmpty()) {
                for (Obstacle obstacle : this.obstacles) {
                    obstacle.draw(canvas);
                }
            }
            // [...]
        }
    }


    public void createObstacle () {
        Bitmap imageObstacle = BitmapFactory.decodeResource(this.getResources(), R.drawable.obstacle);
        this.obstacles.add(new Obstacle(imageObstacle, this, this.displayMetrics.widthPixels, this.displayMetrics.heightPixels));
    }

    public void removeObstacle (Obstacle obstacle) {
        this.obstacles.remove(obstacle);
    }

    private void stopObstacleTimer () {
        if (this.handleObstacleTimer != null  &&  this.runnableObstacleTimer != null) {
            this.handleObstacleTimer.removeCallbacks(this.runnableObstacleTimer);
            this.handleObstacleTimer = null;
        }
    }

    private void startObstacleTimer () {
        if (this.handleObstacleTimer == null) {
            final Handler handler = new Handler();
            this.runnableObstacleTimer = new Runnable() {
                @Override
                public void run() {
                    if (GameLogic.gameState == GameState.RUNNING) {
                        createObstacle();
                        handler.postDelayed(this, 2700);
                    }
                }
            };

            handler.postDelayed(this.runnableObstacleTimer, 2700);

            this.handleObstacleTimer = handler;
        }
    }

    // [...]

    // Called by a custom Thread class
    public void update () {
        if (! this.obstacles.isEmpty()) {
            for (Obstacle obstacle : this.obstacles) {
                obstacle.update();
            }
        }
        // [...]
    }
}

MAINTHREAD (自定義線程類)

public class MainThread extends Thread {

    private SurfaceHolder surfaceHolder;
    private GameView gameView;
    private GameLogic gameLogic;

    private boolean running;

    public static Canvas canvas;


    public MainThread (SurfaceHolder surfaceHolder, GameView gameView, GameLogic gameLogic) {
        super();

        this.surfaceHolder = surfaceHolder;
        this.gameView = gameView;
        this.gameLogic = gameLogic;
    }


        @Override
        public void run() {
            while (this.running) {
                this.canvas = null;

            try {
                this.canvas = this.surfaceHolder.lockCanvas();
                synchronized (this.surfaceHolder) {
                    this.gameView.update();
                    this.gameView.draw(this.canvas);
                    this.gameLogic.update();
                }
            } catch (Exception e) {

            } finally {
                if (this.canvas != null) {
                    try {
                        this.surfaceHolder.unlockCanvasAndPost(this.canvas);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }


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

障礙

public class Obstacle {

    private static final int GAP_MIN_X = 300;
    private static int GAP_MAX_X;
    private static final int GAP_WIDTH = 250;

    private GameView gameView;

    private int displayHeight;

    private Bitmap obstacleLeft;
    private Bitmap obstacleRight;
    private int leftX;
    private int rightX;
    private int y;

    private boolean passed;


    public Obstacle (Bitmap image, GameView gameView, int displayWidth, int displayHeight) {
        this.gameView = gameView;

        this.displayHeight = displayHeight;

        this.obstacleLeft = this.flip(image);
        this.obstacleRight = image;

        GAP_MAX_X = displayWidth - GAP_MIN_X;
        final int randomX = new Random().nextInt((GAP_MAX_X - GAP_MIN_X) + 1) + GAP_MIN_X;

        this.leftX = randomX - this.obstacleLeft.getWidth() - (GAP_WIDTH / 2);
        this.rightX = randomX + (GAP_WIDTH / 2);

        this.y = 0 - this.obstacleLeft.getHeight();

        this.passed = false;
    }


    private Bitmap flip (Bitmap image) {
        Matrix m = new Matrix();
        m.preScale(-1, 1);
        Bitmap result = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), m, false);
        result.setDensity(DisplayMetrics.DENSITY_DEFAULT);
        return result;
    }


    /**
     * Those getters are used for collision
     */
    public int getLeftX () {
        return this.leftX;
    }

    public int getRightX () {
        return this.rightX;
    }

    public int getY () {
        return this.y;
    }

    public int getWidth () {
        return this.obstacleLeft.getWidth();
    }

    public int getHeight () {
        return this.obstacleLeft.getHeight();
    }


    public boolean hasPassed () {
        return this.passed;
    }

    public void setAsPassed () {
        this.passed = true;
    }


    public void draw (Canvas canvas) {
        canvas.drawBitmap(this.obstacleLeft, this.leftX, this.y, null);
        canvas.drawBitmap(this.obstacleRight, this.rightX, this.y, null);
    }


    public void update () {
        if (! (GameLogic.gameState == GameState.GAMEOVER)) {
            this.y += 8;

            if (this.y > this.displayHeight) {
                this.gameView.removeObstacle(this);
            }
        }
    }
}

基本上,我想要的是有相同的結果。 但是,無論游戲在哪款手機上運行,​​都沒有延遲,障礙物以相同的速度運行。

如果在 Obstacle.update() 函數中,將 Y 增量從常量整數 8 更改為與調用更新函數的時間間隔成正比的值,則在任何設備上的速度都相同。 例如,您可以根據上次 update() 調用和當前更新調用的時間之間的差異計算變化

long speed = 100; //you should add this to adjust the speed of the incrementing
long delta = System.currentTimeMillis();
public void update () {
        delta = speed*(System.currentTimeMillis() - delta);
        if (! (GameLogic.gameState == GameState.GAMEOVER)) {
            this.y += delta;

        if (this.y > this.displayHeight) {
            this.gameView.removeObstacle(this);
        }
    }
}

這樣,您的 delta 變量將永遠隨着上次調用和當前調用之間的時間間隔而變化,因為 System.currentTimeMillis() 以毫秒為單位返回當前時間

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM