3D unity小游戏:打飞碟

目录

前言

一、游戏设计

1.资产目录:

2.类的UML设计图

3.部分技术解释

1.对象池技术。

2.刚体(Rigidbody)

二、具体代码

1.)Models

1.DiskData.cs

2.DiskFactory.cs

2.)Controllers/ActionPack

1.SSAction.cs

2.ISSActionCallback.cs

3.SSActionManager.cs

4.IActionManager.cs

3.)Controllers/ActionManager

1.PhysicAction.cs

2.PActionManager.cs

3.KinematicFlyAction.cs

4.KActionManager.cs

4.)Controllers/GameControl

1.SSDirector.cs

2.Singleton.cs

3.ISceneController.cs

4.ScoreRecorder.cs

5.RoundController.cs

5.)Views

1.IUserAction

2.UserGUI.cs

总结


前言

设计要求:

开始前的准备:

准备好预制件“UFO”,具体做法是在场景新建3D模型圆柱体,调整其三维比例后拖拽至项目Assets内。


一、游戏设计

1.资产目录MVC结构:

/Controller
            /ActionManager // 动作和动作管理器模块
                KActionManager.cs // 动力学运动管理器
                PActionManager.cs // 物理运动管理器
                KinematicFlyAction.cs // 动力学运动实现
                PhysisAction.cs // 物理运动实现

            /ActionPack //动作接口、模版、抽象类
                IActionManager.cs // 动作管理器接口
                ISSActionCallback.cs // 回调接口
                SSAction.cs // 抽象动作
                SSActionManager.cs // 动作管理器模板

            /GameControl //游戏控制
                ISceneController.cs
                Singleton.cs
                SSDirector.cs
                RoundController.cs
                ScoreRecorder.cs

/Model
            /Disk //飞碟模型
                DiskData.cs // 飞碟基本数据
                DiskFactory.cs // 工厂模式产生飞碟 

/View //交互模型
            IUserAction.cs
            UserGUI.cs

2.类的UML设计图

3.难度设置

根据回合数动态调整速度和其他属性

4.分数记录功能分离解释

将分数记录器 (ScoreRecorder) 从主控制器 (RoundController) 中分离出来是一个设计上的重要决策,主要是为了增强代码的可维护性、可扩展性和关注点分离

主控制器 RoundController 负责游戏的整体逻辑,如回合控制、生成飞碟等。如果它同时管理分数计算,将导致它承担过多的职责,代码复杂且难以维护。将分数记录的功能提取到一个独立的类 ScoreRecorder 中,使得每个类只专注于其核心职责,提高了代码的模块化和可读性。

当需要调整或者改变分数逻辑时,只需调整 ScoreRecorderRoundController 仍然保持不变。这种解耦使得系统更加灵活。

5.部分技术解释

1.对象池技术。

对象池技术是一种用于管理和复用对象的编程技术,特别适用于那些生命周期短、创建和销毁频繁的对象(如子弹、飞碟等游戏元素)。对象池通过事先创建一组对象并存储在“池”中,当需要时从池中获取对象而不是重新创建,使用后再将对象归还到池中。

飞碟工厂使用对象池技术管理飞碟对象,通过以下步骤提高性能:对象池初始化,创建飞碟,回收飞碟。

最后达到性能优化的目的:对象池避免频繁创建和销毁对象,减少内存开销和性能消耗,特别适用于频繁使用的对象(如飞碟)。

2.刚体(Rigidbody)

在 Unity 中,刚体(Rigidbody) 是一个物理组件,用于让游戏对象受物理引擎的控制。添加刚体组件后,对象会受到重力、碰撞和物理力的影响,能够模拟真实的物理运动效果。刚体通常用于需要动态运动的对象,如角色、车辆、抛射物等。

它的核心属性是Is Kinematic:如果设置为 true,刚体不受物理引擎控制,主要用于需要手动控制位置和旋转的对象。

设置属性:

gameobject.GetComponent<Rigidbody>().isKinematic = true;

二、具体代码

1.)Models

1.DiskData.cs

