Unity3D飞碟

题目

编写一个简单的鼠标打飞碟(Hit UFO)游戏
游戏内容要求:
游戏有 n 个 round,每个 round 都包括10 次 trial;
每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
每个 trial 的飞碟有随机性,总体难度随 round 上升;
鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。

游戏规则

一共有3个回合,每个回合有30个飞盘。飞盘的大小、颜色和移动速度会随着回合而变化,整体难度增加。击中每个飞盘得一分,每回合得够20分,才能进入下个回合。如果不够则游戏失败。在30个飞盘出现前,如果没有击中15个则也游戏失败。游戏失败后可以重新开始游戏。

程序组件

代码文件

1

预制文件

2

程序代码

SSDirector
导演类,负责控制、协调整个游戏的运行。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum State
{
    win, fail, start, still,wait
}

public class SSDirector : System.Object

{
    private static SSDirector _instance;
    public State state { get; set; }
    public ISceneController currentScenceController { get; set; }
    public bool running { get; set; }

    public static SSDirector getInstance()
    {
        if (_instance == null)
        {
            _instance = new SSDirector();
        }
        return _instance;
    }

    public int getFPS()
    {
        return Application.targetFrameRate;
    }

    public void setFPS(int fps)
    {
        Application.targetFrameRate = fps;
    }
}

SceneController
场景控制,负责游戏场景和对象的加载以及游戏规则的实行.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public interface ISceneController
{
    void LoadResources();
}

public class SceneController : MonoBehaviour, ISceneController, IUserAction
{
    public SSActionManager actionManager { get; set; }
    public int round = 0;//轮数
    public int score = 0;//分数
    public Text Score;
    public Text Round;
    public Text Text;
    public Text Lost;
    public int num = 0;
    public int lost = 0;
 
    GameObject explosion;
    GameObject plane;

    public void LoadResources()
    {
        explosion = Instantiate(Resources.Load("prefabs/Explosion"), new Vector3(0, 0, -20), Quaternion.identity) as GameObject;
        plane = Instantiate(Resources.Load("prefabs/Plane"), new Vector3(0, 0, 2), Quaternion.identity) as GameObject;
    }
    void Awake()
    //创建导演实例并载入资源
    {
        SSDirector director = SSDirector.getInstance();
        director.state = State.wait;
        DiskFactory DF = DiskFactory.getInstance();
        DF.sceneControler = this;
        director.currentScenceController = this;
        director.currentScenceController.LoadResources();
        director.setFPS(60);
    }
    void Start()
    {
        round = 1;
    }

    // Update is called once per frame
    void Update()
    {
        lost = num - score;
        Score.text = "Score:" + score.ToString();
        Round.text = "Round:" + round.ToString();
        Lost.text = "Lost:" + lost.ToString();
        if (Input.GetMouseButtonDown(0) && SSDirector.getInstance().state == State.start)
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                if (hit.transform.tag == "Disk")
                {
                    explosion.transform.position = hit.collider.gameObject.transform.position;
                    explosion.GetComponent<Renderer>().material = hit.collider.gameObject.GetComponent<Renderer>().material;
                    explosion.GetComponent<ParticleSystem>().Play();
                    hit.collider.gameObject.SetActive(false);
                    score += 1;
                }
            }
        }
        if (SSDirector.getInstance().state == State.fail)
        {
            Text.text = "Game Over!";
            SSDirector.getInstance().state = State.fail;
        }
        if (SSDirector.getInstance().state == State.win)
        {
            Text.text = "You Win!";
            SSDirector.getInstance().state = State.wait;
        }
    }
   
    public void StartGame()
    {
        num = 0;
        if (SSDirector.getInstance().state == State.wait)
        {
            SSDirector.getInstance().state = State.start;//进入倒计时状态
    
        }
    }
    public void ReStart()
    {
        if (SSDirector.getInstance().state == State.fail) {
            SSDirector.getInstance().state = State.wait;
            SceneManager.LoadScene("task1");
            Awake();
            Start();
        }
            
    }

}

