Java – improving the movement of aliens in space

I wrote a mini Android game scene inspired by space invaders and moon patrol Aliens can be photographed horizontally (see above)

Aliens can also be shot vertically (see below)

But adding aliens does not "expand". For example, it will be very difficult for 15 Aliens to move in all possible collisions The original space invaders and the moon patrol solved this problem. Is it possible to develop a strategy different from the one I used? The exact movement of aliens doesn't matter, it's just "interesting"

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",120,50));

        backgrounds.add(new Background(
                this.context,"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));

            // Draw the background parallax
            drawBackground(0);

            // Draw the rest of the game
            paint.setTextSize(60);
            paint.setColor(Color.argb(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",context.getPackageName());

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

            int alienResID3 = context.getResources().getIdentifier("object1_hdpi",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,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,bg.height);
        Rect toRect2 = new Rect(0,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,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;
    }
}

to update

I have begun to encapsulate the logic of 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",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);
    }
}

Update 2

I changed my strategy Now I'm drawing a spaceship that will bomb the lunar rover

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,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,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",context.getPackageName());

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

            int alienResID3 = context.getResources().getIdentifier("right_side_hdpi",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",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(),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;
    }
}

Solution

Your biggest mistake seems to be allocating 4 bitmaps in the drawing routine Allocate these bitmaps in oncreate and simply call the global bitmaps you initialized on oncreate() This will solve your problem You can draw them where they are

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");

You allocate a bunch of memory objects to call the context and extend drawable and a bunch of other work You may have just used the same alien

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

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

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

Alien ID has not changed from the previous tick

// 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);

These are the same bitmaps as the last tick. Bitmaps are huge. It's slow to get them from resources, and you're doing every tick

}
}

Most other things will scrape away here and there for half an hour, but this may get you to the right FPS baseball field

Don't worry, although you have others

Solve most of your problems by making routines faster It's time to say that you did wrong The typical and correct way to do this is to cycle every 17 ms or so The rest of the time was suspended Some mistakes are obvious

Your biggest mistake seems to be allocating 4 bitmaps in the drawing routine

However, the lottery program will only draw You draw what needs to happen on the canvas, that's it You don't allocate anything that you don't exaggerate. You take out the numbers you have and draw what you've loaded in the memory of that location

You are checking and doing collision detection in the drawing program, and assigning a pile of objects to it when they must be thrown into the woodcutter in a moment

You should not create any objects outside of initialization or in special cases where new aliens exist You should not use "new" anywhere in the drawing program Forever

You're using brute force for collision detection, and you don't Find the beautiful acceleration structure you like and use it For an object, it doesn't matter

Don't call some aliens, although it looks more beautiful, you want the original number of alien boundary box Then, you want to keep them in a structure that allows them to be referenced very quickly (you need to use the frame in less than 17 ms) Invoking a bunch of width commands is not very useful, even if they change size only hit@R_804_2419 @Quantity of These methods allow you to provide some good structures for data, such as an array with sorted hit boxes. You can perform binary search on it and find out whether the moving object hits the object by log (n) updating the structure within log (n) time, or some methods for traversing the axis aligned bounding box tree This is the last thing you need, but as long as you keep it simple, you can't have this However, it's actually just your bitmap that makes most of the deceleration there

There are many other basic problems, such as putting a bounding box in an IF statement instead of making two other rectangles But there are other problems, such as making rectangles! Instead of calling a function with a large ass object, you call the drawing with the actual location Simply call the function with a number

You should have a routine to draw for you according to the position of things It should be able to draw everything needed in less than 17 Ms If it doesn't, you won't reach the 60fps you need to hit Therefore, in this case, reduce some things and do better Does the space background need to be a bitmap? Can you draw a bunch of points for the sky and adjust the graphics accordingly Your drawing program never assigns anything Period If you need to allocate what it should be during init Distribution is the bane of your survival

Your touch updates the location of things AI / Physics check also updates the location of things and checks for collusion Draw draws the content only according to the location and content in memory

Run the update location tag in your own thread You only need to handle concurrent bits that read and write the same data It only needs to synchronize the change data reading of the drawing data, so throw these parts in the synchronization block with the same object (touch position update, check position update, and get the position of the drawing routine itself)

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>