Improve movement of space aliens

Nik*_*ntz 7 java android collision-detection sprite game-physics

在此输入图像描述

I code a mini Android game scenario inspired by Space Invaders and Moon Patrol. It is possible to shoot an alien horizontally (see above).

It is also possible to shoot an alien vertically (see below).

在此输入图像描述

But adding aliens doesn't "scale", it will be very difficult to add for instance 15 aliens moving with respect to all possible collisions. The original space invaders and moon patrol solved this, is it possible to develop a different strategy than the one I am using? The exact movement of aliens is not important, only that it is "fun".

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v4.view.MotionEventCompat;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.ArrayList;
import java.util.List;

public class ParallaxView extends SurfaceView implements Runnable {

    List<Background> backgrounds;

    private volatile boolean running;
    private Thread gameThread = null;

    // For drawing
    private Paint paint;
    private Canvas canvas;
    private SurfaceHolder ourHolder;

    // Holds a reference to the Activity
    Context context;

    // Control the fps
    long fps = 60;

    // Screen resolution
    int screenWidth;
    int screenHeight;

    private void update() {
        // Update all the background positions
        for (Background bg : backgrounds) {
            bg.update(fps);
        }

    }

    ParallaxView(Context context, int screenWidth, int screenHeight) {
        super(context);

        this.context = context;

        this.screenWidth = screenWidth;
        this.screenHeight = screenHeight;

        // Initialize our drawing objects
        ourHolder = getHolder();
        paint = new Paint();

        // Initialize our array list
        backgrounds = new ArrayList<>();

        //load the background data into the Background objects and
        // place them in our GameObject arraylist

        backgrounds.add(new Background(
                this.context,
                screenWidth,
                screenHeight,
                "bg", 0, 120, 50));

        backgrounds.add(new Background(
                this.context,
                screenWidth,
                screenHeight,
                "grass", 70, 110, 200));

        // Add more backgrounds here

    }

    @Override
    public void run() {

        while (running) {
            long startFrameTime = System.currentTimeMillis();

            update();
            if (j > 2000) {
                j = -50;
                k = 0;
            }
            if (o > 2000) {
                o = -50;
                l = 0;
            }
            draw();

            // Calculate the fps this frame
            long timeThisFrame = System.currentTimeMillis() - startFrameTime;
            if (timeThisFrame >= 1) {
                fps = 1000 / timeThisFrame;
            }
        }
    }

    int numberOfshots = 1;
    int[] i = new int[200];
    int j = 0;
    int k = 0;
    int l = 0;
    int m = 0;
    int o = 0;
    boolean down = true;
    long lastTurn = System.currentTimeMillis();
    int xbuggy = 0;
    int xbuggy2 = 0;
    boolean down2 = true;
    long lastTurn2 = System.currentTimeMillis();
    long lastTurn3 = System.currentTimeMillis();
    boolean jump = false;
    boolean shoot = false;
    int ind = 0;

