[Unity3D实验作业]使用PhysisAction的打飞碟小游戏

项目源码:

陈辰昊/打飞碟2 - Gitee.com

演示视频:

【Unity3D实验作业】打飞碟小游戏_哔哩哔哩_bilibili

UML图:

游戏简介:

        游戏分为普通模式和无尽模式,普通模式仅有两轮,无尽模式除非玩家主动返回主界面,否则一直进行。

        一轮游戏有多个轮次,一个轮次有多个回合,每个回合会飞出不同种类的飞碟。系统会根据飞碟的大小、颜色、速度的不同进行计分,玩家可以通过点击飞碟来累积积分。

核心代码介绍:

DiskFactory类为对象池,负责对飞碟对象的克隆、配置属性、分发和销毁。

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

public class DiskFactory : MonoBehaviour
{
    public GameObject diskPrefab; 
    private List<DiskData> used; 
    private List<DiskData> free; 

    public void Start()
    {
        diskPrefab = GameObject.Instantiate(Resources.Load<GameObject>("Prefabs/f1"), Vector3.zero, Quaternion.identity);
        diskPrefab.SetActive(false);
        used = new List<DiskData>();
        free = new List<DiskData>();
    }

    public GameObject GetDisk(Ruler ruler)
    {
        GameObject disk;

        int diskNum = free.Count;
        if (diskNum == 0)
        {
            disk = GameObject.Instantiate(diskPrefab, Vector3.zero, Quaternion.identity);
            disk.AddComponent(typeof(DiskData));
        }
        else
        {
            disk = free[diskNum - 1].gameObject;
            free.Remove(free[diskNum - 1]);
        }

        disk.GetComponent<DiskData>().speed = ruler.speed;
        disk.GetComponent<DiskData>().color = ruler.color;
        disk.GetComponent<DiskData>().size = ruler.size;

        if (ruler.color == "red")
        {
            disk.GetComponent<Renderer>().material.color = Color.red;
        }
        else if (ruler.color == "green")
        {
            disk.GetComponent<Renderer>().material.color = Color.green;
        }
        else
        {
            disk.GetComponent<Renderer>().material.color = Color.blue;
        }

        disk.transform.localScale = new Vector3(1.2f, 0.1f * (float)ruler.size, 1.2f);

        disk.transform.position = ruler.beginPos;

        disk.SetActive(true);

        used.Add(disk.GetComponent<DiskData>());

        return disk;
    }

    public void FreeDisk(GameObject disk)
    {
        foreach (DiskData d in used)
        {
            if (d.gameObject.GetInstanceID() == disk.GetInstanceID())
            {
                disk.SetActive(false);
                used.Remove(d);
                free.Add(d);
                break;
            }

        }
    }
}

PhysisPlayDiskAction类负责实现对飞碟对象的物理运动的模拟

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

public class PhysisPlayDiskAction : SSAction
{
    float speed; 
    Vector3 direction; 

    public static PhysisPlayDiskAction GetSSAction(Vector3 direction, float speed)
    {
        PhysisPlayDiskAction action = ScriptableObject.CreateInstance<PhysisPlayDiskAction>();
        action.speed = speed;
        action.direction = direction;
        return action;
    }

    public override void Start()
    {
        gameObject.GetComponent<Rigidbody>().isKinematic = false;
        gameObject.GetComponent<Rigidbody>().velocity = speed * direction;
    }

    public override void Update()
    {
        if (this.transform.position.y < -5)
        {
            this.destroy = true;
            this.enable = false;
            this.callback.SSActionEvent(this);
        }
    }
}

RoundController类负责请求飞碟工厂生成相应的飞碟对象,控制游戏飞碟对象的发射和轮次的进行。

public class RoundController : MonoBehaviour
{
    private IActionManager actionManager; 
    public ScoreRecorder scoreRecorder; 
    private MainController mainController;
    private Ruler ruler;

    void Start()
    {
        actionManager = gameObject.AddComponent<PhysisActionManager>();
        scoreRecorder = new ScoreRecorder();
        mainController = Director.GetInstance().mainController;
        gameObject.AddComponent<DiskFactory>();
        InitRuler();
    }

    void InitRuler()
    {
        ruler.trialNum = 0;
        ruler.roundNum = 0;
        ruler.sendTime = 0;
        ruler.roundDisksNum = new int[10];
        generateRoundDisksNum();
    }

    public void generateRoundDisksNum()
    {
        for (int i = 0; i < 10; ++i)
        {
            ruler.roundDisksNum[i] = Random.Range(0, 4) + 1;
        }
    }

    public void Reset()
    {
        InitRuler();
        scoreRecorder.Reset();
    }

    public void Record(DiskData disk)
    {
        scoreRecorder.Record(disk);
    }

    public int GetScores()
    {
        return scoreRecorder.score;
    }

    public void SetRoundSum(int roundSum)
    {
        ruler.roundSum = roundSum;
    }

    public void LaunchDisk()
    {
        int[] beginPosY = new int[4] { 0, 0, 0, 0 };

        for (int i = 0; i < ruler.roundDisksNum[ruler.trialNum]; ++i)
        {
            int randomNum = Random.Range(0, 3) + 1;
            ruler.speed = randomNum * (ruler.roundNum + 4);

            randomNum = Random.Range(0, 3) + 1;
            if (randomNum == 1)
            {
                ruler.color = "red";
            }
            else if (randomNum == 2)
            {
                ruler.color = "green";
            }
            else
            {
                ruler.color = "blue";
            }

            ruler.size = Random.Range(0, 3) + 1;

            randomNum = Random.Range(0, 2);
            if (randomNum == 1)
            {
                ruler.direction = new Vector3(3, 1, 0);
            }
            else
            {
                ruler.direction = new Vector3(-3, 1, 0);
            }

            do
            {
                randomNum = Random.Range(0, 4);
            } while (beginPosY[randomNum] != 0);
            beginPosY[randomNum] = 1;
            ruler.beginPos = new Vector3(-ruler.direction.x * 4, -0.5f * randomNum, 0);

            GameObject disk = Singleton<DiskFactory>.Instance.GetDisk(ruler);

            actionManager.PlayDisk(disk, ruler.speed, ruler.direction);
        }
    }

    public void FreeFactoryDisk(GameObject disk)
    {
        Singleton<DiskFactory>.Instance.FreeDisk(disk);
    }

    public void FreeAllFactoryDisk()
    {
        GameObject[] obj = FindObjectsOfType(typeof(GameObject)) as GameObject[];
        foreach (GameObject g in obj)
        {
            if (g.gameObject.name == "Disk(Clone)(Clone)")
            {
                Singleton<DiskFactory>.Instance.FreeDisk(g);
            }
        }
    }

    void Update()
    {
        if (mainController.GetGameState() == (int)GameState.Playing)
        {
            ruler.sendTime += Time.deltaTime;
            if (ruler.sendTime > 2)
            {
                ruler.sendTime = 0;
                if (ruler.roundSum == -1 || ruler.roundNum < ruler.roundSum)
                {
                    mainController.SetViewTip("");
                    LaunchDisk();
                    ruler.trialNum++;
                    if (ruler.trialNum == 10)
                    {
                        ruler.trialNum = 0;
                        ruler.roundNum++;
                        generateRoundDisksNum();
                    }
                }
                else
                {
                    mainController.SetViewTip("Click Restart and Play Again!");
                    mainController.SetGameState((int)GameState.GameOver);
                }
                if (ruler.trialNum == 0) mainController.SetViewRoundNum(ruler.roundNum);
                else mainController.SetViewRoundNum(ruler.roundNum + 1);
                mainController.SetViewTrialNum(ruler.trialNum);
            }
        }
    }
}

ScoreRecorder类负责实现对飞碟的计分工作

public class ScoreRecorder
{
    public int score; 

    public ScoreRecorder()
    {
        score = 0;
    }

    public void Record(DiskData disk)
    {
        int diskSize = disk.size;
        switch (diskSize)
        {
            case 1:
                score += 3;
                break;
            case 2:
                score += 2;
                break;
            case 3:
                score += 1;
                break;
            default: break;
        }

        score += disk.speed;

        string diskColor = disk.color;
        if (diskColor.CompareTo("red") == 0)
        {
            score += 1;
        }
        else if (diskColor.CompareTo("green") == 0)
        {
            score += 2;
        }
        else if (diskColor.CompareTo("blue") == 0)
        {
            score += 3;
        }
    }

    public void Reset()
    {
        score = 0;
    }
}

MainController负责控制View、RoundController的显示和运行

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

enum GameState
{
    Ready = 0, Playing = 1, GameOver = 2
};

public class MainController : MonoBehaviour
{
    private RoundController roundController; 
    private View view; 
    private int N = 2; 
    private int gameState;

    void Start()
    {
        Director.GetInstance().mainController = this;
        roundController = gameObject.AddComponent<RoundController>();
        view = gameObject.AddComponent<View>();
        gameState = (int)GameState.Ready;
    }

    public int GetN()
    {
        return N;
    }

    public void Restart()
    {
        view.Init();
        roundController.Reset();
    }

    public void SetGameState(int state)
    {
        gameState = state;
    }

    public int GetGameState()
    {
        return gameState;
    }

    public void ShowPage()
    {
        switch (gameState)
        {
            case 0:
                view.ShowHomePage();
                break;
            case 1:
                view.ShowGamePage();
                break;
            case 2:
                view.ShowRestart();
                break;
        }
    }

    public void SetRoundSum(int roundSum)
    {
        roundController.SetRoundSum(roundSum);
    }

    public void SetViewTip(string tip)
    {
        view.SetTip(tip);
    }

    public void SetViewScore(int score)
    {
        view.SetScore(score);
    }

    public void SetViewRoundNum(int round)
    {
        view.SetRoundNum(round);
    }

    public void SetViewTrialNum(int trial)
    {
        view.SetTrialNum(trial);
    }

    public void Hit(Vector3 position)
    {
        Camera camera = Camera.main;
        Ray ray = camera.ScreenPointToRay(position);

        RaycastHit[] hits;
        hits = Physics.RaycastAll(ray);

        for (int i = 0; i < hits.Length; i++)
        {
            RaycastHit hit = hits[i];
            if (hit.collider.gameObject.GetComponent<DiskData>() != null)
            {
                hit.collider.gameObject.transform.position = new Vector3(0, -6, 0);
                roundController.Record(hit.collider.gameObject.GetComponent<DiskData>());
                view.SetScore(roundController.scoreRecorder.score);
            }
        }
    }

    public void FreeAllFactoryDisk()
    {
        roundController.FreeAllFactoryDisk();
    }
}

View类负责实现游戏界面的显示、互动和跳转

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

public class View : MonoBehaviour
{
    private MainController mainController;
    private int score;
    private string tip;
    private string roundNum;
    private string trialNum;

    void Start()
    {
        //Debug.Log("q-2");
        score = 0;
        tip = "";
        roundNum = "";
        trialNum = "";
        mainController = Director.GetInstance().mainController;
    }

    public void SetTip(string tip)
    {
        this.tip = tip;
    }

    public void SetScore(int score)
    {
        this.score = score;
    }

    public void SetRoundNum(int round)
    {
        roundNum = "回合: " + round;
    }

    public void SetTrialNum(int trial)
    {
        if (trial == 0) trial = 10;
        trialNum = "Trial: " + trial;
    }

    public void Init()
    {
        score = 0;
        tip = "";
        roundNum = "";
        trialNum = "";
    }

    public void AddTitle()
    {
        GUIStyle titleStyle = new GUIStyle();
        titleStyle.normal.textColor = Color.black;
        titleStyle.fontSize = 50;

        GUI.Label(new Rect(Screen.width / 2 - 80, 20, 60, 100), "Playing Disks", titleStyle);
    }

    public void AddChooseModeButton()
    {
        if (GUI.Button(new Rect(Screen.width / 2 - 80, 200, 160, 80), "Normal\n(默认为" + mainController.GetN() + "回合)"))
        {
            mainController.SetRoundSum(mainController.GetN());
            mainController.Restart();
            mainController.SetGameState((int)GameState.Playing);
        }
        if (GUI.Button(new Rect(Screen.width / 2 - 80, 350, 160, 80), "NoEnding\n(回合数无限)"))
        {
            mainController.SetRoundSum(-1);
            mainController.Restart();
            mainController.SetGameState((int)GameState.Playing);
        }
    }

    public void ShowHomePage()
    {
        //Debug.Log("q1");
        AddChooseModeButton();
    }

    public void AddBackButton()
    {
        //GUI.skin = gameSkin;
        if (GUI.Button(new Rect(10, 10, 60, 40), "Return"))
        {
            mainController.FreeAllFactoryDisk();
            mainController.Restart();
            mainController.SetGameState((int)GameState.Ready);
        }
    }

    public void AddGameLabel()
    {
        GUIStyle labelStyle = new GUIStyle();
        labelStyle.normal.textColor = Color.black;
        labelStyle.fontSize = 30;

        GUI.Label(new Rect(Screen.width - 120, 10, 100, 50), "得分: " + score, labelStyle);
        GUI.Label(new Rect(Screen.width / 2 - 140, 200, 50, 200), tip, labelStyle);
        GUI.Label(new Rect(Screen.width - 120, 60, 100, 50), roundNum, labelStyle);
        GUI.Label(new Rect(Screen.width - 120, 110, 100, 50), trialNum, labelStyle);
    }

    public void AddRestartButton()
    {
        if (GUI.Button(new Rect(Screen.width / 2 , 350, 100, 60), "Restart"))
        {
            mainController.FreeAllFactoryDisk();
            mainController.Restart();
            mainController.SetGameState((int)GameState.Playing);
        }
    }

    public void ShowGamePage()
    {
        //Debug.Log("q2");
        AddGameLabel();
        AddBackButton();
        if (Input.GetButtonDown("Fire1"))
        {
            mainController.Hit(Input.mousePosition);
        }
    }

    public void ShowRestart()
    {
        //Debug.Log("q3");
        ShowGamePage();
        AddRestartButton();
    }

    void OnGUI()
    {
        AddTitle();
        //Debug.Log("q-1");
        //if(mainController==null) Debug.Log("error");
        mainController.ShowPage();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值