Android学习笔记(贪吃蛇升级版)


   通过最近的学习搞懂了原来的贪吃蛇的问题出在哪里了,只是因为屏幕标题占了空间使得算法出错,使得只能用固定值设计View造成了不同手机运行效果不一样的现象,通过隐藏掉标题,随着屏幕分辨率动态设计成功解决了这个问题,另外还修改了一点细节,使得更加人性化了。

改进是在原来贪吃蛇代码基础上修改的,更说明了抽象以及做好结构的重要性,仅仅修改一些参数就差不多了。

点击访问旧版本:

贪吃蛇1.0版本

成品下载:

链接:https://share.weiyun.com/1f9673983201142890bd9182335a5e2e 

密码:

Mh0vpO

简要功能:

1.随机生成食物
2.蛇移动
3.蛇吃食物
4.蛇长身体
5.蛇死亡重生
6.暂停与开始游戏
7.组件显示关键数据
注意:
1.项目中含有图片文件,需要在相应位置修改添加才可运行,建议先看懂代码再拷贝代码测试,否则很可能出现不必要的问题
2.还有食物的大小设置还是固定值,希望读者可以读懂后自己修改

图片样例:


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.ActionBarContainer;
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.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);


        if (getSupportActionBar() != null) {//去掉标题栏
            //因为屏幕标题的原因导致绝对分辨率与相对分辨率存在差异,去掉标题就可以了
            getSupportActionBar().hide();
        }

        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);



        Toast.makeText(this, "made by Changing,略略略略略", Toast.LENGTH_SHORT).show();


        DisplayMetrics dm=new DisplayMetrics();//获取屏幕数据分辨率
        super.getWindowManager().getDefaultDisplay().getMetrics(dm);
        int width=dm.widthPixels,height=dm.heightPixels;


        game.getnum(height,width);//传递数据给游戏view




        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;//记录手指的位置,以此调节蛇的方向


    private float snakeBody;//设置蛇的身材,随着屏幕不同蛇,的胖瘦也不同

    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>=height-30)//判断是否越过边界
        {
            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(width-300) + 50;
                random=new Random();foodpos_y = random.nextInt(height-300) + 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/6*5;
        this.width=width-10;//处理数据使得游戏界面更加合理

        snakeBody=width/38;
    }
    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,height,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.GREEN);//画出蛇的头且稍微大一点
        Point point = mSnakeList.get(0);
        canvas.drawCircle(point.x,point.y,snakeBody+5,snake);


        snake.setColor(Color.RED);
        for(int i=1;i<mSnakeList.size();i++)//画蛇
        {
            Point point1 = mSnakeList.get(i);
            canvas.drawCircle(point1.x,point1.y,snakeBody,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"
             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>


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值