Android围住神经猫开发指南【二】游戏界面开发

说完了游戏介绍,我们开始进入实战的开发。第一步,我们要先设计一下游戏的主界面和游戏包含的一些功能。经过初步的设计,定了如下几个功能:1、开始游戏(开始新的游戏),2、继续游戏(保存游戏进度有后,可以继续游戏),3、排行榜功能(对于成功围住神经猫后的玩家,可以保存记录),4、设置(设置障碍物个数、游戏背景色等)。

上篇文章中已经附图了,看到了游戏的主界面。这篇文章我们就开始探讨一下开始游戏这一部分。

关于游戏开发,尤其这种小游戏,不需要用到一些游戏引擎,只需用SurfaceView即可。关于surfaceView的一些介绍,大家可以查很多文章。好了,我们现在开始正题。

现在先看一下游戏开始后的图:

 

对游戏界面分析,我们可以知道,上部分为一个简单的计步器,下部分为游戏真正发生的地方(不知道用什么形容好了T_T)。我们主要分析的也是这一部分。

好了,分析游戏,首先我们可以看到的是游戏的布局,一个10x10的布局,里面有15个黄色障碍物和一个红色猫,剩下的是一些可以移动和点击的灰色圆。对于游戏场景,我们可以自定义一个Playground.class,然后在这个类里面绘制游戏场景,包括对圆的绘制。然后我们定义一个Dot.class来存放圆的一些属性。

分析圆,它所包含的属性应该有:圆的大小、状态和XY坐标。根据这个,我们可以简单的写出Dot.class的代码


public class Dot {

	int x,y;// 位置
	int status;// 状态
	
	public static final int STATUS_ON = 1;// 可点击状态
	public static final int STATUS_OFF = 0;// 不可点击状态(障碍物)
	public static final int STATUS_IN = 9;// 不可点击状态(猫)
	
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
	public int getStatus() {
		return status;
	}
	public void setStatus(int status) {
		this.status = status;
	}
	
	public void setXY(int x,int y) {
		this.x = x;
		this.y = y;
	}
	
	public Dot(int x, int y) {
		super();
		this.x = x;
		this.y = y;
		status = STATUS_OFF;
	}
}

下一步,分析Playground.class这个类。这个类比较复杂,先贴出代码再分析把

public class Playground extends SurfaceView {

	// Playground 类主要是一些游戏界面的绘制,和一些方法的集合,触控操作放在主类中

	public static  int WIDTH  = 40;
	public static final int ROW = 10;// 行
	public static final int COL = 10;// 列
	private Dot matrix[][];

	public int blocks = 15;// 默认添加路障的个数
	public int blockscolor,catcolor,background;
	private SharedPreferences sp;

	
	public Playground(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		System.out.println("Playground(Context context, AttributeSet attrs, int defStyle)");
		getHolder().addCallback(callback);
		matrix = new Dot[ROW][COL];
		for (int i = 0; i < ROW; i++) {
			for (int j = 0; j < COL; j++) {
				matrix[i][j] = new Dot(j, i);
			}
		}
		sp = context.getSharedPreferences("setting", Context.MODE_PRIVATE);	
		blockscolor = sp.getInt("blockscolor", 0xFFFFFF00);
		catcolor = sp.getInt("catcolor", 0xFFFF0000);
		background = sp.getInt("background", 0xFFCCCCCC);
		blocks = sp.getInt("blocks", 15);	
	}

	// 绘制游戏场景
	public void redraw() {

		Canvas c = getHolder().lockCanvas();// 画布,锁定画布,绘制游戏的界面
		c.drawColor(background);

		Paint paint = new Paint();// 画笔
		paint.setFlags(Paint.ANTI_ALIAS_FLAG);// 抗锯齿
		for (int i = 0; i < ROW; i++) {
			int offset = 0;// 缩进量
			if (i%2 == 0) {// 偶数行缩进
				offset = WIDTH/2;
			}
			for (int j = 0; j < COL; j++) {
				
				Dot one = getDot(j, i);
				
				switch (one.getStatus()) {
				case Dot.STATUS_OFF:
					paint.setColor(0xFFEEEEEE);
					break;
				case Dot.STATUS_ON:
					paint.setColor(blockscolor);
					break;
				case Dot.STATUS_IN:
					paint.setColor(catcolor);
					break;
				default:
					break;
				}
				// 需要注意的地方,画圆
				c.drawOval(new RectF(
						one.getX()*WIDTH+offset, 
						one.getY()*WIDTH, 
						(one.getX()+1)*WIDTH+offset, 
						(one.getY()+1)*WIDTH), paint);
			}
		}
		getHolder().unlockCanvasAndPost(c);
	}

	public boolean isAtEdge(Dot d) {
		if (d.getX()*d.getY() == 0 || d.getX()+1 == COL || d.getY()+1 == ROW) {
			return true;
		}
		return false;
	}