DiskData 是一个用于表示飞碟数据的类。它包含了飞碟的主要属性,如大小、水平速度、垂直速度、颜色、位置、飞行方向和分数。这个类提供了一个构造函数,可以在创建飞碟对象时初始化这些属性。此外,UpdateSpeed 方法可以用于更新飞碟的水平和垂直速度。

using UnityEngine;

namespace Model.Disk
{
    public class DiskData : MonoBehaviour
    {
        public float Size { get; set; }          // 飞碟的大小
        public float HorizontalSpeed { get; set; } // 水平速度
        public float VerticalSpeed { get; set; }   // 垂直速度
        public Color Color { get; set; }         // 飞碟的颜色
        public Vector3 Position { get; set; }    // 飞碟的初始位置
        public Vector3 Direction { get; set; }   // 飞碟的运动方向
        public int Score { get; set; }           // 飞碟的分数

        // 构造函数
        public DiskData(float size, float horizontalSpeed, float verticalSpeed, Color color, Vector3 position, Vector3 direction, int score)
        {
            Size = size;
            HorizontalSpeed = horizontalSpeed;
            VerticalSpeed = verticalSpeed;
            Color = color;
            Position = position;
            Direction = direction;
            Score = score;
        }

        // 可以通过这个方法更新飞碟的速度
        public void UpdateSpeed(float horizontalSpeed, float verticalSpeed)
        {
            HorizontalSpeed = horizontalSpeed;
            VerticalSpeed = verticalSpeed;
        }
    }
}

2.DiskFactory.cs

DiskFactory 是一个管理飞碟对象的类。它创建飞碟并设置属性,包括大小、速度、颜色和初始位置。CreateDisk 方法用于获取并初始化一个飞碟实例,而 RecycleDisk方法用于回收飞碟,使其可以被重复使用。

using UnityEngine;
using System.Collections.Generic;
using UnityEditor.SceneManagement;
using Unity.VisualScripting.FullSerializer;

namespace Model.Disk
{
    public class DiskFactory : MonoBehaviour
    {
        public GameObject ufoPrefab;
        private Queue<GameObject> availableUFOs;
        private List<GameObject> activeUFOs;



        private void Start()
        {
            availableUFOs = new Queue<GameObject>();
            activeUFOs = new List<GameObject>();
        }

        public GameObject CreateDisk(int round)
        {
            GameObject ufo = GetOrCreateUFO(); // 获取或创建一个 UFO
            InitializeUFO(ufo, round);         // 初始化 UFO 的属性
            activeUFOs.Add(ufo);               // 添加到活跃 UFO 列表
            return ufo;
        }

        /// <summary>
        /// 从可用队列中获取 UFO,如果没有则创建新的 UFO。
        /// </summary>
        private GameObject GetOrCreateUFO()
        {
            if (availableUFOs.Count > 0)
            {
                var ufo = availableUFOs.Dequeue();
                ufo.SetActive(true);
                return ufo;
            }

            // 创建新 UFO
            GameObject newUFO = Instantiate(Resources.Load("Prefabs/UFO", typeof(GameObject))) as GameObject;
            newUFO.AddComponent<DiskData>();
            newUFO.AddComponent<Rigidbody>();
            return newUFO;
        }

        /// <summary>
        /// 初始化 UFO 的属性。
        /// </summary>
        /// <param name="ufo">需要初始化的 UFO</param>
        /// <param name="round">当前的回合数</param>
        private void InitializeUFO(GameObject ufo, int round)
        {
            var ufoData = ufo.GetComponent<DiskData>();
            SetDiskData(ufoData, round); // 设置 UFO 的数据

            // 设置外观和位置
            ufo.transform.localScale = new Vector3(1f, 0.05f, 1f);
            ufo.GetComponent<Renderer>().material.color = ufoData.Color;
            ufo.transform.position = ufoData.Position;

            // 设置随机旋转角度
            var randomRotation = new System.Random();
            ufo.transform.localEulerAngles = new Vector3(-randomRotation.Next(-40, 40), 0, 0);

            // 设置物理组件和速度
            Rigidbody rigidbody = ufo.GetComponent<Rigidbody>() ?? ufo.AddComponent<Rigidbody>();
            Vector3 movementVelocity = new Vector3(ufoData.HorizontalSpeed, ufoData.VerticalSpeed, 0);
            rigidbody.velocity = movementVelocity;
        }


        private void SetDiskData(DiskData diskData, int round)
        {

            diskData.Size = Random.Range(0.5f * round, 2.0f * round);
            diskData.HorizontalSpeed = Random.Range(5f, 25f * round);
            diskData.VerticalSpeed = Random.Range(0f, 25f * round);
            diskData.Score = round * 10;
            diskData.Color = Random.ColorHSV();

            diskData.Position = new Vector3(-10f, Camera.main.pixelHeight * 0f + 1f, 0);             // 左侧偏移

            diskData.Direction = new Vector3(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f)).normalized;
        }

        public void RecycleDisk(GameObject ufo)
        {
            ufo.SetActive(false);
            ufo.transform.position = Vector3.zero;
            ufo.transform.localScale = new Vector3(1f, 0.05f, 1f);
            activeUFOs.Remove(ufo);
            availableUFOs.Enqueue(ufo);
        }
    }
}

2.)Controllers/ActionPack

1.SSAction.cs

SSAction 类是动作基类,用于定义游戏对象的行为。它继承自 ScriptableObject,支持多种行为扩展,包含 Start()Update() 方法,允许在子类中定义自定义的行为逻辑。

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; }
    public ISSActionCallback callback { get; set; }

    protected SSAction() { }

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

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

}

2.ISSActionCallback.cs

ISSActionCallback 是一个回调接口,用于在动作完成或状态变化时通知外部。

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

public enum SSActionEventType:int { Started, Completed }

public interface ISSActionCallback
{
	void SSActionEvent(SSAction source, 
		SSActionEventType events = SSActionEventType.Completed,
		int intParam = 0 , 
		string strParam = null, 
		Object objectParam = null);
}


3.SSActionManager.cs

SSActionManager 类用于管理和执行游戏中的动作。它负责添加、更新和删除动作,确保动作按顺序执行。通过该管理器,可以控制不同游戏对象的行为(如飞碟的运动)并在需要时销毁不再使用的动作。

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

public class SSActionManager : MonoBehaviour {

	public Dictionary <int, SSAction> actions = new Dictionary <int, SSAction> ();
    public List <SSAction> waitingAdd = new List<SSAction> ();
    public List<int> waitingDelete = new List<int> ();

    // Update is called once per frame
    public virtual void Moving(GameObject disk) { }
    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()); // release action
			} else if (ac.enable) { 
				ac.Update (); // update action
			}
		}

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

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


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

4.IActionManager.cs

IActionManager用于提供简单的接口给控制器调用,以方便控制飞碟行为(主要是飞行和计算其数量并返回)

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

public interface IActionManager
{

    void Flying(GameObject disk);

    int UFOCount();
}

3.)Controllers/ActionManager

1.PhysicAction.cs

这个类继承了动作基类,用于控制一个物体(飞碟)在物理世界中的行为,并且具有刚体属性(也就是重力和加速度)。

using UnityEngine;

public class PhysicAction : SSAction
{
    public float horizontalSpeed; // 初始水平速度

    public static PhysicAction GetAction(float speed)
    {
        PhysicAction action = ScriptableObject.CreateInstance<PhysicAction>();
        action.horizontalSpeed = speed;
        return action;
    }

    public override void Start()
    {
        Rigidbody rigidbody = gameobject.GetComponent<Rigidbody>();
        rigidbody.isKinematic = false;
        rigidbody.useGravity = true;
        rigidbody.velocity = new Vector3(horizontalSpeed * 5, 0, 0);
    }

    public override void Update()
    {
        if (!this.transform.gameObject.activeSelf)
        {
            this.destroy = true;
            this.callback.SSActionEvent(this);
            return;
        }

        // 判断物体是否超出屏幕视口
        if (IsOutOfViewport())
        {
            this.destroy = true;
            this.callback?.SSActionEvent(this, SSActionEventType.Completed);
        }
    }

