是男人就下100层【第四层】——Crazy贪吃蛇(2)

在上一篇《是男人就下100层【第四层】——Crazy贪吃蛇(1)》中我们让贪吃蛇移动了起来,接下来我们来实现让贪吃蛇可以绕着手机屏幕边线移动并且可以改变方向

一、添加状态并修改代码

首先我们来用另外一种方式实现上一版本中的刷新界面,在Crazy贪吃蛇(1)中我们自定义了一个线程每隔1s钟刷新界面,在线程中我们使用了postInvalidate()方法通知主线程重绘界面,我们打开View的源代码看看到底是如何通知主线程的,原代码如下:

   public void postInvalidate(int left, int top, int right, int bottom) {
        postInvalidateDelayed(0, left, top, right, bottom);
    }

    /**
     * Cause an invalidate to happen on a subsequent cycle through the event
     * loop. Waits for the specified amount of time.
     *
     * @param delayMilliseconds the duration in milliseconds to delay the
     *         invalidation by
     */
    public void postInvalidateDelayed(long delayMilliseconds) {
        // We try only with the AttachInfo because there‘s no point in invalidating
        // if we are not attached to our window
        if (mAttachInfo != null) {
            Message msg = Message.obtain();
            msg.what = AttachInfo.INVALIDATE_MSG;
            msg.obj = this;
            mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
        }
    }

    /**
     * Cause an invalidate of the specified area to happen on a subsequent cycle
     * through the event loop. Waits for the specified amount of time.
     *
     * @param delayMilliseconds the duration in milliseconds to delay the
     *         invalidation by
     * @param left The left coordinate of the rectangle to invalidate.
     * @param top The top coordinate of the rectangle to invalidate.
     * @param right The right coordinate of the rectangle to invalidate.
     * @param bottom The bottom coordinate of the rectangle to invalidate.
     */
    public void postInvalidateDelayed(long delayMilliseconds, int left, int top,
            int right, int bottom) {

        // We try only with the AttachInfo because there‘s no point in invalidating
        // if we are not attached to our window
        if (mAttachInfo != null) {
            final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire();
            info.target = this;
            info.left = left;
            info.top = top;
            info.right = right;
            info.bottom = bottom;

            final Message msg = Message.obtain();
            msg.what = AttachInfo.INVALIDATE_RECT_MSG;
            msg.obj = info;
            mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
        }
    }

从上面源代码中我们可以看到最后一句代码mAttachInfo.mHandler.sendMessageDelayed(msg, delayMillisecods),原来也是通过Handler来实现界面刷新的,既然是这样我们就将我们的代码修改如下:

创建一个RefreshHandler类

    class RefreshHandler extends Handler{
    	@Override
    	public void handleMessage(Message msg) {
    		MySnake.this.update();
    		MySnake.this.invalidate();

    	}

    	public void sleep(long delayMillis) {
			this.removeMessages(0);
			sendMessageDelayed(obtainMessage(0), delayMillis);
		}
    }

定义了游戏中的四种状态

    private enum State{
    	READY,    //就绪
    	PAUSE,    //暂停
    	RUNNING,  //运行
    	LOSE      //失败
    }
    private void update(){
    	if(currentState == State.RUNNING){
			move();
			mRefreshHandler.sleep(1000);
    	}
    }

我们再来看看上个版本中使蛇移动的核心代码:

        case LEFT:
            /*for(int i=0; i<boxs.size(); i++){
                box = boxs.get(i);
                box.setX(box.getX() - boxSize);
            } */
            boxs.add(0, new Box(boxs.get(0).getX() - boxSize, 0));
            boxs.remove(boxs.size() - 1);
            break;
        case RIGHT:  

           /* for(int i=0; i<boxs.size(); i++){
                box = boxs.get(i);
                box.setX(box.getX() + boxSize);
            }  */
            boxs.add(new Box(boxs.get(boxs.size() - 1).getX() + boxSize, 0));
            boxs.remove(0);
            break; 

