《炉石传说》架构设计赏析(1):游戏启动流程

前些天看新闻,Unity Awards两项大奖颁给了暴雪的《炉石传说》,这真是对Unity一个再好不过的宣传了——你看,暴雪都开始用Unity了。大家都知道,目前Unity发布的游戏大多都没有对程序集进行混淆、加密,所以作为一个炉石的玩家&Unity的初学者,自然不能错过这个机会。让我们好好看一下暴雪的代码吧。

炉石传说的游戏内容的非常丰富多彩,所以我花了一些时间分析了其程序集,将一些设计思路记录下来,与大家分析。欢迎各路高手拍砖,欢迎转载,请注明出处:燕良@游戏开发http://blog.csdn.net/neil3d/article/details/39104329

做这些分析的主要目的是:

  1. 看看炉石如何组织游戏逻辑,以支撑复杂的技能逻辑、表现等;
  2. 看看炉石是如何使用Unity的,其结构设计和技巧上有什么值得学习的地方;
  3. 向暴雪的程序员好好学习一下英语。

下面我们就正式开始。我习惯先分析一下游戏的启动流程,这中间就涉及到了游戏基础数据的管理&初始化,各种管理器级别的类,以及相互引用关系也会初步显现。

首先看一下我找到的一些游戏启动过程相关的类,下面是他们的类图:

接下来我们分析一下游戏启动的操作流程。

  • ApplicationMgr对象应该绑定到了一个场景对象中,这个场景应该在游戏启动中加载;
  • ApplicationMgr:Awake()被Unity引擎自动调用;
    • 调用ApplicationMgr:Initialize(),在这个函数中顺序调用了以下成员函数来进行初始化:

      • InitializeMode():设置模式为ApplicationMode.PUBLIC;
      • InitializeUnity():设置了UnityEngine. Application的一些属性;
      • InitializeGame():看来核心的内容在这里,初始化Network,GameMgr等;
      • InitializeWindowTitle();
      • InitializeOptionValues();

游戏启动应该不只这点东西。由于我们纯靠程序集的动态分析,无法知道它的场景编辑、对象的脚本绑定,也不能跟踪调试,所以只能靠猜测了。另外,一些事件是通过网络消息触发的,这也给静态分析带来了一些难度。

OK,我们继续。我注意到了class Login,它从Scene派生。查看了一下Scene的派生类还有不少,我猜测每个派生类,作为特定Scene逻辑处理的脚本。而Login应该是在第0个场景中被激活运行。我们看一下Login:Start(),这属于MonoBehavior自动调用,他主要做了这样几件事:

  • 注册了一些资源版本检测、Login相关的网络消息回调;
  • 通知SceneMgr场景加载完成;
  • 调用成员函数:AutoLogin();此函数调用Network.AutoLogin();
    • 从配置文件中找到User Name,然后调用ConnectAPI.AutoLogin()——奇怪的是发现这个函数只是简单的返回false,并没有进行实际的操作。

我们在来看一下Login:Update(),这个也是属于被自动调用的脚本函数。在这里它检测了Login的状态,并调用了成员函数LoginOk(),而它有主要调用了AssetsVersionCheckCompleted(),这个函数内容很丰富:

  • 通知其他模块,已经登录成功,包括:BaseUI、 InactivePlayerKicker、HealthyGamingMgr、GameMgr;
  • 调用一些模块的Initialize函数,包括:DefLoader、CollectionManager、AdventureProgressMgr、Tournament、StoreManager等;

我们前面看到了Login从Scene派生,并且还有一个SceneMgr类。我们可以断定游戏根据不同的逻辑划分成了一些scene,接下来我们就探索一下Scene切换的流程。还是从Login入手。

以下流程都是在Login类中完成,下面描述的过程都是Login成员函数的调用:

  • 首先我找到了Login:OnNetCacheReadyStep2()函数,这个应该是login流程中某一步的网络消息回调函数;
  • 它会调用 WaitForAchievesThenInit()这个Coroutine函数,这个函数检测了是否需要播放视频,然后调用ReconnectOrChangeMode();
  • 此函数处理重新连接,一般的话应该是调用了ChangMode();
  • ChangMode()处理了新手教程相关的启动逻辑,一般的话会调用ChangeMode_Hub();
  • 这个地方貌似是调用了一个技能特效,特效播放完成之后调用回调函数:OnStartupHubSpellFinished();
  • 此函数调用ShowUnAckedRewardsAndQuests();
  • 这里面主要是调用了HandleUnAckedRewardsAndCompletedQuests(),哦~,这应该是游戏启动的时候显示当前任务还有未领取的奖励的那个界面
  • 它会调用ShowNextUnAckedRewardOrCompletedQuest();
  • 其中主要调用了ShowWelcomeQuests();
  • 当幸亏显示的任务为0时,则调用了这一句:SceneMgr.Get().SetNextMode(SceneMgr.Mode.HUB),这是关键的一步了;

接下来就我们跳转到SceneMgr类中,继续探索Scene切换流程的实现。以下都是指的SceneMgr的成员函数:

  • SetNextMode()函数主要就是把“m_nextMode”成员变量设置为了指定值;
  • 接下来看一下Update(),这个函数主要是检测了是否需要切换Mode,然后调用了:
    • SwitchMode():这个是一个Coroutine,它主要是调用了LoadModeFromModeSwitch(),它的核心也是调用LoadMode();
    • 直接调用LoadMode()
  • LoadMode()函数,主要是根据当前的Mode,调用LoadScene();
  • LoadScene()函数主要是调用了: Application.LoadLevelAdditiveAsync(this.sceneName);
  • 这样就完成了场景的切换。

OK。通过以上分析,我们大体了解了游戏启动过程是这样的:

  • 进行账户验证;
  • 账户验证完毕之后,显示未领取的奖励和任务;
  • 然后切换到SceneMgr.Mode.HUB模式,即加载了相应的Scene。

关于游戏启动的分析告一段落,下一篇将会分析一下炉石的Scene组织。

时间: 2024-10-04 17:20:48

《炉石传说》架构设计赏析(1):游戏启动流程的相关文章

炉石传说 C# 设计文档(序)

经过3个月的开发,有很多感触. 以前一直以为技术是开发成败的第一因素,现在发现,等到你代码写的时间够长,经验够丰富,什么功能都能随手完成,对于业务的分析能力变成了第一位. 炉石山寨版的BS版本用到的HTML5的SVG,我看了一个下午的教程,借鉴以前GUI+和HTML的经验,很快就能写点东西出来了. WebSocket,Github上找了一个开源的C#项目,通讯这块也是几个小时就搞定了.Javascript不是很熟悉,当时闭包这样的一些概念也算听说过,Js也是无障碍就写成了. 整个项目的技术壁垒其

Cocos2dx源码赏析(1)之启动流程与主循环

Cocos2dx源码赏析(1)之启动流程与主循环 我们知道Cocos2dx是一款开源的跨平台游戏引擎,而学习开源项目一个较实用的办法就是读源码.所谓,"源码之前,了无秘密".而笔者从事的也是游戏开发工作,因此,通过梳理下源码的脉络,来加深对Cocos2dx游戏引擎的理解. 既然,Cocos2dx是跨平台的,那么,就有针对不同平台运行的入口以及维持引擎运转的"死循环".下面,就分别从Windows.Android.iOS三个平台说明下Cocos2dx从启动到进入主循环

《炉石传说》架构设计赏析(4):Asset管理

欢迎转载,请注明作者[燕良@游戏开发]及原文地址:http://blog.csdn.net/neil3d/article/details/39580197 另外,欢迎大家来我的QQ群交流各种游戏引擎相关的技术:游戏引擎能吃吗(264656505) 话说,经过这段时间的学习和摸索,对于Unity3D的开发思路已经基本清晰了.唯独还剩下一个AssetBundle机制还没有搞透,这个涉及到前期项目的资源规划.资源管理代码的写法,以及自动更新机制的实现. 所以,还是想先把游戏逻辑的进一步分析押后,先来看

《炉石传说》架构设计赏析(6):卡牌&技能数据的运行时组织

前一篇文章我们看到了<炉石传说>的核心卡牌数据的存储,今天我们继续探索卡牌&技能. 主要的类 通过之前的分析,卡牌&技能涉及到几个类体系:Entity,Actor,Card,Spell,令人十分困惑,特别是前两者.在这里先略带武断的说一下这几个类的基本定位: Entity主要用来做网络数据同步用的: Actor主要处理客户端的渲染对象的控制,作为Component挂载在资源对象上: Spell是技能Prefab挂载的脚本: Card是卡牌Prefab挂载的脚本,在运行时处于中心

《炉石传说》架构设计赏析(3):Gameplay初探

经过前面两篇文章的分析,我们对炉石的代码已经不陌生了,接下来我初步尝试分析其游戏逻辑代码. 欢迎转载,请注明作者[燕良@游戏开发]及原文地址:http://blog.csdn.net/neil3d/article/details/39453291 经过前面的分析,我们已经找到了两个关键的类Gameplay和GameState(当然还有我最感兴趣的Spell和SpellController,这两个还要在后面分析). 首先我们看一下Gameplay这个类的Awake方法,它完成的主要工作是: 调用"

《炉石传说》架构设计赏析(2):Scene管理

上篇文章我们分析到SceneMgr处理了Scene的加载工作,今天我们主要分析一下炉石这款游戏中一共有哪些Scene,他们各自负责什么,以及它内部的逻辑.UI的处理方式. 在正式开始之前,我来对前文中提到的Scene切换再做一些补充分析.前文中我们看到SceneMgr是调用了" Application.LoadLevelAdditiveAsync(this.sceneName);",那内存中的东西岂不是越搞越多吗?我们再仔细看一下SceneMgr:SwitchMode()函数,它是一个

《炉石传说》架构设计赏析(7):使用Google.ProtocolBuffers处理网络消息

这段时间琢磨了一下Unity3D网络游戏开发中的网络消息处理.网络游戏的服务端一般都是自主开发的,所以对应的网络消息处理也要自己开发.客户端/服务端之间的消息传到目前使用JSON和Google.ProtocolBuffers是两种常见的做法.打开炉石的代码看了看它的处理方式,感觉代码写的还是很好的,把它的思路分析一下,与大家分享. 整体机制描述 我们想要达到的目标大概是这样的: 有N个网络消息,每个消息对应一个Proto中的message描述: 每个消息对应一个数字ID: 底层在收到消息是,将其

《炉石传说》架构设计赏析(5):卡牌&amp;技能的静态数据组织

经过前面几次的尝试,我们对炉石的代码已经不陌生了.除了网络机制还没有了解以外,本机的逻辑已经比较熟悉了. 接下来继续向暴雪最NB的技能系统进发,我们的目标是: 分析技能的静态数据描述: 分析技能的运行时数据.逻辑组织: 这篇笔记主要记录对其分析静态数据. 静态数据组织 卡牌数据 卡牌的基本数据对于的AssetFamily为:AssetFamily.CardXML: 数据对于的资源包为"cardxml0.unity3d": 资源包中的资源类型为:TextAsset: 资源加载使用的接口为

炉石传说 C# 开发笔记

最近在大连的同事强力推荐我玩 炉石传说,一个卡牌游戏.加上五一放一个很长很长的假期,为了磨练自己,决定尝试开发一个C#的炉石传说. 这件事情有人已经干过了,开发了一个网页版的炉石,但是貌似不能玩.... http://cnodejs.org/topic/529c1366a6957a0809485f3d 如果这位同志看到这篇文章,请一定和我联系!! [email protected]或Q我377372779 第一天 开始学习炉石传说的玩法,最好的方法是不停的玩游戏. 一个应用是否逻辑清晰,取决于你