0%

Unity项目架构设计与开发管理

1.常见架构#

  • EmptyGo
  • simple GameManager
  • Manager of Managers
  • MVCS
  • MVVM:UFRAME

2.EmptyGo#

  • Put all the code without visual representation in the world onto an empty game object.
  • use GameObject.Find() or inspector target references to communicate with each other.GameObject.Find()不解耦合

3.simple GameManager#

  • 改为一个singleton
  • 包括UI设计,包括模块的访问
  • 全部塞进去,会发生混乱

4.Manager of Managers(中型游戏非常常用)#

  • MainManager(customizes and managers all the submanagers)(submanagers operate as singletons and can easily address each other to collaborate
    1. EventManager:集中管理UI到各个模块之间的消息,以及各个模块相互访问的传递
    2. AudioManager:在场景中任何一个地方播放音乐,都用它来管理
    3. GUIManager:管理所有UI发生的click的事件
    4. PoolManager:把已经初始化,但暂不使用的gameobject放入pool(非常重要)
    5. LevelManager:关卡管理(非常重要)
    6. GameManager:
    7. SaveManager:load page,游戏退出后,进入还想在原处(非常重要)
    8. MenuManager:管理Menu上的动画,外观上的东西(严格与GUIManager事件管理区分开来)

4.1 level manager#

4.1.1 Unity 自带 Application.loadLevel();#

ISSUE 1: you need to know the scene name or the index of the scene you want to load,but most probably the name or order will be changed later.

1
2
Application.loadLevel("FirstLevel");
Application.loadLevel(1);

ISSUE 2: there's no simple method of passing arguments to a scene , e.g., assuming you're resuing one scene for many different levels.

ISSUE 3:managing multiple level work flows is not a simple task. suppose you want to create two versions of your game:

1
2
3
4
5
6
7
8
9
Application.loadLevel(1);
Application.loadLevel(2);
Application.loadLevel(3);
---
VS
---
Application.loadLevel(1);
Application.loadLevel(3);
Application.loadLevel(2);

4.2 level manager设计#

  1. Compose a configuration table.(需要变换加载场景顺序,仅需要在表内变换)
  2. create a new API
    • LevelManager.LoadNext();
  3. In the configuration table, it also should be allowed to set an argument line for each level.
  4. It should be allowed to create multiple configuration tables,and before building your appliaction switch between them.(示例:Unity商店MadLevelManager)

4.3 pool manager设计#

  1. Maintain a list of dormant objects in the pool class:
    1
    private List<GameObject> dormantObjects = new List <GameObject>();
  2. the list contains all different types of game objects / prefabs

SPAWN()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public GameObject Spawn(GameObject go){
GameObject temp = null;
if (dormantObjects.count>0){
foreach(GameObject dob in dormantObjects){
if(dob.name == go.name){
temp = dob;
dormantObjects.remove(temp);
return temp;
}
}
}
temp = GameObejct.Instantiate(go) as GameObejct;
temp.name = go.name;
return temp;
}

DESPAWN()

1
2
3
4
5
6
public GameObject Despawn(GameObject go){
go.transform.parent = PoolManager.transform;
go.SetActive(false);
dormantObjects.Add(go);
Trim();
}

TRIM(超过限制就删除)

1
2
3
4
5
6
7
public void Trim(){
while(dormantObjects.Count>Capacity){
GameObject dob = dormantObjects[0];
dormantObjects.RemoveAt(0);
Destory(dob);
}
}

PROBLEMS 1. This pool is not able to manage the Load/Unload of prefabs. 2. Only dormant objects are managed in the pool, active objects must be managed out of pool separately. 3. The total number of dormant objects can be controlled, rather than the instances of each prefabs.(总物体有数量限制,而不是每中类型没有限制)

better design PoolManager:Singleton,Manage multiple SpawnPools - SpawnPool1 + prefabPool1---Prefab1 + prefabPool2---Prefab2 - SpawnPool2 + prefabPool3---Prefab3 + prefabPool4---Prefab4

Spawnpool:design rules for spawnpool 1. define an empty object,set its transform as the parent of all the instances in the pool.(空物体) 2. manager multiple prefabpools via a dictionary

prefabPool 1. create a prefabPool for each prefab. 2. maintains a list of activated objects and another list of deactive objects. 3. centrally manage the load/unload process here.

4.4 save manager设计#

  1. save and load user preferences and achievements.
    • quit/resume game
  2. a lot of developers are used to save/load data with JSON/XML files.
  3. Is there any better solution?
    • Serialize almost any type of data.
    • it's fast,even on mobile devices.
    • encrypt save date efficiently and securely.
    • snap a screen

5. MVCS:STRANGEIOC(UI和逻辑分开)#

5.1 strangeioc framework#

  1. The core of the framework is binding
  2. basic structure: The key triggers the value.
    1
    IBinder.Bind<Key>().To<Value>();
  3. advanced structure: the name is a discriminator
    1
    IBinder.Bind<Key>().To<Value>().ToName(name);
  4. Type of key
key value Notes
event callback an event triggers a callback
interface implementation binds an interface to its implementation
class dependent class the instantiation of one class triggers the instantiation of dependent class.
  1. a view only does display and input.(UI事件和GameObject上的可视化相关)
  2. the mediator connects the view with the rest of your app
  3. commands are classes triggered by events.

5.2 Mediator#

Binding

1
mediationBinder.Bind<Example View>().To<ExampleMediator>();

Dispatcher - simple format

1
dispatcher.Dispatcher(AttackEvent.FIRE_MISSILE);
- Event + data
1
2
Vector3 orientation = gameObject.transform.loaclRotaion.eulerAngles;
dispatcher.Dispatcher(AttackEvent.FIRE_MISSILE, orientation);

Listener - If Listener is a method

1
2
dispatcher.AddListener(AttackEvent.FIRE_MISSILE, onMissileFire);
dispatcher.RemoveListener(AttackEvent.FIRE_MISSILE, onMissileFire);
- If Listener is a command
1
2
3
4
5
6
commandBinder.Binder(GameEvent.GUN_FIRE,OnGunFireCommand);
class OnGunFireCommand:EventCommand{
override public void Execute(){
...
}
}

5.3 Limitation#

  • Injection empolys reflection, which is slow.(反射机制耗时)
  • if inject sth,you have to map it, otherwise, it will result in null pointer errors.(容易造成空指针)

6 MVVM:UFRAME#

View--->ViewModel--->Model

7 编码策略#

  • 文件命名规范
  • 文件名分类
  • 用空物体来管理同类物体
  • 零容忍warnings and errors
  • 零容忍runtime memory location(动态开辟数组等)