android游戲---貪吃蛇


 

先看看運行的效果

 

最頂層的是wall類,生成和繪制外牆  代碼如下:

package com.example.worm;

import android.content.Context;
import android.util.DisplayMetrics;
import android.view.View;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Bitmap;

public class wall extends View{

    private Context mContext;
    private int width;
    private int height;
    private int widthNum;                           // 方格20 * 20 保存方格行列數;
    private int heightNum;
    private Bitmap bm;
    
    public wall(Context context)
    {
        super(context);
        mContext = context;
        
        DisplayMetrics dm = new DisplayMetrics();
        dm = context.getResources().getDisplayMetrics();
        
        width = dm.widthPixels;
        height = dm.heightPixels;
    
        widthNum = width / 20;
        heightNum = height / 20;
        
        bm = BitmapFactory.decodeResource(context.getResources(), R.drawable.wall);
    }
    
    private void drawTableForm (Canvas canvas)             //繪制表格白線
    {
        Paint paint = new Paint ();
        
        paint.setStrokeWidth(1);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.WHITE);
        
        for (int i = 0; i <= widthNum; i++)
        {
            canvas.drawLine(20 * i, 0, 20 * i, height, paint);
        }
        
        for (int i = 0; i <= heightNum; i++)
        {
            canvas.drawLine(0, 20 * i, width, 20 * i, paint);
        }
        
    }

    private void drawWall(Canvas canvas)               // 在最外層繪制棕色牆體;
    {
        for (int i = 0; i < widthNum; i++)
        {
            canvas.drawBitmap(bm, 20 * i, 0, null);
            canvas.drawBitmap(bm, 20 * i, height - 20, null);
        }
        
        for (int i = 1; i < heightNum - 1; i++)
        {
            canvas.drawBitmap(bm, 0, 20 * i, null);
            canvas.drawBitmap(bm, width - 20, 20 * i, null);
        }
    }
    
    @Override 
    protected void onDraw (Canvas canvas)                //覆蓋onDraw
    {
        super.onDraw(canvas);
        
        drawTableForm (canvas);
        drawWall(canvas);
    }
    
    
}

 

 往上是worm類,此類包含了control層,連帶左右上下控制

package com.example.worm;

import android.view.View;
import android.content.Context;
import android.util.DisplayMetrics;
import android.graphics.Canvas;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.view.MotionEvent;
import android.graphics.Paint;

public class Worm extends View{