    private void draw() {

        if (ourHolder.getSurface().isValid()) {
            //First we lock the area of memory we will be drawing to
            canvas = ourHolder.lockCanvas();
            if (jump) {
                xbuggy = xbuggy + 4;
            }
            if (shoot) {
                xbuggy2 = xbuggy2 + 4;
            }

            if (System.currentTimeMillis() - lastTurn3 >= 1000) {
                // Change direction here
                jump = false;
                lastTurn3 = System.currentTimeMillis();
                xbuggy = 0;
            }
            //draw a background color
            canvas.drawColor(Color.argb(255, 0, 0, 0));

            // Draw the background parallax
            drawBackground(0);

            // Draw the rest of the game
            paint.setTextSize(60);
            paint.setColor(Color.argb(255, 255, 255, 255));

            //canvas.drawText("MOONPATROL3000", 350, screenHeight / 100 * 5, paint);

            int resID = context.getResources().getIdentifier("vehicle",
                    "drawable", context.getPackageName());

            int alienResID = context.getResources().getIdentifier("object3_hdpi",
                    "drawable", context.getPackageName());

            int alienResID2 = context.getResources().getIdentifier("object2_hdpi",
                    "drawable", context.getPackageName());

            int alienResID3 = context.getResources().getIdentifier("object1_hdpi",
                    "drawable", context.getPackageName());

            // Load the bitmap using the id
            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resID);
            Bitmap alienbitmap = BitmapFactory.decodeResource(context.getResources(), alienResID);
            Bitmap alienbitmap2 = BitmapFactory.decodeResource(context.getResources(), alienResID2);
            Bitmap alienbitmap3 = BitmapFactory.decodeResource(context.getResources(), alienResID3);




            //paint.setTextSize(220);
            for (int i1 = 0; i1 < numberOfshots; i1++) {


                // if horizontal missile hits alien 0
                if (java.lang.Math.abs(j - i[i1]) * 2  < (alienbitmap.getWidth() + 60) && java.lang.Math.abs(k +150+ screenHeight / 100 * 45 - (float) (screenHeight * 0.61)) * 2  < (alienbitmap.getHeight() + 60)) {
                    //y1[i2] = -random.nextInt(1000); // reset to new vertical position
                    //score += 1;
                    //onScoreListener.onScore(score);
                    Log.d("missile", "missile hit! ");
                    j=-200;
                }

                // if vertical missile hits alien 0
                if (java.lang.Math.abs(j - 185) * 2  < (alienbitmap.getWidth() + 60) && java.lang.Math.abs(j + 150 + screenHeight / 100 * 45 - (screenHeight / 100 * 95 - i[i1] - xbuggy2)) * 2  < (alienbitmap.getHeight() + 60)) {
                    //y1[i2] = -random.nextInt(1000); // reset to new vertical position
                    //score += 1;
                    //onScoreListener.onScore(score);
                    Log.d("missile", "missile hit! ");
                    j=-200;
                }


                // if horizontal missile hits alien 1, right now this won't happen
                if (java.lang.Math.abs(j - i[i1]) * 2  < (alienbitmap.getWidth() + 60) && java.lang.Math.abs(k +150+ screenHeight / 100 * 45 - (float) (screenHeight * 0.61)) * 2  < (alienbitmap.getHeight() + 60)) {
                    //y1[i2] = -random.nextInt(1000); // reset to new vertical position
                    //score += 1;
                    //onScoreListener.onScore(score);
                    Log.d("missile", "missile hit! ");
                    j=-200;
                }

                // if vertical missile hits alien 1
                if (java.lang.Math.abs(o + 10 - 185) * 2  < (alienbitmap.getWidth() + 60) && java.lang.Math.abs(l + screenHeight / 100 * 25 - (screenHeight / 100 * 95 - i[i1] - xbuggy2)) * 2  < (alienbitmap.getHeight() + 60)) {
                    //y1[i2] = -random.nextInt(1000); // reset to new vertical position
                    //score += 1;
                    //onScoreListener.onScore(score);
                    Log.d("missile", "missile hit! ");
                    o=-200;
                }


                canvas.drawText("o", i[i1], (float) (screenHeight * 0.61), paint);
                canvas.drawText("o", 185, screenHeight / 100 * 95 - i[i1] - xbuggy2, paint);




                if (i1 == numberOfshots - 1 && i[i1] > screenWidth) {
                    if (numberOfshots > 0) numberOfshots--;
                    if (ind > 0) ind--;
                }
            }
            if (System.currentTimeMillis() - lastTurn >= 2000) {
                // Change direction here
                down = !down;
                lastTurn = System.currentTimeMillis();
            }

            if (System.currentTimeMillis() - lastTurn2 >= 7000) {
                // Change direction here
                down2 = !down2;
                lastTurn2 = System.currentTimeMillis();
            }

            canvas.drawBitmap(alienbitmap, j, k +150+ screenHeight / 100 * 45, paint);
            canvas.drawBitmap(alienbitmap2, o + 10, l + screenHeight / 100 * 25, paint);
            //canvas.drawBitmap(alienbitmap3, j+20, k+screenHeight / 100 * 5, paint);
            drawBackground(1);
            canvas.drawBitmap(bitmap, 50, (float) (screenHeight * 0.5) - xbuggy, paint);
            // Draw the foreground parallax

            for (int n = 0; n < numberOfshots; n++)
                i[n] = i[n] + 20;

            j = j + 10;
            o = o + 7;
            if (!down)
                k=k+2;
            else
                k=k-2;

            if (!down2)
                l++;
            else
                l--;

            // Unlock and draw the scene
            ourHolder.unlockCanvasAndPost(canvas);
        }
    }

    // Clean up our thread if the game is stopped
    public void pause() {
        running = false;
        try {
            gameThread.join();
        } catch (InterruptedException e) {
            // Error
        }
    }

    // Make a new thread and start it
    // Execution moves to our run method
    public void resume() {
        running = true;
        gameThread = new Thread(this);
        gameThread.start();
    }

    private void drawBackground(int position) {

        // Make a copy of the relevant background
        Background bg = backgrounds.get(position);

        // define what portion of images to capture and
        // what coordinates of screen to draw them at

        // For the regular bitmap
        Rect fromRect1 = new Rect(0, 0, bg.width - bg.xClip, bg.height);
        Rect toRect1 = new Rect(bg.xClip, bg.startY, bg.width, bg.endY);

        // For the reversed background
        Rect fromRect2 = new Rect(bg.width - bg.xClip, 0, bg.width, bg.height);
        Rect toRect2 = new Rect(0, bg.startY, bg.xClip, bg.endY);

        //draw the two background bitmaps
        if (!bg.reversedFirst) {
            canvas.drawBitmap(bg.bitmap, fromRect1, toRect1, paint);
            canvas.drawBitmap(bg.bitmapReversed, fromRect2, toRect2, paint);
        } else {
            canvas.drawBitmap(bg.bitmap, fromRect2, toRect2, paint);
            canvas.drawBitmap(bg.bitmapReversed, fromRect1, toRect1, paint);
        }
    }

    // Because we call this from onTouchEvent, this code will be executed for both
    // normal touch events and for when the system calls this using Accessibility
    @Override
    public boolean performClick() {
        super.performClick();
        launchMissile();
        return true;
    }

    private void launchMissile() {
        i[ind] = 350;
        ind++;
        xbuggy2 = 0;
        shoot = true;
    }

    // event listener for when the user touches the screen
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean gameOver = false;
        //if (paused) {
        //   paused = false;
        //}
        int action = MotionEventCompat.getActionMasked(event);
        int coordX = (int) event.getX();
        int coordY = (int) event.getY();
        Log.d("coordY", "coordY " + coordY);
        if (coordX < 220 && xbuggy == 0 && action == MotionEvent.ACTION_MOVE) {
            jump = true;
            shoot = false;
            lastTurn3 = System.currentTimeMillis();
            return true; // do nothing
        }

        if (coordX > 219 && action == MotionEvent.ACTION_DOWN) {
            numberOfshots++;
            performClick();
            return true;
        }
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

