如何構建自己的游戲框架並且制作游戲(一)(附源碼)


 這個教程就讓我們學習怎么用這個游戲框架開發一個簡單的空戰游戲吧!由於素材有限,都是用的網上的素材。這個游戲可以改造成為空戰或者植物大戰僵屍等的養成類型游戲或者更多,原理都差不多。    一個出類拔萃的人總是一個有耐心的人! 一個游戲的制作經常會出現小意外,一個不耐心的人往往會不知所措,我看過李華明他的書上面有介紹游戲框架,而且很詳細,但是沒有這個全面,現在的很多游戲書籍也很少有關於游戲框架的構建,希望大家可以多借鑒一下,多提提意見!
先上圖:

  第一個教程就先搭建屬於我們的游戲框架
com.mocn.framework中是框架包
com.mocn.airBottle中是游戲包

 

首先看框架包 中的BaseActivity類,主要用於設置橫豎屏,全屏,屏幕的寬高度等等。

package com.mocn.framework;

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;

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<String, SpriteAction> actions;// 動作集合
        public SpriteAction currentAction;// 當前動作

        public Sprite(Bitmap bitmap, int w, int h, boolean autoAdd) {
                super(bitmap, w, h, autoAdd);
                actions = new Hashtable<String, Sprite.SpriteAction>();// 用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<Layer> vec = new Vector<Layer>(); // 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;
        }
}

  框架搭建完成,第二篇就是游戲的繪制篇了,如果大家在框架上有什么問題可以問我。
下面附上源碼:

 http://files.cnblogs.com/feifei1010/AirBottle.zip

還有看到好多優秀的帖子http://www.apkbus.com/blog-15060-40268.html

歡迎熱愛安卓開發的朋友么加入群一起討論,進步!!成都群252743807  武漢群121592153


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM