Unity游戏开发案例分享

        这个学期学习了Unity,了解了Unity的游戏框架,功能,组件,C#脚本,让我对游戏开发有了基本的了解。在实现这个游戏的过程中,我读了一些软件开发相关的书籍,《UML和模式应用》帮助我了解了迭代开发的流程与优点,明确了开发的思路,解决了我之前用瀑布模式开发带来的迷茫与痛苦,《大话设计模式》《游戏编程模式》帮助我了解了如何用设计模式来解决代码库增大后带来的维护与扩展难题。在实际的开发过程中,我觉得我的编程能力,思维能力,发现和解决问题的能力都有了很大的提高。

项目的github地址:点击打开链接

以下是我开发MiniCar小游戏的过程和心得体会。

使用GitHub迭代开发与版本控制:

我觉得,在独立开发游戏的过程中,始终明确自己的目标是一件非常重要的事情。使用迭代的思路可以找出当前最重要的几个需求,集中精力来实现,避免的一些不要紧和不明确的小需求上浪费过多时间。版本控制可以在让我放心大胆的去写代码,去比较不同的版本哪个更好,github的不同分支可以很好的实现这一点。

面向对象思想:

通过面向对象设计,可以比较好的分配游戏职责,编程的时候思路也更清晰。

软件架构与设计模式:

我使用的是MVC的架构,在这个游戏里,像赛车这样的对象作为模型,提供控制的方法,而用户处理,关卡控制作为控制器,用户的界面显示这些模型的信息。如赛车的速度,关卡能否解锁等。

设计模式可以在代码量增长时提供方便的维护方法,用例如观察者模式,状态模式,等可以很好解耦不同类,不同功能之间的依赖,如赛车受到碰撞时要发出碰撞的音效,如果把物理和音效放在一段代码里,会导致两个系统的直接耦合,不利于之后功能的拓展,且可能会发生难以预测的bug。

在做闯关控制器时,观察者模式也发挥了很大的作用,之前的代码,在流程中加入了对其它控制器的调用,如在倒计时的时候关闭用户赛车控制,在暂停的时候调低音效,在结束的时候调用UI显示,退出的时候进行数据保存等。。。这一个流程下来,关卡控制几乎所有控制器都调用了一遍,如果一个功能出了bug,可能都要修改闯关控制器的代码,所以,为了编程上的思路清晰,代替直接调用其它相关的控制器,在闯关控制器的每个控制阶段都调用一次相关的事件,其它的系统想要进行响应,只需要订阅此事件就可以了。

//事件
public event Action OnChallengePrepare;     //准备阶段调用
public event Action OnChallengeStart;       //开始阶段调用
public event Action OnChallengeGoingOn;     //进行阶段调用
public event Action OnChallengeSucceed;     //成功阶段调用
public event Action OnChallengePaused;      //暂停阶段调用
public event Action OnChallengeFailed;      //失败阶段调用
public event Action OnTurnFinished;         //当完成一圈时
public event Action OnTimeCountChanged;     //当计时进行时

确定需求是快速开发的关键:

在开发的初始阶段,需求要少而精,确定之后就以此为根据进行面向对象,架构与编程模式的设计,要保持写的代码是可以扩展的,职责是合理且明确的。这样的方式可以避免未来大量的修改与重写,极大的提升效率。

代码命名,格式与注释:

类名,成员变量与函数要意义明确,可以根据它所属的类别加上它的功能进行命名,如一个表示赛车速度的内部成员可以命名为:private float m_speed; 命名的规范有多种多样,但是要合理且有区分,这样易与理解与之后的回顾修改。

代码的格式,注释也以易于阅读为目的,我的风格是将变量声明语句,判断语句,执行语句进行隔行分离。

这是我的代码风格:

using UnityEngine;

/// <summary>
/// 检查点
/// 1.检测赛车是否通过此检查点
/// 2.方向错误时调用HUD警告方向错误
/// </summary>
public class CheckPoint : MonoBehaviour 
{
    [Header( "=== 外部控制器 ===" )]
    [SerializeField] private LevelHud m_levelHud;   //关卡HUD

    [Header( "=== 当前检查点状态 ===" )]
    [SerializeField] private string m_identifyTag = "CarCollider";      //标识
    [SerializeField] private bool m_passed = false;     //检查赛车是否通过

    //是否通过当前关卡
    public bool Passed { get { return m_passed; } }

    //初始化外部控制器
    private void Start()
    {
        m_levelHud = FindObjectOfType<LevelHud>();
    }

    //警告错误方向
    private void AlertWrongDirection()
    {
        m_levelHud.SetWrongDirection( 3 );
    }
    
    //当赛车进入trigger时执行
    private void OnTriggerEnter(Collider other)
    {
        //只有速度方向与跑道方向一致,才能认为通过检查点
        bool CorrectDirection = Vector3.Dot( other.GetComponentInParent<Rigidbody>().velocity, transform.forward ) > 0;

        if( !CorrectDirection )
        {
            AlertWrongDirection();
        }

        //若当前检查点已通过,则直接返回
        if ( m_passed )
        {
            return;
        }

        //只有当赛车正确通过时,才将当前检查点设为已通过
        if ( other.CompareTag( m_identifyTag ) && CorrectDirection )
        {
            Debug.Log( "赛车已通过!" );
            m_passed = true;
        }
    }

    //若当前检查点为TurnFlag,则会在赛车离开此检查点后将passed置为false,
    //通过判断“是否通过全部检查点”可以确定行驶一圈后又回到了TurnFlag检查点
    private void OnTriggerExit(Collider other)
    {
        if( name == "TurnFlag" && other.CompareTag( m_identifyTag ) )
        {
            m_passed = false;
            Debug.Log( "赛车已离开TurnFlag!" );
        }
    }

    //公有重设方法
    public void ResetPassState()
    {
        m_passed = false;     
    }
}

我的Unity学习流程:

从零开始学是一件阻力很大的事情,我中间也断断续续的摔过几次键盘偷笑,很大程度上是想的功能太多而一个都实现不了,脑子里有些想法,但是要实现起来不知道从何开始。所有,首先要平静下来,慢慢积累知识,坚持学下去。

我是从官方的新手案例开始入手的:

Roll a ballSpace shooterSurvival Shooter等,也可以在官网上看。

通过照着做可以对Unity的编辑器组件脚本这些有一个概念上的认识,然后再深入系统的看ManualScript API, 然后多做些小demo实践,以实现功能为主。再之后开始学习了一些开发的流程和设计模式,做现在的这个游戏,在这段过程中,代码的规范就变的很重要的,编写前的设计也是。








        

展开阅读全文

没有更多推荐了,返回首页