Unity3D学习笔记(4) 飞碟(Disk)基础版(仅使用射线,动作管理)

声明

本作业借鉴自 https://blog.csdn.net/zzj051319/article/details/66475328
本人学习重点为设计模式,尽力做到高内聚低耦合

描述

  1. 分多个round,每个 round 都是 n 个 trail;
  2. 不同round的飞碟的色彩、大小、速度不一。
  3. 鼠标击中得分,得分与round相关。
    这里写图片描述

设计

这里写图片描述

https://gitee.com/Ernie1/unity3d-learning/tree/hw4/hw4

飞碟数据DiskData

这个方法通过一个变量给游戏对象附加数据属性(分数),将作为Component挂载到一个 disk 游戏对象。

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

public class DiskData : MonoBehaviour {
    public int score;
}

飞碟管理员DiskFactory

这个方法负责接收场记的请求(直接被场记调用),对 disk 游戏对象产生和回收。
这里运用了工厂模式,减少了游戏对象创建与销毁成本,减少创建和销毁次数,使程序易于扩展。

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

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

    public GameObject getDisk() {

        GameObject newDisk;
        if (free.Count == 0)
            newDisk = GameObject.Instantiate(Resources.Load("prefabs/Disk")) as GameObject;
        else {
            newDisk = free[0];
            free.Remove(free[0]);
        }
        newDisk.SetActive(true);
        used.Add(newDisk);
        return newDisk;
    }

    public void freeDisk(GameObject g) {
        for (int i = 0; i < used.Count; i++) {
            if (used[i] == g) {
                used.Remove(g);
                g.SetActive(false);
                free.Add(g);
            }
        }
    }

    public void hideAll() {
        for (int i = 0; i < used.Count; i++)
            used [i].SetActive (false);
        for (int i = 0; i < free.Count; i++)
            free [i].SetActive (false);
    }
}

记分员Scorekeeper

负责根据游戏对象的DiskData组件中的变量score进行分数的累加,分数被场景直接访问,提供清零方法。

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

public class Scorekeeper {

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

    public int score;

    public void reset(){
        score = 0;
    }

    public void record(GameObject hit) {
        score += hit.GetComponent<DiskData> ().score;
    }
}

抛出动作FlyDisk

继承了动作基类SSAction,接收速度级别参数,实现抛出Disk动作。

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

public class FlyDisk : SSAction {
    Vector3 start;   //起点
    Vector3 target;   //要到达的目标  
    Vector3 speed;    //分解速度
    float countTime;
    Vector3 Gravity;

    private int level;

    public override void Start() {
        start = new Vector3(7 - Random.value * 14, 0, 0); 
        target = new Vector3(Random.value * 80 - 40, Random.value * 29 - 4, 30);

        this.transform.position = start;

        float mainSpeed = 5 + level * 6;
        float time = Vector3.Distance(target, start) / mainSpeed;

        speed = new Vector3 ((target.x - start.x) / time, (target.y - start.y) / time + 5 * time, (target.z - start.z) / time);
        Gravity = Vector3.zero;
        countTime = 0;
    }
    public static FlyDisk GetSSAction(int level) {
        FlyDisk action = ScriptableObject.CreateInstance<FlyDisk>();
        action.level = level;
        return action;
    }
    public override void Update() {
        float g = -10;
        Gravity.y = g * (countTime += Time.fixedDeltaTime);// v=gt
        this.transform.position += (speed + Gravity) * Time.fixedDeltaTime;//模拟位移

        if (this.transform.position.z >= target.z) {
            DiskFactory.getInstance().freeDisk(gameobject);
            this.destroy = true;
            this.callback.SSActionEvent(this);
        }
    }
}

主体

导演类SSDirector

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

public interface ISceneController{
    void LoadResources();
}

public class SSDirector : System.Object {

    private static SSDirector _instance;

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

用户交互类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;

    void Start() {
        action = SSDirector.getInstance ().currentScenceController as IUserAction;
    }

    void OnGUI() {
        if (GUI.Button(new Rect(Screen.width/2-38, 38, 76, 20), "(RE)PLAY"))
            action.ReStart();
    }
}

