求大神给一份android studio贪吃蛇的贪吃蛇游戏的源代码

Android贪吃蛇(源码演示)
相关合集:
相关热搜:
华军软件园为小伙伴提供网站源码的软件下载专题。网站源码,也称为源代码,源程序。是指未编译的文本代码或一个网站的全部源码文件,是一系列人类可读的计算机语言指令。我们可以把它理解成源文代码,当前看到的这个网页来说,其实它是由一大堆的源代码组成,通过我们浏览器(如微软的IE浏览器,谷歌的Chrome浏览器等)或服务器翻译成我们所看到的样子...
高速下载地址
联通下载地址
电信下载地址
移动及其他下载地址
(您的评论需要经过审核才能显示)
这款Android贪吃蛇(源码演示)软件很不错啊,最新版本新增的功能简直不要太厉害,以后会不会有更惊喜的功能。
我觉得现在的Android贪吃蛇(源码演示)已经够我用得了,什么时候想换口味了,就试试共享软件的版本
刚下载Android贪吃蛇(源码演示)时不太会用,不过照着网上的各种教程学习之后,感觉太easy了
太感谢了,终于有网站可以下载Android贪吃蛇(源码演示)了,还没用,试过之后再来评论
很不错!Android贪吃蛇(源码演示)用户体验做的越来越棒了,我会一直支持下去的!
Android贪吃蛇(源码演示)哪里不好了?不懂的别瞎哔哔,一点素质都没有
就喜欢用简体中文的软件,其他语言的根本看不懂。
Android贪吃蛇(源码演示)在同类软件里,体积已经非常小巧了,才0.1MB
怎么下载Android贪吃蛇(源码演示)啊?是高速下载吗?是一款国产软件很想试试啊
非常不错,Android贪吃蛇(源码演示)良心,已经很难找到这么好的其他源码软件了
热门关键词本帖子已过去太久远了,不再提供回复功能。#include&stdio.h&&&
&#include&stdlib.h&&&
#include&windows.h&&&
#include&time.h&&&
#include&conio.h&&&&&&
&#define&MOD&28&&//28种模式
#define&SIZE_N&19&&
#define&SIZE_M&12&&&&&
int&cur_x,cur_y;&&
int&score,mark,next,map[SIZE_N][SIZE_M],Gamespeed=300;&&
&int&shape[28][6]={//第一个问题,这些坐标什么意思啊,看不懂,能详解吗
&&&&&{0,-1,0,-2,1,0},&{0,1,1,0,2,0},&{-1,0,0,1,0,2},&{0,-1,-1,0,-2,0},&&
&&&&&{0,-1,0,1,-1,0},&{0,1,1,0,-1,0},&{1,0,0,-1,0,1},&{1,0,-1,0,0,-1},&&
&&&&&{-1,1,0,1,1,0},&{0,-1,1,0,1,1},&{-1,0,0,-1,1,-1},&{-1,-1,-1,0,0,1},&&
&&&&{-1,0,0,1,1,1},&{0,1,1,-1,1,0},&{-1,0,0,1,1,1},&{0,1,1,-1,1,0},&&
&&&&{-1,0,0,-1,0,-2},&{-1,0,-2,0,0,1},&{0,1,0,2,1,0},&{0,-1,1,0,2,0},&&
&&&&{0,1,1,0,1,1},&{0,-1,1,0,1,-1},&{-1,0,0,-1,-1,-1},&{-1,0,-1,1,0,1},&&
&&&&&{0,1,0,2,0,3},&{1,0,2,0,3,0},&{0,-1,0,-2,0,-3},&{-1,0,-2,0,-3,0}&&
&void&gotoxy(int&x,int&y){//gotoxy在TC中是在system.h库文件里的一个函
&&&&&COORD&c;&&
&&&&&c.X=x-1;&c.Y=y-1;&&
&&&&&SetConsoleCursorPosition&(GetStdHandle(STD_OUTPUT_HANDLE),&c);&
&void&Gameover()
&{/*/游戏结束的判断*/&
&&&&int&i,j,flag=0;&&
&&&&&for(j=1;j&SIZE_M-1;j++)
&&&&&&&&&if(map[1][j]!=0)
&&&&&&&&&&&&flag=1;&&
&&&&&&&&}&&
&&&&&if(flag==1)
&&&&&&&&&for(i=1;i&SIZE_N-1;i++)
&&&&&&&&&&&&&gotoxy(2,i+1);&&
&&&&&&&&&&&&&for(j=1;j&SIZE_M-1;j++)
&&&&&&&&&&&&&&&&&printf(&,&);&&
&&&&&&&&&&&&}
&puts(&&);&&
&&&&&&&&&}&&
&&&&&&&&&gotoxy(7,9);&&
&&&&&&&&&printf(&GAME&OVER!&);&&
&&&&&&&&&gotoxy(1,SIZE_N+1);&&
&&&&&&&&&exit(0);&&
&void&ShowMap(int&id)
&&&&&int&i,j;&&
&&&&&gotoxy(1,1);&&
&&&&&if(id!=-1)
&&&&&&&&&for(i=0;i&SIZE_N;i++)
&&&&&&&&&&&&&for(j=0;j&SIZE_M;j++)
&&&&&&&&&&&&&&&&&if(i==0&&j==0&||&i==0&&j==SIZE_M-1&||&j==0&&i==SIZE_N-1&||&j==SIZE_M-1&&i==SIZE_N-1)//第二个,这个又想表达什么意思?
&printf(&&&);&
&&&&&&&&&&&&&&&&&else&
&if(i==0&||&i==SIZE_N-1)
&printf(&--&);&
&&&&&&&&&&&&&&&&&else&
&if(j==0&||&j==SIZE_M-1)
&printf(&|&);&&
&&&&&&&&&&&&&&&&&else&
&if(map[i][j]==2)
&printf(&,&);&&
&&&&&&&&&&&&&&&&&else&
&if(i==cur_x+shape[id][0]&&&&j==cur_y+shape[id][1]&||&&
&&&&i==cur_x+shape[id][2]&&&&j==cur_y+shape[id][3]&||&&
&&&&&&&&&&&&&&&&&&&&&&&&i==cur_x+shape[id][4]&&&&j==cur_y+shape[id][5]&||&&
&&&&&&&&&&&&&&&&&&&&&&&&i==cur_x&&&&j==cur_y)&&
&&&&&&&&&&&&&&&&&&&&&printf(&,&);&&
&&&&&&&&&&&&&&&&&else&
&if(map[i][j]==0)&
&printf(&&&&);&&&
&&&&&&&&&&&&&}&&
&&&&&&&&&&&&&if(i==1)printf(&&&&next:&);&&
&&&&&&&&&&&&&if(i==11)printf(&&&&score&:&&&%d&,score);&&
&&&&&&&&&&&&&if(i==14)printf(&&&&speed&:&&&%d&,score/100+1);&&
&&&&&&&&&&&&&puts(&&);&&
&&&&&&&&&}&&
&&&&&else&{&&
&&&&&&&&&mark=1;&&
&&&&&&&&&for(i=0;i&SIZE_N;i++)
&&&&&&&&&&&&&for(j=0;j&SIZE_M;j++)
&&&&&&&&&&&&&&&&&if(i==0&&j==0&||&i==0&&j==SIZE_M-1&||&j==0&&i==SIZE_N-1&||&j==SIZE_M-1&&i==SIZE_N-1)
&printf(&&&);&&
&&&&&&&&&&&&&&&&&else&
if(i==0&||&i==SIZE_N-1)
&printf(&--&);&&
&&&&&&&&&&&&&&&&else&
if(j==0&||&j==SIZE_M-1)
printf(&|&);&&
&&&&&&&&&&&&&&&&&else&
if(map[i][j]==2)&
&printf(&,&);&&
&&&&&&&&&&&&&&&&else&
if(map[i][j]==0)&
printf(&&&&);&&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&&if(i==1)
&printf(&&&&next:&);&&
&&&&&&&&&&&&&if(i==11)
&printf(&&&&score&:&&&%d&,score);&&
&&&&&&&&&&&&if(i==14)
printf(&&&&speed&:&&&%d&,score/100+1);&&
&&&&&&&&&&&&puts(&&);&&
&&&&&&&&&}&&
&&&&&/*对于&next&方块的处理,先擦除再画图*/&
&&&&&gotoxy(30,6);
&printf(&&&&);&&
&&&&for(i=0;i&6;i=i+2)
&&&&&&&&&gotoxy(30+2*shape[id][i+1],6+shape[id][i]);&//还有这个,第三个???3
&printf(&&&&);&&
&&&&&gotoxy(30,6);
&printf(&,&);&&
&&&&&for(i=0;i&6;i=i+2)
&&&&&&&&&gotoxy(30+2*shape[next][i+1],6+shape[next][i]);
&printf(&,&);&
&&&&&Sleep(Gamespeed);&
&void&init(int&id)
&{/*/初始化函数,cur_x,cur_y是全局变量,标记了移动方块的位置*/&
&int&i,j;&&
&&&&&memset(map,0,sizeof(map));&
&&&&&for(&i=0;i&SIZE_N;i++)
&&&&&&&&&for(&j=0;j&SIZE_M;j++)&&
&&&&&&&&&&&&&if(i==SIZE_N-1&||&j==0&||&j==SIZE_M-1)&&
&&&&&&&&&&&&&&&&&map[i][j]=-1;&&
&&&&&cur_x=0;&cur_y=5;&&
&&&&&ShowMap(id);&&
&int&judge_in(int&x,int&y,int&id){/*/判断是否出界,或者说是否合法*/&
&&&&&int&i;&&
&&&&&if(map[x][y]!=0)
return&0;&&
&&&&&for(&i=0;i&6;i=i+2)
&&&&&&&&&if(map[&x+shape[id][i]&][&y+shape[id][i+1]&]!=0)
&return&0;&&
&return&1;&&
&void&fun_score()
&/*/得分,擦除行的闪烁,还有图形的向下平移*/&
&int&i,j,flag=0;&&
&int&k,ii,&&
&&&&&for(&i=1;i&SIZE_N-1;i++)
&&&&&&flag=0;&&
&&&&&&&&&for(j=1;j&SIZE_M-1;j++)
&&&&&&&&&&&&&if(map[i][j]!=2)
&&&&&&&&&}&&
&&&&&&&&&if(flag==0)
&&&&&&&&&&&&&&k=3;&&
&&&&&&&&&&&&&while(k--)
&&&&&&&&&&&&&&&&gotoxy(2,i+1);&&
&&&&&&&&&&&&&&&&for(&ii=1;ii&SIZE_M-1;ii++)
&&&&&&&&&&&&&&&&&&&&if(map[i][ii]==2)
&&&&&&&&&&&&&&&&&&&&&&&&&if(k%2==1)
&printf(&&&&);&&
&&&&&&&&&&&&&&&&&&&&&&&&&else&printf(&,&);&&
&&&&&&&&&&&&&&&&&&&&&}&&
&&&&&&&&&&&&&&&&&}
Sleep(100);&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&&for(&ii=i;ii&1;ii--)
&&&&&&&&&&&&&&&&&for(jj=1;jj&SIZE_M-1;jj++)
&map[ii][jj]=map[ii-1][jj];&&
&&&&&&&&&&&&&}&&
&&&&&&&&&&&&&ShowMap(-1);&&
&&&&&&&&&&&&score+=10;&&
&&&&&&&&&&&&if(score%100==0&&&&score!=0)
Gamespeed-=50;&&
&&&&&&&&&}&&
&int&main(){&&
&&&&&int&i,id,set=1;&&
&&&&&srand(time(NULL));&
&&&&&id=rand()%MOD;&//id=(id+MOD)%MOD;&
&&&&&next=rand()%MOD;&//next=(next+MOD)%MOD;&
&&&&&init(id);&&
&&&&&while(1)
&Here:&&&mark=0;&
&&&&&&&&&if(set==0)
&&&&&&&&&&&&id=&&
&&&&&&&&&&&&&next=rand()%MOD;&
&next=(next+MOD)%MOD;&
&&&&&&&&&&&&&cur_x=0;cur_y=5;&&
&&&&&&&&&&&&&set=1;&&
&&&&&&&&}&&
&&&&&&&&while(!kbhit())
&&&&&&&&&&&&Gameover();&&
&&&&&&&&&&&&&if(judge_in(cur_x+1,cur_y,id)==1)
&cur_x++;&&
&&&&&&&&&&&&&else&
&&&&&&&&&&&&&&&&&map[cur_x][cur_y]=2;&&
&&&&&&&&&&&&&&&&&for(i=0;i&6;i=i+2)&&
&&&&&&&&&&&&&&&&&&&&&map[&cur_x+shape[id][i]&][&cur_y+shape[id][i+1]&]=2;&&
&&&&&&&&&&&&&&&&fun_score();&&
&&&&&&&&&&&&&&&&&set=0;&&
&&&&&&&&&&&&&}&&
&&&&&&&&&&&&if(mark!=1)
ShowMap(id);&&
&&&&&&&&&&&&goto&H&&
&&&&&&&&&}/*/end&of&while(!kbhit())*/&
&&&&&&&&&char&&&
&&&&&&&&&key=getch();&&
&&&&&&&&&if(key==72){&&
&&&&&&&&&&&&int&tmp=&&
&&&&&&&&&&&&id++;&&
&&&&&&&&&&&&&if(&id%4==0&&&&id!=0&)
&id=id-4;&&
&&&&&&&&&&&&if(judge_in(cur_x,cur_y,id)!=1)
&&&&&&&&&}&&
&&&&&&&&&else&if(key==80&&&&judge_in(cur_x+1,cur_y,id)==1)cur_x++;&//第四个
&&&&&&&&&else&if(key==75&&&&judge_in(cur_x,cur_y-1,id)==1)cur_y--;&&
&&&&&&&&else&if(key==77&&&&judge_in(cur_x,cur_y+1,id)==1)cur_y++;&&
&&&&&&&&else&if(key==27){gotoxy(1,SIZE_N+1);exit(0);}&&
&system(&pause&);
&&&&&return&0;&&&
回复讨论(解决方案)
这个是我从网上找来的,想先研究别人怎么写的,然后自己再“创新”一个
&,但是这几个地方实在不懂,看好几天了,qq群里问好多人,没人理我,所以不得不发到论坛上来了,还请大牛多多见谅,解答疑惑(由于不能发表的东西不能
&包含特殊字符,所以我把方块省略了,用‘,’代替)
你确定这不是俄罗斯方块游戏?
我看也感觉不像贪吃蛇的代码吧!
我确定它就是俄罗斯方块,嘿嘿,因为刚才我用VS2012跑了一遍。
你确定这不是俄罗斯方块游戏?
我确定它就是俄罗斯方块,嘿嘿,因为刚才我用VS2012跑了一遍。
你确定这不是俄罗斯方块游戏? 笔误,,,,,sorry,能不能解答一下?
你确定这不是俄罗斯方块游戏? 求解答
我看也感觉不像贪吃蛇的代码吧! 大牛能不能解答一下????
俺来给你解释一下那个坐标吧,貌似这个设计得有点意思。
1.每个坐标代表一个方块样式,一共有28组坐标,代表28个方块式样。
2.由于在控制台下,光标的初始位置一般是在左上角,所以这里以左上角为原点(0,0),向下为X轴正方向,向右为Y轴正方向。
3.每组坐标有6个数字,实际上有8个数字,只是因为第一位和第二位恒为0,故省略。这样,从第一位开始,每相邻的两个数字为一组,一共得到4组坐标,即为俄罗斯方块中的小方块坐标(常规俄罗斯方块一共有4个小方块)。
4.你可以动手画一画。例如:{-1,0,0,1,0,2},细分为:(x1=0,y1=0),(x2=-1,y2=0),(x3=0,y3=1),(x4=0,y4=2).如图:
先把它运行起来。
俺来给你解释一下那个坐标吧,貌似这个设计得有点意思。
1.每个坐标代表一个方块样式,一共有28组坐标,代表28个方块式样。
2.由于在控制台下,光标的初始位置一般是在左上角,所以这里以左上角为原点(0,0),向下为X轴正方向,向右为Y轴正方向。
3.每组坐标有6个数字,实际上有8个数字,只是因为第一位和第二位恒为0,故省略。这样,从第一位开始,每相邻的两个数字为一组,一共得到4组坐标,即为俄罗斯方块中的小方块坐标(常规俄罗斯方块一共有4个小方块)。
4.你可以动手画一画。例如:{-1,0,0,1,0,2},细分为:(x1=0,y1=0),(x2=-1,y2=0),(x3=0,y3=1),(x4=0,y4=2).如图:
恩,大致明白了,谢谢Android开发之经典游戏贪吃蛇
这款游戏实现的思路和源码参考了Google自带的Snake的例子,其中修改了一些个人认为还不够完善的地方,加入了一些新的功能,比如屏幕上的方向操作盘,暂停按钮,开始按钮,退出按钮。另外,为了稍微增加些用户体验,除了游戏的主界面,本人自己新增了5个界面,分别是登陆界面,菜单界面,背景音乐设置界面,难度设置界面,还有个关于游戏的介绍界面。个人觉得在新手阶段,参考现成的思路和实现方式是难以避免的。重要的是我们需要有自己的理解,读懂代码之后,需要思考代码背后的实现逻辑,形成自己的思维。这样在下次开发工作时,就不用参考别人自己也能涌现出解决的思路。
我觉得经过自己的构思和实践,做出一个可操作有界面的小作品还是挺有成就感的,在探索和思考的过程中时间过的很快。好了,下面切入正题,我考虑了下讲述的顺序,决定就以进入软件后的界面顺序来把。
由于篇幅的关系,布局的XML文件就不发了,而且我把导包的语句也省略了,反正像AS,eclipse这些工具都是可以智能导包的。
那么,首先是登陆界面,找了些网上的资源当背景。布局还是比较简单的。
下图中,上图为效果图,下图为逻辑实现的流程图。
[java] view plain copy
// MainActivity.java
package con.example.wang.
public class MainActivity extends Activity implements OnClickListener{
EditText edit1,edit2;
SharedPreferences.E
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=(Button) findViewById(R.id.login_button);
edit1=(EditText) findViewById(R.id.input1);
edit2=(EditText) findViewById(R.id.input2);
checkbox=(CheckBox) findViewById(R.id.remember_button);
bar=(ProgressBar) findViewById(R.id.progress);
pref= PreferenceManager.getDefaultSharedPreferences(this);
boolean isRemember=pref.getBoolean("rem",false);
//获取代表是否保存密码的变量值,这里初值设为false
if(isRemember) {
//如果记住密码,则将账号和密码自动填充到文本框中
String account=pref.getString("account","");
String password=pref.getString("password","");
edit1.setText(account);
edit2.setText(password);
checkbox.setChecked(true);
button.setOnClickListener(this);
public void onClick(View v){
new Thread(new Runnable(){
//开启线程运行进度条,减少主线程的压力,这里不用子线程也影响不大
public void run() {
for (int i = 0; i & 25; i++) {
int progress = bar.getProgress();
progress = progress + 10;
bar.setProgress(progress);
}).start();
String account=edit1.getText().toString();
String password=edit2.getText().toString();
if(account.equals("admin") && password.equals("123456")) {
editor = pref.edit();
//这个方法用于向SharedPreferences文件中写数据
if(checkbox.isChecked()) {
editor.putBoolean("rem",true);
editor.putString("account",account);
editor.putString("password",password);
editor.clear();
//这个方法必须要有,不然数据不会被保存。生效后,就可以从该文件中读取数据。
Intent intent=new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
//如果用户名或密码不正确,这里会弹出一个提示框
Toast.makeText(MainActivity.this,"账号或用户名错误",Toast.LENGTH_SHORT).show();
这个逻辑还算比较简单,实现了记住密码的功能,这里的数据存储使用的是SharedPreferences。点击登陆后,会进入一个菜单界面,这里设置几个四个按钮,分别做好监听就可以了,然后用Intent在活动间跳转就好了。
效果图也分享一下。
[java] view plain copy
// SecondActivity.java
package com.example.wang.
public class SecondActivity extends Activity implements OnClickListener{
ImageButton button1,button2,button3,button4;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
button1=(ImageButton) findViewById(R.id.button_start);
button2=(ImageButton) findViewById(R.id.button_difficulty);
button3=(ImageButton) findViewById(R.id.button_music);
button4=(ImageButton) findViewById(R.id.button_about);
button4.setOnClickListener(this);
button3.setOnClickListener(this);
button2.setOnClickListener(this);
button1.setOnClickListener(this);
public void onClick(View v){
switch(v.getId()) {
//看下Intent的用法,还是挺方便的,这里用的都是显式的方法
case R.id.button_about:
Intent intent1 = new Intent(SecondActivity.this, AboutActivity.class);
startActivity(intent1);
case R.id.button_music:
Intent intent2 = new Intent(SecondActivity.this, MusicActivity.class);
startActivity(intent2);
case R.id.button_difficulty:
Intent intent3 = new Intent(SecondActivity.this, DifficultyActivity.class);
startActivity(intent3);
case R.id.button_start:
Intent intent4 = new Intent(SecondActivity.this, GameActivity.class);
startActivity(intent4);
下面先讲难度设置界面吧,这个和背景音乐开关其实差不多,所以以此为例,背景音乐开关界面就不铝恕U饫镆彩怯玫SharedPreferences存储数据。这里布局文件里把三个RadioButton放入RadioGroup,实现单选的效果。给三个按钮设置监听,触发事件后分别返回对应的三个变量,这三个变量控制的是贪吃蛇运行的速度。
参考下流程图更好理解。
[java] view plain copy
// DifficultyActivity.java
package com.example.wang.
public class DifficultyActivity extends Activity implements OnClickListener{
private SharedP
private SharedPreferences.E
RadioButton button_jiandan,button_yiban,button_
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_difficulty);
saved = PreferenceManager.getDefaultSharedPreferences(this);
int level = saved.getInt("nandu",500);
button_jiandan = (RadioButton) findViewById(R.id.button_difficulty1);
button_yiban = (RadioButton) findViewById(R.id.button_difficulty2);
button_kunnan = (RadioButton) findViewById(R.id.button_difficulty3);
button_jiandan.setOnClickListener(this);
button_yiban.setOnClickListener(this);
button_kunnan.setOnClickListener(this);
public void onClick(View v){
editor=saved.edit();
switch(v.getId()){
case R.id.button_difficulty1:
if(button_jiandan.isChecked()){
editor.putInt("nandu",500);
case R.id.button_difficulty2:
if(button_yiban.isChecked()){
editor.putInt("nandu",200);
case R.id.button_difficulty3:
if(button_kunnan.isChecked()){
editor.putInt("nandu",100);
其它的两个辅助界面比较简单,背景音乐开关界面也是通过SharedPreferences文件存储一个boolean的值,true的话就播放音乐,false就不播放。关于游戏的介绍界面就加一些文字。上述这些都是辅助,下面是游戏的主体部分。
游戏界面的设计思路就是将手机屏幕分为多行多列的像素块,以像素块为最小单位,确定各点的坐标。这里每个像素块的大小设置为32像素。我的手机模拟器的屏幕分辨率为768*1280,由公式可算出,我的游戏界面x轴上坐标最大为24,y轴上坐标最大为35。坐标完成后,这里会使用三种颜色不同的图片来填充像素块,这里就叫砖块把。
根据java面向对象的逻辑,需要给各块内容分类,蛇,苹果,边界的墙都是必不可少的元素。视图的初始化也是围绕着这三个元素展开的。其实这里蛇,苹果和边界墙就是由不同颜色的砖块表示出来的。
该部分内容包含三个java文件,首先是砖块的初始化。
[java] view plain copy
// TileView.java
package com.example.wang.
public class TileView extends View {
public static int mTileSize =32;
public static int mXTileC //地图上所能容纳的格数
public static int mYTileC
public static int mXO
public static int mYO
Bitmap[] mTileA
//放置图片的数组
int[][] mTileG
//存放各坐标对应的图片
public TileView(Context context, AttributeSet attrs,int defStyle){
super(context,attrs,defStyle);
public TileView(Context context, AttributeSet attrs){
super(context,attrs);
public TileView(Context context){
super(context);
//加载三幅小图片
public void loadTile(int key, Drawable tile) {
Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
tile.setBounds(0, 0, mTileSize, mTileSize);
tile.draw(canvas);
mTileArray[key] =
//给地图数组赋值
public void setTile(int tileindex, int x, int y) {
mTileGrid[x][y] =
public void resetTiles(int tilecount) {
mTileArray = new Bitmap[tilecount];
//我的游戏界面不是占满整个屏幕,所以地图遍历的时候,y不是从0开始
public void clearTiles() {
for (int x = 0; x & mXTileC x++) {
for (int y = 2; y & mYTileCount-8; y++) {
setTile(0, x, y);
//计算当前屏幕在X,Y轴上分别所能容纳的最大砖块数量
//这里输出&/span&&span style="font-size:14"&“mXTileCount"和”mYTileCount"的值后面会用到
public void onSizeChanged(int w, int h, int oldw, int oldh){
//地图数组初始化
mXTileCount = (int) Math.floor(w / mTileSize);
mYTileCount = (int) Math.floor(h / mTileSize);
System.out.println("-------"+mXTileCount+"----------");
System.out.println("-------"+mYTileCount+"----------");
//可能屏幕的长宽不能整除,所以够分成一格的分成一格, 剩下不够一格的分成两份,左边一份,右边一份
mXOffset = ((w - (mTileSize * mXTileCount)) / 2);
mYOffset = ((h - (mTileSize * mYTileCount)) / 2);
System.out.println("-------"+mXOffset+"----------");
System.out.println("-------"+mYOffset+"----------");
mTileGrid = new int[mXTileCount][mYTileCount];
clearTiles();
public void onDraw(Canvas canvas){
super.onDraw(canvas);
其实上述这段程序就是实现了几个方法,loadTile()用于加载图片,setTile()和resetTile()是把图片与坐标联系起来,而onSizedChanged()是把手机屏幕像素块化。这些方法都将为以下这个类服务。为了便于利用这些方法,以下这个类继承自TileView。
由于我加了一些按钮,所以游戏界面生成时没有占满整个屏幕,所以在设置坐标和遍历地图时与源码的数据相差较多。
[java] view plain copy
// SnakeView.java
package com.example.wang.
public class SnakeView extends TileView{
static int mMoveDelay = 500;
private long mLastM
private static final int RED_STAR = 1;
private static final int YELLOW_STAR = 2;
private static final int GREEN_STAR = 3;
private static final int UP = 1;
private static final int DOWN = 2;
private static final int RIGHT = 3;
private static final int LEFT = 4;
static int mDirection = RIGHT;
static int mNextDirection = RIGHT;
// 这里把游戏界面分为5种状态,便于逻辑实现
public static final int PAUSE = 0;
public static final int READY = 1;
public static final int RUNNING = 2;
public static final int LOSE = 3;
public static final int QUIT = 4;
public int mMode = READY;
public int newM
private TextView mStatusT
// 用于每个状态下的文字提醒
public long mScore = 0;
private ArrayList&Coordinate& mSnakeTrail = new ArrayList&Coordinate&(); // 存储蛇的所有坐标的数组
private ArrayList&Coordinate& mAppleList = new ArrayList&Coordinate&(); // 存储苹果的所有坐标的数组
private static final Random RNG = new Random();
//用于生成苹果坐标的随机数
private static final String TAG = "SnakeView";
//开启线程,不断调用更新和重绘。这里利用了Handler类来实现异步消息处理机制
MyHandler handler=new MyHandler();
class MyHandler extends Handler{
public void handleMessage(Message msg) {
SnakeView.this.update();
//不断调用update()方法
SnakeView.this.invalidate();
//请求重绘,不断调用ondraw()方法
//调用sleep后,在一段时间后再sendmessage进行UI更新
public void sleep(int delayMillis) {
this.removeMessages(0);
//清空消息队列
sendMessageDelayed(obtainMessage(0), delayMillis);
//这是三个构造方法,别忘了加上下面这个初始化方法
public SnakeView(Context context, AttributeSet attrs, int defStyle){
super(context,attrs,defStyle);
initNewGame();
public SnakeView(Context context, AttributeSet attrs){
super(context,attrs);
setFocusable(true);
initNewGame();
public SnakeView(Context context){
super(context);
//添加苹果的方法,最后将生成的苹果坐标存储在上面定义的数组中
private void addRandomApple() {
Coordinate newCoord =
boolean found =
while (!found) {
// 这里设定了苹果坐标能随机生成的范围,并生成随机坐标。这里Google源码中是直接使用变量
// mXTileCount和mYTileCount,我编译时会报错,因为随机数不能生成负数,而直接使用这两个变量程序不能
// 识别这个变量减去一个数后是否会是负数,所以我把TileView里输出的确切值放了进去
int newX = 1 + RNG.nextInt(24-2);
int newY = 3 + RNG.nextInt(35-12);
newCoord = new Coordinate(newX, newY);
boolean collision =
int snakelength = mSnakeTrail.size();
//遍历snake, 看新添加的apple是否在snake体内, 如果是,重新生成坐标
for (int index = 0; index & index++) {
if (mSnakeTrail.get(index).equals(newCoord)) {
collision =
if (newCoord == null) {
Log.e(TAG, "Somehow ended up with a null newCoord!");
mAppleList.add(newCoord);
//绘制边界的墙
private void updateWalls() {
for (int x = 0; x & mXTileC x++) {
setTile(GREEN_STAR, x, 2);
setTile(GREEN_STAR, x, mYTileCount - 8);
for (int y = 2; y & mYTileCount - 8; y++) {
setTile(GREEN_STAR, 0, y);
setTile(GREEN_STAR, mXTileCount - 1, y);
//更新蛇的运动轨迹
private void updateSnake(){
boolean growSnake =
Coordinate head = mSnakeTrail.get(0);
Coordinate newHead = new Coordinate(1, 1);
mDirection = mNextD
switch (mDirection) {
case RIGHT: {
newHead = new Coordinate(head.x + 1, head.y);
case LEFT: {
newHead = new Coordinate(head.x - 1, head.y);
case UP: {
newHead = new Coordinate(head.x, head.y - 1);
case DOWN: {
newHead = new Coordinate(head.x, head.y + 1);
//检测是否撞墙
if ((newHead.x & 1) || (newHead.y & 3) || (newHead.x & mXTileCount - 2)
|| (newHead.y & mYTileCount - 9)) {
setMode(LOSE);
//检测蛇头是否撞到自己
int snakelength = mSnakeTrail.size();
for (int snakeindex = 0; snakeindex & snakeindex++) {
Coordinate c = mSnakeTrail.get(snakeindex);
if (c.equals(newHead)) {
setMode(LOSE);
//检测蛇是否吃到苹果
int applecount = mAppleList.size();
for (int appleindex = 0; appleindex & appleindex++) {
Coordinate c = mAppleList.get(appleindex);
if (c.equals(newHead)) {
mAppleList.remove(c);
addRandomApple();
mMoveDelay *= 0.95;
//蛇每迟到一个苹果,延时就会减少,蛇的速度就会加快
growSnake =
mSnakeTrail.add(0,newHead);
if(!growSnake) {
mSnakeTrail.remove(mSnakeTrail.size() - 1);
//蛇头和蛇身分别设置不同的图片
int index=0;
for(Coordinate c:mSnakeTrail) {
if(index == 0) {
setTile(RED_STAR, c.x, c.y);
setTile(YELLOW_STAR,c.x,c.y);
给苹果加载对应的图片
private void updateApples() {
for (Coordinate c : mAppleList) {
setTile(YELLOW_STAR, c.x, c.y);
// 该方法很重要,用于更新蛇,苹果和墙的坐标
// 这里设置了更新的时间间隔,我发现不加这个延时的话蛇运动时容易出现一下跳很多格的情况
public void update(){
if(mMode == RUNNING) {
long now = System.currentTimeMillis();
if (now - mLastMove & mMoveDelay) {
clearTiles();
updateWalls();
updateSnake();
updateApples();
mLastMove =
handler.sleep(mMoveDelay);
//图像初始化,引入图片资源
private void initSnakeView() {
setFocusable(true);
//添加焦点
Resources r = this.getContext().getResources();
//添加几种不同的tile
resetTiles(4);
//从文件中加载图片
loadTile(RED_STAR, r.getDrawable(R.drawable.redstar));
loadTile(YELLOW_STAR, r.getDrawable(R.drawable.yellowstar));
loadTile(GREEN_STAR, r.getDrawable(R.drawable.greenstar));
// 数据初始化方法,定义蛇的起始坐标,运动方向和得分变量。给数组添加坐标的时候注意顺序,因为有蛇头和蛇尾的区别
public void initNewGame() {
mSnakeTrail.clear();
mAppleList.clear();
//snake初始状态时的个数和位置,方向
mSnakeTrail.add(new Coordinate(8, 7));
mSnakeTrail.add(new Coordinate(7, 7));
mSnakeTrail.add(new Coordinate(6, 7));
mSnakeTrail.add(new Coordinate(5, 7));
mSnakeTrail.add(new Coordinate(4, 7));
mSnakeTrail.add(new Coordinate(3, 7));
mDirection = RIGHT;
mNextDirection = RIGHT; // 这个变量必须初始化,不然每次游戏结束重新开始后,蛇初始的方向将不是向右,而是你游戏结束时蛇的方向,
// 如果死的时候,蛇的方向向左,那么再次点击开始时会无法绘出蛇的图像
addRandomApple();
// 根据各个数组中的数据,遍历地图设置各点的图片
public void onDraw(Canvas canvas){
super.onDraw(canvas);
Paint paint=new Paint();
initSnakeView();
//遍历地图绘制界面
for (int x = 0; x & mXTileC x++) {
for (int y = 0; y & mYTileC y++) {
if (mTileGrid[x][y] & 0) {
// 被加了图片的点mTileGird是大于0的
canvas.drawBitmap(mTileArray[mTileGrid[x][y]], mXOffset + x * mTileSize, mYOffset + y * mTileSize, paint);
//把蛇和苹果各点对应的坐标利用一个一维数组储存起来
private int[] coordArrayListToArray(ArrayList&Coordinate& cvec) {
int count = cvec.size();
int[] rawArray = new int[count * 2];
for (int index = 0; index & index++) {
Coordinate c = cvec.get(index);
rawArray[2 * index] = c.x;
rawArray[2 * index + 1] = c.y;
return rawA
//将当前所有的游戏数据全部保存
public Bundle saveState() {
Bundle map = new Bundle();
map.putIntArray("mAppleList", coordArrayListToArray(mAppleList));
map.putInt("mDirection", Integer.valueOf(mDirection));
map.putInt("mNextDirection", Integer.valueOf(mNextDirection));
map.putInt("mMoveDelay", Integer.valueOf(mMoveDelay));
map.putLong("mScore", Long.valueOf(mScore));
map.putIntArray("mSnakeTrail", coordArrayListToArray(mSnakeTrail));
//是coordArrayListToArray()的逆过程,用来读取数组中的坐标数据
private ArrayList&Coordinate& coordArrayToArrayList(int[] rawArray) {
ArrayList&Coordinate& coordArrayList = new ArrayList&Coordinate&();
int coordCount = rawArray.
for (int index = 0; index & coordC index += 2) {
Coordinate c = new Coordinate(rawArray[index], rawArray[index + 1]);
coordArrayList.add(c);
return coordArrayL
//saveState()的逆过程,用于恢复游戏数据
public void restoreState(Bundle icicle) {
setMode(PAUSE);
mAppleList = coordArrayToArrayList(icicle.getIntArray("mAppleList"));
mDirection = icicle.getInt("mDirection");
mNextDirection = icicle.getInt("mNextDirection");
mMoveDelay = icicle.getInt("mMoveDelay");
mScore = icicle.getLong("mScore");
mSnakeTrail = coordArrayToArrayList(icicle.getIntArray("mSnakeTrail"));
// 设置键盘监听,在模拟器中可以使用电脑键盘控制蛇的方向
public boolean onKeyDown(int keyCode, KeyEvent event){
if(keyCode == KeyEvent.KEYCODE_DPAD_UP){
if(mDirection != DOWN) {
mNextDirection = UP;
return (true);
if(keyCode == KeyEvent.KEYCODE_DPAD_DOWN){
if(mDirection != UP) {
mNextDirection = DOWN;
return (true);
if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
if(mDirection != LEFT) {
mNextDirection = RIGHT;
return (true);
if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
if(mDirection != RIGHT) {
mNextDirection = LEFT;
return (true);
return super.onKeyDown(keyCode,event);
public void setTextView(TextView newView) {
mStatusText = newV
// 设置不同状态下提示文字的显示内容和可见状态
public void setMode(int newMode) {
this.newMode=newM
int oldMode = mM
mMode = newM
if (newMode == RUNNING & oldMode != RUNNING) {
mStatusText.setVisibility(View.INVISIBLE);
// 这里定义了一个空字符串,用于放入各个状态下的提醒文字
Resources res = getContext().getResources();
CharSequence str = "";
if (newMode == PAUSE) {
str = res.getText(R.string.mode_pause);
if (newMode == READY) {
str = res.getText(R.string.mode_ready);
if (newMode == LOSE) {
str = res.getString(R.string.mode_lose_prefix) + mScore
+ res.getString(R.string.mode_lose_suffix);
if (newMode == QUIT){
str = res.getText(R.string.mode_quit);
mStatusText.setText(str);
mStatusText.setVisibility(View.VISIBLE);
//记录坐标位置
private class Coordinate {
public Coordinate(int newX, int newY) {
//触碰检测,看蛇是否吃到苹果
public boolean equals(Coordinate other) {
if (x == other.x && y == other.y) {
// 这个方法没研究过起什么作用,我注释掉对程序的运行没有影响
public String toString() {
return "Coordinate: [" + x + "," + y + "]";
以上是自定义View的实现,实现了绘制游戏界面的主逻辑。将SnakeView作为一个UI控件插入到该界面的布局中。
下面开启活动,显示界面。
[java] view plain copy
// GameActivity.java
package com.example.wang.
public class GameActivity extends Activity implements OnClickListener{
private SharedP
private static String ICICLE_KEY = "snake-view";
// 个人认为这个变量就是一个中间值,在该类的最后一个方法中传入该变量,完成操作。
private SnakeView mSnakeV
private ImageButton change_stop,change_start,change_
private ImageButton mL
private ImageButton mR
private ImageButton mUp;
private ImageButton mD
private static final int UP = 1;
private static final int DOWN = 2;
private static final int RIGHT = 3;
private static final int LEFT = 4;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
mSnakeView = (SnakeView) findViewById(R.id.snake); //给自定义View实例化,把这个布局当一个UI控件一样插入进来
mSnakeView.setTextView((TextView) findViewById(R.id.text_show));
change_stop = (ImageButton) findViewById(R.id.game_stop);
change_start = (ImageButton) findViewById(R.id.game_start);
change_quit = (ImageButton) findViewById(R.id.game_quit);
mLeft = (ImageButton) findViewById(R.id.left);
mRight = (ImageButton) findViewById(R.id.right);
mUp = (ImageButton) findViewById(R.id.up);
mDown = (ImageButton) findViewById(R.id.down);
change_start = (ImageButton) findViewById(R.id.game_start);
change_stop = (ImageButton) findViewById(R.id.game_stop);
change_quit = (ImageButton) findViewById(R.id.game_quit);
saved = PreferenceManager.getDefaultSharedPreferences(this);
boolean playMusic = saved.getBoolean("ifon" ,true);
// 获取背景音乐开关的状态变量,在设置开关界面存储,在这里读取
if(playMusic) {
// 如果设置背景音乐打开,则开启服务,播放音乐
Intent intent_service = new Intent(GameActivity.this, MusicService.class);
startService(intent_service);
SnakeView.mMoveDelay=saved.getInt("nandu",500);
// 获取当前设置的代表游戏难度的变量,在难度设置界面保存,在这里读取
// 判断是否有保存数据,如果数据为空就准备重新开始游戏
if (savedInstanceState == null) {
mSnakeView.setMode(SnakeView.READY);
// 暂停后的恢复
Bundle map = savedInstanceState.getBundle(ICICLE_KEY);
if (map != null) {
mSnakeView.restoreState(map);
mSnakeView.setMode(SnakeView.PAUSE);
mDown.setOnClickListener(this);
mUp.setOnClickListener(this);
mRight.setOnClickListener(this);
mLeft.setOnClickListener(this);
change_start.setOnClickListener(this);
change_stop.setOnClickListener(this);
change_quit.setOnClickListener(this);
public void onDestroy(){
super.onDestroy();
saved = PreferenceManager.getDefaultSharedPreferences(this);
boolean playMusic = saved.getBoolean("ifon" ,true);
if(playMusic) {
Intent intent_service = new Intent(GameActivity.this, MusicService.class);
stopService(intent_service);
// 给开始,暂停,退出,上下左右按钮设置监听。根据当前的状态来决定界面的更新操作
public void onClick(View v) {
switch (v.getId()) {
case R.id.game_start:
// 重新开始游戏,这里延时变量必须初始化,不然每次游戏重新开始之后,蛇的运动速度不会初始化
if ( mSnakeView.mMode == SnakeView.READY || mSnakeView.mMode == SnakeView.LOSE) {
SnakeView.mMoveDelay=saved.getInt("nandu",500);
mSnakeView.initNewGame();
mSnakeView.setMode(SnakeView.RUNNING);
mSnakeView.update();
// 暂停后开始游戏,继续暂停前的界面
if ( mSnakeView.mMode == SnakeView.PAUSE) {
mSnakeView.setMode(SnakeView.RUNNING);
mSnakeView.update();
case R.id.game_stop:
if(mSnakeView.mMode == SnakeView.RUNNING) {
mSnakeView.setMode(SnakeView.PAUSE);
case R.id.game_quit:
// 退出,返回菜单界面
mSnakeView.setMode(SnakeView.QUIT);
// 使界面上的方向按钮起作用
case R.id.left:
if (SnakeView.mDirection != RIGHT) {
SnakeView.mNextDirection = LEFT;
case R.id.right:
if (SnakeView.mDirection != LEFT) {
SnakeView.mNextDirection = RIGHT;
case R.id.up:
if (SnakeView.mDirection != DOWN) {
SnakeView.mNextDirection = UP;
case R.id.down:
if (SnakeView.mDirection != UP) {
SnakeView.mNextDirection = DOWN;
protected void onPause() {
super.onPause();
mSnakeView.setMode(SnakeView.PAUSE);
public void onSaveInstanceState(Bundle outState) {
//保存游戏状态
outState.putBundle(ICICLE_KEY, mSnakeView.saveState());
下面是游戏效果图,运行界面和暂停界面。我把逻辑流程图也贴出来,有什么问题大家可以留言,多多交流!
本文通过带大家回忆经典游戏的同时,学习了利用java开发Android游戏――贪吃蛇,希望本文在大家学习Android开发有所帮助。&&&&&
顶一下(0) 踩一下(0)
热门标签:}

我要回帖

更多关于 visual studio 贪吃蛇 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信