我们不用遍历每一个方块来实现蛇的移动,我们只需要去改变蛇首和蛇未即可实现。

修改后的MySnake.java文件

package com.example.crazysnake;  

import java.util.ArrayList;
import java.util.List;  

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
 * CSDN博客:http://blog.csdn.net/dawanganban
 * @author 阳光小强
 */
public class MySnake extends View {
    private Paint paint;
    private RectF rect;  

    private int boxSize = 30;  

   // private SnakeThread snakeThread;  

    private List<Box> boxs = new ArrayList<Box>(); 

    private static final int[] colors = {
        Color.RED,
        Color.BLUE,
        Color.GREEN,
        Color.YELLOW
    };  

    private enum Derectory{
        LEFT,
        RIGHT,
        TOP,
        BOTTOM;
    }  

    private enum State{
    	READY,    //就绪
    	PAUSE,    //暂停
    	RUNNING,  //运行
    	LOSE      //失败
    }

    private Derectory currentDerect = Derectory.RIGHT;
    private State currentState = State.PAUSE;

    private RefreshHandler mRefreshHandler = new RefreshHandler();
    class RefreshHandler extends Handler{
    	@Override
    	public void handleMessage(Message msg) {
    		MySnake.this.update();
    		MySnake.this.invalidate();

    	}

    	public void sleep(long delayMillis) {
			this.removeMessages(0);
			sendMessageDelayed(obtainMessage(0), delayMillis);
		}
    }

    public MySnake(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        rect = new RectF();
        initData();
        //startThread();
    }  

/*    public void startThread(){
        if(snakeThread == null){
            snakeThread = new SnakeThread();
            snakeThread.start();
        }
    } */ 

    private void update(){
    	if(currentState == State.RUNNING){
			move();
			mRefreshHandler.sleep(1000);
    	}
    }

    private void initData(){
        Box box;
        for(int i=0; i<10; i++){
            box = new Box(i*boxSize, 0);
            boxs.add(box);
        }
    }  

    private float mDownX;
    private float mDownY;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        System.out.println("onTouch");
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mDownX = event.getX();
            mDownY = event.getY();
            break;
        case MotionEvent.ACTION_UP:
            float disX = event.getX() - mDownX;
            float disY = event.getY() - mDownY;
            System.out.println("disX = " + disX);
            System.out.println("dixY = " + disY);
            if(Math.abs(disX) > Math.abs(disY)){
                if(disX > 0){
                	if(currentState != State.RUNNING){
                		currentState = State.RUNNING;
                		update();
                	}
                    currentDerect = Derectory.RIGHT;
                }else{
                    currentDerect = Derectory.LEFT;
                }
            }else{
                if(disY > 0){
                    currentDerect = Derectory.BOTTOM;
                }else{
                    currentDerect = Derectory.TOP;
                }
            }
            break;
        }
        return true;
    }  

/*    private class SnakeThread extends Thread{
        private boolean stoped = false;
        @Override
        public void run() {
            while(!stoped){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                move();
                postInvalidate();
            }
        }
    }  */

    private void move(){
        Box box;
        //判断边界条件
        if(boxs.get(0).getX() - boxSize < 0) {
            currentDerect = Derectory.RIGHT;
        }
        if(boxs.get(boxs.size() - 1).getX() + 2 * boxSize > getWidth()){
            currentDerect = Derectory.LEFT;
        }
        switch (currentDerect) {
        case LEFT:
            /*for(int i=0; i<boxs.size(); i++){
                box = boxs.get(i);
                box.setX(box.getX() - boxSize);
            } */
            boxs.add(0, new Box(boxs.get(0).getX() - boxSize, 0));
            boxs.remove(boxs.size() - 1);
            break;
        case RIGHT:  

           /* for(int i=0; i<boxs.size(); i++){
                box = boxs.get(i);
                box.setX(box.getX() + boxSize);
            }  */
            boxs.add(new Box(boxs.get(boxs.size() - 1).getX() + boxSize, 0));
            boxs.remove(0);
            break;
        case TOP:  

            break;
        case BOTTOM:  

            break;
        }
    }  

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for(int i=0; i<boxs.size(); i++){
            paint.setColor(colors[i % colors.length]);
            rect.set(boxs.get(i).getX(), boxs.get(i).getY(), boxs.get(i).getX() + boxSize, boxSize);
            canvas.drawRect(rect, paint);
        }
    }
}