Update

I have started to encapsulate the logic for the aliens according to the following.

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class Alien {
    public Alien(){}
    public Alien(Context context, String name) {
        setAlienResID(context.getResources().getIdentifier("object3_hdpi",
                "drawable", context.getPackageName()));
        setAlienbitmap(BitmapFactory.decodeResource(context.getResources(), this.getAlienResID()));
    }
    public int getAlienResID() {
        return alienResID;
    }

    public void setAlienResID(int alienResID) {
        this.alienResID = alienResID;
    }

    public Bitmap getAlienbitmap() {
        return alienbitmap;
    }

    public void setAlienbitmap(Bitmap alienbitmap) {
        this.alienbitmap = alienbitmap;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    int alienResID;
    Bitmap alienbitmap;
    int width;
    int height;
}


public class AttackingAlien extends Alien {
    public AttackingAlien(Context context, String name) {
        super(context, name);
    }
}
Run Code Online (Sandbox Code Playgroud)

Update 2

I have changed the strategy. Now I am drawing a spaceship which is going to bomb the moon buggy.

在此输入图像描述

The relevant code is

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v4.view.MotionEventCompat;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.ArrayList;
import java.util.List;

public class ParallaxView extends SurfaceView implements Runnable {

    List<Background> backgrounds;

    private volatile boolean running;
    private Thread gameThread = null;

    // For drawing
    private Paint paint;
    private Canvas canvas;
    private SurfaceHolder ourHolder;

    // Holds a reference to the Activity
    Context context;

    // Control the fps
    long fps = 60;

    // Screen resolution
    int screenWidth;
    int screenHeight;

    private void update() {
        // Update all the background positions
        for (Background bg : backgrounds) {
            bg.update(fps);
        }

    }

    ParallaxView(Context context, int screenWidth, int screenHeight) {
        super(context);

        this.context = context;

        this.screenWidth = screenWidth;
        this.screenHeight = screenHeight;

        // Initialize our drawing objects
        ourHolder = getHolder();
        paint = new Paint();

        // Initialize our array list
        backgrounds = new ArrayList<>();

        //load the background data into the Background objects and
        // place them in our GameObject arraylist

        backgrounds.add(new Background(
                this.context,
                screenWidth,
                screenHeight,
                "bg", 0, 120, 50));

        backgrounds.add(new Background(
                this.context,
                screenWidth,
                screenHeight,
                "grass", 70, 110, 200));

        // Add more backgrounds here

    }

    @Override
    public void run() {

        while (running) {
            long startFrameTime = System.currentTimeMillis();

            update();
            if (j > 2000) {
                j = -50;
                k = 0;
            }
            if (o > 2000) {
                o = -50;
                l = 0;
            }
            draw();

            // Calculate the fps this frame
            long timeThisFrame = System.currentTimeMillis() - startFrameTime;
            if (timeThisFrame >= 1) {
                fps = 1000 / timeThisFrame;
            }
        }
    }

    int numberOfshots = 1;
    int[] i = new int[200];
    int j = 0;
    int k = 0;
    int l = 0;
    int m = 0;
    int o = 0;
    boolean down = true;
    long lastTurn = System.currentTimeMillis();
    int xbuggy = 0;
    int xbuggy2 = 0;
    boolean down2 = true;
    long lastTurn2 = System.currentTimeMillis();
    long lastTurn3 = System.currentTimeMillis();
    long lastTurn4 = System.currentTimeMillis();
    boolean jump = false;
    boolean shoot = false;
    int ind = 0;
    int numberOfAlienshots = 1;
    int missileOffSetY = 0;
    private void draw() {

        if (ourHolder.getSurface().isValid()) {
            //First we lock the area of memory we will be drawing to
            canvas = ourHolder.lockCanvas();
            if (jump) {
                xbuggy = xbuggy + 4;
            }
            if (shoot) {
                xbuggy2 = xbuggy2 + 4;
            }



            if (System.currentTimeMillis() - lastTurn4 >= 2000) {
                // Change direction here
               //jump = false;
                lastTurn4 = System.currentTimeMillis();
                missileOffSetY = 0;
            }

            if (System.currentTimeMillis() - lastTurn3 >= 1000) {
                // Change direction here
                jump = false;
                lastTurn3 = System.currentTimeMillis();
                xbuggy = 0;
            }
            //draw a background color
            canvas.drawColor(Color.argb(255, 0, 0, 0));

            // Draw the background parallax
            drawBackground(0);

            // Draw the rest of the game
            paint.setTextSize(60);
            paint.setColor(Color.argb(255, 255, 255, 255));

            //canvas.drawText("MOONPATROL3000", 350, screenHeight / 100 * 5, paint);

            int resID = context.getResources().getIdentifier("vehicle",
                    "drawable", context.getPackageName());

            Alien alien1 = new AttackingAlien(context, "right_side_hdpi");
            Alien alien2 = new AttackingAlien(context, "object2_hdpi");
            Alien alien3 = new AttackingAlien(context, "object1_hdpi");

            int alienResID = context.getResources().getIdentifier("right_side_hdpi",
                    "drawable", context.getPackageName());

            int alienResID2 = context.getResources().getIdentifier("right_side_hdpi",
                    "drawable", context.getPackageName());

            int alienResID3 = context.getResources().getIdentifier("right_side_hdpi",
                    "drawable", context.getPackageName());

            // Load the bitmap using the id
            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resID);
            Bitmap alienbitmap = BitmapFactory.decodeResource(context.getResources(), alienResID);
            Bitmap alienbitmap2 = BitmapFactory.decodeResource(context.getResources(), alienResID2);
            Bitmap alienbitmap3 = BitmapFactory.decodeResource(context.getResources(), alienResID3);

            //paint.setTextSize(220);

            //for (int i1 = 0; i1 < numberOfAlienshots; i1++) {
            if (missileOffSetY < 300) {
                canvas.drawText("|", o + 10 + alienbitmap2.getWidth() / 2, l + screenHeight / 100 * 25 + 75 + missileOffSetY, paint);

                missileOffSetY = missileOffSetY + 10;
            }

            for (int i1 = 0; i1 < numberOfshots; i1++) {


                // if horizontal missile hits alien 0
                if (java.lang.Math.abs(j - i[i1]) * 2  < (alien1.getWidth() + 60) && java.lang.Math.abs(k +150+ screenHeight / 100 * 45 - (float) (screenHeight * 0.61)) * 2  < (alien1.getHeight() + 60)) {
                    //y1[i2] = -random.nextInt(1000); // reset to new vertical position
                    //score += 1;
                    //onScoreListener.onScore(score);
                    Log.d("missile", "missile hit! ");
                    j=-200;
                }

                // if vertical missile hits alien 0
                if (java.lang.Math.abs(j - 185) * 2  < (alienbitmap.getWidth() + 60) && java.lang.Math.abs(j + 150 + screenHeight / 100 * 45 - (screenHeight / 100 * 95 - i[i1] - xbuggy2)) * 2  < (alienbitmap.getHeight() + 60)) {
                    j=-200;
                }


                // if horizontal missile hits alien 1, right now this won't happen
                if (java.lang.Math.abs(j - i[i1]) * 2  < (alienbitmap.getWidth() + 60) && java.lang.Math.abs(k +150+ screenHeight / 100 * 45 - (float) (screenHeight * 0.61)) * 2  < (alienbitmap.getHeight() + 60)) {
                    j=-200;
                }

                // if vertical missile hits alien 1
                if (java.lang.Math.abs(o + 10 - 185) * 2  < (alienbitmap.getWidth() + 60) && java.lang.Math.abs(l + screenHeight / 100 * 25 - (screenHeight / 100 * 95 - i[i1] - xbuggy2)) * 2  < (alienbitmap.getHeight() + 60)) {
                    o=-200;
                }


                canvas.drawText("o", i[i1], (float) (screenHeight * 0.61), paint);
                canvas.drawText("o", 185, screenHeight / 100 * 95 - i[i1] - xbuggy2, paint);




                if (i1 == numberOfshots - 1 && i[i1] > screenWidth) {
                    if (numberOfshots > 0) numberOfshots--;
                    if (ind > 0) ind--;
                }
            }
            if (System.currentTimeMillis() - lastTurn >= 2000) {
                // Change direction here
                down = !down;
                lastTurn = System.currentTimeMillis();
            }

            if (System.currentTimeMillis() - lastTurn2 >= 7000) {
                // Change direction here
                down2 = !down2;
                lastTurn2 = System.currentTimeMillis();
            }

          //  canvas.drawBitmap(alien1.getAlienbitmap(), j, k +150+ screenHeight / 100 * 45, paint);
            canvas.drawBitmap(alienbitmap2, o + 10, l + screenHeight / 100 * 25, paint);
            //canvas.drawBitmap(alienbitmap3, j+20, k+screenHeight / 100 * 5, paint);
            drawBackground(1);
            canvas.drawBitmap(bitmap, 50, (float) (screenHeight * 0.5) - xbuggy, paint);
            // Draw the foreground parallax

            for (int n = 0; n < numberOfshots; n++)
                i[n] = i[n] + 20;

            j = j + 10;
            o = o + 7;
            if (!down)
                k=k+2;
            else
                k=k-2;

            if (!down2)
                l++;
            else
                l--;

            // Unlock and draw the scene
            ourHolder.unlockCanvasAndPost(canvas);
        }
    }

    // Clean up our thread if the game is stopped
    public void pause() {
        running = false;
        try {
            gameThread.join();
        } catch (InterruptedException e) {
            // Error
        }
    }

    // Make a new thread and start it
    // Execution moves to our run method
    public void resume() {
        running = true;
        gameThread = new Thread(this);
        gameThread.start();
    }

    private void drawBackground(int position) {

        // Make a copy of the relevant background
        Background bg = backgrounds.get(position);

        // define what portion of images to capture and
        // what coordinates of screen to draw them at

        // For the regular bitmap
        Rect fromRect1 = new Rect(0, 0, bg.width - bg.xClip, bg.height);
        Rect toRect1 = new Rect(bg.xClip, bg.startY, bg.width, bg.endY);

        // For the reversed background
        Rect fromRect2 = new Rect(bg.width - bg.xClip, 0, bg.width, bg.height);
        Rect toRect2 = new Rect(0, bg.startY, bg.xClip, bg.endY);

        //draw the two background bitmaps
        if (!bg.reversedFirst) {
            canvas.drawBitmap(bg.bitmap, fromRect1, toRect1, paint);
            canvas.drawBitmap(bg.bitmapReversed, fromRect2, toRect2, paint);
        } else {
            canvas.drawBitmap(bg.bitmap, fromRect2, toRect2, paint);
            canvas.drawBitmap(bg.bitmapReversed, fromRect1, toRect1, paint);
        }
    }

    // Because we call this from onTouchEvent, this code will be executed for both
    // normal touch events and for when the system calls this using Accessibility
    @Override
    public boolean performClick() {
        super.performClick();
        launchMissile();
        return true;
    }

    private void launchMissile() {
        i[ind] = 350; // what does it do?
        ind++;
        xbuggy2 = 0;
        shoot = true;
    }

    // event listener for when the user touches the screen
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean gameOver = false;
        //if (paused) {
        //   paused = false;
        //}
        int action = MotionEventCompat.getActionMasked(event);
        int coordX = (int) event.getX();
        int coordY = (int) event.getY();
        Log.d("coordY", "coordY " + coordY);
        if (coordX < 220 && xbuggy == 0 && action == MotionEvent.ACTION_MOVE) {
            jump = true;
            shoot = false;
            lastTurn3 = System.currentTimeMillis();
            return true; // do nothing
        }

        if (coordX > 219 && action == MotionEvent.ACTION_DOWN) {
            numberOfshots++;
            performClick();
            return true;
        }
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

Tat*_*ize 3

您最大的错误似乎是在绘图例程中分配 4 个位图。在 onCreate 中分配这些位图,然后简单地调用您初始化 onCreate() 的全局位图。这将解决你的问题。您可以将它们绘制在它们的位置。

    private void draw() {
        Alien alien1 = new AttackingAlien(context, "right_side_hdpi");
        Alien alien2 = new AttackingAlien(context, "object2_hdpi");
        Alien alien3 = new AttackingAlien(context, "object1_hdpi");
Run Code Online (Sandbox Code Playgroud)

您分配了一堆内存对象来调用上下文并扩展可绘制对象以及一堆其他工作。你可以使用上一次使用的相同外星人。

        int alienResID = context.getResources().getIdentifier("right_side_hdpi",
                "drawable", context.getPackageName());

        int alienResID2 = context.getResources().getIdentifier("right_side_hdpi",
                "drawable", context.getPackageName());

        int alienResID3 = context.getResources().getIdentifier("right_side_hdpi",
                "drawable", context.getPackageName());
Run Code Online (Sandbox Code Playgroud)

外星人的 ID 与上一次相比没有变化。

        // Load the bitmap using the id
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resID);
        Bitmap alienbitmap = BitmapFactory.decodeResource(context.getResources(), alienResID);
        Bitmap alienbitmap2 = BitmapFactory.decodeResource(context.getResources(), alienResID2);
        Bitmap alienbitmap3 = BitmapFactory.decodeResource(context.getResources(), alienResID3);
Run Code Online (Sandbox Code Playgroud)

这些是与上一个刻度相同的位图,并且位图很大,从资源中获取它们很慢,并且您每次刻度都在执行此操作。

    }
}
Run Code Online (Sandbox Code Playgroud)

