您的位置:首页 > 移动开发 > Android开发

Android组件学习笔记(贪吃蛇小demo)

2017-11-11 14:38 465 查看
自学Android也有点时间了,做了个贪吃蛇小demo,花了我大概四天时间,期间遇到很多问题,不过好在一一解决了,对Android体系以及运用也更加的熟练了,总之很有收获,写下文章与大家一起进步加油。






(注意:手机版本不同会导致运行效果不好,我会继续调整的)

这个问题已经解决,请点击前往最新版本查看:贪吃蛇2.0

成品下载:

链接:https://share.weiyun.com/88442b473ddd658b1b7eb7aab159b6a6 

密码:2RBxnL

简要功能:

1.随机生成食物
2.蛇移动
3.蛇吃食物
4.蛇长身体
5.蛇死亡重生
6.暂停与开始游戏
7.组件显示关键数据

遇到问题:

1.自定义View的设计与使用不熟练(经过这个demo熟悉了很多)
2.根据不同的手机运行环境不同,导致游戏效果不同(通过获取屏幕数据来调整,但实际效果仍然未达到我的标准,大家如果下载的的代码的话可能会因为版本导致一些问题)
3.信号的传递效率问题,有些信号为触发的,不需要放置与循环中(新建判断信号来控制是否调用就好)
4.改代码问题(尽量用函数)
5.不知道哪有问题的问题(调试,Android的调试我还不太熟练)
6.信号传递机制(不会使用,上网找资料学习)
7.界面设计问题,自定义的不好再加组件(权重以及布局,在布局中添加,并且一些细节代码会使得其更加美观)
8.存储蛇的数据问题数组十分麻烦(用ArrayList十分方便)
9.触摸信号根据不同状态来调整具体状态

图片:







源代码:

mainactivity代码:

package com.example.hp.likeeatsnake;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutCompat;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget
4000
.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

SnakeView game;//游戏View
Button butstart;//按钮可控制暂停,开始、、重生
TextView textgrade,textjudge;//两个组件显示关键数据
private boolean ifstop=false;//判断是否暂停
int rembut=1;//调节按钮背景图
int remgrade;//显示吃的食物
String stringgrade;//显示吃的食物数//字符串类型才可以显示
private Handler mHandler = new Handler() { //thread handler 消息处理
@Override
public void handleMessage(Message msg) {//消息传递机制
// TODO Auto-generated method stub
super.handleMessage(msg);
if(msg.arg1 == 1) {
if(game != null) {
game.invalidate();//刷新界面
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
butstart=(Button)findViewById(R.id.butstart);
textgrade=(TextView)findViewById(R.id.grade);
textjudge=(TextView)findViewById(R.id.judge);
game=(SnakeView)findViewById(R.id.game);
WindowManager manager = getWindowManager();
DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);//获取屏幕高宽
int width = metrics.widthPixels;  //以要素为单位
int height = metrics.heightPixels;
butstart.setBackgroundResource(R.drawable.stop);
butstart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(game.ifhasdead()==true)//点击一下转变状态和背景图、、如果蛇死了连续点击两次则重新开始
{
game.setsnake();
remgrade=0;
textjudge.setText("活");
}
if(rembut==1)
{
ifstop=true;
butstart.setBackgroundResource(R.drawable.start1);
rembut=2;
}
else
{
ifstop=false;
butstart.setBackgroundResource(R.drawable.stop);
rembut=1;
}
}
});
game.getnum(height,width);//得到屏幕数据
game.creatsnake();//创造蛇
game.setdirect(1);//设置蛇的移动方向

