微智科技网
您的当前位置:首页如何构建自己的游戏框架并且制作游戏

如何构建自己的游戏框架并且制作游戏

来源:微智科技网
这个教程就让我们学习怎么用这个游戏框架开发一个简单的空战游戏吧!由于素材有限,都是用的网上的素材。这个游戏可以改造成为空战或者植物大战僵尸等的养成类型游戏或者更多,原理都差不多。 一个出类拔萃的人总是一个有耐心的人! 一个游戏的制作经常会出现小意外,一个不耐心的人往往会不知所措,我看过李华明他的书上面有介绍游戏框架,而且

很详细,但是没有这个全面,现在的很多游戏书籍也很少有关于游戏框架的构建,希望大家可以多借鉴一下,多提提意见! 先上图:

第一个教程就先搭建属于我们的游戏框架: com.mocn.framework中是框架包 com.mocn.airBottle中是游戏包

首先看框架包 中的BaseActivity类,主要用于设置横竖屏,全屏,屏幕的宽高度等等。 ? package com.mocn.framework; http://biao.qqlove7.com import android.R; import android.app.Activity; import android.content.pm.ActivityInfo; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.Window; import android.view.WindowManager; /** * Activity的基类,本类中只要设置屏幕为竖屏,全屏,得到屏幕的高度和宽度 * * @author Administrator * */ public class BaseActivity extends Activity { /** * Activity创建时执行的方法 */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setFullScreen();// 设置全屏 setLandscape();// 设置横屏 Global.context = this;// 获取上下文事件 // 获取屏幕的宽高 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); Global.screenWidth = dm.widthPixels;// 获取屏幕的宽度 Global.screenHeight = dm.heightPixels;// 获取屏幕的高度 } /** * 设置为全屏的方法 */ public void setFullScreen() { requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); } /** * 设置为竖屏的方法 */ public void setPortrait() { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } /** * 设置为横屏的方法 */ public void setLandscape() { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } } BaseView,主要用于设置线程的开关,游戏界面的绘制 ? package com.mocn.framework; http://dudu.qqq23.com import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; /** * 游戏界面的基类 SurfaceHolder,线程的开启和关闭,添加組件drawSurfaceView * * @author Administrator * */ public abstract class BaseView extends SurfaceView implements Callback, Runnable { private SurfaceHolder holder;// SurfaceHolder的引用 private Thread currentThread;// Thread的引用 public int sleepTime = 20;// 设置睡眠时间 public BaseView(Context context) { super(context); holder = this.getHolder();// 得到holder对象 holder.addCallback(this);// 得到调函数对象 } /** * 开启线程的方法 */ public void startThread() { currentThread = new Thread(this);// 得到线程的对象 currentThread.start();// 开启线程 } /** * 关闭线程的方法 */ public void stopThread() { currentThread = null;// 设置线程为空 } /** * 当界面改变时执行的方法 */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /** * 当界面创建时执行的方法 */ @Override public void surfaceCreated(SurfaceHolder holder) { startThread();// 开启游戏线程 } /** * 当游戏被摧毁时执行的方法 */ @Override public void surfaceDestroyed(SurfaceHolder holder) { stopThread();// 关闭游戏线程 } /** * 绘制界面的方法 * * @param canvas * @param paint */ public void drawSurfaceView(Canvas canvas, Paint paint) { LayerManager.drawLayerManager(canvas, paint);// 绘制组件 } /** * 线程的控制方法 */ @Override public void run() { Canvas canvas; Paint paint = new Paint(); while (currentThread != null) { canvas = holder.lockCanvas(); drawSurfaceView(canvas, paint); holder.unlockCanvasAndPost(canvas); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); } } } } Global类,用于设置一些常量 ? package com.mocn.framework; import android.content.Context; /** * 得到屏幕的宽度,高度,Context对象 * * @author Administrator * */ public class Global { public static Context context;//得到上下文的引用 public static int screenWidth;//屏幕的宽度 public static int screenHeight;//屏幕的高度 } Layer类,所以绘制组件的基类,里面包括组件的坐标,宽高,以及绘制的方法等 ? package com.mocn.framework; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; /** * 层类,组件的父类,添加组件,设置组件位置,绘制自己, 是所有人物和背景的基类 * * @author Administrator * */ public abstract class Layer { public float x;// 层的x坐标 public float y;// 层的y坐标 public int w;// 层的宽度 public int h;// 层的高度 public Rect src, dst;// 引用Rect类 public Bitmap bitmap;// 引用Bitmap类 protected Layer(Bitmap bitmap, int w, int h, boolean autoAdd) { this.bitmap = bitmap; this.w = w; this.h = h; src = new Rect(); dst = new Rect(); if (autoAdd) { LayerManager.addLayer(this);// 在LayerManager类中添加本组件 } } /** * 设置组件位置的方法 * * @param x * @param y */ public void setPosition(float x, float y) { this.x = x; this.y = y; } /** * 绘制自己的抽象接口 * * @param canvas * @param paint */ public abstract void drawSelf(Canvas canvas, Paint paint); } BackGroundLayer类,主要用于背景的绘制,可以用做静态的绘制 ? package com.mocn.framework; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; /** * 游戏背景组件,在LayerManager中添加游戏背景组件,绘制自己 * * @author Administrator * */ public class BackGroundLayer extends Layer { public BackGroundLayer(Bitmap bitmap, int w, int h) { super(bitmap, w, h, true); } @Override public void drawSelf(Canvas canvas, Paint paint) { src.left = 0; src.top = 0; src.right = w; src.bottom = h; dst.left = (int) x; dst.top = (int) y; dst.right = dst.left + w; dst.bottom = dst.top + h; canvas.drawBitmap(bitmap, src, dst, paint); } } Sprite类,精灵类,用于绘制动态人物 ? package com.mocn.framework; import java.util.Hashtable; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; /** * 精灵组件类,添加精灵组件,设置动作,绘制精灵,添加一个动作序列,精灵动作类 * * @author Administrator * */ public class Sprite extends Layer { public int frameIdx;// 当前帧下标 public int currentFrame = 0;// 当前帧 public Hashtable actions;// 动作集合 public SpriteAction currentAction;// 当前动作 public Sprite(Bitmap bitmap, int w, int h, boolean autoAdd) { super(bitmap, w, h, autoAdd); actions = new Hashtable();// 用Hashtable保存动作集合 } /** * 设置动作的方法 * * @param actionName */ public void setAction(String actionName) { currentAction = actions.get(actionName);// 从动作集合中得到该动作 } /** * 绘制精灵的方法 */ @Override public void drawSelf(Canvas canvas, Paint paint) { if (currentAction != null) { currentFrame = currentAction.frames[frameIdx];// 获取当前需要的帧 } // 截取图片中需要的帧 src.left = currentFrame * w;// 左端宽度:当前帧乘上帧的宽度 src.top = 0;// 上端高度:0 src.right = src.left + w;// 右端宽度:左端宽度加上帧的宽度 src.bottom = h;// 下端高度为帧的高度 // 绘制在界面上,取中心点绘制 dst.left = (int) x - w / 2; dst.top = (int) y - h / 2; dst.right = dst.left + w; dst.bottom = dst.top + h; canvas.drawBitmap(bitmap, src, dst, paint);// 绘制当前帧 if (currentAction != null) { currentAction.nextFrame();// 绘制下一帧 } } /** * 添加一个动作集合的方法 * * @param name * @param frames * @param frameTime */ public void addAction(String name, int[] frames, int[] frameTime) { SpriteAction sp = new SpriteAction();// 创建SpiteAction的对象 sp.frames = frames;// 当前帧的数量,用下标表示 sp.frameTime = frameTime;// 每一帧切换的时间 actions.put(name, sp);// 将名字为\"name\"的动作集合,值为sp的动作集合放进acitons中 } /** * 精灵的移动方法 * * @param dx * @param dy */ public void move(int dx, int dy) { this.x += dx; this.y += dy; } // 精灵动作类 class SpriteAction { public int[] frames;// 该动作的帧序列 public int[] frameTime;// 帧序列中每一帧切换对应的时间 private long updateTime;// 记录上次失效时间 /** * 切换到下一帧的方法 */ public void nextFrame() { if (System.currentTimeMillis() > updateTime) { frameIdx++;// 帧下标增加 frameIdx %= frames.length; updateTime = System.currentTimeMillis() + frameTime[frameIdx];// 切换下一帧所需要的时间 } } } } LayerManager类,组件管理类,用于管理组件 ? package com.mocn.framework; import java.util.Vector; import android.graphics.Canvas; import android.graphics.Paint; /** * 组件的管理类,用于存放组件,绘制所有组件,添加一个组件,删除一个组件,插入一组件 * * * @author Administrator * */ public class LayerManager { public static Vector vec = new Vector(); // Vector对象用于存放所有组件 /** * 绘制所有组件的方法 * * @param canvas * @param paint */ public static void drawLayerManager(Canvas canvas, Paint paint) { for (int i = 0; i < vec.size(); i++) { vec.elementAt(i).drawSelf(canvas, paint);// 把存在于Vector对象中的组件绘制出来 } } /** * 添加一个组件的方法 * * @param layer */ public static synchronized void addLayer(Layer layer) { vec.add(layer);// 在Vector对象中添加此组件 } /** * 删除一个组件的方法 * * @param layer */ public static synchronized void deleteLayer(Layer layer) { vec.remove(layer);// 在Vector对象中删除此组件 } /** * 在before指定的位置插入layer,原来对象以及此后的对象依次往后顺延。 * * @param layer * @param before */ public static void insert(Layer layer, Layer before) { for (int i = 0; i < vec.size(); i++) {// 遍历Vector对象 if (before == vec.elementAt(i)) { vec.insertElementAt(layer, i);// 在before对象前面插入layer,该对象位于before之上 return; } } } } 最后一个,Utilsl类,工具类,包含各种取得图片,碰撞事件的检测等方法 ? package com.mocn.framework; import java.io.IOException; import java.io.InputStream; import android.graphics.Bitmap; import android.graphics.BitmapFactory; /** * 工具类 获得一张图片,判断两个矩形是否相交,判断一个点是否在矩形内 * * @author Administrator * */ public class Utils { /** * 获取一张图片的方法 * * @param path * @return */ public static Bitmap getBitmap(String path) { try { InputStream is = Global.context.getAssets().open(path); return BitmapFactory.decodeStream(is); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 判断两个矩形是否相交的方法 * * @param x * @param y * @param w * @param h * @param x2 * @param y2 * @param w2 * @param h2 * @return */ public static boolean colliseWidth(float x, float y, float w, float h, float x2, float y2, float w2, float h2) { if (x > x2 + w2 || x2 > x + w || y > y2 + h2 || y2 > y + h) { return false; } return true; } /** * 判断 一个点是否在矩形内的方法 * * @param x * @param y * @param w * @param h * @param px * @param py * @return */ public static boolean inRect(float x, float y, float w, float h, float px, float py) { if (px > x && px < x + w && py > y && py < y + h) { return true; } return false; } }