二、实现绕手机边界移动的贪吃蛇

先看看实现的效果:

实现代码如下:

package com.example.crazysnake;  

import java.util.ArrayList;
import java.util.List;  

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
 * CSDN博客:http://blog.csdn.net/dawanganban
 * @author 阳光小强
 */
public class MySnake extends View {
    private Paint paint;
    private Paint textPaint;
    private RectF rect;  

    private static int boxSize = 40;  

	private static int xMaxBoxCount;  //x轴方向最多的box数量
	private static int yMaxBoxCount;  //y轴方向最多的box数量

    private List<Box> boxs = new ArrayList<Box>(); 

    private static final int[] colors = {
        Color.RED,
        Color.BLUE,
        Color.GRAY,
        Color.YELLOW
    };  

    private enum Derectory{
        LEFT,
        RIGHT,
        TOP,
        BOTTOM;
    }  

    private enum State{
    	READY,    //就绪
    	PAUSE,    //暂停
    	RUNNING,  //运行
    	LOSE      //失败
    }

    private Derectory currentDerect = Derectory.LEFT;
    private State currentState = State.READY;

    private RefreshHandler mRefreshHandler = new RefreshHandler();
    class RefreshHandler extends Handler{
    	@Override
    	public void handleMessage(Message msg) {
    		MySnake.this.update();
    		MySnake.this.invalidate();

    	}

    	public void sleep(long delayMillis) {
			this.removeMessages(0);
			sendMessageDelayed(obtainMessage(0), delayMillis);
		}
    }

    public MySnake(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        textPaint = new Paint();
        textPaint.setColor(Color.RED);
        textPaint.setTextSize(80);
        rect = new RectF();
        initData();
    }  

    private void update(){
    	if(currentState == State.RUNNING){
			move();
			mRefreshHandler.sleep(150);
    	}
    }

