之前写过的技术类博客很少,如果写的不好还请大家见谅!
在这个系列中,我会以实例的形式来讲解android游戏的所有开发的步骤,估计会有8-10个游戏会陆续的跟大家见面的,由于自己本身现在在上班,所以时间不是很充裕,一般会在每周日定时更新博客,而每一周至少更新一个游戏的所有相关内容。
首先要编写android中的游戏,要了解android在游戏开发的过程中要用到的两个类view、SurfaceView,另外还有一个GLSurfaceview主要是编写3D游戏的好像,现在自己涉及的比较少,所以在这里也不会讲。
View与SurfaceView有什么区别呢,我想大家在网上也能找到很多相关的答案,自己也在这里再重复一下别人的总结,当然也是自己在开发中的体会。
SurfaceView和View最本质的区别在于,surfaceView可以在一个新起的单独线程中重新绘制画面而View必须在UI的主线程中更新画面,所以这就有问题发生了,当我们重新绘制画面所要耗费的时间比较的长时,那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。
当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中 thread处理,一般就需要有一个事件队列的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。
所以基于以上,根据游戏特点,一般分成两类。
1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是触摸屏幕来更新,可以直接使用 invalidate或postInvalidate(在后面会详细讲解一下这两个函数的区别) ,因为这种情况下,这一次触摸屏幕和下一次的触摸屏幕需要的时间比较长些,不会产生影响。
所以五子棋也就要用View来写了。
下面开始上代码:
主要是绘制棋盘与棋子的部分
public class GameView extends View {
//屏幕的宽和高
private int screenWidth = 0;
private int screenHeight = 0;
//画棋盘的起始位置
private int startX = 0;
private int startY = 0;
//棋盘中每个格子的高和宽
private int GRID_WIDTH = 40;
private int GRID_NUM = 12;//要画的棋盘中的线数
private Paint paint = null;
//表示棋子的二维数组,其中数组中的每一个元素代表棋盘上的一个点
private int[][] chess = new int[GRID_NUM][GRID_NUM];
private int CHESS_BLACK = 1;//表示棋子的颜色,1代表黑色,2代表白色,0达标没有棋子
private int CHESS_WHITE = 2;
private int chess_flag = 0;//用于记录上一次下的棋子的颜色,1为黑色,2为白色,0是刚开始下棋,上一次没下棋子
public GameView(Context context) {
super(context);
paint = new Paint();//实例化一个画笔
paint.setColor(0xff000000);//设置画笔的颜色
paint.setAntiAlias(true);//设置画笔去锯齿,没有此语句,画的线或图片周围不圆滑
}
@Override
protected void onDraw(Canvas canvas) {//重写View中的该方法,该方法主要承担绘图的工作,每刷新一次,就调用一次该方法
super.onDraw(canvas);
canvas.drawColor(0xffd700);//把屏幕的底色绘成黄色,此处不仅仅是起把屏幕绘成这种颜色的作用,还有刷屏的作用,对以前绘制的进行清除
paint.setColor(0x458b00);//此处是把画笔变成绿色,是绘制的棋盘变成绿色
for(int i=0;i<GRID_NUM;i++)
{
//画横线
canvas.drawLine(startX, startY+i*GRID_WIDTH,startX+(GRID_NUM-1)*GRID_WIDTH , startY+i*GRID_WIDTH, paint);
//画纵线
canvas.drawLine(startX+i*GRID_WIDTH, startY,startX+i*GRID_WIDTH , startY+(GRID_NUM-1)*GRID_WIDTH, paint);
}
//绘制棋子
for(int i=0;i<GRID_NUM;i++)
{
for(int j=0;j<GRID_NUM;j++)
{
if(chess[i][j] == CHESS_BLACK)
{
paint.setColor(0xff000000);//黑色画笔,画黑棋
canvas.drawCircle(startX+i*GRID_WIDTH,startY+j*GRID_WIDTH , 15, paint);
}
if(chess[i][j] == CHESS_WHITE)
{
paint.setColor(0xffffffff);//白色画笔,画白棋
canvas.drawCircle(startX+i*GRID_WIDTH,startY+j*GRID_WIDTH , 15, paint);
}
}
}
}
//重写View的监听触摸事件的方法
@Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
if(touchX < startX || touchX>startX+(GRID_NUM-1)*GRID_WIDTH || touchY < startY || touchY>startY+(GRID_NUM-1)*GRID_WIDTH)
{//点击到棋盘以外的位置
System.out.println("......哥们点跑偏了,呵呵");
}
else
{
//根据点击的位置,从而获知在棋盘上的哪个位置,即是数组的脚标
int index_x = Math.round((touchX-startX)/GRID_WIDTH);
int index_y = Math.round((touchY-startY)/GRID_WIDTH);
System.out.println("..."+index_x+"..."+index_y);
System.out.println("...startX"+startX+"...touchX"+touchX);
if(chess_flag == 0)
{//此句表示在最开始下棋的时候每次都是黑棋先下
chess[index_x][index_y] = CHESS_BLACK;
chess_flag = CHESS_BLACK;
}else if( chess_flag == CHESS_BLACK && chess[index_x][index_y] == 0)
{
chess[index_x][index_y] = CHESS_WHITE;
chess_flag = CHESS_WHITE;
}else if(chess_flag == CHESS_WHITE && chess[index_x][index_y] == 0)
{
chess[index_x][index_y] = CHESS_BLACK;
chess_flag = CHESS_BLACK;
}
}
invalidate();//点击完成后,通知重绘即再次执行onDraw方法
return super.onTouchEvent(event);
}
}
函数中的 if( chess_flag == CHESS_BLACK && chess[index_x][index_y] == 0)的语句中的chess[index_x][index_y] == 0主要是判断当前位置上现在是否有棋子,如果有就不能再这个位置上再放置棋子了
效果图: