1
- [ TOC]
2
-
3
1
# 普通英雄和超级英雄
4
2
5
3
## 需求
6
4
7
5
8
6
我们需要开发一个游戏,游戏中有两种人物:普通英雄和超级英雄,他们具有下面的行为:
7
+
9
8
- 普通英雄只能移动
10
9
- 超级英雄不仅能够移动,还能飞行
11
10
12
11
我们使用下面的方法来渲染:
12
+
13
13
- 使用Instance技术来一次性批量渲染所有的普通英雄
14
14
- 一个一个地渲染每个超级英雄
15
15
@@ -49,18 +49,22 @@ World是游戏世界,由多个普通英雄和多个超级英雄组成。World
49
49
50
50
首先,我们看下Client的代码;
51
51
然后,我们依次看下Client代码中前两个步骤的代码,它们包括:
52
+
52
53
- 创建WorldState的代码
53
54
- 创建场景的代码
54
55
55
56
然后,因为创建场景时操作了普通英雄和超级英雄,所以我们看下它们的代码,它们包括:
57
+
56
58
- 普通英雄移动的代码
57
59
- 超级英雄移动和飞行的代码
58
60
59
61
然后,我们依次看下Client代码中剩余的两个步骤的代码,它们包括:
62
+
60
63
- 初始化的代码
61
64
- 主循环的代码
62
65
63
66
然后,我们看下主循环的一帧中每个步骤的代码,它们包括:
67
+
64
68
- 主循环中更新的代码
65
69
- 主循环中渲染的代码
66
70
@@ -333,6 +337,7 @@ OneByOne渲染 SuperHero...
333
337
5.打印了WorldState
334
338
335
339
我们看下打印的WorldState:
340
+
336
341
- WorldState的normalHeroes中一共有两个普通英雄的数据,其中有一个普通英雄数据的position为[ 2,2,2] 而不是初始的[ 0,0,0] ,说明该普通英雄进行了移动操作;
337
342
- WorldState的superHeroes中一共有两个超级英雄的数据,其中有一个超级英雄数据的position为[ 6,6,6] ,说明该超级英雄进行了移动和飞行操作
338
343
@@ -405,17 +410,21 @@ World是游戏世界,由多个GameObject组成。World负责管理所有的Gam
405
410
406
411
首先,我们看下Client的代码;
407
412
然后,我们依次看下Client代码中前两个步骤的代码,它们包括:
413
+
408
414
- 创建WorldState的代码
409
415
- 创建场景的代码
410
416
411
417
然后,因为创建场景时操作了普通英雄和超级英雄,所以我们看下它们的代码,它们包括:
418
+
412
419
- 移动的相关代码
413
420
- 飞行的相关代码
414
421
415
422
然后,我们依次看下Client代码中剩余的两个步骤的代码,它们包括:
423
+
416
424
- 初始化和主循环的代码
417
425
418
426
然后,我们看下主循环的一帧中每个步骤的代码,它们包括:
427
+
419
428
- 主循环中更新的代码
420
429
- 主循环中渲染的代码
421
430
@@ -791,11 +800,13 @@ OneByOne渲染 SuperHero...
791
800
792
801
通过打印的数据,可以看到运行的步骤与之前一样
793
802
不同之处在于:
803
+
794
804
- 更新4个英雄现在变为更新4个positionComponent
795
805
- 打印的WorldState不一样
796
806
797
807
798
808
我们看下打印的WorldState:
809
+
799
810
- WorldState的gameObjects包括了4个gameObject的数据,其中有一个gameObject数据的positionComponent的position为[ 2,2,2] ,说明它进行了移动操作;
800
811
- 有一个gameObject数据的positionComponent的position为[ 6,6,6] ,说明它进行了移动和飞行操作
801
812
@@ -859,6 +870,7 @@ GameObject不再有数据和逻辑了,而只是一个全局唯一的id。组
859
870
860
871
861
872
- 增加System这一层,来实现行为的逻辑
873
+
862
874
一个System实现一个行为,比如这一层中的MoveSystem、FlySystem分别实现了移动和飞行的行为逻辑
863
875
864
876
@@ -867,6 +879,7 @@ GameObject不再有数据和逻辑了,而只是一个全局唯一的id。组
867
879
868
880
869
881
值得注意的是:
882
+
870
883
- GameObject和组件的数据被移到了Manager中,逻辑则被移到了Manager和System中。其中只操作自己数据的逻辑(如getPosition、setPosition)被移到了Manager中,其它逻辑(通常为行为逻辑,需要操作多种组件)被移到了System中
871
884
- 一种组件的Manager只对该种组件进行操作,而一个System可以对多种组件进行操作
872
885
@@ -890,6 +903,7 @@ World是游戏世界,虽然仍然实现了初始化和主循环的逻辑,不
890
903
891
904
我们看下System这一层:
892
905
有多个System,每个System实现一个行为逻辑。每个System的职责如下:
906
+
893
907
- CreateStateSystem实现创建WorldState的逻辑,创建的WorldState包括了所有的Manager的state数据;
894
908
- UpdateSystem实现更新所有人物的position的逻辑,具体是更新所有PositionComponent的position;
895
909
- MoveSystem实现一个人物的移动的逻辑,具体是根据挂载到该人物gameObject上的一个positionComponent和一个velocityComponent,更新该positionComponent的position;
@@ -974,21 +988,26 @@ Manager层:
974
988
975
989
首先,我们看下Client的代码;
976
990
然后,我们看下Client代码中第一步的代码:
991
+
977
992
- 创建WorldState的代码
978
993
979
994
然后,因为创建WorldState时会创建Data Oriented组件的Manager的state,其中的关健是创建各自的ArrayBuffer,所以我们看下创建它的代码
980
995
981
996
然后,我们看下Client代码中第二步的代码:
997
+
982
998
- 创建场景的代码
983
999
984
1000
然后,因为创建场景时操作了普通英雄和超级英雄,所以我们看下它们的代码,它们包括:
1001
+
985
1002
- 移动的相关代码
986
1003
- 飞行的相关代码
987
1004
988
1005
然后,我们依次看下Client代码中剩余的两个步骤的代码,它们包括:
1006
+
989
1007
- 初始化和主循环的代码
990
1008
991
1009
然后,我们看下主循环的一帧中每个步骤的代码,它们包括:
1010
+
992
1011
- 主循环中更新的代码
993
1012
- 主循环中渲染的代码
994
1013
@@ -1047,6 +1066,7 @@ export type state = {
1047
1066
` ` `
1048
1067
1049
1068
这是PositionComponentManager的state的类型定义,它的字段解释如下:
1069
+
1050
1070
- buffer字段保存了一个ArrayBuffer,它用来保存所有的positionComponent的数据。目前每个positionComponent的数据只有position,它的类型是三个float
1051
1071
- positions字段保存了ArrayBuffer的一个视图,通过它可以读写所有的positionComponent的position
1052
1072
- maxIndex字段是ArrayBuffer上最大的索引值,用于在创建一个positionComponent时生成它的index值
@@ -1468,6 +1488,7 @@ OneByOne渲染 SuperHero...
1468
1488
1469
1489
1470
1490
我们看下打印的WorldState:
1491
+
1471
1492
- WorldState的gameObjectManagetState的maxUID为4,说明创建了4个gameObject;
1472
1493
- WorldState的positionComponentManagerState的maxIndex为4,说明创建了4个positionComponent;
1473
1494
- WorldState的positionComponentManagerState的positions有3个连续的值是2、2、2,说明有一个positionComponent组件进行了移动操作;有另外3个连续的值是6、6、6,说明有另外一个positionComponent组件进行了移动操作和飞行操作;
@@ -1624,15 +1645,18 @@ Component+GameObject层:
1624
1645
首先,我们看下属于用户的抽象代码
1625
1646
然后,我们看下World的抽象代码
1626
1647
然后,我们看下System层的抽象代码,它们包括:
1648
+
1627
1649
- CreateStateSystem的抽象代码
1628
1650
- OtherSystem的抽象代码
1629
1651
1630
1652
然后,我们看下Manager层的抽象代码,它们包括:
1653
+
1631
1654
- GameObjectManager的抽象代码
1632
1655
- DataOrientedComponentManager的抽象代码
1633
1656
- OtherComponentManager的抽象代码
1634
1657
1635
1658
最后,我们看下Component+GameObject层的抽象代码,它们包括:
1659
+
1636
1660
- GameObject的抽象代码
1637
1661
- DataOrientedComponent的抽象代码
1638
1662
- OtherComponent的抽象代码
0 commit comments