my射飞碟小游戏

# 射飞碟游戏 #

### 具体要求如下: ###

假设有一支枪在摄像机位置(0,1,-10),在(0,0,0-10-20)放置三个小球作为距离标记,调整视角直到小球在下中部
将鼠标所在平面坐标,转换为子弹(球体)射出的角度方向。子弹使用物理引擎,初速度恒定。(U3d 坐标变换: http://www.cnblogs.com/tekkaman/p/3809409.html )

`Vector3 mp = Input.mousePosition; //get Screen Position
print (mp.ToString());
Vector3 mp1 = cam.camera.ScreenToViewportPoint (mp);
mp1.z = 10; //距摄像头 10 位置立面
mp1 = cam.camera.ViewportToWorldPoint (mp1);
print (mp1.ToString());`

游戏要分多个 round , 飞碟数量每个 round 都是 n 个,但色彩,大小;发射位置,速度,角度,每次发射数量按预定规则变化。
用户按空格后,321倒数3秒,飞碟飞出(物理引擎控制),点击鼠标,子弹飞出。飞碟落地,或被击中,则准备下一次射击。

以下是一些技术要求:
子弹仅需要一个,不用时处于 deactive 状态
飞碟用一个带缓存的工厂生产,template 中放置预制的飞碟对象
程序类图设计大致如下:![](http://ss.sysu.edu.cn/~pml/se347/_images/HitDisk_2.png)

下面是游戏的组件代码:
###1、GameModel.cs###
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using Com.Mygame;

    public class GameModel : MonoBehaviour {
    public float countDown = 3f;  
    public float timeToEmit;      
    private bool counting;      
    private bool shooting;     
     
    public bool isCounting() {
        return counting;
    }

    public bool isShooting() {
        return shooting;
    } 

    private List<GameObject> disks = new List<GameObject>();    // 飞碟对象列表  
    private List<int> diskIds = new List<int>();             
    private int diskScale;        
    private Color diskColor;           
    private Vector3 emitPosition;      
    private Vector3 emitDirection;       
    private float emitSpeed;            
    private int emitNumber;              
    private bool emitEnable;           

    private SceneController scene;

    void Awake() {
        scene = SceneController.getInstance();
        scene.setGameModel(this);
    }

    public void setting(int scale, Color color, Vector3 emitPos, Vector3 emitDir, float speed, int num) {  // 场景设置
        diskScale = scale;  // 没什么好说的,赋值
        diskColor = color;
        emitPosition = emitPos;
        emitDirection = emitDir;
        emitSpeed = speed;
        emitNumber = num;
    }

    // 准备下一次发射  
    public void prepareToEmitDisk() {
        if (counting == false && shooting == false) {
            timeToEmit = countDown;
            emitEnable = true;  // 可发射变为真
        }
    }

    // 发射飞碟  
    void emitDisks() {
        for (int i = 0; i < emitNumber; ++i) {
            diskIds.Add(Factory.getInstance().getDisk());
            disks.Add(Factory.getInstance().getDiskObject(diskIds[i]));
            disks[i].transform.localScale *= diskScale;
            disks[i].transform.position = new Vector3(emitPosition.x, emitPosition.y + i, emitPosition.z);
            disks[i].SetActive(true);
            disks[i].rigidbody.AddForce(emitDirection * Random.Range(emitSpeed * 5, emitSpeed * 10) / 10, ForceMode.Impulse);
        }
    }

    // 回收  
    void freeADisk(int i) {
        Factory.getInstance().free(diskIds[i]);
        disks.RemoveAt(i);
        diskIds.RemoveAt(i);
    }

    void FixedUpdate() {
        if (timeToEmit > 0) {
            counting = true;
            timeToEmit -= Time.deltaTime;
        } else {
            counting = false;
            if (emitEnable == true) {
                emitDisks();
                emitEnable = false;  // 改变之后可发射变为假
                shooting = true;
            }
        }
    }

    void Update() {
        for (int i = 0; i < disks.Count; i++) {
            if (!disks[i].activeInHierarchy) {
                scene.getJudge().scoreADisk();
                freeADisk(i);
            } else if (disks[i].transform.position.y < 0) {
                scene.getJudge().failADisk();
                freeADisk(i);
            }
        }
        if (disks.Count == 0) {  // 如果不存在飞碟了,停止射击
            shooting = false;
        }
    }
    }

这个文件控制的是游戏场景,通过调用Factory.getInstance()功能来获取飞碟的实例,当飞碟被击中或者自己落地的时候,将被freeDisk()函数回收,并且通过调用Judge类中的函数,来决定分数的获得和扣除,并以此来决定是否结束游戏或者进入下一关卡。FixedUpdate()和Update()函数通过bool条件判断,来决定是否可以继续射击。

###2、UserInterface###
    using UnityEngine;
    using UnityEngine.UI;
    using System.Collections;
    using Com.Mygame;

    public class UserInterface : MonoBehaviour {
    public Text mainText;
    public Text scoreText;  
    public Text roundText; 
    private int round;  // 判定当前回合 
    public GameObject bullet;        
    public ParticleSystem explosion;   
    public float fireRate = .25f;      
    public float speed = 500f;     
    private float nextFireTime;        
    private IUserInterface userInt;
    private IQueryStatus queryInt;  
    void Start() {  // 游戏开始,加载
        bullet = GameObject.Instantiate(bullet) as GameObject;
        explosion = GameObject.Instantiate(explosion) as ParticleSystem;
        userInt = SceneController.getInstance() as IUserInterface;
        queryInt = SceneController.getInstance() as IQueryStatus;
    }

    void Update() {
        if (queryInt.isCounting()) {
            mainText.text = ((int)queryInt.getEmitTime()).ToString();
        } else {
            if (Input.GetKeyDown("space")) {  // 输入空格开始
                yield return new WaitforSeconds(3f);  // 倒数3秒后开始
                userInt.emitDisk();
            }
            if (queryInt.isShooting()) {
                mainText.text = "";     // 隐藏maintext
            }
            // 发射子弹  
            if (queryInt.isShooting() && Input.GetMouseButtonDown(0) && Time.time > nextFireTime) {
                nextFireTime = Time.time + fireRate;  // 开火冷却时间
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                bullet.rigidbody.velocity = Vector3.zero;                       // 重置子弹速度 
                bullet.transform.position = transform.position;                  // 子弹射出  
                bullet.rigidbody.AddForce(ray.direction * speed, ForceMode.Impulse);
                RaycastHit hit;
                if (Physics.Raycast(ray, out hit) && hit.collider.gameObject.tag == "Disk") {
                    explosion.transform.position = hit.collider.gameObject.transform.position;
                    explosion.Play();
                    // 击中飞碟自动回收  
                    hit.collider.gameObject.SetActive(false);
                }
            }
        }
        roundText.text = "Round: " + queryInt.getRound().ToString();
        scoreText.text = "Score: " + queryInt.getPoint().ToString(); 
        if (round != queryInt.getRound()) {
            round = queryInt.getRound();
            mainText.text = "Round " + round.ToString() + " Start";
        }
    }
    }

该文件创建用户界面,其中包含着加载、提示、游戏主体等部分。作业要求中,用户按空格后,321倒数3秒,飞碟飞出(物理引擎控制),点击鼠标左键,子弹飞出。飞碟落地,或被击中,则准备下一次射击。我用了waitforSeconds函数来实现,在等待3秒之后,开始飞出飞碟,飞碟落地或被击中的函数已经在GameModel.cs文件中写出,这里就不再赘述。值得一提的是,刚开始我测试游戏的时候,子弹的速度会越来越快,这是因为我没有将其清零的缘故,后来我令其velocity赋值为0来进行清零。上一次的作业中我的子弹使用的是射线判定,这次则用的是有碰撞体积的物理引擎,这点可以在装载之后发现。

###3、SceneController.cs###
    using UnityEngine;
    using System.Collections;
    using Com.Mygame;

    namespace Com.Mygame {
    public interface IUserInterface {  // 场景控制器,是游戏中十分重要的一个环节
        void emitDisk();
    }

    public interface IQueryStatus {  // 记录回合和得分
        bool isCounting();
        bool isShooting();
        int getRound();
        int getPoint();
        int getEmitTime();
    }

    public interface IJudgeEvent {
        void nextRound();
        void setPoint(int point);
    }

    public class SceneController : System.Object, IQueryStatus, IUserInterface, IJudgeEvent {  // 继承各类
        private static SceneController _instance;
        private SceneControllerBC _baseCode;  // 分别为SceneControllerBC、GameModel、Judege
        private GameModel _gameModel;
        private Judge _judge;

        private int _round;
        private int _point;

        public static SceneController getInstance() {
            if (_instance == null) {
                _instance = new SceneController();  // 返回SceneController的实例
            }
            return _instance;
        }

        public void setGameModel(GameModel obj) {
            _gameModel = obj;
        }

        internal GameModel getGameModel() {
            return _gameModel;
        }

        public void setJudge(Judge obj) {
            _judge = obj;
        }

        internal Judge getJudge() {
            return _judge;
        }

        public void setSceneControllerBC(SceneControllerBC obj) {
            _baseCode = obj;
        }
        internal SceneControllerBC getSceneControllerBC() {
            return _baseCode;
        }

        public void emitDisk() {
            _gameModel.prepareToEmitDisk();
        }

        public bool isCounting() {
            return _gameModel.isCounting();
        }

        public bool isShooting() {
            return _gameModel.isShooting();
        }

        public int getRound() {
            return _round;
        }

        public int getPoint() {
            return _point;
        }

        public int getEmitTime() {
            int result = (int)_gameModel.timeToEmit + 1;
            return result;
        }

        public void setPoint(int point) {
            _point = point;
        }

        public void nextRound() {
            _point = 0; _baseCode.loadRoundData(++_round);
        }
    }
    }
场景控制器,实现各种成员变量的返回实现,以及接口定义和保存注入对象。其中它有两个私有变量round和point,分别记录游戏正在进行的回合,以及玩家目前的得分,应用在GameModel中实现。

###4、SceneControllerBC.cs###
    UnityEngine;
    using System.Collections;
    using Com.Mygame;

    public class SceneControllerBC : MonoBehaviour {
    private Color color;
    private Vector3 emitPos;
    private Vector3 emitDir;
    private float speed;

    void Awake() {
        SceneController.getInstance().setSceneControllerBC(this);
    }

    public void loadRoundData(int round) {  // 关卡的设计
        switch (round) {
            case 1:     // 第一关  
                color = Color.green;
                emitPos = new Vector3(-2.5f, 0.2f, -5f);  // 初始条件
                emitDir = new Vector3(24.5f, 40.0f, 67f);
                speed = 4;
                SceneController.getInstance().getGameModel().setting(1, color, emitPos, emitDir.normalized, speed, 1);
                break;
            case 2:     // 第二关  
                color = Color.red;
                emitPos = new Vector3(2.5f, 0.2f, -5f);
                emitDir = new Vector3(-24.5f, 35.0f, 67f);
                speed = 4;
                SceneController.getInstance().getGameModel().setting(1, color, emitPos, emitDir.normalized, speed, 2);  // 设定条件
                break;
            case 3:     // 第三关  
                color = Color.red;
                emitPos = new Vector3(2.5f, 0.2f, -5f);
                emitDir = new Vector3(-24.5f, 35.0f, 67f);  // 飞碟初始位置不变,仅改变速度
                speed = 5;
                SceneController.getInstance().getGameModel().setting(1, color, emitPos, emitDir.normalized, speed, 4);  // 其实改一下飞碟的速度就可以了
                break;
        }
    }
    }
此文件为关卡类的定义,我只做了3个关卡,题目要求我:游戏要分多个 round , 飞碟数量每个 round 都是 n 个,但色彩,大小;发射位置,速度,角度,每次发射数量按预定规则变化。因此我没有改变飞碟的数量,位置和角度,从速度入手,越到后面的关卡越快。函数Awake()用来获取场景控制器实例,loadRoundData()用来初始化游戏场景,即定义飞碟的属性。

###5、Factory.cs###
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using Com.Mygame;

    namespace Com.Mygame {
    public class Factory : System.Object {
        private static Factory _instance;  // 获取实例
        private static List<GameObject> diskList;
        public GameObject diskTemplate;        

        public static Factory getInstance() {  // 工厂实例
            if (_instance == null) {
                _instance = new Factory();
                diskList = new List<GameObject>();
            }
            return _instance;
        }

        public int getDisk() {
            for (int i = 0; i < diskList.Count; i++) {
                if (!diskList[i].activeInHierarchy) {  //  判断是否飞碟空闲
                    return i; 
                }
            }
            diskList.Add(GameObject.Instantiate(diskTemplate) as GameObject);  // 设置新的飞碟
            return diskList.Count-1;
        }

        public void free(int id) {
            if (id >= 0 && id < diskList.Count) {  // 判断是否有效
                diskList[id].rigidbody.velocity = Vector3.zero;  // 速度清零
                diskList[id].transform.localScale = diskTemplate.transform.localScale;
                diskList[id].SetActive(false);  // 活动能力重置
            }
        }

        public GameObject getDiskObject(int id) {
            if (id > -1 && id < diskList.Count) {
                return diskList[id];
            }
            return null;
        }

        
    }
    }

    public class DiskFactoryBC : MonoBehaviour {  // 另一个类BC
    public GameObject disk;
    void Awake() {
        Factory.getInstance().diskTemplate = disk;  // 用于获取飞碟实例
    }
    }
题目要求:飞碟用一个带缓存的工厂生产,template 中放置预制的飞碟对象。这个就是飞碟工厂,管理飞碟实例,同时对外屏蔽飞碟实例的的提取和回收细节。它定义了获取、回收飞碟的功能,并且由于是public函数,可以被其他函数直接调用,来管理、应用飞碟。

###6、Judge.cs###
    using UnityEngine;
    using System.Collections;
    using Com.Mygame;

    public class Judge : MonoBehaviour {  // 判定得分失分,能否进入下一回合
    public int oneDiskScore = 10;
    public int oneDiskFail = 10;
    public int disksToWin = 4;
    private SceneController scene;

    void Awake() {
        scene = SceneController.getInstance();
        scene.setJudge(this);  // 设定规则
    }

    void Start() {
        scene.nextRound();  // 第一关  
    }
 
    public void scoreADisk()  // 得分
    {
        scene.setPoint(scene.getPoint() + oneDiskScore);
        if (scene.getPoint() == disksToWin * oneDiskScore) {
            scene.nextRound();
        }
    }

    public void failADisk() {  // 失分
        scene.setPoint(scene.getPoint() - oneDiskFail);  // 判定条件,飞碟掉落
    }
    }
用以判断得失分的类,当符合得分条件时,调用得分函数;当符合失分条件时(即飞碟未击中而掉落时),调用失分函数。当得分符合条件时,进入下一回合。


*题目条件:有一支枪在摄像机位置(0,1,-10),在(0,0,0-10-20)放置三个小球作为距离标记,调整视角直到小球在下中部。*
部件设定:
摄像机:# 射飞碟游戏 #

### 具体要求如下: ###

假设有一支枪在摄像机位置(0,1,-10),在(0,0,0-10-20)放置三个小球作为距离标记,调整视角直到小球在下中部
将鼠标所在平面坐标,转换为子弹(球体)射出的角度方向。子弹使用物理引擎,初速度恒定。(U3d 坐标变换: http://www.cnblogs.com/tekkaman/p/3809409.html )

`Vector3 mp = Input.mousePosition; //get Screen Position
print (mp.ToString());
Vector3 mp1 = cam.camera.ScreenToViewportPoint (mp);
mp1.z = 10; //距摄像头 10 位置立面
mp1 = cam.camera.ViewportToWorldPoint (mp1);
print (mp1.ToString());`

游戏要分多个 round , 飞碟数量每个 round 都是 n 个,但色彩,大小;发射位置,速度,角度,每次发射数量按预定规则变化。
用户按空格后,321倒数3秒,飞碟飞出(物理引擎控制),点击鼠标,子弹飞出。飞碟落地,或被击中,则准备下一次射击。

以下是一些技术要求:
子弹仅需要一个,不用时处于 deactive 状态
飞碟用一个带缓存的工厂生产,template 中放置预制的飞碟对象
程序类图设计大致如下:![](http://ss.sysu.edu.cn/~pml/se347/_images/HitDisk_2.png)

下面是游戏的组件代码:
###1、GameModel.cs###
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using Com.Mygame;

    public class GameModel : MonoBehaviour {
    public float countDown = 3f;  
    public float timeToEmit;      
    private bool counting;      
    private bool shooting;     
     
    public bool isCounting() {
        return counting;
    }

    public bool isShooting() {
        return shooting;
    } 

    private List<GameObject> disks = new List<GameObject>();    // 飞碟对象列表  
    private List<int> diskIds = new List<int>();             
    private int diskScale;        
    private Color diskColor;           
    private Vector3 emitPosition;      
    private Vector3 emitDirection;       
    private float emitSpeed;            
    private int emitNumber;              
    private bool emitEnable;           

    private SceneController scene;

    void Awake() {
        scene = SceneController.getInstance();
        scene.setGameModel(this);
    }

    public void setting(int scale, Color color, Vector3 emitPos, Vector3 emitDir, float speed, int num) {  // 场景设置
        diskScale = scale;  // 没什么好说的,赋值
        diskColor = color;
        emitPosition = emitPos;
        emitDirection = emitDir;
        emitSpeed = speed;
        emitNumber = num;
    }

    // 准备下一次发射  
    public void prepareToEmitDisk() {
        if (counting == false && shooting == false) {
            timeToEmit = countDown;
            emitEnable = true;  // 可发射变为真
        }
    }

    // 发射飞碟  
    void emitDisks() {
        for (int i = 0; i < emitNumber; ++i) {
            diskIds.Add(Factory.getInstance().getDisk());
            disks.Add(Factory.getInstance().getDiskObject(diskIds[i]));
            disks[i].transform.localScale *= diskScale;
            disks[i].transform.position = new Vector3(emitPosition.x, emitPosition.y + i, emitPosition.z);
            disks[i].SetActive(true);
            disks[i].rigidbody.AddForce(emitDirection * Random.Range(emitSpeed * 5, emitSpeed * 10) / 10, ForceMode.Impulse);
        }
    }

    // 回收  
    void freeADisk(int i) {
        Factory.getInstance().free(diskIds[i]);
        disks.RemoveAt(i);
        diskIds.RemoveAt(i);
    }

    void FixedUpdate() {
        if (timeToEmit > 0) {
            counting = true;
            timeToEmit -= Time.deltaTime;
        } else {
            counting = false;
            if (emitEnable == true) {
                emitDisks();
                emitEnable = false;  // 改变之后可发射变为假
                shooting = true;
            }
        }
    }

    void Update() {
        for (int i = 0; i < disks.Count; i++) {
            if (!disks[i].activeInHierarchy) {
                scene.getJudge().scoreADisk();
                freeADisk(i);
            } else if (disks[i].transform.position.y < 0) {
                scene.getJudge().failADisk();
                freeADisk(i);
            }
        }
        if (disks.Count == 0) {  // 如果不存在飞碟了,停止射击
            shooting = false;
        }
    }
    }

这个文件控制的是游戏场景,通过调用Factory.getInstance()功能来获取飞碟的实例,当飞碟被击中或者自己落地的时候,将被freeDisk()函数回收,并且通过调用Judge类中的函数,来决定分数的获得和扣除,并以此来决定是否结束游戏或者进入下一关卡。FixedUpdate()和Update()函数通过bool条件判断,来决定是否可以继续射击。

###2、UserInterface###
    using UnityEngine;
    using UnityEngine.UI;
    using System.Collections;
    using Com.Mygame;

    public class UserInterface : MonoBehaviour {
    public Text mainText;
    public Text scoreText;  
    public Text roundText; 
    private int round;  // 判定当前回合 
    public GameObject bullet;        
    public ParticleSystem explosion;   
    public float fireRate = .25f;      
    public float speed = 500f;     
    private float nextFireTime;        
    private IUserInterface userInt;
    private IQueryStatus queryInt;  
    void Start() {  // 游戏开始,加载
        bullet = GameObject.Instantiate(bullet) as GameObject;
        explosion = GameObject.Instantiate(explosion) as ParticleSystem;
        userInt = SceneController.getInstance() as IUserInterface;
        queryInt = SceneController.getInstance() as IQueryStatus;
    }

    void Update() {
        if (queryInt.isCounting()) {
            mainText.text = ((int)queryInt.getEmitTime()).ToString();
        } else {
            if (Input.GetKeyDown("space")) {  // 输入空格开始
                yield return new WaitforSeconds(3f);  // 倒数3秒后开始
                userInt.emitDisk();
            }
            if (queryInt.isShooting()) {
                mainText.text = "";     // 隐藏maintext
            }
            // 发射子弹  
            if (queryInt.isShooting() && Input.GetMouseButtonDown(0) && Time.time > nextFireTime) {
                nextFireTime = Time.time + fireRate;  // 开火冷却时间
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                bullet.rigidbody.velocity = Vector3.zero;                       // 重置子弹速度 
                bullet.transform.position = transform.position;                  // 子弹射出  
                bullet.rigidbody.AddForce(ray.direction * speed, ForceMode.Impulse);
                RaycastHit hit;
                if (Physics.Raycast(ray, out hit) && hit.collider.gameObject.tag == "Disk") {
                    explosion.transform.position = hit.collider.gameObject.transform.position;
                    explosion.Play();
                    // 击中飞碟自动回收  
                    hit.collider.gameObject.SetActive(false);
                }
            }
        }
        roundText.text = "Round: " + queryInt.getRound().ToString();
        scoreText.text = "Score: " + queryInt.getPoint().ToString(); 
        if (round != queryInt.getRound()) {
            round = queryInt.getRound();
            mainText.text = "Round " + round.ToString() + " Start";
        }
    }
    }

该文件创建用户界面,其中包含着加载、提示、游戏主体等部分。作业要求中,用户按空格后,321倒数3秒,飞碟飞出(物理引擎控制),点击鼠标左键,子弹飞出。飞碟落地,或被击中,则准备下一次射击。我用了waitforSeconds函数来实现,在等待3秒之后,开始飞出飞碟,飞碟落地或被击中的函数已经在GameModel.cs文件中写出,这里就不再赘述。值得一提的是,刚开始我测试游戏的时候,子弹的速度会越来越快,这是因为我没有将其清零的缘故,后来我令其velocity赋值为0来进行清零。上一次的作业中我的子弹使用的是射线判定,这次则用的是有碰撞体积的物理引擎,这点可以在装载之后发现。

###3、SceneController.cs###
    using UnityEngine;
    using System.Collections;
    using Com.Mygame;

    namespace Com.Mygame {
    public interface IUserInterface {  // 场景控制器,是游戏中十分重要的一个环节
        void emitDisk();
    }

    public interface IQueryStatus {  // 记录回合和得分
        bool isCounting();
        bool isShooting();
        int getRound();
        int getPoint();
        int getEmitTime();
    }

    public interface IJudgeEvent {
        void nextRound();
        void setPoint(int point);
    }

    public class SceneController : System.Object, IQueryStatus, IUserInterface, IJudgeEvent {  // 继承各类
        private static SceneController _instance;
        private SceneControllerBC _baseCode;  // 分别为SceneControllerBC、GameModel、Judege
        private GameModel _gameModel;
        private Judge _judge;

        private int _round;
        private int _point;

        public static SceneController getInstance() {
            if (_instance == null) {
                _instance = new SceneController();  // 返回SceneController的实例
            }
            return _instance;
        }

        public void setGameModel(GameModel obj) {
            _gameModel = obj;
        }

        internal GameModel getGameModel() {
            return _gameModel;
        }

        public void setJudge(Judge obj) {
            _judge = obj;
        }

        internal Judge getJudge() {
            return _judge;
        }

        public void setSceneControllerBC(SceneControllerBC obj) {
            _baseCode = obj;
        }
        internal SceneControllerBC getSceneControllerBC() {
            return _baseCode;
        }

        public void emitDisk() {
            _gameModel.prepareToEmitDisk();
        }

        public bool isCounting() {
            return _gameModel.isCounting();
        }

        public bool isShooting() {
            return _gameModel.isShooting();
        }

        public int getRound() {
            return _round;
        }

        public int getPoint() {
            return _point;
        }

        public int getEmitTime() {
            int result = (int)_gameModel.timeToEmit + 1;
            return result;
        }

        public void setPoint(int point) {
            _point = point;
        }

        public void nextRound() {
            _point = 0; _baseCode.loadRoundData(++_round);
        }
    }
    }
场景控制器,实现各种成员变量的返回实现,以及接口定义和保存注入对象。其中它有两个私有变量round和point,分别记录游戏正在进行的回合,以及玩家目前的得分,应用在GameModel中实现。

###4、SceneControllerBC.cs###
    UnityEngine;
    using System.Collections;
    using Com.Mygame;

    public class SceneControllerBC : MonoBehaviour {
    private Color color;
    private Vector3 emitPos;
    private Vector3 emitDir;
    private float speed;

    void Awake() {
        SceneController.getInstance().setSceneControllerBC(this);
    }

    public void loadRoundData(int round) {  // 关卡的设计
        switch (round) {
            case 1:     // 第一关  
                color = Color.green;
                emitPos = new Vector3(-2.5f, 0.2f, -5f);  // 初始条件
                emitDir = new Vector3(24.5f, 40.0f, 67f);
                speed = 4;
                SceneController.getInstance().getGameModel().setting(1, color, emitPos, emitDir.normalized, speed, 1);
                break;
            case 2:     // 第二关  
                color = Color.red;
                emitPos = new Vector3(2.5f, 0.2f, -5f);
                emitDir = new Vector3(-24.5f, 35.0f, 67f);
                speed = 4;
                SceneController.getInstance().getGameModel().setting(1, color, emitPos, emitDir.normalized, speed, 2);  // 设定条件
                break;
            case 3:     // 第三关  
                color = Color.red;
                emitPos = new Vector3(2.5f, 0.2f, -5f);
                emitDir = new Vector3(-24.5f, 35.0f, 67f);  // 飞碟初始位置不变,仅改变速度
                speed = 5;
                SceneController.getInstance().getGameModel().setting(1, color, emitPos, emitDir.normalized, speed, 4);  // 其实改一下飞碟的速度就可以了
                break;
        }
    }
    }
此文件为关卡类的定义,我只做了3个关卡,题目要求我:游戏要分多个 round , 飞碟数量每个 round 都是 n 个,但色彩,大小;发射位置,速度,角度,每次发射数量按预定规则变化。因此我没有改变飞碟的数量,位置和角度,从速度入手,越到后面的关卡越快。函数Awake()用来获取场景控制器实例,loadRoundData()用来初始化游戏场景,即定义飞碟的属性。

###5、Factory.cs###
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using Com.Mygame;

    namespace Com.Mygame {
    public class Factory : System.Object {
        private static Factory _instance;  // 获取实例
        private static List<GameObject> diskList;
        public GameObject diskTemplate;        

        public static Factory getInstance() {  // 工厂实例
            if (_instance == null) {
                _instance = new Factory();
                diskList = new List<GameObject>();
            }
            return _instance;
        }

        public int getDisk() {
            for (int i = 0; i < diskList.Count; i++) {
                if (!diskList[i].activeInHierarchy) {  //  判断是否飞碟空闲
                    return i; 
                }
            }
            diskList.Add(GameObject.Instantiate(diskTemplate) as GameObject);  // 设置新的飞碟
            return diskList.Count-1;
        }

        public void free(int id) {
            if (id >= 0 && id < diskList.Count) {  // 判断是否有效
                diskList[id].rigidbody.velocity = Vector3.zero;  // 速度清零
                diskList[id].transform.localScale = diskTemplate.transform.localScale;
                diskList[id].SetActive(false);  // 活动能力重置
            }
        }

        public GameObject getDiskObject(int id) {
            if (id > -1 && id < diskList.Count) {
                return diskList[id];
            }
            return null;
        }

        
    }
    }

    public class DiskFactoryBC : MonoBehaviour {  // 另一个类BC
    public GameObject disk;
    void Awake() {
        Factory.getInstance().diskTemplate = disk;  // 用于获取飞碟实例
    }
    }
题目要求:飞碟用一个带缓存的工厂生产,template 中放置预制的飞碟对象。这个就是飞碟工厂,管理飞碟实例,同时对外屏蔽飞碟实例的的提取和回收细节。它定义了获取、回收飞碟的功能,并且由于是public函数,可以被其他函数直接调用,来管理、应用飞碟。

###6、Judge.cs###
    using UnityEngine;
    using System.Collections;
    using Com.Mygame;

    public class Judge : MonoBehaviour {  // 判定得分失分,能否进入下一回合
    public int oneDiskScore = 10;
    public int oneDiskFail = 10;
    public int disksToWin = 4;
    private SceneController scene;

    void Awake() {
        scene = SceneController.getInstance();
        scene.setJudge(this);  // 设定规则
    }

    void Start() {
        scene.nextRound();  // 第一关  
    }
 
    public void scoreADisk()  // 得分
    {
        scene.setPoint(scene.getPoint() + oneDiskScore);
        if (scene.getPoint() == disksToWin * oneDiskScore) {
            scene.nextRound();
        }
    }

    public void failADisk() {  // 失分
        scene.setPoint(scene.getPoint() - oneDiskFail);  // 判定条件,飞碟掉落
    }
    }
用以判断得失分的类,当符合得分条件时,调用得分函数;当符合失分条件时(即飞碟未击中而掉落时),调用失分函数。当得分符合条件时,进入下一回合。


*题目条件:有一支枪在摄像机位置(0,1,-10),在(0,0,0-10-20)放置三个小球作为距离标记,调整视角直到小球在下中部。*
部件设定:
摄像机:
飞碟:

子弹:
标记球:

1、

2、

3、

最后在摄像机上挂载文件就可以了。一个射飞碟的小游戏就做好了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值