SSAction
动作基类,模板

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SSAction : ScriptableObject
{
    public bool enable = true;
    public bool destroy = false;

    public GameObject gameobject { get; set; }
    public Transform transform { get; set; }

    protected SSAction() { }

    public virtual void Start()
    {
        throw new System.NotImplementedException();
    }

    public virtual void Update()
    {
        throw new System.NotImplementedException();
    }
}

Move
飞盘移动的类,控制飞盘的动作

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move : SSAction
{
    public SceneController sceneControler = (SceneController)SSDirector.getInstance().currentScenceController;
    public GameObject end;   //要到达的目标  
    public float speed;    //速度  
    float startX;
    float endX;
    private float distanceToEnd;   
    
 

    public override void Start()
    {
        speed = 5 + sceneControler.round * 3;//速度随轮数变化
        startX = 5 - Random.value * 10;//在(-5,5)随机发射
        if (Random.value > 0.5)//使其对角发射
        {
         endX = 30;
        }
        else
        {
         endX = -30;
        }
        this.transform.position = new Vector3(startX, 0, -5);
        end = new GameObject();
        end.transform.position = new Vector3 (endX, -5, 30);
        //计算两者之间的距离  
        distanceToEnd = Vector3.Distance(this.transform.position, end.transform.position);
    }
    public static Move GetSSAction()
    {
        Move action = ScriptableObject.CreateInstance<Move>();
        return action;
    }
    public override void Update()
    {
        Vector3 endPos = end.transform.position;
        gameobject.transform.LookAt (endPos);

        //计算弧线中的夹角 
        float angle = Mathf.Min(1, Vector3.Distance(gameobject.transform.position, endPos) / distanceToEnd) * 45;
        gameobject.transform.rotation = gameobject.transform.rotation * Quaternion.Euler(Mathf.Clamp(-angle, -42, 42), 0, 0);
        float currentDist = Vector3.Distance(gameobject.transform.position, end.transform.position);
        gameobject.transform.Translate(Vector3.forward * Mathf.Min(speed * Time.deltaTime, currentDist));
        if (this.transform.position == end.transform.position)
        {
            DiskFactory.getInstance().cacheDisk(gameobject);
            Destroy (end);
            this.enable = false;
            this.destroy = true;
        }
    }
}

CCActionManager
动作管理基类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CCActionManager : SSActionManager
{
    public SceneController sceneController;
    public DiskFactory diskFactory;
    public Move DiskMove;
    int count = 0;
    protected void Start()
    {
        sceneController = (SceneController)SSDirector.getInstance().currentScenceController;
        diskFactory = DiskFactory.getInstance();
        sceneController.actionManager = this;
    }

    // Update is called once per frame
    protected new void Update()
    {
        if (sceneController.round <= 3 && SSDirector.getInstance().state == State.start)
        {
            count++;
            if (count == 60)
            {
                DiskMove = Move.GetSSAction();
                this.RunAction(diskFactory.getDisk(sceneController.round), DiskMove);
                sceneController.num++;
                count = 0;
            }
            base.Update();
        }
    }
}

SSActionManager
动作管理基类,创建 管理一个动作集合,动作做完自动回收动作

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SSActionManager : MonoBehaviour
{
    private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();
    private List<SSAction> waitingAdd = new List<SSAction>();
    private List<int> waitingDelete = new List<int>();

    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    protected void Update()
    {
        foreach (SSAction ac in waitingAdd)
        {
            actions[ac.GetInstanceID()] = ac;
        }
        waitingAdd.Clear();

        foreach (KeyValuePair<int, SSAction> kv in actions)
        {
            SSAction ac = kv.Value;
            if (ac.destroy)
            {
                waitingDelete.Add(ac.GetInstanceID());
            }
            else if (ac.enable)
            {
                ac.Update();
            }
        }

        foreach (int key in waitingDelete)
        {
            SSAction ac = actions[key];
            actions.Remove(key);
            DestroyObject(ac);
        }
        waitingDelete.Clear();
    }

    public void RunAction(GameObject gameobject, SSAction action)
    {
        action.gameobject = gameobject;
        action.transform = gameobject.transform;
        waitingAdd.Add(action);
        action.Start();
    }
}