大多数其他内容都会在这里或那里减少半毫秒,但这里可能会让你达到正确的 FPS 水平。


别担心,尽管你还有其他人。

你的大部分问题都可以通过加快例程的速度来解决。现在是时候说“你做错了”。执行此操作的典型且正确的方法是每 17 毫秒左右进行一次循环。其余时间暂停。有些错误是显而易见的。

您最大的错误似乎是在绘图例程中分配 4 个位图。

但是,绘制例程进行绘制。你在画布上画出需要发生的事情,仅此而已。你不分配任何东西,也不膨胀任何东西,你获取东西所在位置的数字,并在该位置绘制你已经加载到内存中的东西。

您在绘制例程中勾选并进行碰撞检测,并为此分配一堆对象,而无论如何它们都必须在瞬间被扔进木材削片机中。

您不应该在初始化之外或在新外星人存在的特殊情况下创建任何对象。您不应该在绘图例程中的任何地方使用“new”。曾经。

您正在使用蛮力进行碰撞检测,但最终不会。找到一个你喜欢的加速结构并使用它。对于 1 个对象来说,这并不重要。

不要调用某些外星人类,虽然它看起来更漂亮,但您需要外星人边界框的原始数字。然后,您希望将它们保留在某种允许快速引用它们的结构中(您需要在 17 毫秒以内获得帧)。调用一堆宽度命令实际上并没有多大帮助,即使它们更改了大小也只是更改了碰撞框的数字。这些方法为您提供了一些很好的数据结构,例如拥有一个排序的命中框数组,您可以对它们进行二分搜索,并通过对结构的 log(n) 更新来查找移动的对象是否在 log(n) 时间内命中该对象,或者遍历轴对齐边界框树的一些不同方法。这是您最终需要的东西,但只要您保持简单,即使没有它也可能起作用。不过,说实话,这只是你的位图造成了大部分速度减慢。

还有很多其他基本问题,例如将边界框放在 if 语句内,而不是制作两个额外的矩形。但还有其他问题,比如制作矩形!您可以使用实际位置来调用绘图,而不是分配一些大对象来调用函数。只需用数字调用该函数即可。


您应该制定一个例程,根据物品的位置为您进行绘图。它应该能够在不到 17 毫秒的时间内绘制所需的所有内容。如果不能,您将永远无法达到所需的 60 fps。所以在这种情况下,少画一些东西,并做得更好。该空间背景需要是位图吗?您可以为天空绘制一堆点,并相应地调整图形吗?你的绘制例程永远不会分配任何东西。时期。如果您需要分配某些内容,则应该在 init 期间进行。分配是你存在的祸根。

你的触摸会更新物品的位置。人工智能/物理勾选还会更新事物的位置并检查是否存在共谋。绘制仅根据内存中的位置和内容绘制内容。

在其自己的线程中运行更新位置刻度。您只需要处理读取和写入相同数据的并发位。它只需要同步绘制数据的变化数据读取,因此将这些部分(触摸中的位置更新、tick 中的位置更新以及获取绘制例程本身的位置)放入具有相同对象的同步块中。