框架搭建完成,第二篇就是游戏的绘制篇了,如果大家在框架上有

什么问题可以问我。

现在我们进行第二篇教学,有了框架我们可以自由地在屏幕上绘制我们想要的东西了。背景是用的BackGround组件,人物和子弹,还有精灵都是用的Sprite精灵组件

GameActivity类,游戏的主Activity类,在这里继承基类,只需要将界面替换为GameView就可以了。 ? package com.mocn.airBottle; import android.R; import android.os.Bundle; import com.mocn.framework.BaseActivity; import com.mocn.framework.BaseView; /** * 游戏的Activity类 * * @author Administrator * */ public class PlaneGameActivity extends BaseActivity { public BaseView baseView;// 引用BaseView public GameView gameView;// 引用GameView @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); baseView = new GameView(this);// 得到baseView对象 setContentView(baseView);;// 设置显示界面为baseView } } GameView类,游戏的主界面绘制类,在这里我们要绘制飞机和敌军,判断检测子弹和敌军的碰撞事件 ? package com.mocn.airBottle; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import com.mocn.framework.BackGroundLayer; import com.mocn.framework.BaseView; import com.mocn.framework.Utils; public class GameView extends BaseView implements OnTouchListener { BackGroundLayer backLayer;// 背景组件 Plane plane;// 飞机类 public boolean pressPlane = false; public GameView(Context context) { super(context); setOnTouchListener(this); // 绘制背景 backLayer = new BackGroundLayer(Utils.getBitmap(\"game/bg.png\"), 800, 480); backLayer.setPosition(0, 0); // 绘制飞机 plane = new Plane(Utils.getBitmap(\"game/plane.png\"), 150, 179); plane.setPosition(40, 300); } @Override public void drawSurfaceView(Canvas canvas, Paint paint) { super.drawSurfaceView(canvas, paint); GameData.bulletsAndEnemy();// 判断子弹和敌军的碰撞 GameData.createEnemy();// 创建敌军 } /** * 触摸事件执行的方法 */ @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) {// 按下执行的事件 // 按下点中飞机执行的方法 if (Utils.inRect(plane.x - plane.w / 2, plane.y - plane.h / 2, plane.w, plane.h, event.getX(), event.getY())) { pressPlane = true;// 将飞机可移动设置为true } } else if (event.getAction() == MotionEvent.ACTION_MOVE) {// 拖动执行的事件 if (pressPlane) { plane.setPosition(event.getX(), event.getY());// 将飞机的坐标设置为拖动时的坐标 } } else if (event.getAction() == MotionEvent.ACTION_UP) {// 释放按键时执行的方法 pressPlane = false;// 将飞机可移动设置为false } return true; } } Plane,飞机类,在飞机类中我们给它顺便装上子弹 ? package com.mocn.airBottle; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import com.mocn.framework.LayerManager; import com.mocn.framework.Sprite; import com.mocn.framework.Utils; /** * 飞机类 * * @author Administrator * */ public class Plane extends Sprite { public int timeSpan = 1000;// 飞机的发子弹间隔时间 public long updateTime = 0;// 飞机的更新时间 public Plane(Bitmap bitmap, int w, int h) { super(bitmap, w, h, true); } @Override public void drawSelf(Canvas canvas, Paint paint) { super.drawSelf(canvas, paint); // 给飞机装上子弹 if (System.currentTimeMillis() > updateTime) { // 创建子弹 Bullet b = new Bullet(Utils.getBitmap(\"game/buttle.png\"), 50, 50); b.setPosition(x + w / 2, y);// 设置子弹的位置 b.setAction(\"bb\");// 设置子弹的动作 LayerManager.insert(b, this);// 在飞机层的前面插入子弹层 GameData.bullets.add(b);// 添加一颗子弹 updateTime = System.currentTimeMillis() + timeSpan; } } } Buttle类,子弹类,在这个类中我们要设置子弹的动作和路线 ? package com.mocn.airBottle; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import com.mocn.framework.LayerManager; import com.mocn.framework.Sprite; /** * 子弹类,继承精灵类 * * @author Administrator * */ public class Bullet extends Sprite { public int speed = 10;// 子弹的速度 public Bullet(Bitmap bitmap, int w, int h) { super(bitmap, w, h, false); addAction(\"bb\new int[] { 0, 1, 2, 3, 4, 5 }, new int[] { 50, 50, 50, 50, 50, 50 }); } @Override public void drawSelf(Canvas canvas, Paint paint) { super.drawSelf(canvas, paint); x += speed;// 让子弹移动 // 当子弹超出屏幕移除子弹 if (x >= 800) { LayerManager.deleteLayer(this); GameData.bullets.remove(this); } } } ? Enemy类,敌军类,在这个类中我们要给它设置动作和路线 package com.mocn.airBottle; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import com.mocn.framework.Sprite; /** * 敌军的绘制类 * * @author Administrator * */ public class Enemy extends Sprite { public Enemy(Bitmap bitmap, int w, int h) { super(bitmap, w, h, true); addAction(\"left\new int[] { 0, 1, 2, 3, 4 }, new int[] { 50, 50, 50, 50, 50 });// 设置动作集合 } @Override public void drawSelf(Canvas canvas, Paint paint) { super.drawSelf(canvas, paint); x -= 2;// 敌军往左移动 } } 最后一个,GameData类,游戏数据类,在这里我们有创建敌军的方法和子弹和敌军的碰撞处理 ? package com.mocn.airBottle; import java.util.Vector; import com.mocn.framework.LayerManager; import com.mocn.framework.Utils; /** * 游戏数据类,用于控制敌军的出现和子弹与敌军的碰撞 * * @author Administrator * */ public class GameData { public static Vector bullets = new Vector(); public static Vector enemys = new Vector(); private static long updateTime;// 设置更新时间 /** * 创建敌军的方法 */ public static void createEnemy() { if (System.currentTimeMillis() < updateTime) return; updateTime = System.currentTimeMillis() + 3000;// 设置更新时间,3秒出一只 // 创建敌军 Enemy e = new Enemy(Utils.getBitmap(\"game/enemy.png\"), 72, 69); e.setPosition(800, (float) Math.random() * 480);// 设置敌军的位置,x坐标固定,y坐标随机 e.setAction(\"left\");// 设置动作 enemys.add(e);// 在Vector中添加一个敌军 } /** * 子弹和敌军碰撞后的处理方法 */ public static void bulletsAndEnemy() { // 遍历子弹和敌军 for (int i = bullets.size() - 1; i >= 0; i--) { Bullet b = bullets.elementAt(i); for (int j = enemys.size() - 1; j >= 0; j--) { Enemy e = enemys.elementAt(j); // 调用工具类中的碰撞检测方法 boolean t = Utils.colliseWidth(b.x - b.w / 2, b.y - b.h / 2, b.w, b.h, e.x - e.w / 2, e.y - e.h / 2, e.w, e.h); if (t) { bullets.remove(b);// 移除Vector中的子弹 enemys.remove(e);// 移除Vector中的敌军 LayerManager.deleteLayer(b);// 移除组件中的子弹 LayerManager.deleteLayer(e);// 移除组件中的敌军 } } } } }

至此,整个游戏教学完成。

这是一个简单的游戏,但是代码量却不少,特别是框架部分,但是这个框架可以说是很基础的,但却囊括了游戏的很多方面,如果以后有机会去游戏公司,框架部分会更复杂,现在的辛苦只是为了以后的轻松而准备,我相信,如果一个人可以克服困难,看懂它的话,那他离真正的游戏大师也差不多远了,真正的机遇留个有准备的人!

因篇幅问题不能全部显示,请点此查看更多更全内容