    private Context mContext;
    private int widthNum;                                 //行列數,方便起見,此處以減去牆體,所以  widthNum = dm.widthPixels / 20 - 2
private int heightNum; private int[] wormX = new int[35]; //保存蛇的 X Y坐標, wormX[0], wormY[0] 為蛇頭 private int[] wormY = new int[35]; private float[] wormRotate = new float[35]; //因為蛇頭,蛇身在旋轉時需要圖片相應轉動 此處保存蛇個部位圖片的旋轉角度 private int length; //蛇長 private Bitmap bmHead; private Bitmap bmBody; private Bitmap bmFood; public int direction; //運動方向 private float startX; //此為判斷控制的參數 private float startY; private float stopX; private float stopY; private long startTime; private long stopTime; private int food[] = new int[2]; //food[0] 為food的X坐標, food[1] 為food的Y坐標; private int score = 0; public long speed = 500; private int level = 1; private final static int LEFT = 0; private final static int RIGHT = 1; private final static int UP = 2; private final static int DOWN = 3; private OnGameOverListener listener; public Worm (Context context) { super(context); mContext = context; DisplayMetrics dm = new DisplayMetrics(); dm = mContext.getResources().getDisplayMetrics(); widthNum = dm.widthPixels / 20 - 2; heightNum = dm.heightPixels / 20 - 2; bmHead = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.head); bmBody = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.body); bmFood = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.food); } public void reSet() //重置貪吃蛇,點擊重新開始游戲時需要調用 { length = 3; wormX[0] = 2; wormX[1] = 1; wormX[2] = 0; wormY[0] = 10; wormY[1] = 10; wormY[2] = 10; wormRotate[0] = 0.0f; wormRotate[1] = 0.0f; wormRotate[2] = 0.0f; direction = RIGHT; updateFood(); } @Override protected void onDraw(Canvas canvas) { drawFood(canvas); drawWorm(canvas); drawText(canvas); } private void drawWorm(Canvas canvas) //繪制蛇 { Matrix m = new Matrix(); Matrix rotateM = new Matrix(); Bitmap bm; m.setTranslate(20 * (1 + wormX[0]), 20 * (1 + wormY[0])); rotateM.setRotate(wormRotate[0]); bm = Bitmap.createBitmap(bmHead, 0, 0, //先得到旋轉后的圖片 bmHead.getWidth(), bmHead.getHeight(), rotateM, true); canvas.drawBitmap(bm, m, null); //繪制蛇頭 for (int i = 1; i < length; i++) //繪制蛇身 { m.setTranslate( 20 * (1 + wormX[i]), 20 * (1 + wormY[i])); rotateM.setRotate(wormRotate[i]); bm = Bitmap.createBitmap(bmBody, 0, 0, //同樣先得到旋轉后的圖片 bmBody.getWidth(), bmBody.getHeight(), rotateM, true); canvas.drawBitmap(bm, m, null); } } private void drawFood(Canvas canvas) //繪制food { canvas.drawBitmap(bmFood, 20 * (1 + food[0]), 20 * (1 + food[1]), null); } private void drawText (Canvas canvas) // 繪制 score和 level { Paint paint = new Paint(); paint.setTextSize(40); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(5); paint.setAlpha(50); paint.setColor(Color.GREEN); canvas.drawText("Score: ", 100, 40, paint); canvas.drawText("Level: ", 300, 40, paint); paint.setTextSize(50); paint.setColor(Color.RED); canvas.drawText(String.valueOf(score), 210, 40, paint); canvas.drawText(String.valueOf(level), 400, 40, paint); } private void upDateBody() //更新蛇身 位置 { for (int i = length - 1; i > 0; i--) { wormX[i] = wormX[i - 1]; wormY[i] = wormY[i - 1]; wormRotate[i] = wormRotate[i - 1]; } } private boolean isAble(int dir) //判斷蛇頭的下一步是否可行 { switch(dir) { case LEFT: if (wormX[0] - 1 < 0) return false; break; case RIGHT: if (wormX[0] + 1 == widthNum) return false; break; case UP: if (wormY[0] - 1 < 0) return false; break; case DOWN: if (wormY[0] + 1 == heightNum) return false; break; } return true; } private void eatFood() //判斷是否遲到food { if (wormX[0] == food[0] && wormY[0] == food[1]) { score ++; length ++; if (score > 30) { score = 0; level ++; speed = (long) (speed * 0.8f); length = 3; wormX[0] = 2; wormX[1] = 1; wormX[2] = 0; wormY[0] = 10; wormY[1] = 10; wormY[2] = 10; } updateFood(); } } public void turnLeft() //左轉 { if (isBody(wormX[0] - 1, wormY[0]) || !isAble(LEFT)) //下一步不可行, 這調用onGameOver() { listener.onGameOver(); return ; } upDateBody(); //可行時,先更新Body位置 在更新蛇頭 wormX[0]--; wormRotate[0] = 180.0f; direction = LEFT; eatFood(); this.invalidate(); } public void turnRight() { if (isBody(wormX[0] + 1, wormY[0]) || !isAble(RIGHT)) { listener.onGameOver(); return ; } upDateBody(); wormX[0]++; wormRotate[0] = 0.0f; direction = RIGHT; eatFood(); this.invalidate(); } public void turnUp() { if (isBody(wormX[0], wormY[0] - 1) || !isAble(UP)) { listener.onGameOver(); return ; } upDateBody(); wormY[0]--; wormRotate[0] = -90.0f; direction = UP; eatFood(); this.invalidate(); } public void turnDown() { if (direction == UP || !isAble(DOWN)) { listener.onGameOver(); return ; } upDateBody(); wormY[0]++; wormRotate[0] = 90.0f; direction = DOWN; eatFood(); this.invalidate(); } public void setOnGameOverListener(OnGameOverListener listener) //自定義的一個listener { this.listener = listener; } private boolean isBody(int x, int y) //判斷該位置是否是蛇身 { for (int i = 1; i < length - 1; i++) { if (x == wormX[i] && y == wormY[i]) return true; } return false; } private boolean isLegitFood(int x, int y) //判斷food的位置是否合法 { for (int i = 0; i < length; i++) { if (x == wormX[i] && y == wormY[i]) return false; } return true; } private void updateFood() //隨機生成一個food位置 { food[0] = (int) (Math.random() * (widthNum - 1)); food[1] = (int) (Math.random() * (heightNum - 1)); while (!isLegitFood(food[0], food[1])) { food[0] = (int) (Math.random() * (widthNum - 1)); food[1] = (int) (Math.random() * (heightNum - 1)); } } @Override public boolean onTouchEvent(MotionEvent event) // 控制操作 { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startX = event.getX(); startY = event.getY(); startTime = event.getEventTime(); break; case MotionEvent.ACTION_UP: stopX = event.getX(); stopY = event.getY(); stopTime = event.getDownTime(); if (stopTime - startTime > 1000) //當按壓時間超過1000ms是無效 break; if ((stopX - startX) > 100) //左右上下滑動超過100有效 { if (direction != LEFT) direction = RIGHT; } else if ((stopX - startX) < -100) { if (direction != RIGHT) direction = LEFT; } else if ((stopY - startY) > 100) { if (direction != UP) direction = DOWN; } else if ((stopY - startY) < -100) { if (direction != DOWN) direction = UP; } else if (stopTime - startTime < 150) //滑動不夠100並且時間小於150ms調用onGamePause()暫停游戲 { listener.onGamePause(); } break; } return true; } }


其中使用了自定義的一個listener   用於Main類可以相應GameOver和GamePause事件   如下:

package com.example.worm;

public interface OnGameOverListener {

    public void onGameOver();
    public void onGamePause();
}

 

下面是main類

package com.example.worm;

import java.util.Timer;
import java.util.TimerTask;
import android.os.Bundle;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.ViewGroup.LayoutParams;
import android.os.Handler;
import android.content.Intent;

public class MainActivity extends Activity {

    private wall mWall;
    private Worm mWorm;
    private Timer timer = new Timer();
    private TimerTask timerTask;
    private int message = 1;                              //發送messge控制游戲的進行和暫停 1為進行 2為暫停
    
    
    private Handler handler = new Handler()
    {
        @Override 
        public void handleMessage(Message msg)
        {
            switch(msg.what)
            {
            case 1:                                     //當收到1時  進行游戲
                switch(mWorm.direction)                 //direction是個int, 0, 1, 2, 3, 分別代表4個方向
                {
                case 0:
                    mWorm.turnLeft();
                    break;
                    
                case 1:
                    mWorm.turnRight();
                    break;
                    
                case 2:
                    mWorm.turnUp();
                    break;
                    
                case 3:
                    mWorm.turnDown();
                    break;
                }
                break;
            case 2:                                         //收到2 時  直接退出
                break;
            }
            sendMsg();                                     //不斷的發送消息,保證游戲連續進行
            
            super.handleMessage(msg);
        }
    };
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        mWall = new wall(this);
        mWorm = new Worm(this);
         
        setContentView(mWall);
        addContentView(mWorm, 
             new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        
        mWorm.setOnGameOverListener(new OnGameOverListener()              // 定義一個OnGameListener 當發生GameOver 和 GamePause是main類知道怎么做
        {
            public void onGameOver()
            {
                 gameStop();
            }
            public void onGamePause()
            {
                gamePause();
            }
        });
        
        sendMsg();                                                      //發送第一條消息
    }
    
