Android Canvas打飛機之主角秀

上一篇講過游戲背景圖的加載以及場景運動效果,如果還需要了解的請<a href="http://www.lxweimin.com/p/a87a9ed6a8b2">移駕這里</a>
今天要研究的是游戲主角戰機的運動以及邏輯的實現。

1.創建一個主角的類DrawPlayer。

package com.tangyx.game.holder;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;

import com.tangyx.game.R;
import com.tangyx.game.util.BitmapUtils;
import com.tangyx.game.util.ScreenUtils;
import com.tangyx.game.util.SizeUtils;

/**
 * Created by tangyx on 2016/12/22.
 *
 */

public class DrawPlayer extends DrawGame {
    /**
     * 主角
     */
    private Bitmap mPlayer;
    private float mPlayerX;
    private float mPlayerY;
    /**
     * 主角的控制位置
     */
    private Bitmap mCollect;
    private float mCollectX;
    private float mCollectY;
    private int mCollectCount;
    private Paint mCollectPaint;
    /**
     * 尾氣噴氣
     */
    private Bitmap mPlayerBlow;
    private float mSpeedAngle=0.05f;
    private float mBlowAngle = 1;
    private Matrix mBlowMatrix;

    public DrawPlayer(Context context,int player) {
        super(context,player);
    }

    @Override
    void initialize(Object... objects) {
        mPlayer = BitmapUtils.ReadBitMap(getContext(), (Integer) objects[0]);
        int wh = SizeUtils.dp2px(getContext(),20);
        mPlayer = BitmapUtils.getBitmap(mPlayer,wh,wh);
        mPlayerBlow = BitmapUtils.ReadBitMap(getContext(), R.drawable.playblow0);
        mPlayerBlow = BitmapUtils.getBitmap(mPlayerBlow,wh,wh);
        mCollect = BitmapUtils.ReadBitMap(getContext(),R.drawable.collect);
        wh = SizeUtils.dp2px(getContext(),30);
        mCollect = BitmapUtils.getBitmap(mCollect,wh,wh);
        int screenW = ScreenUtils.getScreenWidth(getContext());
        int screenH = ScreenUtils.getScreenHeight(getContext());
        //初始化戰機的位置
        mPlayerX = screenW/2-mPlayer.getWidth()/2;
        mPlayerY = screenH-mPlayer.getHeight()-screenH/10;
        mCollectX = screenW/2-mCollect.getWidth()/2;
        mCollectY = mPlayerY+mPlayer.getHeight()+mCollect.getHeight()/2;
        mBlowMatrix = new Matrix();
        mCollectPaint = new Paint();
        mCollectPaint.setAntiAlias(true);
    }

    @Override
    void onDraw(Canvas canvas) {
        mPaint.setAlpha(255);
        canvas.drawBitmap(mPlayer,mPlayerX,mPlayerY,mPaint);
        canvas.drawBitmap(getBlowAnimation(), (mPlayerX-mPlayerBlow.getWidth()/4),mPlayerY+mPlayerBlow.getHeight()/1.5f,mPaint);
    }

    /**
     * 尾氣噴氣動畫
     */
    private Bitmap getBlowAnimation(){
        mBlowAngle += mSpeedAngle;
        float sx =1.5f;
        float sy = mBlowAngle;
        mBlowMatrix.reset();
        mBlowMatrix.postScale(sx,sy);
        if(mBlowAngle>=1.2||mBlowAngle<1){
            mSpeedAngle=-mSpeedAngle;
        }
        return Bitmap.createBitmap(mPlayerBlow,0,0,mPlayerBlow.getWidth(),mPlayerBlow.getHeight(),mBlowMatrix,true);
    }

    /**
     * 繪制操作的位置按鈕
     */
    public void onDrawCollect(Canvas canvas,String text){
        if(mCollectCount==(Integer.MAX_VALUE-1)){
            mCollectCount=0;
        }
        mCollectPaint.setTextSize(20f);
        mCollectCount++;
        if(mCollectCount%2==0){
            mCollectPaint.setAlpha(0);
        }else{
            mCollectPaint.setAlpha(255);
        }
        mCollectX = mPlayerX-(mCollect.getWidth()-mPlayer.getWidth())/2;
        mCollectY = mPlayerY+mPlayer.getHeight()+mCollect.getHeight()/2;
        canvas.drawBitmap(mCollect,mCollectX,mCollectY,mCollectPaint);
        String fire = getContext().getString(R.string.fire);
        Rect rect = getTextRect(fire,mCollectPaint);
        float tx = mCollectX+(mCollect.getWidth()-rect.width())/2;
        float ty = mCollectY+mCollect.getHeight()/2+rect.height()/2;
        //點擊這個地方游戲繼續
        canvas.drawText(fire, tx, ty, mCollectPaint);
        int w = ScreenUtils.getScreenWidth(getContext());
        int h = ScreenUtils.getScreenHeight(getContext());
        mPaint.setTextSize(SizeUtils.sp2px(getContext(),20));
        //游戲暫停提示語
        rect = getTextRect(text,mPaint);
        canvas.drawText(text,(w-rect.width())/2 ,h/3, mPaint);
    }

