Unity打飞碟游戏

本项目利用Unity的物理引擎,实现了简单的打飞碟游戏,UML图如上。

项目的代码共有五个文件,其中Controller负责管理整个场景以及每一轮的游戏,DiskFactory负责飞碟的生产和回收,Disk存储飞碟数据,BasePoint定义了每种颜色飞碟的基础分,其成员变量ColorPoint可以在Inspector中修改。

本项目实现了每一轮的飞碟数量、大小、各种颜色的出现频率、速度、发射角度都不尽相同,且每一轮飞碟的分数也有所增加。

B站视频:Unity飞碟游戏_哔哩哔哩_bilibili

下面是每一个文件的完整代码和相关解释:

BasePoint.cs

using UnityEngine;

[CreateAssetMenu(fileName = "BasePoint", menuName = "Custom/BasePoint")]
public class BasePoint : ScriptableObject
{
    public enum DiskColor
    {
        Orange,
        Red,
        DeepBlue,
        Black
    }
    void OnEnable()
    {
        if (colorPoints == null || colorPoints.Length == 0)
        {
            colorPoints = new ColorPoint[4];
            colorPoints[0].color = DiskColor.Orange;
            colorPoints[1].color = DiskColor.Red;
            colorPoints[2].color = DiskColor.DeepBlue;
            colorPoints[3].color = DiskColor.Black;

            colorPoints[0].baseColor = new Color(1.0f, 0.5f, 0.0f);
            colorPoints[1].baseColor = Color.red;
            colorPoints[2].baseColor = new Color(0.0f, 0.0f, 0.5f);
            colorPoints[3].baseColor = Color.black;

        }
    }
    [System.Serializable]
    public struct ColorPoint
    {
        public DiskColor color;
        public Color baseColor;
        public int baseScore;
    }

    [SerializeField]
    public ColorPoint[] colorPoints;

    
}

这段代码定义了一个名为BasePointScriptableObjectScriptableObject是Unity中的一个特殊类,用于持久化一些数据,例如配置或设置。在这个例子中,BasePoint就像一个数据表,它存储了关于不同颜色飞碟的一些信息。

首先,这段代码定义了一个名为DiskColor的枚举类型,用于表示飞碟可能的颜色:Orange, Red, DeepBlue, 和 Black。

然后,在OnEnable方法中,如果colorPoints数组为空或长度为0,会为其分配空间并初始化。每个ColorPoint结构体表示一种颜色的飞碟,包括飞碟的颜色、基础颜色值以及基础分数。注意,这段代码中并没有为ColorPointbaseScore赋值,这是在Inspector中完成的。

总结起来,这个BasePoint类就是一个飞碟颜色与其对应属性(包括基础颜色值和基础分数)的映射。这样,你可以在游戏中方便地根据飞碟的颜色获取其相关信息。

Controller.cs

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

public class Controller : MonoBehaviour
{

    DiskFactory factory;
    public BasePoint basePoint;
    List<Disk> LDisk;
    public static int score;
    int round;
    public static bool gameover;
    // the first scripts
    void Awake()
    {
        factory = DiskFactory.Instance;
        factory.Initialize();
        LDisk = new List<Disk>(); // 创建一个空的列表来存储 Disk
    }

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

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

    // Use this for initialization
    void Start()
    {
        ;
    }

    // Update is called once per frame
    void Update()
    {   if(gameover)
        { return;
        }
        if(LDisk.Count == 0)
        {
            //give advice first
            round += 1;
            Debug.Log("Round " + round);
            Ruler r = new Ruler(round);
            int N = r.num();
            for (int i = 0; i < N; i++)
            {
                Disk d = factory.GetDisk(r);
                LDisk.Add(d); // 将得到的 Disk 添加到列表中

                for (int j = 0; j < 4; j++)
                {
                    Debug.Log(d.color);
                    if (d.color == basePoint.colorPoints[j].baseColor)
                    {
                        Rigidbody rb = d.GetComponent<Rigidbody>();
                        Debug.Log("x:" + d.transform.localScale.x);
                        float score = basePoint.colorPoints[j].baseScore + rb.velocity.magnitude + (2 - d.transform.localScale.x) * 10;
                        Debug.Log("Score: " + (int)score);
                        d.setscore((int)score);

                    }
                }
            }
        }
        //give advice first
        for (int i = LDisk.Count - 1; i >= 0; i--)
        {
            Disk disk = LDisk[i];
            if (!disk.gameObject.activeSelf)
            {
                if (disk.goal)
                {
                    score += disk.score; // 将得分加到静态变量 score 上
                    Debug.Log("当前得分:" + score);
                }
                LDisk.RemoveAt(i); // 从列表中移除该 Disk
            }
        }
        if(LDisk.Count == 0 && round == 6)
        {
            gameover = true;
        }
    }
}

这段代码定义了一个名为`Controller`的MonoBehaviour类,它是你的飞碟游戏的主要控制器。这个类在每一轮中管理和追踪飞碟的生成和得分,还决定何时结束游戏。

Awake() 方法:
在`Awake`方法中,控制器初始化了`DiskFactory`实例和一个用来存储`Disk`的列表。

Start() 方法:
在`Start`方法中,没有执行任何代码。

Update() 方法:
`Update`方法是每帧都会调用的方法,用于更新游戏的状态。

1. 首先,如果游戏已经结束(`gameover`为true),则直接返回,不执行任何操作。
2. 如果当前没有活动的飞碟(`LDisk.Count`为0),则进入下一轮,生成一定数量的飞碟,数量由`Ruler`类计算得出。每个飞碟的得分是基于它的颜色、速度和大小的。
3. 接着,对于每一个活动的飞碟,如果它不再活动(可能是飞出屏幕或被击中),则根据是否命中目标来更新总得分,并从活动飞碟的列表中移除。
4. 如果所有轮次都结束并且没有活动的飞碟,游戏结束。

Pause() 和 Resume() 方法:
这两个方法目前还没有实现,但从名字来看,它们应该用于暂停和恢复游戏。

总的来说,这个`Controller`类负责游戏的主要流程,包括飞碟的生成和移除,得分的计算,以及决定何时结束游戏。

Disk.cs

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

public class Disk : MonoBehaviour
{
    public float scale;
    public Color color;
    public int score;
    public bool goal;

    public void Initialize(float scale, Color color)
    {
        this.scale = scale;
        this.color = color;
        score = 0;
        float newscale = scale * 2;
        Debug.Log("newscale:" + newscale);
        transform.localScale = new Vector3(newscale, 0.05f, newscale);

        Renderer renderer = GetComponent<Renderer>();
        renderer.material.color = color;
    }

    public void setscore(int s)
    {
        score = s;
    }
    void Start()
    {
        ;
    }

    // 当对象被鼠标点击时的处理
    void OnMouseDown()
    {
        goal = true;
        // 将对象设为非活动状态
        this.gameObject.SetActive(false);
        
    }

    // 当对象发生碰撞时的处理
    void OnCollisionEnter(Collision collision)
    {
        // 如果碰撞的对象是地面
        if (collision.gameObject.tag == "ground")
        {
            // 启动协程,延迟一段时间后再将对象设为非活动状态
            StartCoroutine(DisableAfterSeconds(1.0f));
        }
    }

    // 协程,延迟一段时间后将对象设为非活动状态
    IEnumerator DisableAfterSeconds(float seconds)
    {
        // 等待指定的秒数
        yield return new WaitForSeconds(seconds);

        // 将对象设为非活动状态
        this.gameObject.SetActive(false);
    }

    private void Update()
    {
        if (transform.position.y < -10) this.gameObject.SetActive(false);
    }
}

这个`Disk`类是一个特定的Unity物体,代表在你的飞碟游戏中的飞碟。

Initialize() 方法:
`Initialize`方法用于设置飞碟的大小和颜色。它接受scale和color作为参数,然后将这些值设置到飞碟的transform和renderer组件上。该方法还将飞碟的分数重置为0。

setscore() 方法:
`setscore`方法接受一个分数作为参数,并将这个分数赋值给飞碟的score。

OnMouseDown() 方法:
`OnMouseDown`方法会在鼠标点击该飞碟时被调用。在被点击时,飞碟会被标记为goal(被击中),并立即被设置为非活动状态(隐藏)。

OnCollisionEnter() 方法:
`OnCollisionEnter`方法在飞碟碰撞到其他物体时被调用。如果飞碟碰撞到的对象标签为"ground",那么它会启动一个协程,在1秒后将飞碟设置为非活动状态。

DisableAfterSeconds() 方法:
`DisableAfterSeconds`是一个协程,它会等待传入的秒数,然后将飞碟设置为非活动状态。

Update() 方法:
在`Update`方法中,如果飞碟的位置低于-10(即飞离了游戏场地),它会立即被设置为非活动状态。

综上,`Disk`类主要负责飞碟的初始化、状态改变(包括被击中和落地后的处理)以及分数设置。

DiskFactory.cs

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

public class Disk : MonoBehaviour
{
    public float scale;
    public Color color;
    public int score;
    public bool goal;

    public void Initialize(float scale, Color color)
    {
        this.scale = scale;
        this.color = color;
        score = 0;
        float newscale = scale * 2;
        Debug.Log("newscale:" + newscale);
        transform.localScale = new Vector3(newscale, 0.05f, newscale);

        Renderer renderer = GetComponent<Renderer>();
        renderer.material.color = color;
    }

    public void setscore(int s)
    {
        score = s;
    }
    void Start()
    {
        ;
    }

    // 当对象被鼠标点击时的处理
    void OnMouseDown()
    {
        goal = true;
        // 将对象设为非活动状态
        this.gameObject.SetActive(false);
        
    }

    // 当对象发生碰撞时的处理
    void OnCollisionEnter(Collision collision)
    {
        // 如果碰撞的对象是地面
        if (collision.gameObject.tag == "ground")
        {
            // 启动协程,延迟一段时间后再将对象设为非活动状态
            StartCoroutine(DisableAfterSeconds(1.0f));
        }
    }