    private void initData(){
        Box box;
        for(int i=5; i<10; i++){
            box = new Box(i, 0);
            boxs.add(box);
        }
    }  

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    	super.onSizeChanged(w, h, oldw, oldh);
    	xMaxBoxCount = (int) Math.floor(w / boxSize);
		yMaxBoxCount = (int) Math.floor(h / boxSize);
    }

    private float mDownX;
    private float mDownY;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        System.out.println("onTouch");
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mDownX = event.getX();
            mDownY = event.getY();
            break;
        case MotionEvent.ACTION_UP:
            float disX = event.getX() - mDownX;
            float disY = event.getY() - mDownY;
            System.out.println("disX = " + disX);
            System.out.println("dixY = " + disY);
            if(Math.abs(disX) > Math.abs(disY)){
                if(disX > 0){
                  //  currentDerect = Derectory.RIGHT;
                }else{
                	if(currentState != State.RUNNING){
                		currentState = State.RUNNING;
                		currentDerect = Derectory.LEFT;
                		update();
                	}

                }
            }else{
                if(disY > 0){
                  //  currentDerect = Derectory.BOTTOM;
                }else{
                  //  currentDerect = Derectory.TOP;
                }
            }
            break;
        }
        return true;
    }  

    private void move(){
        Box box;
        if(currentDerect == Derectory.LEFT && boxs.get(0).getX() <= 0){
        	currentDerect = Derectory.BOTTOM;
        }
        if(currentDerect == Derectory.BOTTOM && boxs.get(0).getY() >= yMaxBoxCount -1){
        	currentDerect = Derectory.RIGHT;
        }
        if(currentDerect == Derectory.RIGHT && boxs.get(0).getX() >= xMaxBoxCount - 1){
        	currentDerect = Derectory.TOP;
        }
        if(currentDerect == Derectory.TOP && boxs.get(0).getY() <= 0){
        	currentDerect = Derectory.LEFT;
        }
        switch (currentDerect) {
        case LEFT:
            boxs.add(0, new Box(boxs.get(0).getX() - 1, boxs.get(0).getY()));
            boxs.remove(boxs.size() - 1);
            break;
        case RIGHT:
        	 boxs.add(0, new Box(boxs.get(0).getX() + 1, boxs.get(0).getY()));
             boxs.remove(boxs.size() - 1);
            break;
        case TOP:
        	boxs.add(0, new Box(boxs.get(0).getX(), boxs.get(0).getY() - 1));
            boxs.remove(boxs.size() - 1);
            break;
        case BOTTOM:
        	boxs.add(0, new Box(boxs.get(0).getX(), boxs.get(0).getY() + 1));
            boxs.remove(boxs.size() - 1);
            break;
        }
    }  

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for(int i=0; i<boxs.size(); i++){
            paint.setColor(colors[i % colors.length]);
            rect.set(boxs.get(i).getX() * boxSize, boxs.get(i).getY() * boxSize,
            		(boxs.get(i).getX() + 1) * boxSize, (boxs.get(i).getY() + 1) * boxSize);
            canvas.drawRect(rect, paint);
        }
        if(currentState == State.READY){
        	canvas.drawText("请向左滑动", (xMaxBoxCount * boxSize - textPaint.measureText("请向左滑动")) / 2,
        			xMaxBoxCount * boxSize / 2, textPaint);
        }
    }
}

源码下载说明:前一个版本在GitHub上,这一版我将该项目上传到了CSDN的CODE上面,可以使用SVN或Git下载
CODE源码下载地址:https://code.csdn.net/lxq_xsyu/crazysnake

CSDN下载地址:http://download.csdn.net/detail/lxq_xsyu/7629435

是男人就下100层【第四层】——Crazy贪吃蛇(2),布布扣,bubuko.com

时间: 2024-08-05 23:15:00

是男人就下100层【第四层】——Crazy贪吃蛇(2)的相关文章

是男人就下100层【第四层】——Crazy贪吃蛇(1)

贪吃蛇是一款很经典的游戏,这些经典游戏给我们的童年增加了不少乐趣,今天开始我们来一步一步的在Android设备上实现一款贪吃蛇游戏,我也是第一次写这个游戏,有可能会写错,或者走弯路,但是最终希望能有一个好的结果,接下来我们一起来一步步的摸着石头开发吧. 一.建立一个工程 二.自定义View(贪吃蛇界面) package com.example.crazysnake; import android.content.Context; import android.graphics.Canvas; i

是男人就下100层【第四层】——Crazy贪吃蛇(3)

