在这一节,我们通过一些纸上设计,来说明框架的最佳实践方法。
《点点点》功能规划
尝试把《点点点》这个游戏项目用纸上设计的方式给完善掉。
目前《点点点》我们预留了几个数据,代码如下
GameModel
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| namespace FrameWorkDesign.Example { public interface IGameModel : IModel { BindableProperty<int> KillCount { get; } BindableProperty<int> Gold { get; } BindableProperty<int> Score { get; } BindableProperty<int> BestScore { get; } } public class GameModel : AbstractModel , IGameModel { public BindableProperty<int> KillCount { get; } = new BindableProperty<int>() { Value = 0 }; public BindableProperty<int> Gold { get; } = new BindableProperty<int>() { Value = 0 }; public BindableProperty<int> Score { get; } = new BindableProperty<int>() { Value = 0 }; public BindableProperty<int> BestScore { get; } = new BindableProperty<int>() { Value = 0 };
protected override void OnInit() { } } }
|
我们增加几个功能
功能 |
规则 |
最佳分数 |
存储并记录最佳分数 |
倒计时 |
游戏倒计时10秒 |
计分 |
点错一次扣5分,点对一次得10分,结束时倒计时每剩余1秒得10分 |
金币 |
每次点击正确的方块,有一定概率获得1~3金币 |
商店 |
游戏开始前可以在商店购买,能够抵消点击错误的次数 |
成就 |
百分成就、手残成就(分数为负数)、零失误成就、 |
重开 |
游戏结束后回到首页再来一次 |
比起UML类图,用铅笔和橡皮在纸上涂改才是最高效的纸上设计
最佳分数纸上设计
我们的《点点点》目前还没有完全引进各个层级,所以我们先完善层级绘图

由于有倒计时系统计分规则,所以游戏的最终分数只能在游戏结束时计算,我们需要在游戏结束时记录并比较最佳分数。
目前游戏结束的事件,是我们在KillEnemyCommand
中发送的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| namespace FrameWorkDesign.Example { public class KillEnemyCommand : AbstractCommand { protected override void OnExecute() { var gameModel = this.GetModel<IGameModel>(); gameModel.KillCount.Value++; if (gameModel.KillCount.Value == 9) { this.SendEvent<GameEndEvent>(); } } } }
|
我们可以监听GameEndEvent
,每次它发生时比较并记录最高分。

在后续的功能中,会有一些分数的计算规则,这些规则我们写在IScoreSystem一个系统中,

最佳分数实现
在FrameworkDesign——Example——Scripts里面新建Utility文件夹,在其中新建IStorage
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| using UnityEngine;
namespace FrameWorkDesign.Example { public interface IStorage : IUtility { void SaveInt(string key, int value); int LoadInt(string key, int defaultValue = 0); } public class PlayerPrefStorage : IStorage { public int LoadInt(string key, int defaultValue = 0) { return PlayerPrefs.GetInt(key,defaultValue); }
public void SaveInt(string key, int value) { PlayerPrefs.SetInt(key, value); } } }
|
修改PointGame
1 2 3 4 5 6 7 8 9 10 11
| namespace FrameWorkDesign.Example { public class PointGame : Architecture<PointGame> { protected override void Init() { RegisterModel<IGameModel>(new GameModel()); RegisterUtility<IStorage>(new PlayerPrefStorage()); } } }
|
我们在GameModel
里面的OnInit
方法中获取并调用IStorage
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| namespace FrameWorkDesign.Example { public interface IGameModel : IModel { } public class GameModel : AbstractModel , IGameModel { protected override void OnInit() { var storage = this.GetUtility<IStorage>(); BestScore.Value = storage.LoadInt(nameof(BestScore)); BestScore.OnValueChanged += score => storage.SaveInt(nameof(BestScore), score); } } }
|
实现IScoreSystem
在在FrameworkDesign——Example——Scripts里面新建System文件夹,在其中新建IScoreSystem
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| using UnityEngine;
namespace FrameWorkDesign.Example { public interface IScoreSystem : ISystem { } public class ScoreSystem : AbstractSystem, IScoreSystem { protected override void OnInit() { var gameModel = this.GetModel<IGameModel>();
this.RegisterEvent<GameEndEvent>(e => { gameModel.Score.Value = Random.Range(1, 50); Debug.Log("Score: "+gameModel.Score.Value); Debug.Log("BestScore: "+gameModel.BestScore.Value);
if (gameModel.Score.Value > gameModel.BestScore.Value) { gameModel.BestScore.Value = gameModel.Score.Value; Debug.Log("新纪录"); } }); } } }
|
别忘记在PointGame
内注册一下IScoreSystem
1 2 3 4 5 6 7 8 9 10 11 12
| namespace FrameWorkDesign.Example { public class PointGame : Architecture<PointGame> { protected override void Init() { RegisterSystem<IScoreSystem>(new ScoreSystem()); RegisterModel<IGameModel>(new GameModel()); RegisterUtility<IStorage>(new PlayerPrefStorage()); } } }
|
运行后,点击直至结束游戏时,刷新结果

总结
我们通过纸上分析设计,然后再去实现功能。
在纸上分析设计的时候,可以充分利用现有的代码,而不是不断去写新的轮子。
当项目特别复杂的时候,纸上分析设计是必须做的。
作为项目技术负责人的时候,纸上分析设计也是必须的。
当需要沟通实现思路的时候,拿一张纸,画上四个层级,然后画出交互方式和关键对象,就可以很清晰地传达想法,大大减少沟通成本。