    // 协程,延迟一段时间后将对象设为非活动状态
    IEnumerator DisableAfterSeconds(float seconds)
    {
        // 等待指定的秒数
        yield return new WaitForSeconds(seconds);

        // 将对象设为非活动状态
        this.gameObject.SetActive(false);
    }

    private void Update()
    {
        if (transform.position.y < -10) this.gameObject.SetActive(false);
    }
}

这段代码定义了一个名为DiskFactory的类,它是一个单例工厂类,用于在游戏中创建、回收和管理飞碟(Disk)对象。

Initialize() 方法:
Initialize方法用于初始化freeDiskusedDisk列表,分别用于存储未使用和正在使用的飞碟对象。

FreeDisk() 方法:
FreeDisk方法会检查所有正在使用的飞碟,如果有飞碟不再活动(可能是飞出屏幕或被击中),则将其回收到未使用的飞碟列表中。

Instance 属性:
DiskFactory类使用了单例模式,Instance属性用于获取这个类的唯一实例。

GetRandomLocation() 方法:
GetRandomLocation方法会生成一个随机的飞碟出现位置。

GetRandomColor() 和 GetColorByIndex() 方法:
这两个方法用于生成一个随机颜色,根据Ruler对象中的概率数组决定颜色的生成概率。

GetDisk() 方法:
GetDisk方法是工厂的主要方法,用于生成一个新的飞碟。它首先会尝试回收所有不活动的飞碟,然后生成一个新的飞碟。如果有未使用的飞碟,就直接取出一个进行初始化;如果没有,就创建一个新的飞碟。飞碟的位置、颜色、形状和初速度都是随机生成的,具体的生成规则由传入的Ruler对象决定。

总的来说,DiskFactory类的主要责任是飞碟对象的管理和生成,包括对象的回收和重用,以及新对象的创建。通过这种方式,可以有效地管理游戏中的飞碟对象,避免了频繁的对象创建和销毁,优化了内存和性能。

Ruler.cs

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

public class Disk : MonoBehaviour
{
    public float scale;
    public Color color;
    public int score;
    public bool goal;

    public void Initialize(float scale, Color color)
    {
        this.scale = scale;
        this.color = color;
        score = 0;
        float newscale = scale * 2;
        Debug.Log("newscale:" + newscale);
        transform.localScale = new Vector3(newscale, 0.05f, newscale);

        Renderer renderer = GetComponent<Renderer>();
        renderer.material.color = color;
    }

    public void setscore(int s)
    {
        score = s;
    }
    void Start()
    {
        ;
    }

    // 当对象被鼠标点击时的处理
    void OnMouseDown()
    {
        goal = true;
        // 将对象设为非活动状态
        this.gameObject.SetActive(false);
        
    }

    // 当对象发生碰撞时的处理
    void OnCollisionEnter(Collision collision)
    {
        // 如果碰撞的对象是地面
        if (collision.gameObject.tag == "ground")
        {
            // 启动协程,延迟一段时间后再将对象设为非活动状态
            StartCoroutine(DisableAfterSeconds(1.0f));
        }
    }

    // 协程,延迟一段时间后将对象设为非活动状态
    IEnumerator DisableAfterSeconds(float seconds)
    {
        // 等待指定的秒数
        yield return new WaitForSeconds(seconds);

        // 将对象设为非活动状态
        this.gameObject.SetActive(false);
    }

    private void Update()
    {
        if (transform.position.y < -10) this.gameObject.SetActive(false);
    }
}

Ruler类用于控制每一轮飞碟的相关参数。这些参数包括飞碟的速度范围、发射角度范围、飞碟大小的缩放因子、飞碟的颜色概率,以及当前轮次。

Ruler() 构造函数:
根据当前的游戏轮次round来初始化飞碟的参数。速度v_minv_max会随着轮次增加而增加,使得游戏难度逐渐提升。飞碟大小的缩放因子scale会随着轮次增加而减小,也就是飞碟会变得越来越小。飞碟颜色概率数组probability会随着轮次的增加而调整,颜色的选择变得越来越多。

num() 方法:
num方法用于随机生成一个数值,这个数值的范围在1到5 + round之间。这个方法可能用于决定每轮生成的飞碟数量。

总的来说,Ruler类是一个飞碟参数生成器,它会根据当前的游戏轮次来调整飞碟的各种参数,以此来控制游戏的难度。

UserGUI.cs

using UnityEngine;

public class UserGUI : MonoBehaviour
{
    public GUIStyle textStyle; // 自定义的GUIStyle,用于设置字体颜色

    void OnGUI()
    {
        textStyle.normal.textColor = Color.black; // 将字体颜色设置为黑色
        GUI.Label(new Rect(10, 10, 200, 20), "Score: " + Controller.score, textStyle);

        if (Controller.gameover)
        {
            GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 10, 100, 20), "Game Over", textStyle);
            GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 + 10, 100, 20), "Final Score: " + Controller.score, textStyle);
        }
    }
}

该类实现了提示玩家当前得分,以及显示游戏结束时的总得分的功能。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值