1.框架整体很小,上手快,做大游戏的公司没多少,做小游戏的个人开发者铺天盖地,相比动则上升到引擎级的庞然大物,小型的框架更加实用,更加考虑大多数开发者的利益。
2.小不等于不完善,之所以剥SDK的游戏示例代码的框架出来,就是学习后发现它对于系统事件的处理比较完善,另外我个人还修正了它对于来电处理等异常事件不完美之处,使其更加完善。
R.layout.main 布局文件
-
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- android:id="@+id/gameview"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- android:id="@+id/textview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:gravity="center_horizontal"
- android:textColor="#88ffffff"
- android:textSize="24sp" />
- package com.mstanford.gameframework;
- import com.mstanford.gameframe.R;
- import android.app.Activity;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.widget.TextView;
- public class GameActivity extends Activity {
- private GameSurfaceView gameSurfaceView;
- private GameThread gameThread;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- gameSurfaceView = (GameSurfaceView) this.findViewById(R.id.gameview);
- gameThread = gameSurfaceView.getThread();
- gameSurfaceView.setTextView((TextView) findViewById(R.id.textview));
- if (savedInstanceState == null) {
- // 游戏第一次启动时,初始化游戏状态
- gameThread.doStart();
- Log.w(this.getClass().getName(), "SIS is null");
- }
- else {
- // 从其他应用界面切回游戏时,如果Activity重新创建,则恢复上次切出游戏时的各项数据
- gameThread.restoreState(savedInstanceState);
- Log.w(this.getClass().getName(), "SIS is nonnull");
- }
- }
- /**
- * 当Activity被切换到后台时调用,存储Activity重新创建时需要恢复的游戏数据
- */
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- gameThread.saveState(outState);
- Log.w(this.getClass().getName(), "SIS called");
- }
- /**
- * 当Activity被切换到后台时调用,在这里对游戏做"暂停"的处理
- */
- @Override
- protected void onPause() {
- super.onPause();
- // 暂停游戏
- gameSurfaceView.getThread().pause();
- }
- /**
- * 当Activity切换到前台时调用
- */
- @Override
- protected void onResume() {
- super.onResume();
- // 游戏结束暂停状态,游戏正常进行
- gameSurfaceView.getThread().unpause();
- }
- /**
- * 创建游戏菜单
- */
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // TODO Auto-generated method stub
- return super.onCreateOptionsMenu(menu);
- }
- /**
- * 定义游戏菜单的点击事件处理
- */
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // TODO Auto-generated method stub
- return super.onOptionsItemSelected(item);
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- Log.v(this.getClass().getName(), "onDestroy");
- //停止游戏
- gameThread.setRunning(false);
- boolean retry = true;
- while (retry) {
- try {
- //阻塞Activity的主线程直到游戏线程执行完
- gameThread.join();
- retry = false;
- } catch (InterruptedException e) {
- }
- }
- }
- }
- package com.mstanford.gameframework;
- import android.content.Context;
- import android.os.Handler;
- import android.os.Message;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.view.SurfaceHolder.Callback;
- import android.widget.TextView;
- public class GameSurfaceView extends SurfaceView implements Callback {
- private GameThread gameThread;
- private TextView textview;
- public GameSurfaceView(Context context, AttributeSet attrs) {
- super(context, attrs);
- SurfaceHolder holder = getHolder();
- holder.addCallback(this);
- gameThread = new GameThread(holder, context, new Handler() {
- @Override
- public void handleMessage(Message m) {
- textview.setText(m.getData().getString("text"));
- }
- });
- // 设置可获得焦点,确保能捕获到KeyEvent
- setFocusable(true);
- }
- /**
- * 获取一个Activity传来的View协助SurfaceView显示游戏视图,View的具体类型可以根据游戏需要来定
- */
- public void setTextView(TextView view) {
- this.textview = view;
- }
- public GameThread getThread() {
- return gameThread;
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- return gameThread.doKeyDown(keyCode, event);
- }
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- return gameThread.doKeyUp(keyCode, event);
- }
- /**
- * 当SurfaceView得到或失去焦点时调用,使游戏暂停/恢复运行,
- */
- @Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- if (!hasWindowFocus) {
- gameThread.pause();
- }
- else {
- gameThread.unpause();
- }
- }
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- Log.v(this.getClass().getName(), "surfaceChanged()");
- gameThread.setSurfaceSize(width, height);
- gameThread.setRunning(true);
- if (gameThread.isAlive()) {
- Log.v(this.getClass().getName(), "unpause gameThread");
- gameThread.unpause();
- }
- else {
- Log.v(this.getClass().getName(), "start gameThread");
- gameThread.start();
- }
- }
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.v(this.getClass().getName(), "surfaceCreated()");
- }
- /**
- * 为防止surface还会被创建(比如来电)导致gameThread再次启动出现错误,且Activity的onPause方法中已做暂停处理,
- * 这边不对gameThread做处理
- * @param holder
- */
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- Log.v(this.getClass().getName(), "surfaceDestroyed");
- }
- package com.mstanford.gameframework;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.os.Bundle;
- import android.os.Handler;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.view.SurfaceHolder;
- public class GameThread extends Thread {
- // 游戏状态值:ready
- public final static int GS_READY = 0;
- //游戏线程每执行一次需要睡眠的时间
- private final static int DELAY_TIME = 100;
- //上下文,方便获取到应用的各项资源,如图片、音乐、字符串等
- private Context context;
- //与Activity其他View交互用的handler
- private Handler handler;
- //由SurfaceView提供的SurfaceHolder
- private SurfaceHolder surfaceHolder;
- //游戏线程运行开关
- private boolean running = false;
- //游戏状态
- private int gameState;
- //当前surface/canvas的高度,在surfaceChanged方法中被设置
- private int mCanvasHeight = 1;
- //当前surface/canvas的宽度,在surfaceChanged方法中被设置
- private int mCanvasWidth = 1;
- /**
- * 游戏是否暂停
- */
- private boolean isPaused = false;
- public GameThread(SurfaceHolder holder, Context context, Handler handler) {
- this.surfaceHolder = holder;
- this.context = context;
- this.handler = handler;
- }
- /**
- * 设置游戏状态
- * @param mode 游戏状态
- */
- public void setState(int mode) {
- synchronized (surfaceHolder) {
- setState(mode, null);
- }
- }
- /**
- * 设置游戏状态
- * @param mode 游戏状态
- * @param message 设置游戏状态时的附加文字信息
- */
- public void setState(int mode, CharSequence message) {
- synchronized (surfaceHolder) {
- // TODO
- }
- }
- /**
- * 暂停游戏
- */
- public void pause() {
- synchronized (surfaceHolder) {
- isPaused = true;
- }
- }
- /**
- * 恢复运行游戏
- */
- public void unpause() {
- //如果游戏中有时间,别忘记应将其在这里调整到正常
- synchronized (surfaceHolder) {
- isPaused = false;
- }
- }
- /**
- * 当Activity因销毁而被重新创建时,在这里恢复游戏上次运行的数据
- * @param saveState Activity传来的保存游戏数据的容器
- */
- public void restoreState(Bundle saveState) {
- //TODO
- }
- /**
- * 在Activity切到后台时保存游戏的数据
- * @param outState 保存游戏数据的容器
- */
- public void saveState(Bundle outState)
- {
- //TODO
- }
- /**
- * 设置游戏线程运行开关
- * @param b 开/关
- */
- public void setRunning(boolean b) {
- running = b;
- }
- /**
- * 处理按下按键的事件
- * @param keyCode 按键事件动作值
- * @param msg 按键事件对象
- * @return 是否处理完
- */
- public boolean doKeyDown(int keyCode, KeyEvent msg) {
- synchronized (surfaceHolder) {
- // TODO
- return false;
- }
- }
- /**
- * 处理弹起按键的事件
- * @param keyCode 按键事件动作值
- * @param msg 按键事件对象
- * @return 是否处理完
- */
- public boolean doKeyUp(int keyCode, KeyEvent msg) {
- synchronized (surfaceHolder) {
- // TODO
- }
- return false;
- }
- /**
- * 设置surface/canvas的宽度和高度
- * @param width 由SurfaceHolder传来的宽度
- * @param height 由SurfaceHolder传来的高度
- */
- public void setSurfaceSize(int width, int height) {
- // synchronized to make sure these all change atomically
- synchronized (surfaceHolder) {
- mCanvasWidth = width;
- mCanvasHeight = height;
- //不要忘记每次画布的宽度和高度改变时, 在这里对图片等资源做缩放等相关适配屏幕的处理
- //TODO
- }
- }
- public void run() {
- while (running) {
- if (!isPaused) {
- Canvas c = null;
- try {
- c = surfaceHolder.lockCanvas(null);
- synchronized (surfaceHolder) {
- doDraw(c);
- }
- logic();
- } finally {
- if (c != null) {
- surfaceHolder.unlockCanvasAndPost(c);
- }
- }
- try {
- Thread.sleep(DELAY_TIME);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- /**
- * 游戏逻辑处理
- */
- public void logic()
- {
- Log.v(this.getClass().getName(), "logic");
- //TODO
- }
- /**
- * 游戏绘画
- */
- private void doDraw(Canvas canvas) {
- Log.v(this.getClass().getName(), "doDraw");
- //TODO
- }
- /**
- * 初始化游戏开始时的参数
- */
- private void doStart() {
- //TODO
- }
- }