Singleton
单例模式模板

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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;
        }
    }
}

DiskFactory
工厂类,控制飞盘的创建与销毁

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class DiskFactory : System.Object
{
    private static DiskFactory _instance;
    public SceneController sceneControler { get; set; }
    public List<GameObject> used;
    public List<GameObject> cache;
    // Use this for initialization

    public static DiskFactory getInstance()
    {
        if (_instance == null)
        {
            _instance = new DiskFactory();
            _instance.used = new List<GameObject>();
            _instance.cache = new List<GameObject>();
        }
        return _instance;
    }

    public GameObject getDisk(int round)
    {
        if ( sceneControler.score == round * 20)
        //每轮总共发射30个,如果得分达到一定要求进入下一轮,否则GameOver
        {
            sceneControler.round++;
            sceneControler.lost = 0;
        }
        else if (sceneControler.lost == 15)
        {
            SSDirector.getInstance().state = State.fail;//游戏结束
        }
        if(sceneControler.round == 4)
        {
            SSDirector.getInstance().state = State.win;
        }
        GameObject newDisk;
        if (cache.Count == 0)
        {
            newDisk = GameObject.Instantiate(Resources.Load("prefabs/Disk"),new Vector3(0,0,-10), Quaternion.identity) as GameObject;
        }
        else
        {
            newDisk = cache[0];
            cache.Remove(cache[0]);
        }
        switch (round)
        {
            case 1:
                float size1 = 1.0f;
                newDisk.transform.localScale = new Vector3(size1, size1/3, size1);
                newDisk.GetComponent<Renderer>().material.color = Color.blue;
                break;
            case 2:
                float size2 = 0.8f;
                newDisk.transform.localScale = new Vector3(size2, size2/3, size2);
                newDisk.GetComponent<Renderer>().material.color = Color.yellow;
                break;
            case 3:
                float size3 = 0.6f;
                newDisk.transform.localScale = new Vector3(size3, size3/3, size3);
                newDisk.GetComponent<Renderer>().material.color = Color.black;
                break;
        }
        used.Add(newDisk);
        return newDisk;
    }

    public void cacheDisk(GameObject disk1)
    {
        for (int i = 0; i < used.Count; i++)
        {
            if (used[i] == disk1)
            {
                used.Remove(disk1);
                disk1.SetActive(true);
                cache.Add(disk1);
            }
        }
    }
}

UserGUI
用户界面,与用户交互

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public interface IUserAction
{
    void StartGame();
    void ReStart();
}

public class UserGUI : MonoBehaviour
{
    private IUserAction action;
    // Use this for initialization
    void Start()
    {
        action = SSDirector.getInstance().currentScenceController as IUserAction;
    }
    void OnGUI()
    {
        GUIStyle fontstyle1 = new GUIStyle();
        fontstyle1.fontSize = 50;
        fontstyle1.normal.textColor = new Color(255, 255, 255);
        if (SSDirector.getInstance().state == State.wait)
        {
            if (GUI.Button(new Rect(0, 20, 120, 40), "开始游戏"))
            {
                action.StartGame();
            }
        }
        if (SSDirector.getInstance().state == State.fail)
            {    
            if (GUI.Button(new Rect(0, 20, 120, 40), "重新开始"))
            {
                action.ReStart();
            }
        }
        
    }
    // Update is called once per frame
    void Update()
    {
        //
    }
}

游戏演示

演示视频

以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值