最简单的贪吃蛇

最近想着忙里偷闲写点简单的Android应用,增加一些生活乐趣,由于平时工作主要精力并不是集中在书写apk上,更多的是解决代码问题和维护模块稳定,但是写代码本身是一件比较有趣的事情,因为这个过程是从无到有的。

名称:贪吃蛇

开发环境:Android Studio

思路:

定时刷新界面,因为蛇是不会停止的

随机产生食物

蛇体的更新

蛇体如何出现移动的效果

缺陷:没有结束,没有碰壁,没有追尾,除非推出(现在知道为什么是最简单的了吧)

代码分析:

MyActivity, 主要作用就是定时刷新界面,让蛇不停的前进private SnakeView mSnakeView; //填充窗口的View,刷新的对象

private static final int REFRESH = 1; //定义消息 防止硬编码

private static final int REFRESHINTERVAL = 300; //刷新的时间间隔

private boolean isPaused = false; //线程的停止标志位

private Handler mHandler = new Handler() { //thread handler 消息处理

@Override

public void handleMessage(Message msg) {

// TODO Auto-generated method stub

super.handleMessage(msg);

if(msg.arg1 == REFRESH) {

if(mSnakeView != null) {

mSnakeView.invalidate();

}

}

}

};

private Thread mRefreshThread; //用于发送刷新消息的线程

//Activity的onCreate方法

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mSnakeView = new SnakeView(this);

setContentView(mSnakeView);

isPaused = false;