    // 检查物体是否离开屏幕视口
    private bool IsOutOfViewport()
    {
        Vector3 screenPoint = Camera.main.WorldToViewportPoint(this.transform.position);
        return screenPoint.x < -0.1f || screenPoint.x > 1.1f || screenPoint.y < -0.1f || screenPoint.y > 1.1f;
    }
}

2.PActionManager.cs

物理刚体动作的管理器,PActionManager继承自 SSActionManager,实现了 ISSActionCallbackIActionManager 接口。它主要负责管理与物理相关的动作,如控制飞碟的运动,并在飞碟生命周期结束时回收它。它的方法Start()在初始化时,从 SSDirector 获取当前场景控制器(RoundController),并设置为 actionManager。还实例化了 DiskFactory,以调用其的回收飞碟的方法。

using Controller.Round;
using Model.Disk;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhysicActionManager : SSActionManager, ISSActionCallback, IActionManager
{
    public RoundController sceneController;
    public PhysicAction action;
    public DiskFactory factory;

    protected new void Start()
    {
        sceneController = (RoundController)SSDirector.getInstance().currentSceneController;
        sceneController.actionManager = this as IActionManager;
        factory = Singleton<DiskFactory>.Instance;
    }

    public void UFOMoving(GameObject disk)
    {
        float reducedHorizontalSpeed = disk.GetComponent<DiskData>().HorizontalSpeed * 0.06f;
        Debug.Log(reducedHorizontalSpeed);

        action = PhysicAction.GetAction(reducedHorizontalSpeed);
        RunAction(disk, action, this);
    }

    public int UFOCount()
    {
        return actions.Count;
    }

    public void SSActionEvent(SSAction source,
        SSActionEventType events = SSActionEventType.Completed,
        int intParam = 0,
        string strParam = null,
        Object objectParam = null)
    {

        factory.RecycleDisk(source.transform.gameObject);
    }

    protected new void Update() { }

    public void UFO() { }
}

3.KinematicFlyAction.cs

运动学飞行的动作类,KinematicFlyAction类继承自SSAction,用于控制飞碟(或其他游戏物体)以运动方向和速度沿平面飞行。它是一个“运动”类,负责在飞碟上应用无重力的物理运动。

using UnityEngine;

public class KinematicFlyAction : SSAction
{
    public float horizontalSpeed; 
    public float verticalSpeed;   
    private Vector3 direction;    
    private Camera mainCamera;

    public static KinematicFlyAction GetAction(float horizontalSpeed, float verticalSpeed)
    {
        KinematicFlyAction action = ScriptableObject.CreateInstance<KinematicFlyAction>();
        action.horizontalSpeed = horizontalSpeed;
        action.verticalSpeed = verticalSpeed;
        return action;
    }

    // 初始化动作
    public override void Start()
    {
        mainCamera = Camera.main;  
        gameobject.GetComponent<Rigidbody>().isKinematic = true;
        this.direction = new Vector3(horizontalSpeed, verticalSpeed, 0); 
    }

    public override void Update()
    {
        if (this.gameobject == null || !this.gameobject.activeSelf)
        {
            this.destroy = true;
            this.callback?.SSActionEvent(this, SSActionEventType.Completed);
            return;
        }

        // 判断物体是否超出视口
        if (IsOutOfViewport())
        {
            this.destroy = true;
            this.callback?.SSActionEvent(this, SSActionEventType.Completed);
            return;
        }

        // 更新物体位置
        this.transform.position += this.direction * Time.deltaTime;
    }

    // 检查物体是否离开屏幕视口
    private bool IsOutOfViewport()
    {
        Vector3 screenPoint = mainCamera.WorldToViewportPoint(this.transform.position);
        // 判断物体是否完全超出了屏幕(可以设置适当的缓冲区)
        return screenPoint.x < -0.1f || screenPoint.x > 1.1f || screenPoint.y < -0.1f || screenPoint.y > 1.1f;
    }
}

