最简单的贪吃蛇

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

名称:贪吃蛇

开发环境:IntelliJ IDEA 14.0.3

思路:

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

2. 随机产生食物

3. 蛇体的更新

4. 蛇体如何出现移动的效果

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

代码分析:

1. 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(); //启动线程
}
  1. 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<Point> 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<Point>();
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<Point> 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有点不流畅实际效果很流畅)

代码附件:

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

欢迎讨论!

<Android 应用 之路> 简易贪吃蛇的更多相关文章

  1. C - 简易贪吃蛇的编写

    不多废话,直接进入正题——用C编写简易贪吃蛇.附上拙劣的源码 * c-snake * 首先说明使画面动起来的原理:通过 system("cls"); 清除当前控制台的显示,再pri ...

  2. Luat Inside | 致敬经典,使用Air724UG制作简易贪吃蛇

    作者简介: 打盹的消防车--活跃于Luat社群的新生代全能开发者,东北小伙儿爽朗幽默.好学敏思,更是实力行动派.幼年曾手握火红炽铁而后全然无恙,堪称魔幻经历:如今热衷于各类嵌入式软硬件研究,快意物联江 ...

  3. Android学习之路——简易版微信为例(一)

    这是“Android学习之路”系列文章的开篇,可能会让大家有些失望——这篇文章中我们不介绍简易版微信的实现(不过不是标题党哦,我会在后续博文中一步步实现这个应用程序的).这里主要是和广大园友们聊聊一个 ...

  4. Android学习之路——简易版微信为例(三)

    最近好久没有更新博文,一则是因为公司最近比较忙,另外自己在Android学习过程和简易版微信的开发过程中碰到了一些绊脚石,所以最近一直在学习充电中.下面来列举一下自己所走过的弯路: (1)本来打算前端 ...

  5. Android学习之路——简易版微信为例(二)

    1 概述 从这篇博文开始,正式进入简易版微信的开发.深入学习前,想谈谈个人对Android程序开发一些理解,不一定正确,只是自己的一点想法.Android程序开发不像我们在大学时候写C控制台程序那样, ...

  6. <Android 应用 之路> 简易手电筒

    前言 快一个月没有写自己的博客了,由于最近换了工作,换了居住地,所以有一些杂事需要处理,从今天开始恢复正常,不赘述了.进入今天的主题 -– 简易的手电筒. 这个Demo中使用的是比较新的API,M版本 ...

  7. Python实例:贪吃蛇(简单贪吃蛇编写)🐍

    d=====( ̄▽ ̄*)b 叮~ Python -- 简易贪吃蛇实现 目录: 1.基本原理 2.需要学习的库 3.代码实现 1.基本原理 基本贪吃蛇所需要的东西其实很少,只需要有一块让蛇动的屏幕, 在 ...

  8. Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录

    一.项目简介 贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏. 我已经将做好的案例上传到了应用宝,无病毒.无广告,大家可以放心下载下来把玩一下.应用宝 ...

  9. android贪吃蛇(超级简陋版)

    public class body { public int ax;//代表X周变量 public int ay;//代表Y轴变量 public int getAx() { return ax; } ...

随机推荐

  1. 【转】有的共享软件赚了一百万美元,而为什么你没有?&&我的软件推广成功之路

    有的共享软件赚了一百万美元,而为什么你没有? 转自:http://blog.csdn.net/wangjiwei2010/article/details/1267044 译:DreamGoal 原作: ...

  2. POJ2387(最短路入门)

    Til the Cows Come Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 38556   Accepted ...

  3. MMU的理解

    MMU内存管理单元相关知识点总结 1.MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器.物理存储器的控制线路,同时也负责虚 ...

  4. Lagom学习(一)

    Lagom是JAVA系下响应式 微服务框架,其特性包括: 目前,大多数已有的微服务框架关注于简化单个微服务的构建,Lagom将其扩展到了微服务所构成的系统,分布式系统的复杂性. 同步通信使用HTTP, ...

  5. SRAM SROM DRAM DROM DDR NAND FLASH EMMC的区别

    RAM(Random Access Memory)的全名为随机存取记忆体,它相当于PC机上的移动存储,用来存储和保存数据的.它在任何 时候都可以读写,RAM通常是作为操作系统或其他正在运行程序的临时存 ...

  6. JSP环境探针-当前电脑所有系统参数

    1 <%@ page contentType="text/html;charset=gb2312" %> <%@ page import="java.u ...

  7. 在浏览器端用JS创建和下载文件

    前端很多项目中,都有文件下载的需求,特别是JS生成文件内容,然后让浏览器执行下载操作(例如在线图片编辑.在线代码编辑.iPresst等). 但受限于浏览器,很多情况下我们都只能给出个链接,让用户点击打 ...

  8. 0003_Linux基础之常用命令

    1.pwd:查看当前所在目录 2.cd :切换目录 3.ls:查看当前目录下的文件及文件夹: 4.ls -l :列出当前目录下文件及详细信息         drwxr-xr-x   第一个字符为d则 ...

  9. 在VMWare上安装ubuntu及VMWare&amp;nbs…

    在VMWare上安装ubuntu及VMWare Tools 一.摘要 该文主要介绍了如何在虚拟机上安装ubuntu,和安装VMWare Tools设置共享文件夹,最后对ubuntu做了简单的介绍. 二 ...

  10. Linear Algebra - Determinant(几何意义)

    二阶行列式的几何意义 二阶行列式 \(D = \begin{vmatrix}a_1&a_2\\b_1&b_2\end{vmatrix} = a_1b_2 - a_2b_1\) 的几何意 ...