mRefreshThread = new Thread("TimerThread"){

@Override

public void run() {

// TODO Auto-generated method stub

super.run();

while(!isPaused) {

Message msg = mHandler.obtainMessage();

msg.arg1 = REFRESH;

mHandler.sendMessage(msg);

try {

Thread.sleep(REFRESHINTERVAL); //休眠一段时间后再发送消息刷新界面

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

};

mRefreshThread.start(); //启动线程

}

SnakeView ,主游戏界面,蛇体,背景和食物的显示界面//自定义View

public class SnakeView extends View{

public static final String TAG = "SnakeView";

private int mWidth; //view的宽

private int mHeight; //View的高

private static final int sXOffset = 0 ;

private static final int sYOffset = 0 ; // X坐标和Y坐标的偏移量,可以修改来缩小游戏范围

private final int BOXWIDTH = 30; //食物的边长,蛇体的宽度

private Random mRandom = new Random(); //用于产生随机数

private Point mFoodPosition; //食物的位置

private boolean mIsFoodDone = true; //食物是否已经被吃掉

private ArrayList mSnakeList; //蛇体可以看做是很多食物组成的

private Paint mSnakePaint; //用于画蛇的画笔

private int mSnakeDirection = 0; //蛇体运动的方向

private final int UP = 1;

private final int DOWN = 2;

private final int LEFT = 3;

private final int RIGHT =4;

private Paint mBgPaint;//游戏背景画笔

private Paint mFoodPaint;//食物画笔

public SnakeView(Context context) {

super(context);

// TODO Auto-generated constructor stub

mSnakeList = new ArrayList();

mSnakePaint = new Paint();

mSnakePaint.setColor(Color.RED);

mSnakePaint.setStyle(Paint.Style.FILL_AND_STROKE);

mSnakeList.add(new Point(500,500));

mSnakeList.add(new Point(500,530)); //初始化一条丑陋的蛇

mSnakeDirection = RIGHT;

mIsFoodDone = true;

mFoodPosition= new Point();

mFoodPaint = new Paint();

mFoodPaint.setColor(Color.CYAN);

mFoodPaint.setStyle(Paint.Style.FILL);

mBgPaint = new Paint();

Paint paint = new Paint();

paint.setColor(Color.WHITE); //初始化各种画笔

}

@Override

public boolean onTouchEvent(MotionEvent event) { //通过手势来改变蛇体运动方向

// TODO Auto-generated method stub

int x = (int)(event.getX());

int y = (int)(event.getY());

Log.e(TAG, "x =" + x + " y = " + y + " mSnakeDirection = " + mSnakeDirection);

if(mSnakeDirection == UP || mSnakeDirection == DOWN) {

if(x < head.x) mSnakeDirection = LEFT;

if(x > head.x) mSnakeDirection = RIGHT;

} else if(mSnakeDirection == LEFT || mSnakeDirection == RIGHT) {

if(y < head.y) mSnakeDirection = UP;

if(y > head.y) mSnakeDirection= DOWN;

}

//Log.e(TAG, "after adjust mSnakeDirection = " + mSnakeDirection);

return super.onTouchEvent(event);

}

@Override

protected void onDraw(Canvas canvas) {

// TODO Auto-generated method stub

//Log.e(TAG ,"onDraw");

super.onDraw(canvas);

drawBg(canvas, mBgPaint); //画背景

drawFood(canvas, mFoodPaint);//画食物

drawSnake(canvas, mSnakePaint); //画蛇

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

// TODO Auto-generated method stub

super.onSizeChanged(w, h, oldw, oldh);

mWidth = w;

mHeight = h;

}

//画背景 这里通过sXOffset, sYOffset可以实现对蛇活动区域的限制

private void drawBg(Canvas canvas, Paint paint) {

canvas.drawColor(Color.WHITE);

//Rect rect = new Rect(sXOffset, sYOffset, mWidth - sXOffset, mHeight - sYOffset);

//canvas.drawRect(rect, paint);

}

//画蛇体

private void drawSnake(Canvas canvas, Paint paint) {

for(int i = 0 ; i < mSnakeList.size() ; i++ ) {

Point point = mSnakeList.get(i);

Rect rect = new Rect(point.x , point.y , point.x + BOXWIDTH , point.y + BOXWIDTH);

canvas.drawRect(rect, paint);

}

//蛇移动,更新list为下一次刷新做准备

snakeMove(mSnakeList, mSnakeDirection);

if(isFoodEaten()) { //如果吃了食物,长度加1

mIsFoodDone = true;

} else { //如果没有吃食物,由于前进时加了一个 这里删除尾巴,出现移动的效果

mSnakeList.remove(mSnakeList.size() - 1);

}

}

//画食物

private void drawFood(Canvas canvas, Paint paint) {

if(mIsFoodDone) { //只在前一个食物被吃掉的情况下才产生食物

mFoodPosition.x = mRandom.nextInt(mWidth - 2*sXOffset - BOXWIDTH) + sXOffset ;

mFoodPosition.y = mRandom.nextInt(mWidth - 2*sYOffset - BOXWIDTH) + sYOffset ;

mIsFoodDone = false;

}

Rect food = new Rect(mFoodPosition.x , mFoodPosition.y , mFoodPosition.x + BOXWIDTH , mFoodPosition.y + BOXWIDTH);

canvas.drawRect(food, paint);

}

public void snakeMove(ArrayList list , int direction) {

//Log.e(TAG," snakeMove ArrayList = " + list.toString());

Point orighead = list.get(0);

Point newhead = new Point();

//蛇前进,实现原理就是头加尾减,若吃到食物,头加尾不减

switch(direction) {

case UP:

newhead.x = orighead.x;

newhead.y = orighead.y - BOXWIDTH ;

break;

case DOWN:

newhead.x = orighead.x;

newhead.y = orighead.y + BOXWIDTH ;

break;

case LEFT:

newhead.x = orighead.x - BOXWIDTH;

newhead.y = orighead.y;

break;

case RIGHT:

newhead.x = orighead.x + BOXWIDTH ;

newhead.y = orighead.y;

break;

default:

break;

}

adjustHead(newhead);

list.add(0, newhead);

}

//边界判断

private boolean isOutBound(Point point) {

if(point.x < sXOffset || point.x > mWidth - sXOffset) return true;

if(point.y < sYOffset || point.y > mHeight - sYOffset) return true;

return false;

}

//出了边界,重新回来

private void adjustHead(Point point) {

//Log.e(TAG, "checkBound = " + isOutBound(point));

if(isOutBound(point)){

if(mSnakeDirection == UP) point.y = mHeight - sYOffset - BOXWIDTH;

if(mSnakeDirection == DOWN) point.y = sYOffset;

if(mSnakeDirection == LEFT) point.x = mWidth - sYOffset - BOXWIDTH;

if(mSnakeDirection == RIGHT) point.x = sXOffset;

}

}

//判断食物是否可以被吃

private boolean isFoodEaten() {

if(!mIsFoodDone) {

Rect foodrect = new Rect(mFoodPosition.x, mFoodPosition.y, mFoodPosition.x + BOXWIDTH, mFoodPosition.y + BOXWIDTH);

Point head = mSnakeList.get(0);

Rect headrect = new Rect(head.x, head.y, head.x + BOXWIDTH , head.y + BOXWIDTH);

return foodrect.intersect(headrect);

}

return false;

}

}

效果展示:

(制作Gif有点不流畅实际效果很流畅)

9b00d01ff2e0bf16ac00d09b9f89bed0.gif

代码附件:

http://download.csdn.net/detail/poorkick/9497370

更新代码

最开始学习Android时写的Demo工程,最近有朋友在项目运行上存在疑问。更新代码至Github,请自行查阅。

https://github.com/onlyloveyd/SnakeGame

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