4.KActionManager.cs

KActionManager 类继承自 SSActionManager,实现了 ISSActionCallbackIActionManager 接口,负责管理和控制飞碟的动作和生命周期。它与飞碟的运动和回收操作有关。它和PActionManager类似可以控制飞碟的飞行和返回飞碟数量。

using Controller.Round;
using Model.Disk;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KActionManager : SSActionManager, ISSActionCallback, IActionManager
{
    public RoundController sceneController;
    public KinematicFlyAction action;
    public DiskFactory factory;

    protected new void Start()
    {
        sceneController = (RoundController)SSDirector.getInstance().currentSceneController;
        sceneController.actionManager = this as IActionManager;
        factory = Singleton<DiskFactory>.Instance;
    }

    public void UFOMoving(GameObject disk)
    {
        DiskData data = disk.GetComponent<DiskData>();

        float reducedHorizontalSpeed = data.HorizontalSpeed * 0.1f;
        float reducedVerticalSpeed = data.VerticalSpeed * 0.1f;
        Debug.Log(reducedHorizontalSpeed);
        Debug.Log(reducedVerticalSpeed);

        action = KinematicFlyAction.GetAction(reducedHorizontalSpeed, reducedVerticalSpeed);
        RunAction(disk, action, this);
    }

    public int UFOCount()
    {
        return actions.Count;
    }

    public void SSActionEvent(SSAction source,
        SSActionEventType events = SSActionEventType.Completed,
        int intParam = 0,
        string strParam = null,
        Object objectParam = null)
    {
        factory.RecycleDisk(source.transform.gameObject);
    }

    public void UFO() { }
}

4.)Controllers/GameControl

1.SSDirector.cs

SDirector 类是一个 单例模式 的实现,通常用于控制游戏的场景和状态。在 Unity 中,这个类充当了 导演(Director) 的角色,负责管理和协调游戏中的各个部分。在任何地方调用 SSDirector.getInstance() 都会返回同一个实例。这是通过 _instance 私有静态变量实现的,如果实例为空,则创建一个新的 SSDirector 对象。

currentSceneController 是一个 ISceneController 类型的属性,它负责管理当前游戏场景的控制。具体的场景控制器(如 RoundController)将实现 ISceneController 接口,并通过 SSDirector 来访问。

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

public class SSDirector : System.Object {
	// singlton instance
	private static SSDirector _instance;

	public ISceneController currentSceneController { get; set;}
	public bool running{ get; set;} 

	// get instance anytime anywhare!
	public static SSDirector getInstance() {
		if (_instance == null) {
			_instance = new SSDirector ();
		}
		return _instance;
	}

}

2.Singleton.cs

Singleton<T> 类是一个 通用单例模式(Generic Singleton) 的实现,用于确保类 T 在整个应用程序中只有一个实例,并且能够方便地访问这个实例。

using UnityEngine;

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T _instance;

    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindFirstObjectByType<T>();

                if (_instance == null)
                {
                    GameObject singletonObject = new GameObject(typeof(T).Name);
                    _instance = singletonObject.AddComponent<T>();
                }
            }
            return _instance;
        }
    }
}

3.ISceneController.cs

场景控制器接口,LoadResources()负责导入场景资源,UserAct()提供响应用户交互的接口。

using System;

public interface ISceneController
{
	void LoadResources();
	void UserAct();
}


4.ScoreRecorder.cs

ScoreRecorder 类是 Unity 游戏中的一个管理类,用于记录和计算玩家的分数。它的主要功能是根据击中的飞碟(hitDisk)的分数更新总分,并将其显示在用户界面中。

它引用了 RoundController 类,表示当前回合的控制器。ScoreRecorder 会将自己赋值给 roundController.scoreRecorder,使得回合控制器可以访问到当前的分数记录器。

同时还引用了 UserGUI 类,负责显示用户界面。ScoreRecorderStart() 方法中获取 UserGUI 组件,并在分数更新时与之交互,将当前分数显示在游戏界面中。