	public Dot getNeighbor(Dot one, int dir)
	{
		switch (dir) {
		case 1:
			return getDot(one.getX()-1, one.getY());
		case 2:
			if (one.getY() % 2 == 0) {
				return getDot(one.getX(), one.getY()-1);
			}else {
				return getDot(one.getX()-1, one.getY()-1);
			}
		case 3:
			if (one.getY() % 2 == 0) {
				return getDot(one.getX()+1, one.getY()-1);
			}else {
				return getDot(one.getX(), one.getY()-1);
			}
		case 4:
			return getDot(one.getX()+1, one.getY());
		case 5:
			if (one.getY() % 2 == 0) {
				return getDot(one.getX()+1, one.getY()+1);
			}else {
				return getDot(one.getX(), one.getY()+1);
			}
		case 6:
			if (one.getY() % 2 == 0) {
				return getDot(one.getX(), one.getY()+1);
			}else {
				return getDot(one.getX()-1, one.getY()+1);
			}
		default:
			break;
		}
		return null;
	}
// 判断距离,在移动的时候用
	public int getDistance(Dot one, int dir)
	{
		int distance = 0;
		Dot ori, next;// 定义下一个点和当前点
		ori = one;
		while (true) {
			next = getNeighbor(ori, dir);
			// 如果碰到边缘,或者是碰到障碍物,即可返回距离
			if (next.getStatus() == Dot.STATUS_ON) {
				return distance*-1;
			}
			if (isAtEdge(next)) {
				distance ++;
				return distance;
			}
			distance++;
			ori = next;// 迭代
		}
	}
// 坐标转换!!!因为触控的XY坐标和数组的XY坐标相反,所以需要getDot转换坐标
	public Dot getDot(int x, int y) {
		return matrix[y][x];
	}
// surfaceView回调函数
	Callback callback = new Callback() {

		@Override
		public void surfaceDestroyed(SurfaceHolder arg0) {

		}

		// view创建时调用
		@Override
		public void surfaceCreated(SurfaceHolder arg0) {
			WIDTH = getWidth()/(COL+1);
			redraw();			
		}

		// 当view发生变换调用
		@Override
		public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
			WIDTH = arg2/(COL+1);
			redraw();
		}
	};

	// 初始化游戏
	public void initGame() {

		WIDTH = getWidth() / (COL+1);
		
		for (int i = 0; i <ROW; i++) {
			for (int j = 0; j < COL; j++) {
				matrix[i][j].setStatus(Dot.STATUS_OFF);
			}
		}
		// 初始化猫的位置
		new Dot(4, 5);// 计算从0开始,且相反,所以应为第六行第五列
		getDot(4, 5).setStatus(Dot.STATUS_IN);

		for (int i = 0; i < blocks	;) {
			int x = (int) ((Math.random()*1000)%COL);
			int y = (int) ((Math.random()*1000)%COL);
			if (getDot(x, y).getStatus() == Dot.STATUS_OFF)
			{
				getDot(x, y).setStatus(Dot.STATUS_ON);
				i++;
			}
		}
	}
	
	public void continueGame() {

		String continueGame = sp.getString("remember", "null");

		for (int i = 0; i < 100; i++) {
			int id = Integer.valueOf(continueGame.charAt(i));
			// id = 48 代表空白
			// id = 49 代表障碍物
			// id = 57 代表猫
			switch (id) {
			case 48:
				matrix[i/10][i%10].setStatus(Dot.STATUS_OFF);
				break;
			case 49:
				matrix[i/10][i%10].setStatus(Dot.STATUS_ON);
				break;
			case 57:
				matrix[i/10][i%10].setStatus(Dot.STATUS_IN);
				break;
			default:
				break;
			}
		}
	}
}

因为涉及到了保存游戏和设置游戏相关的一些数据,所以一下子看可能看不懂。 因为涉及到了保存,大家可以把那些参数自己定义,不需要用SharedPreferences。

游戏中涉及到猫的移动,所以关于是否可以移动以及移动的最优方向进行了判断。先看下是否可移动,这个包含了两种可能,第一种是到达了游戏的边界,即isatEdge()

public boolean isAtEdge(Dot d) {
		if (d.getX()*d.getY() == 0 || d.getX()+1 == COL || d.getY()+1 == ROW) {
			return true;
		}
		return false;
	}

只需传入猫的位置, d.getX()*d.getY() == 0表示在游戏的上边界和左边界。d.getX()+1 == COL 和d.getY()+1 == ROW表示到达游戏的右边界和下边界。

public Dot getNeighbor(Dot one, int dir)
	{
		switch (dir) {
		case 1:
			return getDot(one.getX()-1, one.getY());
		case 2:
			if (one.getY() % 2 == 0) {
				return getDot(one.getX(), one.getY()-1);
			}else {
				return getDot(one.getX()-1, one.getY()-1);
			}
		case 3:
			if (one.getY() % 2 == 0) {
				return getDot(one.getX()+1, one.getY()-1);
			}else {
				return getDot(one.getX(), one.getY()-1);
			}
		case 4:
			return getDot(one.getX()+1, one.getY());
		case 5:
			if (one.getY() % 2 == 0) {
				return getDot(one.getX()+1, one.getY()+1);
			}else {
				return getDot(one.getX(), one.getY()+1);
			}
		case 6:
			if (one.getY() % 2 == 0) {
				return getDot(one.getX(), one.getY()+1);
			}else {
				return getDot(one.getX()-1, one.getY()+1);
			}
		default:
			break;
		}
		return null;
	}
getNeighbor()函数,是对猫附近的六个方向进行遍历。1-6分别为从左边开始的方向。
	// 判断距离,在移动的时候用
	public int getDistance(Dot one, int dir)
	{
		int distance = 0;
		Dot ori, next;// 定义下一个点和当前点
		ori = one;
		while (true) {
			next = getNeighbor(ori, dir);
			// 如果碰到边缘,或者是碰到障碍物,即可返回距离
			if (next.getStatus() == Dot.STATUS_ON) {
				return distance*-1;
			}
			if (isAtEdge(next)) {
				distance ++;
				return distance;
			}
			distance++;
			ori = next;// 迭代
		}
	}
getDistance()函数,某一方向的距离判断。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值