场记类SceneController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SceneController : MonoBehaviour, ISceneController, IUserAction
{
    public CCActionManager actionManager { get; set; }
    public Scorekeeper scorekeeper;
    public DiskFactory DF;
    private int round = 0;
    public int totalRound = 3;
    public int trial = 10;
    public Text ScoreText;
    public Text RoundText;
    public Text GameText;
    private bool play = false;
    private int num = 0;
    private float heartbeat;

    GameObject disk;
    GameObject explosion;

    void Awake() {
        SSDirector director = SSDirector.getInstance();
        DF = DiskFactory.getInstance();
        DF.sceneControler = this;
        director.setFPS(60);
        director.currentScenceController = this;
        director.currentScenceController.LoadResources();

        scorekeeper = Scorekeeper.getInstance ();
    }
    void Start() {
        round = 1;
        heartbeat = 0;
    }
    public void LoadResources() {
        explosion = Instantiate(Resources.Load("prefabs/Explosion"), new Vector3(-40, 0, 0), Quaternion.identity) as GameObject;
        Instantiate(Resources.Load("prefabs/Light"));
    }

    void Update() {
        if (play) {
            if (heartbeat >= 1) {
                launchDisk ();
                heartbeat = 0;
            }
            heartbeat += Time.deltaTime;
        }

        if (Input.GetButtonDown("Fire1") && play) {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit)) {
                GameText.text = "";
                if (hit.transform.tag == "Disk")
                {
                    explosion.transform.position = hit.collider.gameObject.transform.position;
                    explosion.GetComponent<ParticleSystem>().Play();
                    hit.collider.gameObject.SetActive(false);
                    scorekeeper.record (hit.collider.gameObject);
                }
            }
        }
        updateStatus ();
    }

    public void StartGame() {
        num = 0;
        play = true;
        scorekeeper.reset ();
    }
    public void ReStart() {
        round = 1;
        heartbeat = 0;
        num = 0;
        play = true;
        GameText.text = "";
        DF.hideAll ();
        scorekeeper.reset ();
    }

    private void launchDisk() {
        GameObject newDisk = DF.getDisk ();
        if (!newDisk.GetComponent<DiskData> ())
            newDisk.AddComponent<DiskData> ();
        newDisk.GetComponent<DiskData> ().score = round;
        newDisk.GetComponent<Renderer> ().material.color = new Color ((round % 10) * 0.1F, 0.4F, 0.8F);


        float size = (float)(1.0f - 0.2 * round);
        newDisk.transform.localScale = new Vector3(4*size, size/5, 4*size);
        num++;
        actionManager.singleRunAction (newDisk, round);
    }

    private void updateStatus() {
        ScoreText.text = "Score:" + scorekeeper.score.ToString();
        RoundText.text = "Round:" + round.ToString();
        if (scorekeeper.score >= 6) {
            ++round;
            GameText.text = "Round " + round.ToString();
            scorekeeper.reset ();
            num = 0;
        }
        if (round > totalRound) {
            play = false;
            GameText.text = "Win";
        }
        if (num >= trial) {
            play = false;
            GameText.text = "Game Over";
        }
    }
}

动作基类SSAction

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

public enum SSActionEventType : int { Started, Competeted }

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

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 () {}

    //Use this for initialization
    public virtual void Start () {
        throw new System.NotImplementedException ();
    }

    // Update is called once per frame
    public virtual void Update () {
        throw new System.NotImplementedException ();
    }
}

动作管理基类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, ISSActionCallback manager) {
        action.gameobject = gameobject;
        action.transform = gameobject.transform;
        action.callback = manager;
        waitingAdd.Add(action);
        action.Start();
    }
}

实战动作管理CCActionManager

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

public class CCActionManager : SSActionManager, ISSActionCallback {

    public SceneController sceneController;
    public DiskFactory diskFactory;

    void Start() {
        sceneController = (SceneController)SSDirector.getInstance ().currentScenceController;
        sceneController.actionManager=this;
        diskFactory = DiskFactory.getInstance();
    }

    public new void Update () {
        base.Update ();
    }

    public void singleRunAction (GameObject gameObject, int speedLevel) {
        this.RunAction (gameObject, FlyDisk.GetSSAction (speedLevel), this);
    }

    #region ISSActionCallback implementation
    public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
        int intParam = 0, string strParam = null, Object objectParam = null){

    }
    #endregion
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习Unity3D时,以下是一些重要的笔记: 1. Unity3D基础知识: - 游戏对象(Game Objects)和组件(Components):了解游戏对象的层次结构和组件的作用。 - 场景(Scenes)和摄像机(Cameras):学会如何创建场景并设置摄像机视角。 - 材质(Materials)和纹理(Textures):掌握如何创建和应用材质和纹理。 - 动画(Animations):学习如何创建和控制游戏对象的动画。 2. 脚本编程: - C#语言基础:了解C#语言的基本语法和面向对象编程概念。 - Unity脚本编写:学习如何编写脚本来控制游戏对象的行为和交互。 - 常见组件和功能:掌握常见的Unity组件和功能,如碰撞器(Colliders)、刚体(Rigidbodies)、触发器(Triggers)等。 3. 游戏开发流程: - 设计游戏关卡:了解如何设计游戏场景和关卡,包括布局、道具、敌人等。 - 游戏逻辑实现:将游戏规则和玩家交互转化为代码实现。 - UI界面设计:学习如何设计游戏中的用户界面,包括菜单、计分板等。 - 游戏优化和调试:优化游戏性能,解决常见的错误和问题。 4. 学习资源: - Unity官方文档和教程:官方提供了大量的文档和教程,逐步引导你学习Unity3D。 - 在线教程和视频教程:网上有很多免费和付费的Unity教程和视频教程,可根据自己的需求选择学习。 - 社区论坛和博客:加入Unity开发者社区,与其他开发者交流并获取帮助。 通过系统地学习这些内容,你将能够掌握Unity3D基础知识并开始开发自己的游戏项目。记得不断实践和尝试,不断提升自己的技能!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值