using Model.Disk;
using UnityEngine;

namespace Controller.Round
{
    public class ScoreRecorder : MonoBehaviour
    {
        private int score = 0;
        public RoundController roundController;
        public UserGUI userGUI;

        // 计算分数
        public void CalculateScore(GameObject hitDisk)
        {
            score += hitDisk.GetComponent<DiskData>().Score;
            userGUI.totalScore = score;
        }

        void Start()
        {
            roundController = (RoundController)SSDirector.getInstance().currentSceneController;
            roundController.scoreRecorder = this;
            userGUI = this.gameObject.GetComponent<UserGUI>();
        }

    }
}

5.RoundController.cs

RoundController 类负责整个回合的控制流程,管理飞碟的生成、玩家的操作、分数的计算以及游戏结束的判断。它协调了多个组件(如 DiskFactoryScoreRecorderUserGUIPhysicActionManagerKActionManager)的工作,确保游戏按照预期的规则进行,并实时更新游戏状态。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using Model.Disk;
using Controller.Round;

public class RoundController : MonoBehaviour, ISceneController, IUserAction
{
    GameObject disk;
    DiskFactory factory;
    public IActionManager actionManager;
    public ScoreRecorder scoreRecorder;
    public UserGUI userGUI;

    int turn = 0;
    int mturn = 10;
    float timer = 0.5f;

    private float spawnTimer = 0.5f; // 每个飞碟的生成间隔
    private int disksToSpawn = 0;   // 当前回合剩余待生成的飞碟数量

    private void Update()
    {
        if (userGUI.displayMode == 0) return;

        UpdateActionManager(); // 确保 ActionManager 的类型正确
        UserAct();             // 处理用户输入
        gameOver();            // 检查游戏是否结束

        if (turn > mturn) return;

        UpdateTimers(); // 更新计时器

        if (disksToSpawn > 0 && spawnTimer <= 0)
        {
            SpawnDisks(); // 生成飞碟
        }

        if (timer <= 0 && actionManager.UFOCount() == 0 && disksToSpawn == 0)
        {
            StartNewRound(); // 开始新回合
        }
    }

    // 确保 ActionManager 使用正确类型
    private void UpdateActionManager()
    {
        if (!userGUI.useKinematic)
        {
            actionManager = gameObject.GetComponent<PhysicActionManager>() as IActionManager;
        }
        else
        {
            actionManager = gameObject.GetComponent<KActionManager>() as IActionManager;
        }
    }

    // 更新计时器
    private void UpdateTimers()
    {
        timer -= Time.deltaTime;
        if (disksToSpawn > 0)
        {
            spawnTimer -= Time.deltaTime;
        }
    }

    // 生成飞碟
    private void SpawnDisks()
    {
        disk = factory.CreateDisk(turn);
        actionManager.UFOMoving(disk);
        disksToSpawn--;         // 减少待生成飞碟数
        spawnTimer = 0.5f;      // 重置生成间隔
    }

    // 开始新回合
    private void StartNewRound()
    {
        disksToSpawn = turn+4;       // 当前回合需要生成的飞碟数量
        turn++;
        if (turn <= mturn)
        {
            userGUI.currentRound = turn;
        }
        timer = Mathf.Max(4.0f - turn * 0.5f, 1.0f); // 动态调整每回合等待时间,避免前期等待过久
    }



    void Awake()
    {
        InitDirector();
        InitComponent();
    }
    void InitDirector()
    {
        SSDirector director = SSDirector.getInstance();
        director.currentSceneController = this;
    }
    void InitComponent()
    {
        gameObject.AddComponent<UserGUI>();
        gameObject.AddComponent<PhysicActionManager>();
        gameObject.AddComponent<KActionManager>();
        gameObject.AddComponent<ScoreRecorder>();
        gameObject.AddComponent<DiskFactory>();
        factory = Singleton<DiskFactory>.Instance;
        userGUI = gameObject.GetComponent<UserGUI>();
    }


