一、老惯例不多说先上最终效果图
二、模拟射击类小游戏
1、实现步骤:
①创建自定义的SurfaceView—-GameUI
②使GameUI实现SurfaceHolder.Callback接口
③使GameUI实现Runnable接口完成界面绘制工作
④将Activity中setContentView参数修改为GameUI对象
2、关于帧率
①FPS即Frames per Second,中文翻译为每秒显示帧数,俗称帧率。多用于影视制作和游戏。
②由于人类眼睛的特殊生理结构,如果所看画面显示的速率在29.97时候,就会认为是连贯的,这也就是为什么电影胶片是一格一格拍摄出来,然后快速播放的。
③而对游戏,一般来说,第一人称射击游戏比较注重FPS的高低,如果FPS<30的话,游戏会显得不连贯。所以有一句有趣的话:“FPS(指FPS游戏)重在FPS(指帧率)。
抽取共性
图片
坐标
绘制自己的方法
游戏元素
小人
移动的方法
用户点击屏幕时产生一个笑脸
笑脸
移动的方法
按键:
需要设置按压之后的图片
判断用户是否点击方向按键,处理点击效果
如果在现有的基础上继续开发,需要完善那些功能
功能一:游戏界面的切换
切换方式一:进行Activity之间切换
切换方式二:在SurfaceView中完成不同界面的切换
①需要将当前界面需要显示的内容进行统一管理,就像在电影放映时会将当前场景显示的内容放置到一张胶片上。
②同时电影放映时需要有人控制胶片的切换。
功能二:元素动作处理
速度变化快的动作(显示、隐藏)
有一个执行时间的动作(移动、跳跃等)
功能三:游戏声音处理(音乐、音效)
其他功能……
这些工作是否已经有人帮我们干了?
三、具体实现代码
Ⅰ、画布控件的基类 精灵类Sprite.java
package net.dxs.game.bean;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
/**
* 画布控件的基类 精灵
* @author lijian
*
*/
public abstract class Sprite {
protected Point position;//位置
protected Bitmap defaultBitMap;//图片
public Sprite(Point position, Bitmap defaultBitMap) {
if (position == null) {
position = new Point(0, 0);
}
this.position = position;
this.defaultBitMap = defaultBitMap;
}
public Point getPosition() {
return position;
}
/**
* 绘制自己
* @param canvas
*/
public void drawSelf(Canvas canvas) {
if (defaultBitMap != null)
canvas.drawBitmap(defaultBitMap, position.x, position.y, null);
}
}
Ⅱ、小人的类Man.java
package net.dxs.game.bean;
import net.dxs.game.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
/**
* 小人
* @author lijian
*
*/
public class Man extends Sprite {
public static final int DOWN = 10;
public static final int TOP = 11;
public static final int RIGHT = 12;
public static final int LEFT = 13;
public int speed = 5;
public Man(Point position, Bitmap defaultBitMap) {
super(position, defaultBitMap);
}
/**
* 创建笑脸
* @param context
* @param touchPoint 点击的点 笑脸移动的目标点
* @return
*/
public Face createFace(Context context, Point touchPoint) {
Face face = new Face(new Point(position.x + 45, position.y + 50), BitmapFactory.decodeResource(context.getResources(), R.drawable.rating_small), touchPoint);
return face;
}
public void move(int d) {
switch (d) {
case DOWN:
this.position.y += speed;
break;
case TOP:
this.position.y -= speed;
break;
case RIGHT:
this.position.x += speed;
break;
case LEFT:
this.position.x -= speed;
break;
default:
break;
}
}
}
Ⅲ、笑脸类Face.java
package net.dxs.game.bean;
import android.graphics.Bitmap;
import android.graphics.Point;
/**
* 笑脸
* @author lijian
*
*/
public class Face extends Sprite {
private Point touchPoint;//触摸的点
private int speed = 5;//速度
private int tx;
private int ty;
public Face(Point position, Bitmap defaultBitMap, Point touchPoint) {
super(position, defaultBitMap);
int X = touchPoint.x - position.x;
int Y = touchPoint.y - position.y;
this.touchPoint = touchPoint;
int D = (int) Math.sqrt(X * X + Y * Y);
tx = speed * X / D;
ty = speed * Y / D;
}
/**
* 笑脸移动
*/
public void move() {
position.x += tx;
position.y += ty;
}
}
Ⅳ、控制小人移动的按钮MyButton.java
package net.dxs.game.bean;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
/**
* 控制小人移动的按钮
* @author lijian
*
*/
public class MyButton extends Sprite {
private boolean isClick;//按钮是否被点击
private Bitmap pressBitmap;
public MyButton(Point position, Bitmap defaultBitMap, Bitmap pressBitmap) {
super(position, defaultBitMap);
this.pressBitmap = pressBitmap;
}
@Override
public void drawSelf(Canvas canvas) {
if (!isClick) {
super.drawSelf(canvas);
} else {
canvas.drawBitmap(pressBitmap, position.x, position.y, null);
}
}
public boolean isClick(Point point) {
Rect rect = new Rect(position.x, position.y, position.x + pressBitmap.getWidth(), position.y + pressBitmap.getHeight());
isClick = rect.contains(point.x, point.y);
return isClick;
}
public void setClick(boolean isClick) {
this.isClick = isClick;
}
private ClickListener clickListener;
public void setClickListener(ClickListener clickListener) {
this.clickListener = clickListener;
}
/**
* 点击事件的回调接口
* @author lijian
*
*/
public interface ClickListener {
void onClick();
}
public void click() {
if (clickListener != null) {
clickListener.onClick();
}
}
}
Ⅴ、游戏画布控制器GameUI.java
package net.dxs.game;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import net.dxs.game.bean.Face;
import net.dxs.game.bean.Man;
import net.dxs.game.bean.MyButton;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* 游戏画布控制器
* @author lijian
*
*/
public class GameUI extends SurfaceView implements SurfaceHolder.Callback {
private RenderThread thread;
private boolean isRender;//线程的开关
private SurfaceHolder holder;
private List<Face> faceList;
/**
* 小人
*/
private Man man;
/**
* 笑脸
*/
private Face face;
/**
* 控制按钮
*/
private MyButton btn_bottom;
private MyButton btn_top;
private MyButton btn_left;
private MyButton btn_right;
public GameUI(Context context) {
super(context);
holder = this.getHolder();
holder.addCallback(this);//保证下面的三个方法有效
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("surfaceCreated");
faceList = new CopyOnWriteArrayList<Face>();//这个集合可以在遍历的过程中增删
man = new Man(new Point(0, 0), BitmapFactory.decodeResource(getResources(), R.drawable.avatar_boy));
btn_bottom = new MyButton(new Point(getWidth() / 2, getHeight() - 100), BitmapFactory.decodeResource(getResources(), R.drawable.bottom_default), BitmapFactory.decodeResource(getResources(), R.drawable.bottom_press));
btn_top = new MyButton(new Point(getWidth() / 2, getHeight() - 244), BitmapFactory.decodeResource(getResources(), R.drawable.top_default), BitmapFactory.decodeResource(getResources(), R.drawable.top_press));
btn_left = new MyButton(new Point(getWidth() / 2 - 64, getHeight() - 164), BitmapFactory.decodeResource(getResources(), R.drawable.left_default), BitmapFactory.decodeResource(getResources(), R.drawable.left_press));
btn_right = new MyButton(new Point(getWidth() / 2 + 64, getHeight() - 164), BitmapFactory.decodeResource(getResources(), R.drawable.right_default), BitmapFactory.decodeResource(getResources(), R.drawable.right_press));
//设置按钮的点击事件
btn_bottom.setClickListener(new MyButton.ClickListener() {
@Override
public void onClick() {
//让小人向下移动
man.move(Man.DOWN);
}
});
btn_top.setClickListener(new MyButton.ClickListener() {
@Override
public void onClick() {
//让小人向上移动
man.move(Man.TOP);
}
});
btn_left.setClickListener(new MyButton.ClickListener() {
@Override
public void onClick() {
//让小人向左移动
man.move(Man.LEFT);
}
});
btn_right.setClickListener(new MyButton.ClickListener() {
@Override
public void onClick() {
//让小人向右移动
man.move(Man.RIGHT);
}
});
thread = new RenderThread();
isRender = true;
thread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
System.out.println("surfaceChanged");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("surfaceDestroyed");
isRender = false;
}
private class RenderThread extends Thread {
@Override
public void run() {
while (isRender) {
renderGame();
}
}
}
private void renderGame() {
//1 Canvas lockCanvas
Canvas lockCanvas = holder.lockCanvas();
Paint paint = new Paint();
paint.setColor(Color.GRAY);
lockCanvas.drawRect(0, 0, getWidth(), getHeight(), paint);
//2 拿到Canvas可以绘制界面
man.drawSelf(lockCanvas);
btn_bottom.drawSelf(lockCanvas);
btn_top.drawSelf(lockCanvas);
btn_left.drawSelf(lockCanvas);
btn_right.drawSelf(lockCanvas);
if (faceList.size() != 0) {
for (Face face : faceList) {
face.drawSelf(lockCanvas);
face.move();//笑脸移动
if (face.getPosition().x < 0 || face.getPosition().x > getWidth() || face.getPosition().y < 0 || face.getPosition().y > getHeight()) {
faceList.remove(face);
}
}
}
//3 unLockCanvas(Canvas canvas);解锁画布 post() or postAll() is called
//二合一 unlockCanvasAndPost(Canvas canvas);
holder.unlockCanvasAndPost(lockCanvas);
}
/**
* 处理游戏的点击事件
* @param event
*/
public void handleTouch(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://按下
Point point = new Point((int) event.getX(), (int) event.getY());
if (btn_bottom.isClick(point)) {
btn_bottom.setClick(true);
btn_bottom.click();
} else if (btn_top.isClick(point)) {
btn_top.setClick(true);
btn_top.click();
} else if (btn_left.isClick(point)) {
btn_left.setClick(true);
btn_left.click();
} else if (btn_right.isClick(point)) {
btn_right.setClick(true);
btn_right.click();
} else {
face = man.createFace(getContext(), point);
faceList.add(face);//将创建的笑脸添加到集合
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
btn_bottom.setClick(false);
btn_top.setClick(false);
btn_left.setClick(false);
btn_right.setClick(false);
break;
}
}
}
Ⅵ、在MainActivity.java中显示游戏
package net.dxs.game;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
public class MainActivity extends Activity {
private GameUI gameUI;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameUI = new GameUI(this);
setContentView(gameUI);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
gameUI.handleTouch(event);
return super.onTouchEvent(event);
}
}
本案例源代码: http://download.csdn.net/detail/shenqingxiaojian/7282223
六、讲到这里,你也许会发现,这些一系列的工作,全部自己实现有些麻烦的,是不是有现成的实现工具,
很高兴的告诉你真的有那就是名气不菲的cocos2d二维游戏引擎
那么接下来我们就开始对cocos2d进行入门级讲解
欢迎大家继续阅读