    @Override
    public void onStart()
    {    
        mWorm.reSet();                                               //之所以要將reSet()放在onStart()中方便暫停重開
        super.onStart();
    }
    
    @Override
    public void onResume()                                           //繼續游戲時 將message改回 1;
    {
   
        message = 1;       
        super.onResume();
    }
    
    @Override
    public void onActivityResult (int requestCode, int resultCode, Intent data)    //暫停和結束都是調用了一個Acitivity 這個函數可以回收信息
    {
        switch(requestCode)
        {
        case 1:                                                         //1 為調用了pauseActivity
            switch (resultCode)
            {
            case 0:                                                    //0 為繼續游戲
                this.onResume();
                break;
            case 1:                                                    //1 為重新開始
                this.onStart();
                break;
            case 2:                                                    //2 為結束游戲
                finish();                         
                break;
            }
            break;
            
        case 2:                                                       //2 為調用stopActivity
            switch (resultCode)
            {
            case 0:                                                   // 重新開始
                this.onStart();
                break;
            case 1:                                                  // 結束游戲
                finish();
                break;
            }
            break;
        
        }
        
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onPause()
    {
        message = 2;                                                       //暫停時修改messge為 2;
        super.onPause();
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
    
    private void gamePause()                                                    //gamePause()調用reStartActivity
    {
        message = 2;
        Intent intent = new Intent(this, reStartActivity.class);
        startActivityForResult (intent, 1);
    }
    
    private void gameStop()                                                     //gameStop()調用onStopActivity
    {
        message = 2;
        Intent intent = new Intent(this, onStopActivity.class);
        startActivityForResult (intent, 2);
    }
    
    private void sendMsg()                                                     //發送消息
    {
        timerTask = new TimerTask()
        {
            @Override
            public void run()
            {
                Message msg = new Message();
                msg.what = message;
                handler.sendMessage(msg);
            }
        };
        
        timer.schedule(timerTask, mWorm.speed);                               //消息發送延遲 mWorm.speed;
    }
    
    
}

就下來是兩個輔助Activity和他們的layout

package com.example.worm;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class reStartActivity extends Activity{
    
    private Button resume;
    private Button reStart;
    private Button stop;
    
    @Override 
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_restart);
        
        resume  = (Button) findViewById (R.id.resume);
        reStart = (Button) findViewById (R.id.reStart);
        stop    = (Button) findViewById (R.id.stop);
        
        resume.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                setResult(0);
                finish();
            }
        });
        
        reStart.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                setResult(1);
                finish();
            }
        });
        
        stop.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                setResult(2);
                finish();
            }
        });
    }
    
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <Button 
        android:id="@+id/resume"
        android:text="繼續游戲"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <Button
        android:id="@+id/reStart"
        android:text="重新開始"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <Button 
        android:id="@+id/stop"
        android:text="結束游戲"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</LinearLayout>

 

package com.example.worm;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class onStopActivity extends Activity{

    private Button reStart;
    private Button stop;
    
    @Override
    public void onCreate (Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_onstop);
        
        reStart = (Button) findViewById (R.id.reStart);
        stop    = (Button) findViewById (R.id.stop);
        
        
        reStart.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                setResult(0);
                finish();
            }
        });
        stop.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                setResult(1);
                finish();
            }
        });
    }
}

 

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    

    <Button 
        android:id="@+id/reStart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="重新開始"/>
    <Button
        android:id="@+id/stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="結束游戲"/>
    
</LinearLayout>

最后要注意的是配置文件的設置,以上兩個Activity的theme要定義為theme.Dialog;

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.worm"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".reStartActivity" 
            android:theme="@android:style/Theme.Dialog">
        </activity>
        
        <activity
            android:name=".onStopActivity" 
            android:theme="@android:style/Theme.Dialog">
        </activity>
        
        
    </application>

</manifest>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM