3D游戏编程作业第六章 物理系统与碰撞

改进飞碟(Hit UFO)游戏:

上一篇

游戏内容要求:

  • 按 adapter模式 设计图修改飞碟游戏
  • 使它同时支持物理运动与运动学(变换)运动

工厂 DiskFactory.cs:新增实现 IActionManager 接口的功能,将原本设定的所有飞碟皆受重力作用给为仅当mode为PHYSICS时增加Rigidbody(预制不添加Rigidbody)和重力作用。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PriestsAndDevils;
// 工厂模式
public class DiskFactory : MonoBehaviour, IActionManager
{
    private List<Disk> toDelete = new List<Disk>();
    private List<Disk> toUse = new List<Disk>();
    public Color[] colors = {Color.white,Color.yellow,Color.red,Color.blue,Color.green,Color.black};//可选颜色
    public GameObject GetDisk(int round,ActionMode mode){//根据回合数对飞碟设置属性并返回
        GameObject newDisk = null;
        if (toUse.Count > 0){
            newDisk = toUse[0].gameObject;
            toUse.Remove(toUse[0]);
        }else{
            newDisk = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/disk"), Vector3.zero, Quaternion.identity);
            newDisk.AddComponent<Disk>();
        }
        //commonProperities();
        if (mode == ActionMode.PHYSICS){
            newDisk.AddComponent<Rigidbody>();
            newDisk.GetComponent<Rigidbody>().AddForce(Vector3.down * 9.8f, ForceMode.Acceleration);
        }
          // 飞碟的速度为round*7
        newDisk.GetComponent<Disk>().speed = 7.0f * round;
        // 飞碟随round越来越小
        newDisk.GetComponent<Disk>().size = (1 - round*0.1f);
        // 飞碟颜色随机
        int color = UnityEngine.Random.Range(0, 6);//共有六种颜色
        newDisk.GetComponent<Disk>().color = colors[color];
        // 飞碟的发射方向
        float RanX = UnityEngine.Random.Range(-1, 3) < 1 ? -1 : 1;//-1,0则为负方向,1,2则为正方向
        newDisk.GetComponent<Disk>().direction = new Vector3(-RanX, UnityEngine.Random.Range(-2f, 2f), 0);
        // 飞碟的初始位置
        newDisk.GetComponent<Disk>().position = new Vector3(RanX*13, UnityEngine.Random.Range(-2f, 2f), UnityEngine.Random.Range(-1f, 1f));
        toDelete.Add(newDisk.GetComponent<Disk>());
        newDisk.SetActive(false);
        newDisk.name = newDisk.GetInstanceID().ToString();
        return newDisk;
    }
    public void FreeDisk(GameObject disk){
        Disk cycledDisk = null;
        foreach (Disk toCycle in toDelete){
            if (disk.GetInstanceID() == toCycle.gameObject.GetInstanceID()){
                cycledDisk = toCycle;
            }
        }
        if (cycledDisk != null){
            cycledDisk.gameObject.SetActive(false);
            toUse.Add(cycledDisk);
            toDelete.Remove(cycledDisk);
        }
    }
}

ActionManager.cs:没有改变
SceneController.cs:没有改变

场景控制FirstSceneController.cs:第一场景控制器,负责控制游戏场景的加载和切换。增加mode作为成员变量,并将其传递给 DiskFactory 的 GetDisk() 函数生成所需的飞碟。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PriestsAndDevils;
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    protected static T instance;
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = (T)FindObjectOfType(typeof(T));
                if (instance == null) {  
                    Debug.LogError ("An instance of " + typeof(T) +
                    " is needed in the scene, but there is none.");  
                }  
            }
            return instance;
        }
    }
}
public class FirstSceneController : MonoBehaviour, ISceneController{
    public int diskFlyTimes; //已经发射的飞碟个数,每回合10个,最多30个
    public float time;// 时间,用于控制飞碟发射间隔
    public int round;  // 当前回合数
    public ActionMode mode;//模式选择
    // 飞碟队列
    public Queue<GameObject> diskQueue = new Queue<GameObject>();//飞碟队列
    public SceneController  sceneCtrl;
    public ActionMode getMode() 
    {
        return mode; 
    }
    public void setMode(ActionMode m)
    {
        //if (m == ActionMode.KINEMATIC) this.gameObject.AddComponent<CCActionManager>();
    //    else this.gameObject.AddComponent<PhysicActionManager>();
        mode = m;
    }
    // Start is called before the first frame update
    void Start(){
        // 当前场景控制器
        Director.getInstance().currentSceneController = this;
        this.gameObject.AddComponent<DiskFactory>();
        this.gameObject.AddComponent<UserGUI>();
        Director.getInstance().currentSceneController.Init();//初始化FirstSceneController相关数据
        mode = ActionMode.PHYSICS;
    }
    // 初始化每个回合的飞碟队列,每个回合的飞碟属性不同
    void initQueue(){
        diskQueue.Clear();//clear first
        for(int i = 0;i < 10;i ++)
            diskQueue.Enqueue(Singleton<DiskFactory>.Instance.GetDisk(round,getMode()));
    }
    // Update is called once per frame
    void Update() {
       // round = sceneCtrl.getRound();
        time += Time.deltaTime;
        // 发射飞碟的间隔回合数成反比
        if(time >= 2.0f-0.3*round){
            if(diskFlyTimes >= 30){//游戏结束
                Reset();
            }else if ((diskFlyTimes % 10) == 0 ){//更新回合(此步骤必须在发射飞碟前面)
                round ++;//在initQueue();前面才行
                sceneCtrl.addRound();//回合数增加
                initQueue();//初始化新的飞盘队列
            }
            if (diskFlyTimes < 30){
                time = 0;
                ThrowDisk();//发射飞盘
                diskFlyTimes ++;//飞盘数增加
                sceneCtrl.addTotal();//综费盘数增加
            }
        }
    }
    public void ThrowDisk()
    {
        if(diskQueue.Count > 0)
        {
            GameObject disk = diskQueue.Dequeue();
            disk.GetComponent<Renderer>().material.color = disk.GetComponent<Disk>().color;
            disk.transform.position = disk.GetComponent<Disk>().position;
            disk.transform.localScale = disk.GetComponent<Disk>().size * disk.transform.localScale;
            disk.SetActive(true);
            disk.AddComponent<ActionManager>();
            disk.GetComponent<ActionManager>().diskFly(disk.GetComponent<Disk>().direction, disk.GetComponent<Disk>().speed);
        }
    }
    /*public int getRound(){
        return sceneCtrl.getRound();
    }
    public int getTotal(){
        return sceneCtrl.getTotal();
    }*/
    public void Init()
    {
        sceneCtrl = new SceneController();//SceneController元素归0
        diskFlyTimes = 0;
        time = 0;
        round = 0;
        diskQueue.Clear();//清空飞盘队列
    }
    public SceneController  getSceneController(){
        return sceneCtrl;
    }
    void Reset()
    {
        this.gameObject.GetComponent<UserGUI>().reset = 1;
    }
}

UserGUI.cs:新增模式选择功能。负责输出提示信息,包括回合数,未击中飞碟数,分数,以及在游戏结束时输出重新开始的按钮。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PriestsAndDevils;
public class UserGUI : MonoBehaviour
{
    /*public int round;//直接在此定义使用时旧的数字不会消失
    public int total;
    public int score;*/
    public int reset;
    GUIStyle style;
    GUIStyle buttonStyle;
   // public ISceneController userAction;直接用可以运行,但是会报错
    // Start is called before the first frame update
    ActionMode mode;
    void Start()
    {
        reset = 0;//不能一开始就设定为1,否则需要按两下按钮才会消失
        style = new GUIStyle();
        style.fontSize = 30;
        //style.alignment = TextAnchor.MiddleCenter;
        style.normal.textColor = Color.green;// 
        buttonStyle = new GUIStyle("button");
        buttonStyle.fontSize = 15;
        buttonStyle.normal.textColor = Color.green;// 
        //userAction = Director.getInstance().currentSceneController;//此处挂载失败
        mode = ActionMode.PHYSICS;
    }
    // Update is called once per frame
    void Update()
    {
    }
    private void OnGUI()
    {
        if(reset == 1){
            /*if(GUI.Button(new Rect(380, 250, 100, 80), "Reset",buttonStyle)){
                //userAction.Init();
                Director.getInstance().currentSceneController.Init();
                reset = 0;
            }*/
           if(GUI.Button(new Rect(200, 250, 100, 80), "KINEMATIC",buttonStyle)){
                mode = ActionMode.KINEMATIC;
                Director.getInstance().currentSceneController.setMode(mode);
                Director.getInstance().currentSceneController.Init();
                reset = 0;
                return;
            }
            if(GUI.Button(new Rect(400, 250, 100, 80), "PHYSICS",buttonStyle)){
                mode = ActionMode.PHYSICS;
                Director.getInstance().currentSceneController.setMode(mode);
                Director.getInstance().currentSceneController.Init();
                reset = 0;
                return;
            } 
           // else mode = ActionMode.PHYSICS;
        }
        if (reset == 0){
            int round = Director.getInstance().currentSceneController.getSceneController().getRound();
            int total = Director.getInstance().currentSceneController.getSceneController().getTotal();
            int score = Director.getInstance().currentSceneController.getSceneController().getScore();
            int miss = total - score;//未击中的飞碟数
            //string text = "Round: " + userAction.getSceneController().GetRound().ToString() + "\nTotal:  " + total.ToString() + "\nScores:  " + score.ToString();
            string text = "Round: " + round.ToString() + "\nMiss:  " + miss.ToString() + "\nScores:  " + score.ToString();
            GUI.Label(new Rect(10, 10, Screen.width, 50),text,style); 
        }     
    }
}

运行

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值