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>

 

posted @ 2012-08-30 11:49  MonkeyDLky  阅读(2586)  评论(2编辑  收藏  举报