Android游戏开发入门讲解-SurfaceView-2

一、老惯例不多说先上最终效果图



二、模拟射击类小游戏

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进行入门级讲解

欢迎大家继续阅读






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值