    public void gameOver()
    {
        if (turn > mturn && actionManager.UFOCount() == 0)
            userGUI.feedbackMessage = "Game Over!";
    }

    public void UserAct()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            Camera ca = Camera.main;
            Ray ray = ca.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                scoreRecorder.CalculateScore(hit.transform.gameObject);
                hit.transform.gameObject.SetActive(false);
            }
        }
    }

    void Start() { }
}

5.)Views

1.IUserAction

IUserAction 是一个接口,定义了两个方法:gameOver()UserAct(),这两个方法是游戏控制和用户交互的核心。

主要功能:gameOver():用于处理游戏结束时的逻辑。UserAct():用于处理玩家的操作输入,如点击或其他互动。

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

//用户接口
public interface IUserAction
{
    void gameOver();
    void UserAct();

}

2.UserGUI.cs

UserGUI 类处理游戏中的图形用户界面(GUI),包括显示玩家的分数、回合信息,并管理游戏的界面切换。它为玩家提供了直观的反馈和交互功能,帮助玩家在游戏中进行操作。

using UnityEngine;

public class UserGUI : MonoBehaviour
{
    public int displayMode;
    public int totalScore;
    public int currentRound;
    public string feedbackMessage;
    public bool useKinematic;
    private IUserAction playerAction;

    public GUIStyle headerStyle, defaultStyle, labelStyle;
    public Font gameFont;  // 引用字体

    private int btnWidth, btnHeight;

    void Start()
    {
        btnWidth = Screen.width / 5;
        btnHeight = Screen.width / 10;

        if (gameFont == null)
        {
            Debug.LogError("Font not assigned.");
            return;
        }

        headerStyle = CreateGUIStyle(gameFont, 50, Color.white, TextAnchor.MiddleCenter);
        labelStyle = CreateGUIStyle(gameFont, 20, Color.white, TextAnchor.MiddleCenter);
        defaultStyle = CreateGUIStyle(null, 50, Color.black, TextAnchor.MiddleCenter);

        useKinematic = true;
        displayMode = 0;
        feedbackMessage = "";
        playerAction = SSDirector.getInstance().currentSceneController as IUserAction;
    }

    private GUIStyle CreateGUIStyle(Font font, int fontSize, Color color, TextAnchor alignment)
    {
        GUIStyle style = new GUIStyle
        {
            font = font,
            fontSize = fontSize,
            normal = { textColor = color },
            alignment = alignment
        };
        return style;
    }

    void OnGUI()
    {
        GUI.skin.button.fontSize = 20;
        GUI.skin.button.font = gameFont;  // 设置按钮使用的字体

        if (displayMode == 0)
        {
            ShowMainMenu();
        }
        else if (displayMode == 1)
        {
            ShowGameScreen();
        }
    }

    void ShowMainMenu()
    {
        GUI.Label(new Rect(Screen.width / 2 - btnWidth * 0.5f, Screen.height * 0.1f, btnWidth, btnHeight), "点击开始游戏", headerStyle);
        if (GUI.Button(new Rect(Screen.width / 2 - btnWidth * 0.5f, Screen.height * 3 / 7, btnWidth, btnHeight), "开始"))
        {
            displayMode = 1;
        }
    }

    void ShowGameScreen()
    {
        GUI.Label(new Rect(300, 60, 50, 200), feedbackMessage, headerStyle);
        GUI.Label(new Rect(280, 0, 100, 50), "分数: " + totalScore, labelStyle);
        GUI.Label(new Rect(560, 0, 100, 50), "当前回合: " + currentRound, labelStyle);

        // 根据 useKinematic 的值动态设置按钮文本
        string buttonText = useKinematic ? "切换到物理模式" : "切换到运动学模式";

        // 显示按钮并根据当前模式切换
        if (GUI.Button(new Rect(0, 0, 200, 50), buttonText))
        {
            useKinematic = !useKinematic;
        }
    }

}

总结

以上就是本文的内容,说明如何使用unity制作在物理引擎作用下的打飞碟游戏。

项目地址:天明五蕴/Unity游戏打飞碟

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值