    @Override
    void updateGame() {

    }

    public void setPlayerX(float mPlayerX) {
        this.mPlayerX = mPlayerX-mPlayer.getWidth()/1.5f;
    }

    public void setPlayerY(float mPlayerY) {
        this.mPlayerY = mPlayerY-mPlayer.getHeight() * 2.5f;
    }

    public float getCollectX() {
        return mCollectX;
    }

    public float getCollectY() {
        return mCollectY;
    }


    public Bitmap getCollect() {
        return mCollect;
    }
}

主角戰機組成部分:飛機+尾部噴氣+手指操作按鈕。
1.戰機部分就跟簡單,默認開始坐標在屏幕底部中心位置。

Paste_Image.png
canvas.drawBitmap(mPlayer,mPlayerX,mPlayerY,mPaint);

2.因為是戰機,肯定需要尾部火焰噴氣效果嘛,不然不夠炫。
火焰的位置就是位于戰機的尾部,所以前面繪制完成戰機以后,通過得到戰機的x,y計算出噴氣的位置。

canvas.drawBitmap(getBlowAnimation(), (mPlayerX-mPlayerBlow.getWidth()/4),mPlayerY+mPlayerBlow.getHeight()/1.5f,mPaint);

其中有一個getBlowAnimation的方法,通過它實時更改火焰圖片的高度來給人一種噴射的感覺。

Paste_Image.png

其中主要是通過Matrix類來完成一些特效,這個類也是非常非常非常的重要,在<a >官網</a>有詳細的介紹,可自行查看。
3.戰機是通過我們用手按住屏幕來移動,所以我們需要提供一個可操控的位置,操控的位置也是一張圖片,它的位置一直緊隨著噴氣的底部,而噴氣是緊隨戰機,所以操作動作就是去移動戰機在屏幕的位置。

Paste_Image.png

操作按鈕中心就是一個FIRE的字體,字體和按鈕通過<a >Paint</a>設置透明度的變化產生一個閃爍的效果,并且手離開屏幕的時候操作按鈕就會出現,并且提示游戲狀態以及下一步操作,手按下屏幕的時候就按鈕就會消失并且游戲繼續。

device-2016-12-23-105428.png

---------我是分割線----------
這里只是把戰機繪制出來,那怎么讓戰機跟隨我的手指運動呢?
回到<b>GameView</b>類,既然是手勢操作,你想到的是什么?我想到就是實現onTouchEvent。
1.暫時給游戲定義三個狀態

Paste_Image.png

2.默認是游戲加載到可操作狀態READY。
當游戲可以操作的時候,這時候把手放到操作按鈕的位置(上圖的白色圓圈),就可以變更游戲狀態為ING。點擊其他位置不做任何變化。

Paste_Image.png

3.手指移動變更戰機的位置x,y。

Paste_Image.png

4.手離開屏幕,游戲進入暫停狀態。

Paste_Image.png

5.在GameView的onGameDraw方法中調用主角繪制。

/**
     * 繪制內容以及更新內容
     */
    private void onGameDraw(){
        if(mCanvas==null)return;
        mCanvas.drawColor(Color.WHITE);
        //背景
        mDrawBackground.onDraw(mCanvas);
        mDrawBackground.updateGame();
        //主角
        mPlayer.onDraw(mCanvas);
        mPlayer.updateGame();
        //判斷當前游戲狀態
        switch (GAME_STATE){
            case ING:
                break;
            case READY:
                mPlayer.onDrawCollect(mCanvas,getContext().getString(R.string.reading));
                break;
            case PAUSE:
                mPlayer.onDrawCollect(mCanvas,getContext().getString(R.string.conution));
                break;
        }
    }```



![player.gif](http://upload-images.jianshu.io/upload_images/3982371-222c5de5c612988b.gif?imageMogr2/auto-orient/strip)

主角戰機的核心思路就是以上部分,最后是提供持續更新的源碼。
<a >源碼傳送門</a>

<a href="http://www.lxweimin.com/p/a87a9ed6a8b2">上一篇</a>     <a href="http://www.lxweimin.com/p/966a3e9d8bdf">下一篇</a>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容