上一篇<是男人就下100层[第四层]--Crazy贪吃蛇(2)>实现了贪吃蛇绕着屏幕四周移动,这一篇我们来完成贪吃蛇的所有功能. 一.随机产生苹果 private void addAppleBox(){ int randomX = random.nextInt(xMaxBoxCount); int randomY = random.nextInt(yMaxBoxCount); for(int i=0; i<boxs.size(); i++){ if(boxs.get(i).getX()

是男人就下100层【第五层】——2048游戏

前言: 在"阳光小强"的实战系列博文<是男人就下100层>的上一层我们一起从零开始完成了我们自己的贪吃蛇游戏--CrazySnake,可能很多朋友还不过瘾,那么我们今天就来玩一玩最近一直比较火的2048游戏,让大家再过一把瘾.由于"阳光小强"目前并没有从事Android的游戏开发工作,所以这些游戏的实现并不需要很专业的游戏开发知识,如果你有Android的基础就可以一起来参与进来共同完成这个游戏.有些朋友可能就会说"这些小游戏,会不会有点简单,

是男人就下100层【第五层】——2048游戏从源码到发布市场

上一篇<是男人就下100层[第五层]--换肤版2048游戏>中阳光小强对2048游戏用自己的方式进行了实现,并分享了核心源码,这一篇阳光小强打算将该项目的所有源代码公开并结合这个实例在这篇文章中介绍一下如何添加广告和实现分享功能. 最终运行效果如下(更多运行效果请看<是男人就下100层[第五层]--换肤版2048游戏>): 一.如何实现换肤 换肤的思路其实很简单,在ActionBar中添加菜单,当用户选择某一个皮肤后就将当前的皮肤状态修改并保存到SharedPreference中,

超多经典 canvas 实例,动态离子背景、移动炫彩小球、贪吃蛇、坦克大战、是男人就下100层、心形文字等等等

超多经典 canvas 实例 普及:<canvas> 元素用于在网页上绘制图形.这是一个图形容器,您可以控制其每一像素,必须使用脚本来绘制图形. 注意:IE 8 以及更早的版本不支持 <canvas> 元素. 贴士:全部例子都分享在我的 GayHub - https://github.com/bxm0927/canvas-special 尤雨溪个人主页炫彩三角纽带效果,点击还可变换 GitHub源码 . Demo演示 知乎登录注册页动态离子背景效果 GitHub源码 . Demo演

【编程马拉松】【026-是男人就下100层】

[编程马拉松算法目录] [026-是男人就下100层][工程下载>>>] 1 题目描述 相信大家都听说过"是男人就下100层"系列游戏,游戏中包括多个长度和高度各不相同的平台,地面是最低的平台,高度为零,长度无限. 一个男人在开始的时候从高于所有平台的某处开始下落,它的下落速度始终为1米/秒.当他落到某个平台上时,游戏者选择让他向左或向右跑,跑动的速度也是1米/秒.当他跑到平台的边缘时会继续下落.要求每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束. 请帮忙

HTML5游戏开发_是男人就下100层

项目流程 市场调研(可行性分析)--> 可行性报告书  需求分析师.客户经理 需求分析--> 需求说明书  项目经理.需求分析师 概要设计--> 概要设计说明书(ER图, UML)  项目经理.项目组长 详细设计--> 详细设计说明书(流程图) 数据库建好.项目周期表(甘特图) office project visio 项目组长.开发人员 编码 --> 测试(单元测试) 提交svn 测试用例  开发人员 测试 --> 集成测试.黑白盒测试.冒烟测试  测试人员 --&g

是男人就下100层【第六层】——高仿豆瓣客户端

前一段时间阳光小强安装了一个豆瓣客户端,第一次打开就被这种界面风格吸引了,今天早上起来在打开豆瓣听音乐的时候,突然产生一个念头,来试着实现一下这种效果,打开客户端分析了一下发现其实这种效果的实现并不是想象中的那么难,下面我先分析一下这种效果的实现思路,然后一步步解释实现的过程,希望大家能提出意见和建议,一起交流学习. 先给大家展示一下我的成果吧: 其实豆瓣客户端的界面上还有其他的文字和菜单,但是这两个的实现效果和其他几个类似,可以作为代表,所以就不绘制那么多组件了. 转载请说明出处:http:/

是男人就下100层【第三层】——高仿交通银行手机客户端界面

http://blog.csdn.net/seiyagoo/article/details/46554133 http://blog.csdn.net/seiyagoo/article/details/46554135 http://blog.csdn.net/seiyagoo/article/details/46554141 http://blog.csdn.net/seiyagoo/article/details/46554151 http://blog.csdn.net/seiyagoo/