android airplane war

  1. package com.pbicv.ddpx.game;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.graphics.RectF;
    import android.text.TextPaint;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    import com.pbicv.ddpx.R;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    
    public class GameView extends View {
    
        private paint paint;
        private Paint textPaint;
        private CombatAircraft combatAircraft = null;
        private List<Sprite> sprites = new ArrayList<Sprite>();
        private List<Sprite> spritesNeedAdded = new ArrayList<Sprite>();
        //0:combatAircraft
        //1:explosion
        //2:yellowBullet
        //3:blueBullet
        //4:smallEnemyPlane
        //5:middleEnemyPlane
        //6:bigEnemyPlane
        //7:bombAward
        //8:bulletAward
        //9:pause1
        //10:pause2
        //11:bomb
        private List<Bitmap> bitmaps = new ArrayList<Bitmap>();
        private float density = getResources().getDisplayMetrics().density;//Screen density
        public static final int STATUS_GAME_STARTED = 1;//The game starts
        public static final int STATUS_GAME_PAUSED = 2; //Game paused
        public static final int STATUS_GAME_OVER = 3;//The game is over
        public static final int STATUS_GAME_DESTROYED = 4;//The game is destroyed
        private int status = STATUS_GAME_DESTROYED;//initially destroyed state
        private long frame = 0;//Total number of frames drawn
        private long score = 0; //Total score
        private float fontSize = 12; //Default font size, used to draw text in the upper left corner
        private float fontSize2 = 20;//Used to draw text in Dialog when Game Over
        private float borderSize = 2;//The border of Game Over’s Dialog
        private Rect continueRect = new Rect();//Rect of the "Continue" and "Restart" buttons
    
        //Variables related to touch events
        private static final int TOUCH_MOVE = 1;//Move
        private static final int TOUCH_SINGLE_CLICK = 2;//Click
        private static final int TOUCH_DOUBLE_CLICK = 3; //Double click
        //A click event is composed of two events, DOWN and UP. Assuming that the interval from down to up is less than 200 milliseconds, we consider a click event to have occurred.
        private static final int singleClickDurationTime = 200;
        //A double-click event is composed of two click events. If the time between the two click events is less than 300 milliseconds, we consider a double-click event to have occurred.
        private static final int doubleClickDurationTime = 300;
        private long lastSingleClickTime = -1;//The last time a click occurred
        private long touchDownTime = -1;//The moment the contact is pressed
        private long touchUpTime = -1;//The moment when the contact pops up
        private float touchX = -1;//x coordinate of the touch point
        private float touchY = -1;//Y coordinate of the touch point
    
        public GameView(Context context) {
            super(context);
            init(null, 0);
        }
    
        public GameView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(attrs, 0);
        }
    
        public GameView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init(attrs, defStyle);
        }
    
        private void init(AttributeSet attrs, int defStyle) {
            final TypedArray a = getContext().obtainStyledAttributes(
                    attrs, R.styleable.GameView, defStyle, 0);
            a.recycle();
            //Initialize paint
            paint = new Paint();
            paint.setStyle(Paint.Style.FILL);
            //Set textPaint, set to anti-aliasing, and bold
            textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FAKE_BOLD_TEXT_FLAG);
            textPaint.setColor(0xff000000);
            fontSize = textPaint.getTextSize();
            fontSize *= density;
            fontSize2 *= density;
            textPaint.setTextSize(fontSize);
            borderSize *= density;
        }
    
        public void start(int[] bitmapIds){
            destroy();
            for(int bitmapId : bitmapIds){
                Bitmap bitmap = BitmapFactory.decodeResource(getResources(), bitmapId);
                bitmaps.add(bitmap);
            }
            startWhenBitmapsReady();
        }
        
        private void startWhenBitmapsReady(){
            combatAircraft = new CombatAircraft(bitmaps.get(0));
            //Set the game to start state
            status = STATUS_GAME_STARTED;
            postInvalidate();
        }
        
        private void restart(){
            destroyNotRecyleBitmaps();
            startWhenBitmapsReady();
        }
    
        public void pause(){
            //Set the game to pause state
            status = STATUS_GAME_PAUSED;
        }
    
        private void resume(){
            //Set the game to running state
            status = STATUS_GAME_STARTED;
            postInvalidate();
        }
    
        private long getScore(){
            //Get game score
            return score;
        }
    
        /*----------------------------------draw---------------- ---------------------*/
    
        @Override
        protected void onDraw(Canvas canvas) {
            //We check at each frame whether the conditions for delayed triggering of the click event are met
            if(isSingleClick()){
                onSingleClick(touchX, touchY);
            }
    
            super.onDraw(canvas);
    
            if(status == STATUS_GAME_STARTED){
                drawGameStarted(canvas);
            }else if(status == STATUS_GAME_PAUSED){
                drawGamePaused(canvas);
            }else if(status == STATUS_GAME_OVER){
                drawGameOver(canvas);
            }
        }
    
        //Draw the game in running state
        private void drawGameStarted(Canvas canvas){
    
            drawScoreAndBombs(canvas);
    
            //When drawing for the first time, move the fighter to the bottom of the Canvas, in the center of the horizontal direction
            if(frame == 0){
                float centerX = canvas.getWidth() / 2;
                float centerY = canvas.getHeight() - combatAircraft.getHeight() / 2;
                combatAircraft.centerTo(centerX, centerY);
            }
    
            //Add spritesNeedAdded to sprites
            if(spritesNeedAdded.size() > 0){
                sprites.addAll(spritesNeedAdded);
                spritesNeedAdded.clear();
            }
    
            //Check the situation when the fighter runs in front of the bullet
            destroyBulletsFrontOfCombatAircraft();
    
            //Remove the destroyed Sprite before drawing
            removeDestroyedSprites();
    
            //Randomly add Sprite every 30 frames
            if(frame % 30 == 0){
                createRandomSprites(canvas.getWidth());
            }
            frame + + ;
    
            //Traverse sprites and draw enemy aircraft, bullets, rewards, and explosion effects
            Iterator<Sprite> iterator = sprites.iterator();
            while (iterator.hasNext()){
                Sprite s = iterator.next();
    
                if(!s.isDestroyed()){
                    //The destroy method may be called in the draw method of Sprite
                    s.draw(canvas, paint, this);
                }
    
                //Here we need to determine whether the Sprite was destroyed after executing the draw method.
                if(s.isDestroyed()){
                    //If the Sprite is destroyed, remove it from Sprites
                    iterator.remove();
                }
            }
    
            if(combatAircraft != null){
                //Finally draw the fighter
                combatAircraft.draw(canvas, paint, this);
                if(combatAircraft.isDestroyed()){
                    //If the fighter is hit and destroyed, the game is over
                    status = STATUS_GAME_OVER;
                }
                //By calling the postInvalidate() method, the View continues to render to achieve dynamic effects.
                postInvalidate();
            }
        }
    
        //Draw the game in paused state
        private void drawGamePaused(Canvas canvas){
            drawScoreAndBombs(canvas);
    
            //Call the Sprite's onDraw method instead of the draw method, so that the static Sprite can be rendered without letting the Sprite change its position.
            for(Sprites : sprites){
                s.onDraw(canvas, paint, this);
            }
            if(combatAircraft != null){
                combatAircraft.onDraw(canvas, paint, this);
            }
    
            //Draw Dialog and display score
            drawScoreDialog(canvas, "continue");
    
            if(lastSingleClickTime > 0){
                postInvalidate();
            }
        }
    
        //Draw the end state of the game
        private void drawGameOver(Canvas canvas){
            //After Game Over, only draw a pop-up window to display the final score
            drawScoreDialog(canvas, "restart");
    
            if(lastSingleClickTime > 0){
                postInvalidate();
            }
        }
    
        private void drawScoreDialog(Canvas canvas, String operation){
            int canvasWidth = canvas.getWidth();
            int canvasHeight = canvas.getHeight();
            //Storage original value
            float originalFontSize = textPaint.getTextSize();
            Paint.Align originalFontAlign = textPaint.getTextAlign();
            int originalColor = paint.getColor();
            Paint.Style originalStyle = paint.getStyle();
            /*
            W = 360
            w1 = 20
            w2 = 320
            buttonWidth = 140
            buttonHeight = 42
            H = 558
            h1 = 150
            h2 = 60
            h3 = 124
            h4 = 76
            */
            int w1 = (int)(20.0 / 360.0 * canvasWidth);
            int w2 = canvasWidth - 2 * w1;
            int buttonWidth = (int)(140.0 / 360.0 * canvasWidth);
    
            int h1 = (int)(150.0 / 558.0 * canvasHeight);
            int h2 = (int)(60.0 / 558.0 * canvasHeight);
            int h3 = (int)(124.0 / 558.0 * canvasHeight);
            int h4 = (int)(76.0 / 558.0 * canvasHeight);
            int buttonHeight = (int)(42.0 / 558.0 * canvasHeight);
    
            canvas.translate(w1, h1);
            //Draw background color
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(0xFFD7DDDE);
            Rect rect1 = new Rect(0, 0, w2, canvasHeight - 2 * h1);
            canvas.drawRect(rect1, paint);
            //Draw the border
            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(0xFF515151);
            paint.setStrokeWidth(borderSize);
            //paint.setStrokeCap(Paint.Cap.ROUND);
            paint.setStrokeJoin(Paint.Join.ROUND);
            canvas.drawRect(rect1, paint);
            //Draw text "Airplane Battle Score"
            textPaint.setTextSize(fontSize2);
            textPaint.setTextAlign(Paint.Align.CENTER);
            canvas.drawText("Final score", w2 / 2, (h2 - fontSize2) / 2 + fontSize2, textPaint);
            //Draw the horizontal line under "Aircraft Battle Score"
            canvas.translate(0, h2);
            canvas.drawLine(0, 0, w2, 0, paint);
            //Draw the actual score
            String allScore = String.valueOf(getScore());
            canvas.drawText(allScore, w2 / 2, (h3 - fontSize2) / 2 + fontSize2, textPaint);
            //Draw a horizontal line under the fraction
            canvas.translate(0, h3);
            canvas.drawLine(0, 0, w2, 0, paint);
            //Draw button border
            Rect rect2 = new Rect();
            rect2.left = (w2 - buttonWidth) / 2;
            rect2.right = w2 - rect2.left;
            rect2.top = (h4 - buttonHeight) / 2;
            rect2.bottom = h4 - rect2.top;
            canvas.drawRect(rect2, paint);
            //Draw text "continue" or "restart"
            canvas.translate(0, rect2.top);
            canvas.drawText(operation, w2 / 2, (buttonHeight - fontSize2) / 2 + fontSize2, textPaint);
            continueRect = new Rect(rect2);
            continueRect.left = w1 + rect2.left;
            continueRect.right = continueRect.left + buttonWidth;
            continueRect.top = h1 + h2 + h3 + rect2.top;
            continueRect.bottom = continueRect.top + buttonHeight;
    
            //Reset
            textPaint.setTextSize(originalFontSize);
            textPaint.setTextAlign(originalFontAlign);
            paint.setColor(originalColor);
            paint.setStyle(originalStyle);
        }
    
        //Draw the score in the upper left corner and the number of bombs in the lower left corner
        private void drawScoreAndBombs(Canvas canvas){
            //Draw the pause button in the upper left corner
            Bitmap pauseBitmap = status == STATUS_GAME_STARTED ? bitmaps.get(9) : bitmaps.get(10);
            RectF pauseBitmapDstRecF = getPauseBitmapDstRecF();
            float pauseLeft = pauseBitmapDstRecF.left;
            float pauseTop = pauseBitmapDstRecF.top;
            canvas.drawBitmap(pauseBitmap, pauseLeft, pauseTop, paint);
            //Draw the total score in the upper left corner
            float scoreLeft = pauseLeft + pauseBitmap.getWidth() + 20 * density;
            float scoreTop = fontSize + pauseTop + pauseBitmap.getHeight() / 2 - fontSize / 2;
            canvas.drawText(score + "", scoreLeft, scoreTop, textPaint);
    
            //Draw the lower left corner
            if(combatAircraft != null & amp; & amp; !combatAircraft.isDestroyed()){
                int bombCount = combatAircraft.getBombCount();
                if(bombCount > 0){
                    //Draw the bomb in the lower left corner
                    Bitmap bombBitmap = bitmaps.get(11);
                    float bombTop = canvas.getHeight() - bombBitmap.getHeight();
                    canvas.drawBitmap(bombBitmap, 0, bombTop, paint);
                    //Draw the number of bombs in the lower left corner
                    float bombCountLeft = bombBitmap.getWidth() + 10 * density;
                    float bombCountTop = fontSize + bombTop + bombBitmap.getHeight() / 2 - fontSize / 2;
                    canvas.drawText("X " + bombCount, bombCountLeft, bombCountTop, textPaint);
                }
            }
        }
    
        //Check the situation when the fighter runs in front of the bullet
        private void destroyBulletsFrontOfCombatAircraft(){
            if(combatAircraft != null){
                float aircraftY = combatAircraft.getY();
                List<Bullet> aliveBullets = getAliveBullets();
                for(Bullet bullet : aliveBullets){
                    //If the fighter runs in front of the bullet, then destroy the bullet
                    if(aircraftY <= bullet.getY()){
                        bullet.destroy();
                    }
                }
            }
        }
    
        //Remove the destroyed Sprite
        private void removeDestroyedSprites(){
            Iterator<Sprite> iterator = sprites.iterator();
            while (iterator.hasNext()){
                Sprite s = iterator.next();
                if(s.isDestroyed()){
                    iterator.remove();
                }
            }
        }
    
        //Generate random Sprite
        private void createRandomSprites(int canvasWidth){
            Sprite sprite = null;
            int speed = 2;
            //callTime represents the number of times the createRandomSprites method is called
            int callTime = Math.round(frame / 30);
            if((callTime + 1) % 25 == 0){
                //Send props and prizes
                if((callTime + 1) % 50 == 0){
                    //Send bomb
                    sprite = new BombAward(bitmaps.get(7));
                }
                else{
                    //Send double bullets
                    sprite = new BulletAward(bitmaps.get(8));
                }
            }
            else{
                //Send enemy aircraft
                int[] nums = {0,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,1,2};
                int index = (int)Math.floor(nums.length*Math.random());
                int type = nums[index];
                if(type==0){
                    //Small enemy plane
                    sprite = new SmallEnemyPlane(bitmaps.get(4));
                }
                else if(type == 1){
                    //hit enemy aircraft
                    sprite = new MiddleEnemyPlane(bitmaps.get(5));
                }
                else if(type == 2){
                    //Big enemy aircraft
                    sprite = new BigEnemyPlane(bitmaps.get(6));
                }
                if(type != 2){
                    if(Math.random() < 0.33){
                        speed = 4;
                    }
                }
            }
    
            if(sprite != null){
                float spriteWidth = sprite.getWidth();
                float spriteHeight = sprite.getHeight();
                float x = (float)((canvasWidth - spriteWidth)*Math.random());
                float y = -spriteHeight;
                sprite.setX(x);
                sprite.setY(y);
                if(sprite instanceof AutoSprite){
                    AutoSprite autoSprite = (AutoSprite)sprite;
                    autoSprite.setSpeed(speed);
                }
                addSprite(sprite);
            }
        }
    
        /*----------------------------------touch---------------- ------------------*/
    
        @Override
        public boolean onTouchEvent(MotionEvent event){
            //Get the event type we want by calling the resolveTouchType method
            //It should be noted that the resolveTouchType method will not return the TOUCH_SINGLE_CLICK type
            //We will call the isSingleClick method to detect whether the click event is triggered every time the onDraw method is executed.
            int touchType = resolveTouchType(event);
            if(status == STATUS_GAME_STARTED){
                if(touchType == TOUCH_MOVE){
                    if(combatAircraft != null){
                        combatAircraft.centerTo(touchX, touchY);
                    }
                }else if(touchType == TOUCH_DOUBLE_CLICK){
                    if(status == STATUS_GAME_STARTED){
                        if(combatAircraft != null){
                            //Double click will cause the fighter to use bombs
                            combatAircraft.bomb(this);
                        }
                    }
                }
            }else if(status == STATUS_GAME_PAUSED){
                if(lastSingleClickTime > 0){
                    postInvalidate();
                }
            }else if(status == STATUS_GAME_OVER){
                if(lastSingleClickTime > 0){
                    postInvalidate();
                }
            }
            return true;
        }
    
        //Synthesize the event type we want
        private int resolveTouchType(MotionEvent event){
            int touchType = -1;
            int action = event.getAction();
            touchX = event.getX();
            touchY = event.getY();
            if(action == MotionEvent.ACTION_MOVE){
                long deltaTime = System.currentTimeMillis() - touchDownTime;
                if(deltaTime > singleClickDurationTime){
                    //contact movement
                    touchType = TOUCH_MOVE;
                }
            }else if(action == MotionEvent.ACTION_DOWN){
                //contact pressed
                touchDownTime = System.currentTimeMillis();
            }else if(action == MotionEvent.ACTION_UP){
                //Contact pops up
                touchUpTime = System.currentTimeMillis();
                //Calculate the time difference between when the contact is pressed and when the contact pops up
                long downUpDurationTime = touchUpTime - touchDownTime;
                //If the time difference between pressing and lifting this contact is less than the time difference specified by a click event,
                //Then we think a click occurred
                if(downUpDurationTime <= singleClickDurationTime){
                    //Calculate the time difference between this click and the last click
                    long twoClickDurationTime = touchUpTime - lastSingleClickTime;
    
                    if(twoClickDurationTime <= doubleClickDurationTime){
                        //If the time difference between two clicks is less than the time difference between a double-click event execution,
                        //Then we think that a double-click event occurred
                        touchType = TOUCH_DOUBLE_CLICK;
                        //reset variables
                        lastSingleClickTime = -1;
                        touchDownTime = -1;
                        touchUpTime = -1;
                    }else{
                        //If a click event is formed this time, but a double-click event is not formed, then we will not trigger the click event formed this time.
                        //We should see if a second click event is formed again after doubleClickDurationTime milliseconds
                        //If a second click event is formed at that time, then we will synthesize a double-click event with this click event.
                        //Otherwise this click event will be triggered after doubleClickDurationTime milliseconds
                        lastSingleClickTime = touchUpTime;
                    }
                }
            }
            return touchType;
        }
    
        //Call this method in the onDraw method and check whether a click event occurs in each frame
        private boolean isSingleClick(){
            boolean singleClick = false;
            //Let's check whether the last click event meets the conditions for triggering a click event after doubleClickDurationTime milliseconds.
            if(lastSingleClickTime > 0){
                //Calculate the time difference between the current moment and the last click event
                long deltaTime = System.currentTimeMillis() - lastSingleClickTime;
    
                if(deltaTime >= doubleClickDurationTime){
                    //If the time difference exceeds the time difference required for a double-click event,
                    //Then delay the click event that should have occurred before triggering at this moment
                    singleClick = true;
                    //reset variables
                    lastSingleClickTime = -1;
                    touchDownTime = -1;
                    touchUpTime = -1;
                }
            }
            return singleClick;
        }
    
        private void onSingleClick(float x, float y){
            if(status == STATUS_GAME_STARTED){
                if(isClickPause(x, y)){
                    //pause button clicked
                    pause();
                }
            }else if(status == STATUS_GAME_PAUSED){
                if(isClickContinueButton(x, y)){
                    //The "Continue" button was clicked
                    resume();
                }
            }else if(status == STATUS_GAME_OVER){
                if(isClickRestartButton(x, y)){
                    //The "Restart" button was clicked
                    restart();
                }
            }
        }
    
        //Whether the pause button in the upper left corner is clicked
        private boolean isClickPause(float x, float y){
            RectF pauseRecF = getPauseBitmapDstRecF();
            return pauseRecF.contains(x, y);
        }
    
        //Whether you clicked "Continue" in the paused state
        private boolean isClickContinueButton(float x, float y){
            return continueRect.contains((int)x, (int)y);
        }
    
        //Whether the "Restart" button in the GAME OVER state has been clicked
        private boolean isClickRestartButton(float x, float y){
            return continueRect.contains((int)x, (int)y);
        }
    
        private RectF getPauseBitmapDstRecF(){
            Bitmap pauseBitmap = status == STATUS_GAME_STARTED ? bitmaps.get(9) : bitmaps.get(10);
            RectF recF = new RectF();
            recF.left = 15 * density;
            recF.top = 15 * density;
            recF.right = recF.left + pauseBitmap.getWidth();
            recF.bottom = recF.top + pauseBitmap.getHeight();
            return recF;
        }
    
        /*----------------------------------destroy---------------- ------------------*/
        
        private void destroyNotRecyleBitmaps(){
            //Set the game to destruction state
            status = STATUS_GAME_DESTROYED;
    
            //reset frame
            frame = 0;
    
            //reset score
            score = 0;
    
            //Destroy fighter
            if(combatAircraft != null){
                combatAircraft.destroy();
            }
            combatAircraft = null;
    
            //Destroy enemy aircraft, bullets, rewards, explosions
            for(Sprites : sprites){
                s.destroy();
            }
            sprites.clear();
        }
    
        public void destroy(){
            destroyNotRecyleBitmaps();
    
            //Release Bitmap resources
            for(Bitmap bitmap : bitmaps){
                bitmap.recycle();
            }
            bitmaps.clear();
        }
    
        /*----------------------------------public methods--------------- ------------------*/
    
        //Add Sprite to Sprites
        public void addSprite(Sprite sprite){
            spritesNeedAdded.add(sprite);
        }
    
        //Add score
        public void addScore(int value){
            score + = value;
        }
    
        public int getStatus(){
            return status;
        }
    
        public float getDensity(){
            return density;
        }
    
        public Bitmap getYellowBulletBitmap(){
            return bitmaps.get(2);
        }
    
        public Bitmap getBlueBulletBitmap(){
            return bitmaps.get(3);
        }
    
        public Bitmap getExplosionBitmap(){
            return bitmaps.get(1);
        }
    
        //Get active enemy aircraft
        public List<EnemyPlane> getAliveEnemyPlanes(){
            List<EnemyPlane> enemyPlanes = new ArrayList<EnemyPlane>();
            for(Sprites : sprites){
                if(!s.isDestroyed() & amp; & amp; s instanceof EnemyPlane){
                    EnemyPlane sprite = (EnemyPlane)s;
                    enemyPlanes.add(sprite);
                }
            }
            return enemyPlanes;
        }
    
        //Get the active bomb reward
        public List<BombAward> getAliveBombAwards(){
            List<BombAward> bombAwards = new ArrayList<BombAward>();
            for(Sprites : sprites){
                if(!s.isDestroyed() & amp; & amp; s instanceof BombAward){
                    BombAward bombAward = (BombAward)s;
                    bombAwards.add(bombAward);
                }
            }
            return bombAwards;
        }
    
        //Get the active bullet reward
        public List<BulletAward> getAliveBulletAwards(){
            List<BulletAward> bulletAwards = new ArrayList<BulletAward>();
            for(Sprites : sprites){
                if(!s.isDestroyed() & amp; & amp; s instanceof BulletAward){
                    BulletAward bulletAward = (BulletAward)s;
                    bulletAwards.add(bulletAward);
                }
            }
            return bulletAwards;
        }
    
        //Get the active bullet
        public List<Bullet> getAliveBullets(){
            List<Bullet> bullets = new ArrayList<Bullet>();
            for(Sprites : sprites){
                if(!s.isDestroyed() & amp; & amp; s instanceof Bullet){
                    Bullet bullet = (Bullet)s;
                    bullets.add(bullet);
                }
            }
            return bullets;
        }
    }

    The above code uses Java code to complete various logics in the aircraft battle.

  2. The following are some screenshots of the aircraft battle:

This is a very simple Android game. Friends in need can chat with me privately!