Thread t=new Thread(new Runnable() {
@Override
public void run() {
while(true)
{
Message msg = mHandler.obtainMessage();//消息处理机制
msg.arg1 = 1;
mHandler.sendMessage(msg);
try {//必须要用try catch 不知道为啥,否则就有错
if(ifstop==false)
{
game.engine();//未暂停时游戏引擎运行
}
if(game.ifeat()==true)//如果蛇吃到了食物则得到数据,并刷新显示他的组件
{
remgrade=game.givegrade();
stringgrade=String.valueOf(remgrade);
try {//为啥这里要用try catch我不知道
textgrade.setText(stringgrade);
} catch (Exception e) {
e.printStackTrace();
}
game.setifeatfood();//恢复原来的状态,进行下一次捕食
}
if(game.ifhasdead()==true)//蛇死了就刷新显示的组件
{
try {//为啥这里要用try catch我不知道
textjudge.setText("死");
} catch (Exception e) {
e.printStackTrace();
}
}
if(remgrade<=5)//根据得分调整蛇的移动速度
{
Thread.sleep(300);
}
else if(remgrade>=5&&remgrade<=10)
{
Thread.sleep(200);
}
else if(remgrade>10&&remgrade<=20)
{
Thread.sleep(100);
}
else
{
Thread.sleep(50);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();//开启线程
}
}
自定义View代码:

package com.example.hp.likeeatsnake;

import android.view.View;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Random;
import java.util.Vector;

public class SnakeView extends View {
private Paint edge,snake;//画边界的画笔与画蛇与食物的画笔
private int height,width,direct=1,speed=30;//记录屏幕高度宽度与蛇的方向1,2,3,4和蛇移动步伐大小
private float foodpos_x=800,foodpos_y=800;//记录食物的位置
Random random;//随机数使用前必须刷新
private boolean ifcreatfood=true;//判断条件是否允许产生食物
private boolean ifdead=false;//判断蛇是否死亡
private boolean ifstop=false;//游戏是否暂停//可能为暂停,也可能为蛇死亡
private boolean ifeatfood=false;//判断是否吃到了食物
private ArrayList<Point> mSnakeList;  //蛇体可以看做是很多食物组成的
private int grade=0;//记录吃的食物个数
private int ifbenew=0;//它是信号,显示是否刷新画布
private float jx,jy,jx2,jy2;//记录手指的位置,以此调节蛇的方向

public SnakeView(Context context)//画笔初始化不在这里,我也不知道为啥
{
super(context);
}
public SnakeView(Context context, AttributeSet set)//画笔初始化在这里,我还是不知道为啥,另外少了这段代码无法运行成功
{
super(context,set);

mSnakeList = new ArrayList<Point>();

edge=new Paint();//画笔初始化
edge.setColor(Color.BLACK);
edge.setStrokeWidth(20);
edge.setStyle(Paint.Style.STROKE);//设置画笔风格,空心或实心

snake=new Paint();//画笔初始化
snake.setColor(Color.RED);
snake.setStrokeWidth(30);
snake.setStyle(Paint.Style.FILL);
}
public void creatsnake()//创造蛇
{
mSnakeList.add(new Point(500,500));
ifcreatfood=true;//初始化蛇的数据
ifdead=false;
}
public void ifsnakedead()//判断蛇是否死亡
{
int test=1;
if(mSnakeList.get(0).x<=30||mSnakeList.get(0).x>=width-30||mSnakeList.get(0).y<=30||mSnakeList.get(0).y>=1280)//判断是否越过边界
{
ifdead= true;
}
else
{
ifdead=false;
}
for(int i=4;i<mSnakeList.size();i++)
{
if(mSnakeList.get(0).x==mSnakeList.get(i).x&&mSnakeList.get(0).y==mSnakeList.get(i).y)
{
ifdead= true;
}
}
}

//给外界信号作为判断依据,并有函数从外界来调节信号
public boolean ifhasdead()
{
return ifdead;
}

public void setsnake()//复活蛇
{
ifdead=false;
mSnakeList=new ArrayList<>();//
mSnakeList.add(new Point(500,500));
ifcreatfood=true;//初始化蛇的数据
grade=0;
ifdead=false;
}
public boolean ifeat()
{
return ifeatfood;
}

public void setifeatfood()
{
ifeatfood=false;
}

public void snakeeat()
{
Point oldhead=mSnakeList.get(0);
if (oldhead.x - foodpos_x <= 30&&oldhead.x-foodpos_x>=0 || foodpos_x - oldhead.x <= 30&&foodpos_x - oldhead.x >=0) {
if (oldhead.y - foodpos_y <= 30&&oldhead.y-foodpos_y>=0 || foodpos_y-oldhead.y>=0&&foodpos_y - oldhead.y <= 30) {
Point newhead=new Point();
switch (direct)//上下左右、 头动
{
case 1:
newhead.x = oldhead.x;
newhead.y = oldhead.y  - speed ;
break;
case 2:
newhead.x = oldhead.x;
newhead.y = oldhead.y  + speed ;
break;
case 3:
newhead.x = oldhead.x  - speed;
newhead.y = oldhead.y;
break;
case 4:
newhead.x = oldhead.x + speed ;
newhead.y = oldhead.y;
break;
default:
break;
}
mSnakeList.add(0,newhead);//吃东西头部加一,尾部不管
grade+=1;ifeatfood=true;
ifcreatfood=true;//准备生产新的食物
}
}
}
public int givegrade()
{
return grade;
}
public boolean ifcancreatfood()//告诉系统是否生成食物
{
return ifcreatfood;
}
public void snakemove()//控制蛇的移动
{
if(ifdead==false)
{
Point oldhead = mSnakeList.get(0);
Point newhead = new Point();
//身体除了头外全部移动
switch (direct)//上下左右、 头动
{
case 1:
newhead.x = oldhead.x;
newhead.y = oldhead.y  - speed ;
break;
case 2:
newhead.x = oldhead.x;
newhead.y = oldhead.y  + speed ;
break;
case 3:
newhead.x = oldhead.x  - speed;
newhead.y = oldhead.y;
break;
case 4:
newhead.x = oldhead.x + speed ;
newhead.y = oldhead.y;
break;
default:
break;
}
mSnakeList.add(0,newhead);//头部加一,尾部减一实现移动
mSnakeList.remove(mSnakeList.size() - 1);
}
}
public void creatfood()//状态允许的话使用随机数生成下一个事物的位置
{
Point head=mSnakeList.get(0);
if(ifcreatfood==true)
{
int ok;
while(true)//食物的位置不能与蛇的身体重合
{
ok=0;
random=new Random();foodpos_x = random.nextInt(970) + 50;
random=new Random();foodpos_y = random.nextInt(1200) + 50;
for(int i=0;i<mSnakeList.size();i++)
{
if(foodpos_x!=head.x||foodpos_y!=head.y)
{
ok++;
}
}
if(ok==mSnakeList.size())break;
}
ifcreatfood=false;
}
}
public void getnum(int height,int width)//从外界得到屏幕的数据
{
this.height=height;
this.width=width;
}
public void setdirect(int direct)//从外界得到一个数字表示方向
{
this.direct=direct;
}
public void engine()//游戏引擎
{
ifsnakedead();
snakeeat();
creatfood();
snakemove();
ifbenew=1;
}
public void drawedge(Canvas canvas)//画出边界
{
canvas.drawRect(10,10,width-10,1300,edge);
}
public void drawfood(Canvas canvas)//画食物
{
snake.setColor(Color.BLUE);
canvas.drawCircle(foodpos_x,foodpos_y,30,snake);//坐标,半径,使用的画笔
}
public void drawsnake(Canvas canvas)//画蛇
{
snake.setColor(Color.RED);
for(int i=0;i<mSnakeList.size();i++)//画蛇
{
Point point = mSnakeList.get(i);
canvas.drawCircle(point.x,point.y,30,snake);
}
}
@Override
protected void onDraw(Canvas canvas) //画画
{
super.onDraw(canvas);
drawedge(canvas);
drawfood(canvas);
drawsnake(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) //根据触屏滑动改变方向
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
jx=event.getX();
jy=event.getY();
break;
case MotionEvent.ACTION_UP:
jx2=event.getX();
jy2=event.getY();
float endx=jx-jx2,endy=jy-jy2;
if(endx>0)
{
if(endy>0)
{
if(endx>endy) direct=3;
else direct=1;//
}
else if(endy<0)
{
endy*=-1;
if(endx>endy) direct=3;
else direct=2;
}
}
else if(endx<0)
{
endx*=-1;
if(endy>0)
{
if(endx<endy) direct=1;
else direct=4;
}
else if(endy<0)
{
endy*=-1;
if(endx<endy) direct=2;
else direct=4;
}
}
break;
}
return true;
}
}
布局代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hp.likeeatsnake.MainActivity">

<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"

app:layout_constraintVertical_weight="12"

tools:layout_editor_absoluteY="8dp"
tools:layout_editor_absoluteX="8dp">

<com.example.hp.likeeatsnake.SnakeView
android:id="@+id/game"
android:layout_width="match_parent"
android:layout_height="wrap_content"

android:layout_weight="12"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="0dp" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:orientation="horizontal">

<TextView
android:id="@+id/grade"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="left"
android:gravity="center"
android:text="0"
android:textAlignment="center"
android:textAllCaps="false"
android:textSize="30sp"

a05d
android:textStyle="bold" />

<Button
android:id="@+id/butstart"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"

tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="0dp" />

<TextView
android:id="@+id/judge"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="right"
android:gravity="center"

android:text="活"
android:textAlignment="center"
android:textSize="30sp"
android:textStyle="bold" />

</LinearLayout>

</LinearLayout>

</android.support.constraint.ConstraintLayout>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: