3D游戏编程与设计作业5——简易打飞碟游戏

2023-11-04

一、 作业要求

        1. 编写一个简单的自定义 Component

                 用自定义组件定义几种飞碟,做成预制

        2. 编写一个简单的鼠标打飞碟游戏

内容要求: 

• 游戏有多个轮次,每个轮次都包括10个轨迹;

• 每个轨迹的飞碟的色彩、大小、发射位置、速度、角度、同时出现的 个数都可能不同。它们由该轮次的 ruler 控制;

• 每个轨迹的飞碟有随机性,总体难度随轮次上升;

• 鼠标点中得分,计分规则按色彩、大小、速度不同计算,可自由设定

设计要求:

• 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类

• 尽可能使用前面 MVC 结构实现人机交互与游戏模型分离

二、设计思路

        本次采用了MVC结构,主要设计有DiskAction, DiskController和UserGUI三个类分别承担结构中model, controller和viewer的功能,另外还有类DiskFactory与Singleton用于使用带缓存的工厂模式管理不同飞碟的生产与回收。

三、具体代码

  DickAction类

// 飞碟动作类
// 飞碟可以从视图边界的任意处飞入,沿直线运行直至飞出
// 飞碟具有水平方向速度与垂直方向速度
public class DiskAction : MonoBehaviour
{
    public float speedX=1;
    public float speedY=1;
    public int score=2;
    static DiskFactory fc = Singleton.GetInstance();

    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        // 飞碟超出边界,销毁
        if (this.transform.position.x>100||this.transform.position.x<-100 || this.transform.gameObject.active==false){
            fc.FreeDisk(this.transform.gameObject);
            return;
        }
        // 飞碟的移动
        transform.position += new Vector3(speedX, speedY, 0) * Time.deltaTime * 2;
    }
}

DiskController类

public class DiskController : MonoBehaviour
{
    static public int isRun = 0; //标识游戏是否运行
    private int diskNum = 0; //目前场景上的飞碟数量
    private int round = 1;
    private int max_round = 3; //最大关卡等级
    private float timer = 0.5f;
    private float roundTime = 30f;

    public UserGUI userGUI;
    DiskFactory fc = Singleton.GetInstance();

    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        if(isRun==0 || isOver())
            return;
        GetHit();
        roundTime -= Time.deltaTime;
        timer -= Time.deltaTime;
        if (timer <= 0) {
            //从工厂中得到round个飞碟
            for (int i = 0; i < round; ++i) {
                GameObject disk;
                disk = fc.GetDisk(round);
            }
            timer = 0.5f;
        }
        if (roundTime<=0){
            round += 1;
            userGUI.setRound (round);
        }
    }

    public void GetHit() {
            if (Input.GetButtonDown("Fire1")) {
                Camera ca = Camera.main;
                Ray ray = ca.ScreenPointToRay(Input.mousePosition);

                //Return the ray's hit
                RaycastHit hit;
                if (Physics.Raycast(ray, out hit)) {
                    userGUI.setScore( userGUI.getScore() + hit.transform.gameObject.GetComponent<DiskAction>().score);
                    hit.transform.gameObject.SetActive(false);
                }
            }
        }
    
    public bool isOver() 
    {
        if (round > max_round){
            userGUI.setGameMessage("Game Over!");
            isRun = 2;
            return true;
        }
        return false;
            
    }
}

UserGUI类

public class UserGUI : MonoBehaviour
{
    public int round;
    string gameMessage;
    int score;
    public GUIStyle bigStyle, smallStyle;
    public Font pixelFont;
    private int menu_width = Screen.width / 5, menu_height = Screen.width / 10;//主菜单每一个按键的宽度和高度
    // Start is called before the first frame update
    void Start()
    {
        gameMessage = "";

        //大字体初始化
        bigStyle = new GUIStyle();
        bigStyle.normal.textColor = Color.white;
        bigStyle.normal.background = null;
        bigStyle.fontSize = 50;
        bigStyle.alignment=TextAnchor.MiddleCenter;

        //小字体初始化
        smallStyle = new GUIStyle();
        smallStyle.normal.textColor = Color.white;
        smallStyle.normal.background = null;
        smallStyle.fontSize = 20;
        smallStyle.alignment=TextAnchor.MiddleCenter;
    }

    // Update is called once per frame
    void OnGUI()
    {
        if(DiskController.isRun==0)
            mainMenu();
        else
            GameStart();
    }

    void mainMenu() {
        GUI.Label(new Rect(Screen.width / 2 - menu_width * 0.5f, Screen.height * 0.1f, menu_width, menu_height), "Hit Disks", bigStyle);
        bool button = GUI.Button(new Rect(Screen.width / 2 - menu_width * 0.5f, Screen.height * 3 / 7, menu_width, menu_height), "Start");
        if (button) {
            DiskController.isRun = 1;
        }
    }

    void GameStart() {
        GUI.Label(new Rect(300, 60, 50, 200), gameMessage, bigStyle);
        GUI.Label(new Rect(0,0,100,50), "Score: " + score, smallStyle);
        GUI.Label(new Rect(560,0,100,50), "Round: " + round, smallStyle);
    }

    public void setGameMessage(string m){ gameMessage =m; }
    public void setScore(int s){ score = s; }
    public void setRound(int r){ round = r; }

    public int getScore(){return score;}
}

DiskFactory类

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

// 飞碟工厂类
public class DiskFactory : MonoBehaviour
{
    List<GameObject> used = new List<GameObject>();
    List<GameObject> free = new List<GameObject>();
    System.Random rand= new System.Random(100);

    // Start is called before the first frame update
    void Start()
    {
    }

   
    public GameObject GetDisk(int round) {
        GameObject disk ;
        if (free.Count > 1) {
            disk = free[0];
            free.Remove(disk);
        }
        else{
            if (rand.Next(0,10)<8){
                disk =Instantiate(Resources.Load("Prefabs/blueDisk")) as GameObject;
                disk.AddComponent<DiskAction>();
            }
            else{
                disk = Instantiate(Resources.Load("Prefabs/yellowDisk")) as GameObject;
                disk.AddComponent<DiskAction>();
                disk.GetComponent<DiskAction>().score=5;
            } 
        }
        
        //根据不同round设置飞碟速度
        disk.GetComponent<DiskAction>().speedX *= round;
        disk.GetComponent<DiskAction>().speedY *= round;
        
        //飞碟可从四个方向飞入(左上、左下、右上、右下)
        int direction = rand.Next(1,5);

        if (direction == 1) {
            disk.transform.Translate(new Vector3(5,0,-5));
            disk.GetComponent<DiskAction>().speedY *= -1;
        }
        else if (direction == 2) {
            disk.transform.Translate(new Vector3(-5,0,-5));
            
        }
        else if (direction == 3) {
            disk.transform.Translate(new Vector3(5,0,5));
            disk.GetComponent<DiskAction>().speedX *= -1;
            disk.GetComponent<DiskAction>().speedY *= -1;
        }
        else if (direction == 4) {
            disk.transform.Translate(new Vector3(-5,0,5));
            disk.GetComponent<DiskAction>().speedX *= -1;
        }
        used.Add(disk);
        disk.SetActive(true);
        Debug.Log("generate disk");
        return disk;
    }

    public void FreeDisk(GameObject disk) {
        disk.SetActive(false);
        //将位置速度恢复到预制,这点很重要!
        disk.transform.position = new Vector3(0, 0,0);
        disk.GetComponent<DiskAction>().speedX=2;
        disk.GetComponent<DiskAction>().speedY=2;
        Debug.Log("free disk");
        used.Remove(disk);
        free.Add(disk);
    }
}

Singleton类

public class Singleton
{
    private static DiskFactory _instance = null;

    private Singleton()
    {
    }

    public static DiskFactory GetInstance()
    {
        if (_instance == null)
        {
            _instance = new DiskFactory();
        }
        return _instance;
    }
}

四、运行结果

打飞碟

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

3D游戏编程与设计作业5——简易打飞碟游戏 的相关文章

随机推荐