.
This commit is contained in:
@@ -10,4 +10,9 @@
|
|||||||
<ProjectReference Include="..\Engine\Engine.csproj" />
|
<ProjectReference Include="..\Engine\Engine.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="asset\model\" />
|
||||||
|
<Folder Include="data\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 70 KiB |
210
DoomDeathmatch/asset/map/default/colliders.obj
Normal file
210
DoomDeathmatch/asset/map/default/colliders.obj
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
# Blender 4.2.3 LTS
|
||||||
|
# www.blender.org
|
||||||
|
o Cube.001
|
||||||
|
v -24.000000 -6.000000 -2.000000
|
||||||
|
v -24.000000 -6.000000 6.000000
|
||||||
|
v -24.000000 -4.000000 -2.000000
|
||||||
|
v -24.000000 -4.000000 6.000000
|
||||||
|
v 24.000000 -6.000000 -2.000000
|
||||||
|
v 24.000000 -6.000000 6.000000
|
||||||
|
v 24.000000 -4.000000 -2.000000
|
||||||
|
v 24.000000 -4.000000 6.000000
|
||||||
|
s 0
|
||||||
|
f 1 2 4 3
|
||||||
|
f 3 4 8 7
|
||||||
|
f 7 8 6 5
|
||||||
|
f 5 6 2 1
|
||||||
|
f 3 7 5 1
|
||||||
|
f 8 4 2 6
|
||||||
|
o Cube.002
|
||||||
|
v -24.000000 4.000000 -2.000000
|
||||||
|
v -24.000000 4.000000 6.000000
|
||||||
|
v -24.000000 6.000000 -2.000000
|
||||||
|
v -24.000000 6.000000 6.000000
|
||||||
|
v -8.000000 4.000000 -2.000000
|
||||||
|
v -8.000000 4.000000 6.000000
|
||||||
|
v -8.000000 6.000000 -2.000000
|
||||||
|
v -8.000000 6.000000 6.000000
|
||||||
|
s 0
|
||||||
|
f 9 10 12 11
|
||||||
|
f 11 12 16 15
|
||||||
|
f 15 16 14 13
|
||||||
|
f 13 14 10 9
|
||||||
|
f 11 15 13 9
|
||||||
|
f 16 12 10 14
|
||||||
|
o Cube.003
|
||||||
|
v -24.000000 -6.000000 -2.000000
|
||||||
|
v -24.000000 -6.000000 6.000000
|
||||||
|
v -26.000000 -6.000000 -2.000000
|
||||||
|
v -26.000000 -6.000000 6.000000
|
||||||
|
v -24.000000 6.000000 -2.000000
|
||||||
|
v -24.000000 6.000000 6.000000
|
||||||
|
v -26.000000 6.000000 -2.000000
|
||||||
|
v -26.000000 6.000000 6.000000
|
||||||
|
s 0
|
||||||
|
f 17 18 20 19
|
||||||
|
f 19 20 24 23
|
||||||
|
f 23 24 22 21
|
||||||
|
f 21 22 18 17
|
||||||
|
f 19 23 21 17
|
||||||
|
f 24 20 18 22
|
||||||
|
o Cube.004
|
||||||
|
v -8.000000 6.000000 -2.000000
|
||||||
|
v -8.000000 6.000000 6.000000
|
||||||
|
v -10.000000 6.000000 -2.000000
|
||||||
|
v -10.000000 6.000000 6.000000
|
||||||
|
v -8.000000 45.031250 -2.000000
|
||||||
|
v -8.000000 45.031250 6.000000
|
||||||
|
v -10.000000 45.031250 -2.000000
|
||||||
|
v -10.000000 45.031250 6.000000
|
||||||
|
s 0
|
||||||
|
f 25 26 28 27
|
||||||
|
f 27 28 32 31
|
||||||
|
f 31 32 30 29
|
||||||
|
f 29 30 26 25
|
||||||
|
f 27 31 29 25
|
||||||
|
f 32 28 26 30
|
||||||
|
o Cube.005
|
||||||
|
v 50.000000 47.031250 -2.000000
|
||||||
|
v 50.000000 47.031250 6.000000
|
||||||
|
v 50.000000 45.031250 -2.000000
|
||||||
|
v 50.000000 45.031250 6.000000
|
||||||
|
v -10.000002 47.031250 -2.000000
|
||||||
|
v -10.000002 47.031250 6.000000
|
||||||
|
v -10.000002 45.031250 -2.000000
|
||||||
|
v -10.000002 45.031250 6.000000
|
||||||
|
s 0
|
||||||
|
f 33 34 36 35
|
||||||
|
f 35 36 40 39
|
||||||
|
f 39 40 38 37
|
||||||
|
f 37 38 34 33
|
||||||
|
f 35 39 37 33
|
||||||
|
f 40 36 34 38
|
||||||
|
o Cube.006
|
||||||
|
v 12.450001 4.000000 -2.000000
|
||||||
|
v 12.450001 4.000000 6.000000
|
||||||
|
v 8.000000 4.000000 -2.000000
|
||||||
|
v 8.000000 4.000000 6.000000
|
||||||
|
v 12.450001 8.031248 -2.000000
|
||||||
|
v 12.450001 8.031248 6.000000
|
||||||
|
v 8.000000 8.031248 -2.000000
|
||||||
|
v 8.000000 8.031248 6.000000
|
||||||
|
s 0
|
||||||
|
f 41 42 44 43
|
||||||
|
f 43 44 48 47
|
||||||
|
f 47 48 46 45
|
||||||
|
f 45 46 42 41
|
||||||
|
f 43 47 45 41
|
||||||
|
f 48 44 42 46
|
||||||
|
o Cube.007
|
||||||
|
v 11.200001 8.031250 -2.000000
|
||||||
|
v 11.200001 8.031250 6.000000
|
||||||
|
v 8.000000 8.031248 -2.000000
|
||||||
|
v 8.000000 8.031248 6.000000
|
||||||
|
v 11.200001 37.031250 -2.000000
|
||||||
|
v 11.200001 37.031250 6.000000
|
||||||
|
v 8.000000 37.031250 -2.000000
|
||||||
|
v 8.000000 37.031250 6.000000
|
||||||
|
s 0
|
||||||
|
f 49 50 52 51
|
||||||
|
f 51 52 56 55
|
||||||
|
f 55 56 54 53
|
||||||
|
f 53 54 50 49
|
||||||
|
f 51 55 53 49
|
||||||
|
f 56 52 50 54
|
||||||
|
o Cube.008
|
||||||
|
v 26.200001 27.031250 -2.000000
|
||||||
|
v 26.200001 27.031250 6.000000
|
||||||
|
v 11.200001 27.031250 -2.000000
|
||||||
|
v 11.200001 27.031250 6.000000
|
||||||
|
v 26.200001 37.031250 -2.000000
|
||||||
|
v 26.200001 37.031250 6.000000
|
||||||
|
v 11.200001 37.031250 -2.000000
|
||||||
|
v 11.200001 37.031250 6.000000
|
||||||
|
s 0
|
||||||
|
f 57 58 60 59
|
||||||
|
f 59 60 64 63
|
||||||
|
f 63 64 62 61
|
||||||
|
f 61 62 58 57
|
||||||
|
f 59 63 61 57
|
||||||
|
f 64 60 58 62
|
||||||
|
o Cube.009
|
||||||
|
v 26.000000 -6.000000 -2.000000
|
||||||
|
v 26.000000 -6.000000 6.000000
|
||||||
|
v 24.000000 -6.000000 -2.000000
|
||||||
|
v 24.000000 -6.000000 6.000000
|
||||||
|
v 26.000000 4.000000 -2.000000
|
||||||
|
v 26.000000 4.000000 6.000000
|
||||||
|
v 24.000000 4.000000 -2.000000
|
||||||
|
v 24.000000 4.000000 6.000000
|
||||||
|
s 0
|
||||||
|
f 65 66 68 67
|
||||||
|
f 67 68 72 71
|
||||||
|
f 71 72 70 69
|
||||||
|
f 69 70 66 65
|
||||||
|
f 67 71 69 65
|
||||||
|
f 72 68 66 70
|
||||||
|
o Cube.010
|
||||||
|
v 31.799999 4.000002 -2.000000
|
||||||
|
v 31.799999 4.000002 6.000000
|
||||||
|
v 17.450001 4.000000 -2.000000
|
||||||
|
v 17.450001 4.000000 6.000000
|
||||||
|
v 31.799999 8.031251 -2.000000
|
||||||
|
v 31.799999 8.031251 6.000000
|
||||||
|
v 17.450001 8.031249 -2.000000
|
||||||
|
v 17.450001 8.031249 6.000000
|
||||||
|
s 0
|
||||||
|
f 73 74 76 75
|
||||||
|
f 75 76 80 79
|
||||||
|
f 79 80 78 77
|
||||||
|
f 77 78 74 73
|
||||||
|
f 75 79 77 73
|
||||||
|
f 80 76 74 78
|
||||||
|
o Cube.011
|
||||||
|
v 33.799999 6.000000 -2.000000
|
||||||
|
v 33.799999 6.000000 6.000000
|
||||||
|
v 31.799999 6.000000 -2.000000
|
||||||
|
v 31.799999 6.000000 6.000000
|
||||||
|
v 33.799999 37.031250 -2.000000
|
||||||
|
v 33.799999 37.031250 6.000000
|
||||||
|
v 31.799999 37.031250 -2.000000
|
||||||
|
v 31.799999 37.031250 6.000000
|
||||||
|
s 0
|
||||||
|
f 81 82 84 83
|
||||||
|
f 83 84 88 87
|
||||||
|
f 87 88 86 85
|
||||||
|
f 85 86 82 81
|
||||||
|
f 83 87 85 81
|
||||||
|
f 88 84 82 86
|
||||||
|
o Cube.012
|
||||||
|
v 33.799999 35.031250 -2.000000
|
||||||
|
v 33.799999 35.031250 6.000000
|
||||||
|
v 33.799999 37.031250 -2.000000
|
||||||
|
v 33.799999 37.031250 6.000000
|
||||||
|
v 50.000000 35.031250 -2.000000
|
||||||
|
v 50.000000 35.031250 6.000000
|
||||||
|
v 50.000000 37.031250 -2.000000
|
||||||
|
v 50.000000 37.031250 6.000000
|
||||||
|
s 0
|
||||||
|
f 89 90 92 91
|
||||||
|
f 91 92 96 95
|
||||||
|
f 95 96 94 93
|
||||||
|
f 93 94 90 89
|
||||||
|
f 91 95 93 89
|
||||||
|
f 96 92 90 94
|
||||||
|
o Cube.013
|
||||||
|
v 52.000000 35.031250 -2.000000
|
||||||
|
v 52.000000 35.031250 6.000000
|
||||||
|
v 50.000000 35.031250 -2.000000
|
||||||
|
v 50.000000 35.031250 6.000000
|
||||||
|
v 52.000000 47.031250 -2.000000
|
||||||
|
v 52.000000 47.031250 6.000000
|
||||||
|
v 50.000000 47.031250 -2.000000
|
||||||
|
v 50.000000 47.031250 6.000000
|
||||||
|
s 0
|
||||||
|
f 97 98 100 99
|
||||||
|
f 99 100 104 103
|
||||||
|
f 103 104 102 101
|
||||||
|
f 101 102 98 97
|
||||||
|
f 99 103 101 97
|
||||||
|
f 104 100 98 102
|
||||||
238
DoomDeathmatch/asset/map/default/mesh.obj
Normal file
238
DoomDeathmatch/asset/map/default/mesh.obj
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
# Blender 4.2.3 LTS
|
||||||
|
# www.blender.org
|
||||||
|
o Plane
|
||||||
|
v -24.000000 -4.000000 0.000000
|
||||||
|
v 24.000000 -4.000000 0.000000
|
||||||
|
v -24.000000 4.000000 0.000000
|
||||||
|
v 24.000000 4.000000 0.000000
|
||||||
|
v -8.000000 -4.000000 0.000000
|
||||||
|
v 8.000000 -4.000000 0.000000
|
||||||
|
v 8.000000 4.000000 0.000000
|
||||||
|
v -8.000000 4.000000 0.000000
|
||||||
|
v 8.000000 37.031250 0.000000
|
||||||
|
v -8.000000 37.031250 0.000000
|
||||||
|
v 8.000000 45.031250 0.000000
|
||||||
|
v -8.000000 45.031250 0.000000
|
||||||
|
v 50.000000 37.031250 0.000000
|
||||||
|
v 50.000000 45.031250 0.000000
|
||||||
|
v 26.200001 37.031250 0.000000
|
||||||
|
v 31.799999 37.031250 0.000000
|
||||||
|
v 31.799999 45.031250 0.000000
|
||||||
|
v 26.200001 45.031250 0.000000
|
||||||
|
v 26.200001 27.031250 0.000000
|
||||||
|
v 31.799999 27.031250 0.000000
|
||||||
|
v 26.200001 8.031250 0.000000
|
||||||
|
v 31.799999 8.031250 0.000000
|
||||||
|
v 11.200001 27.031250 0.000000
|
||||||
|
v 11.200001 8.031250 0.000000
|
||||||
|
v 17.450001 27.031250 0.000000
|
||||||
|
v 12.450001 27.031250 0.000000
|
||||||
|
v 12.450001 8.031250 0.000000
|
||||||
|
v 17.450001 8.031250 0.000000
|
||||||
|
v 12.450001 4.000000 0.000000
|
||||||
|
v 17.450001 4.000000 0.000000
|
||||||
|
v 12.450001 -4.000000 0.000000
|
||||||
|
v 17.450001 -4.000000 0.000000
|
||||||
|
v -24.000000 -4.000000 4.000000
|
||||||
|
v 24.000000 -4.000000 4.000000
|
||||||
|
v -24.000000 4.000000 4.000000
|
||||||
|
v 24.000000 4.000000 4.000000
|
||||||
|
v -8.000000 -4.000000 4.000000
|
||||||
|
v 8.000000 -4.000000 4.000000
|
||||||
|
v 8.000000 4.000000 4.000000
|
||||||
|
v -8.000000 4.000000 4.000000
|
||||||
|
v 8.000000 37.031250 4.000000
|
||||||
|
v -8.000000 37.031250 4.000000
|
||||||
|
v 8.000000 45.031250 4.000000
|
||||||
|
v -8.000000 45.031250 4.000000
|
||||||
|
v 50.000000 37.031250 4.000000
|
||||||
|
v 50.000000 45.031250 4.000000
|
||||||
|
v 26.200001 37.031250 4.000000
|
||||||
|
v 31.799999 37.031250 4.000000
|
||||||
|
v 31.799999 45.031250 4.000000
|
||||||
|
v 26.200001 45.031250 4.000000
|
||||||
|
v 26.200001 27.031250 4.000000
|
||||||
|
v 31.799999 27.031250 4.000000
|
||||||
|
v 26.200001 8.031250 4.000000
|
||||||
|
v 31.799999 8.031250 4.000000
|
||||||
|
v 11.200001 27.031250 4.000000
|
||||||
|
v 11.200001 8.031250 4.000000
|
||||||
|
v 17.450001 27.031250 4.000000
|
||||||
|
v 12.450001 27.031250 4.000000
|
||||||
|
v 12.450001 8.031250 4.000000
|
||||||
|
v 17.450001 8.031250 4.000000
|
||||||
|
v 12.450001 4.000000 4.000000
|
||||||
|
v 17.450001 4.000000 4.000000
|
||||||
|
v 12.450001 -4.000000 4.000000
|
||||||
|
v 17.450001 -4.000000 4.000000
|
||||||
|
vn -0.0000 -0.0000 -1.0000
|
||||||
|
vn -0.0000 -0.0000 1.0000
|
||||||
|
vn 1.0000 -0.0000 -0.0000
|
||||||
|
vn -1.0000 -0.0000 -0.0000
|
||||||
|
vn -0.0000 1.0000 -0.0000
|
||||||
|
vn -0.0000 -1.0000 -0.0000
|
||||||
|
vt 0.757888 0.095816
|
||||||
|
vt 0.900966 0.310434
|
||||||
|
vt 0.757888 0.310434
|
||||||
|
vt 0.829427 0.095816
|
||||||
|
vt 0.829427 0.310434
|
||||||
|
vt 0.900966 0.095816
|
||||||
|
vt 0.871139 0.898505
|
||||||
|
vt 0.787715 0.773370
|
||||||
|
vt 0.829427 0.773370
|
||||||
|
vt 0.787715 0.898505
|
||||||
|
vt 0.871139 0.773370
|
||||||
|
vt 0.829427 0.898505
|
||||||
|
vt 0.123250 0.042329
|
||||||
|
vt 0.123250 0.985848
|
||||||
|
vt 0.074426 0.042329
|
||||||
|
vt 0.074426 0.985846
|
||||||
|
vt 0.178788 0.042329
|
||||||
|
vt 0.178788 0.985846
|
||||||
|
vt 0.123250 0.985846
|
||||||
|
vt 0.025602 0.042329
|
||||||
|
vt 0.025602 0.985848
|
||||||
|
vt 0.195876 0.042329
|
||||||
|
vt 0.195876 0.985848
|
||||||
|
vt 0.136830 0.042329
|
||||||
|
vt 0.136830 0.985848
|
||||||
|
vt 0.152087 0.042329
|
||||||
|
vt 0.172074 0.985848
|
||||||
|
vt 0.172074 0.042329
|
||||||
|
vt 0.178788 0.985848
|
||||||
|
vt 0.152087 0.985848
|
||||||
|
vt 0.251414 0.042329
|
||||||
|
vt 0.251414 0.985846
|
||||||
|
vt 0.074426 0.985848
|
||||||
|
vt 0.195876 0.985846
|
||||||
|
vt 0.133015 0.042329
|
||||||
|
vt 0.133015 0.985848
|
||||||
|
s 0
|
||||||
|
f 4/1/1 32/2/1 30/2/1
|
||||||
|
f 3/3/1 5/4/1 1/1/1
|
||||||
|
f 8/5/1 6/6/1 5/4/1
|
||||||
|
f 10/5/1 7/2/1 8/5/1
|
||||||
|
f 12/5/1 9/2/1 10/5/1
|
||||||
|
f 14/2/1 16/2/1 17/2/1
|
||||||
|
f 18/2/1 9/2/1 11/2/1
|
||||||
|
f 17/2/1 15/2/1 18/2/1
|
||||||
|
f 20/2/1 15/2/1 16/2/1
|
||||||
|
f 22/2/1 19/2/1 20/2/1
|
||||||
|
f 24/2/1 26/2/1 27/2/1
|
||||||
|
f 28/2/1 19/2/1 21/2/1
|
||||||
|
f 27/2/1 25/2/1 28/2/1
|
||||||
|
f 30/2/1 27/2/1 28/2/1
|
||||||
|
f 32/2/1 29/2/1 30/2/1
|
||||||
|
f 7/2/1 31/2/1 6/6/1
|
||||||
|
f 64/7/2 36/8/2 62/7/2
|
||||||
|
f 37/9/2 35/10/2 33/8/2
|
||||||
|
f 38/11/2 40/12/2 37/9/2
|
||||||
|
f 39/7/2 42/12/2 40/12/2
|
||||||
|
f 41/7/2 44/12/2 42/12/2
|
||||||
|
f 48/7/2 46/7/2 49/7/2
|
||||||
|
f 41/7/2 50/7/2 43/7/2
|
||||||
|
f 47/7/2 49/7/2 50/7/2
|
||||||
|
f 47/7/2 52/7/2 48/7/2
|
||||||
|
f 51/7/2 54/7/2 52/7/2
|
||||||
|
f 58/7/2 56/7/2 59/7/2
|
||||||
|
f 51/7/2 60/7/2 53/7/2
|
||||||
|
f 57/7/2 59/7/2 60/7/2
|
||||||
|
f 59/7/2 62/7/2 60/7/2
|
||||||
|
f 61/7/2 64/7/2 62/7/2
|
||||||
|
f 63/7/2 39/7/2 38/11/2
|
||||||
|
f 9/13/3 39/14/3 7/13/3
|
||||||
|
f 8/15/4 42/16/4 10/15/4
|
||||||
|
f 19/17/4 47/18/4 15/17/4
|
||||||
|
f 12/15/5 43/19/5 11/13/5
|
||||||
|
f 1/20/4 35/21/4 3/20/4
|
||||||
|
f 16/22/3 52/23/3 20/22/3
|
||||||
|
f 29/24/4 59/25/4 27/24/4
|
||||||
|
f 30/26/5 36/27/5 4/28/5
|
||||||
|
f 22/22/6 53/29/6 21/17/6
|
||||||
|
f 10/15/4 44/16/4 12/15/4
|
||||||
|
f 28/26/3 62/30/3 30/26/3
|
||||||
|
f 4/28/3 34/27/3 2/28/3
|
||||||
|
f 14/31/3 45/32/3 13/31/3
|
||||||
|
f 32/26/6 63/25/6 31/24/6
|
||||||
|
f 3/20/5 40/33/5 8/15/5
|
||||||
|
f 20/22/3 54/23/3 22/22/3
|
||||||
|
f 13/31/6 48/34/6 16/22/6
|
||||||
|
f 5/15/6 33/21/6 1/20/6
|
||||||
|
f 24/35/4 55/36/4 23/35/4
|
||||||
|
f 11/13/5 50/18/5 18/17/5
|
||||||
|
f 6/13/6 37/33/6 5/15/6
|
||||||
|
f 23/35/5 58/25/5 26/24/5
|
||||||
|
f 15/17/6 41/19/6 9/13/6
|
||||||
|
f 31/24/6 38/14/6 6/13/6
|
||||||
|
f 2/28/6 64/30/6 32/26/6
|
||||||
|
f 21/17/6 60/30/6 28/26/6
|
||||||
|
f 7/13/5 61/25/5 29/24/5
|
||||||
|
f 25/26/5 51/29/5 19/17/5
|
||||||
|
f 17/22/5 46/32/5 14/31/5
|
||||||
|
f 26/24/5 57/30/5 25/26/5
|
||||||
|
f 18/17/5 49/34/5 17/22/5
|
||||||
|
f 27/24/6 56/36/6 24/35/6
|
||||||
|
f 4/1/1 2/1/1 32/2/1
|
||||||
|
f 3/3/1 8/5/1 5/4/1
|
||||||
|
f 8/5/1 7/2/1 6/6/1
|
||||||
|
f 10/5/1 9/2/1 7/2/1
|
||||||
|
f 12/5/1 11/2/1 9/2/1
|
||||||
|
f 14/2/1 13/2/1 16/2/1
|
||||||
|
f 18/2/1 15/2/1 9/2/1
|
||||||
|
f 17/2/1 16/2/1 15/2/1
|
||||||
|
f 20/2/1 19/2/1 15/2/1
|
||||||
|
f 22/2/1 21/2/1 19/2/1
|
||||||
|
f 24/2/1 23/2/1 26/2/1
|
||||||
|
f 28/2/1 25/2/1 19/2/1
|
||||||
|
f 27/2/1 26/2/1 25/2/1
|
||||||
|
f 30/2/1 29/2/1 27/2/1
|
||||||
|
f 32/2/1 31/2/1 29/2/1
|
||||||
|
f 7/2/1 29/2/1 31/2/1
|
||||||
|
f 64/7/2 34/8/2 36/8/2
|
||||||
|
f 37/9/2 40/12/2 35/10/2
|
||||||
|
f 38/11/2 39/7/2 40/12/2
|
||||||
|
f 39/7/2 41/7/2 42/12/2
|
||||||
|
f 41/7/2 43/7/2 44/12/2
|
||||||
|
f 48/7/2 45/7/2 46/7/2
|
||||||
|
f 41/7/2 47/7/2 50/7/2
|
||||||
|
f 47/7/2 48/7/2 49/7/2
|
||||||
|
f 47/7/2 51/7/2 52/7/2
|
||||||
|
f 51/7/2 53/7/2 54/7/2
|
||||||
|
f 58/7/2 55/7/2 56/7/2
|
||||||
|
f 51/7/2 57/7/2 60/7/2
|
||||||
|
f 57/7/2 58/7/2 59/7/2
|
||||||
|
f 59/7/2 61/7/2 62/7/2
|
||||||
|
f 61/7/2 63/7/2 64/7/2
|
||||||
|
f 63/7/2 61/7/2 39/7/2
|
||||||
|
f 9/13/3 41/19/3 39/14/3
|
||||||
|
f 8/15/4 40/33/4 42/16/4
|
||||||
|
f 19/17/4 51/29/4 47/18/4
|
||||||
|
f 12/15/5 44/16/5 43/19/5
|
||||||
|
f 1/20/4 33/21/4 35/21/4
|
||||||
|
f 16/22/3 48/34/3 52/23/3
|
||||||
|
f 29/24/4 61/25/4 59/25/4
|
||||||
|
f 30/26/5 62/30/5 36/27/5
|
||||||
|
f 22/22/6 54/23/6 53/29/6
|
||||||
|
f 10/15/4 42/16/4 44/16/4
|
||||||
|
f 28/26/3 60/30/3 62/30/3
|
||||||
|
f 4/28/3 36/27/3 34/27/3
|
||||||
|
f 14/31/3 46/32/3 45/32/3
|
||||||
|
f 32/26/6 64/30/6 63/25/6
|
||||||
|
f 3/20/5 35/21/5 40/33/5
|
||||||
|
f 20/22/3 52/23/3 54/23/3
|
||||||
|
f 13/31/6 45/32/6 48/34/6
|
||||||
|
f 5/15/6 37/33/6 33/21/6
|
||||||
|
f 24/35/4 56/36/4 55/36/4
|
||||||
|
f 11/13/5 43/19/5 50/18/5
|
||||||
|
f 6/13/6 38/14/6 37/33/6
|
||||||
|
f 23/35/5 55/36/5 58/25/5
|
||||||
|
f 15/17/6 47/18/6 41/19/6
|
||||||
|
f 31/24/6 63/25/6 38/14/6
|
||||||
|
f 2/28/6 34/27/6 64/30/6
|
||||||
|
f 21/17/6 53/29/6 60/30/6
|
||||||
|
f 7/13/5 39/14/5 61/25/5
|
||||||
|
f 25/26/5 57/30/5 51/29/5
|
||||||
|
f 17/22/5 49/34/5 46/32/5
|
||||||
|
f 26/24/5 58/25/5 57/30/5
|
||||||
|
f 18/17/5 50/18/5 49/34/5
|
||||||
|
f 27/24/6 59/25/6 56/36/6
|
||||||
10
DoomDeathmatch/asset/map/default/monster_spawners.obj
Normal file
10
DoomDeathmatch/asset/map/default/monster_spawners.obj
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Blender 4.2.3 LTS
|
||||||
|
# www.blender.org
|
||||||
|
o Spawners
|
||||||
|
v -21.000000 0.000000 0.000000
|
||||||
|
v -5.000000 41.000000 0.000000
|
||||||
|
v 48.000000 41.000000 0.000000
|
||||||
|
v 20.000000 0.000000 0.000000
|
||||||
|
v 15.000000 23.000000 0.000000
|
||||||
|
s 0
|
||||||
|
f 5 3 4 1 2
|
||||||
BIN
DoomDeathmatch/asset/map/default/texture.png
Normal file
BIN
DoomDeathmatch/asset/map/default/texture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
12
DoomDeathmatch/asset/map/default/valuable_spawners.obj
Normal file
12
DoomDeathmatch/asset/map/default/valuable_spawners.obj
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Blender 4.2.3 LTS
|
||||||
|
# www.blender.org
|
||||||
|
o Valuables
|
||||||
|
v 0.000000 0.000000 0.000000
|
||||||
|
v 25.000000 40.000000 0.000000
|
||||||
|
v 0.000000 40.000000 0.000000
|
||||||
|
v 0.000000 20.000000 0.000000
|
||||||
|
v 21.000000 17.000000 0.000000
|
||||||
|
v 15.000000 0.000000 0.000000
|
||||||
|
v -16.000000 0.000000 0.000000
|
||||||
|
s 0
|
||||||
|
f 3 2 5 6 1 7 4
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
# Blender 4.2.3 LTS
|
|
||||||
# www.blender.org
|
|
||||||
o Plane
|
|
||||||
v -14.316629 -4.684887 0.000000
|
|
||||||
v 14.316629 -4.684887 0.000000
|
|
||||||
v -14.316629 4.684887 0.000000
|
|
||||||
v 14.316629 4.684887 0.000000
|
|
||||||
v 6.822107 -4.684887 0.000000
|
|
||||||
v 6.822107 4.684887 0.000000
|
|
||||||
v 14.316629 33.607601 0.000000
|
|
||||||
v 6.822107 33.607601 0.000000
|
|
||||||
v 14.316629 25.280016 0.000000
|
|
||||||
v 6.822107 25.280016 0.000000
|
|
||||||
v -6.847844 33.607601 0.000000
|
|
||||||
v -6.847844 25.280016 0.000000
|
|
||||||
v -25.254845 24.277735 0.000000
|
|
||||||
v -18.173466 20.114567 0.000000
|
|
||||||
v -26.336294 7.837210 0.000000
|
|
||||||
v -19.225933 10.395360 0.000000
|
|
||||||
v -14.316629 -4.684887 3.000000
|
|
||||||
v 14.316629 -4.684887 3.000000
|
|
||||||
v 14.316629 4.684887 3.000000
|
|
||||||
v 6.822107 -4.684887 3.000000
|
|
||||||
v 14.316629 33.607601 3.000000
|
|
||||||
v 6.822107 33.607601 3.000000
|
|
||||||
v 14.316629 25.280016 3.000000
|
|
||||||
v -6.847844 33.607601 3.000000
|
|
||||||
v -25.254845 24.277735 3.000000
|
|
||||||
v -26.336294 7.837210 3.000000
|
|
||||||
v -14.316629 4.684887 3.000000
|
|
||||||
v 6.822107 4.684887 3.000000
|
|
||||||
v 6.822107 25.280016 3.000000
|
|
||||||
v -6.847844 25.280016 3.000000
|
|
||||||
v -18.173466 20.114567 3.000000
|
|
||||||
v -19.225933 10.395360 3.000000
|
|
||||||
vn -0.0000 -0.0000 1.0000
|
|
||||||
vn -1.0000 -0.0000 -0.0000
|
|
||||||
vn 0.7214 0.6925 -0.0000
|
|
||||||
vn 0.9978 -0.0656 -0.0000
|
|
||||||
vn 0.4521 -0.8920 -0.0000
|
|
||||||
vn -0.0000 -1.0000 -0.0000
|
|
||||||
vn -0.0000 1.0000 -0.0000
|
|
||||||
vn -0.7583 -0.6519 -0.0000
|
|
||||||
vn 1.0000 -0.0000 -0.0000
|
|
||||||
vn -0.4150 0.9098 -0.0000
|
|
||||||
vn -0.9942 0.1077 -0.0000
|
|
||||||
vt 1.000000 0.000000
|
|
||||||
vt 0.738258 1.000000
|
|
||||||
vt 0.738258 0.000000
|
|
||||||
vt 0.000000 1.000000
|
|
||||||
vt 0.000000 0.000000
|
|
||||||
vt 1.000000 1.000000
|
|
||||||
s 0
|
|
||||||
f 2/1/1 6/2/1 5/3/1
|
|
||||||
f 5/3/1 3/4/1 1/5/1
|
|
||||||
f 9/6/1 8/2/1 10/2/1
|
|
||||||
f 4/6/1 10/2/1 6/2/1
|
|
||||||
f 8/2/1 12/2/1 10/2/1
|
|
||||||
f 11/2/1 14/2/1 12/2/1
|
|
||||||
f 14/2/1 15/2/1 16/2/1
|
|
||||||
f 3/4/1 15/2/1 1/5/1
|
|
||||||
f 2/1/2 19/6/2 4/6/2
|
|
||||||
f 15/2/3 17/5/3 1/5/3
|
|
||||||
f 13/2/4 26/2/4 15/2/4
|
|
||||||
f 4/6/2 23/6/2 9/6/2
|
|
||||||
f 11/2/5 25/2/5 13/2/5
|
|
||||||
f 7/6/6 22/2/6 8/2/6
|
|
||||||
f 8/2/6 24/2/6 11/2/6
|
|
||||||
f 1/5/7 20/3/7 5/3/7
|
|
||||||
f 5/3/7 18/1/7 2/1/7
|
|
||||||
f 9/6/2 21/6/2 7/6/2
|
|
||||||
f 12/2/7 29/2/7 10/2/7
|
|
||||||
f 3/4/8 32/2/8 16/2/8
|
|
||||||
f 10/2/9 28/2/9 6/2/9
|
|
||||||
f 14/2/10 30/2/10 12/2/10
|
|
||||||
f 6/2/6 27/4/6 3/4/6
|
|
||||||
f 16/2/11 31/2/11 14/2/11
|
|
||||||
f 2/1/1 4/6/1 6/2/1
|
|
||||||
f 5/3/1 6/2/1 3/4/1
|
|
||||||
f 9/6/1 7/6/1 8/2/1
|
|
||||||
f 4/6/1 9/6/1 10/2/1
|
|
||||||
f 8/2/1 11/2/1 12/2/1
|
|
||||||
f 11/2/1 13/2/1 14/2/1
|
|
||||||
f 14/2/1 13/2/1 15/2/1
|
|
||||||
f 3/4/1 16/2/1 15/2/1
|
|
||||||
f 2/1/2 18/1/2 19/6/2
|
|
||||||
f 15/2/3 26/2/3 17/5/3
|
|
||||||
f 13/2/4 25/2/4 26/2/4
|
|
||||||
f 4/6/2 19/6/2 23/6/2
|
|
||||||
f 11/2/5 24/2/5 25/2/5
|
|
||||||
f 7/6/6 21/6/6 22/2/6
|
|
||||||
f 8/2/6 22/2/6 24/2/6
|
|
||||||
f 1/5/7 17/5/7 20/3/7
|
|
||||||
f 5/3/7 20/3/7 18/1/7
|
|
||||||
f 9/6/2 23/6/2 21/6/2
|
|
||||||
f 12/2/7 30/2/7 29/2/7
|
|
||||||
f 3/4/8 27/4/8 32/2/8
|
|
||||||
f 10/2/9 29/2/9 28/2/9
|
|
||||||
f 14/2/10 31/2/10 30/2/10
|
|
||||||
f 6/2/6 28/2/6 27/4/6
|
|
||||||
f 16/2/11 32/2/11 31/2/11
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
|||||||
# Blender 4.2.3 LTS
|
|
||||||
# www.blender.org
|
|
||||||
o Cube
|
|
||||||
v -1.000000 -1.000000 1.000000
|
|
||||||
v -1.000000 1.000000 1.000000
|
|
||||||
v -1.000000 -1.000000 -1.000000
|
|
||||||
v -1.000000 1.000000 -1.000000
|
|
||||||
v 1.000000 -1.000000 1.000000
|
|
||||||
v 1.000000 1.000000 1.000000
|
|
||||||
v 1.000000 -1.000000 -1.000000
|
|
||||||
v 1.000000 1.000000 -1.000000
|
|
||||||
vn -1.0000 -0.0000 -0.0000
|
|
||||||
vn -0.0000 -0.0000 -1.0000
|
|
||||||
vn 1.0000 -0.0000 -0.0000
|
|
||||||
vn -0.0000 -0.0000 1.0000
|
|
||||||
vn -0.0000 -1.0000 -0.0000
|
|
||||||
vn -0.0000 1.0000 -0.0000
|
|
||||||
vt 0.625000 0.000000
|
|
||||||
vt 0.375000 0.250000
|
|
||||||
vt 0.375000 0.000000
|
|
||||||
vt 0.625000 0.250000
|
|
||||||
vt 0.375000 0.500000
|
|
||||||
vt 0.625000 0.500000
|
|
||||||
vt 0.375000 0.750000
|
|
||||||
vt 0.625000 0.750000
|
|
||||||
vt 0.375000 1.000000
|
|
||||||
vt 0.125000 0.750000
|
|
||||||
vt 0.125000 0.500000
|
|
||||||
vt 0.875000 0.500000
|
|
||||||
vt 0.625000 1.000000
|
|
||||||
vt 0.875000 0.750000
|
|
||||||
s 0
|
|
||||||
f 2/1/1 3/2/1 1/3/1
|
|
||||||
f 4/4/2 7/5/2 3/2/2
|
|
||||||
f 8/6/3 5/7/3 7/5/3
|
|
||||||
f 6/8/4 1/9/4 5/7/4
|
|
||||||
f 7/5/5 1/10/5 3/11/5
|
|
||||||
f 4/12/6 6/8/6 8/6/6
|
|
||||||
f 2/1/1 4/4/1 3/2/1
|
|
||||||
f 4/4/2 8/6/2 7/5/2
|
|
||||||
f 8/6/3 6/8/3 5/7/3
|
|
||||||
f 6/8/4 2/13/4 1/9/4
|
|
||||||
f 7/5/5 5/7/5 1/10/5
|
|
||||||
f 4/12/6 2/14/6 6/8/6
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# Blender 4.2.3 LTS
|
|
||||||
# www.blender.org
|
|
||||||
o Cube
|
|
||||||
v -1.000000 -1.000000 1.000000
|
|
||||||
v -1.000000 1.000000 1.000000
|
|
||||||
v -1.000000 -1.000000 -1.000000
|
|
||||||
v -1.000000 1.000000 -1.000000
|
|
||||||
v 1.000000 -1.000000 1.000000
|
|
||||||
v 1.000000 1.000000 1.000000
|
|
||||||
v 1.000000 -1.000000 -1.000000
|
|
||||||
v 1.000000 1.000000 -1.000000
|
|
||||||
vt 0.625000 0.000000
|
|
||||||
vt 0.375000 0.250000
|
|
||||||
vt 0.375000 0.000000
|
|
||||||
vt 0.625000 0.250000
|
|
||||||
vt 0.375000 0.500000
|
|
||||||
vt 0.625000 0.500000
|
|
||||||
vt 0.375000 0.750000
|
|
||||||
vt 0.625000 0.750000
|
|
||||||
vt 0.375000 1.000000
|
|
||||||
vt 0.125000 0.750000
|
|
||||||
vt 0.125000 0.500000
|
|
||||||
vt 0.875000 0.500000
|
|
||||||
vt 0.625000 1.000000
|
|
||||||
vt 0.875000 0.750000
|
|
||||||
s 0
|
|
||||||
f 2/1 3/2 1/3
|
|
||||||
f 4/4 7/5 3/2
|
|
||||||
f 8/6 5/7 7/5
|
|
||||||
f 6/8 1/9 5/7
|
|
||||||
f 7/5 1/10 3/11
|
|
||||||
f 4/12 6/8 8/6
|
|
||||||
f 2/1 4/4 3/2
|
|
||||||
f 4/4 8/6 7/5
|
|
||||||
f 8/6 6/8 5/7
|
|
||||||
f 6/8 2/13 1/9
|
|
||||||
f 7/5 5/7 1/10
|
|
||||||
f 4/12 2/14 6/8
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# Blender 4.2.3 LTS
|
|
||||||
# www.blender.org
|
|
||||||
o Cube
|
|
||||||
v -1.000000 -1.000000 1.000000
|
|
||||||
v -1.000000 1.000000 1.000000
|
|
||||||
v -1.000000 -1.000000 -1.000000
|
|
||||||
v -1.000000 1.000000 -1.000000
|
|
||||||
v 1.000000 -1.000000 1.000000
|
|
||||||
v 1.000000 1.000000 1.000000
|
|
||||||
v 1.000000 -1.000000 -1.000000
|
|
||||||
v 1.000000 1.000000 -1.000000
|
|
||||||
s 0
|
|
||||||
f 2 3 1
|
|
||||||
f 4 7 3
|
|
||||||
f 8 5 7
|
|
||||||
f 6 1 5
|
|
||||||
f 7 1 3
|
|
||||||
f 4 6 8
|
|
||||||
f 2 4 3
|
|
||||||
f 4 8 7
|
|
||||||
f 8 6 5
|
|
||||||
f 6 2 1
|
|
||||||
f 7 5 1
|
|
||||||
f 4 2 6
|
|
||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 116 KiB |
BIN
DoomDeathmatch/asset/texture/fireball.png
Normal file
BIN
DoomDeathmatch/asset/texture/fireball.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
@@ -0,0 +1,75 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Model.Enemy;
|
||||||
|
using DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
|
||||||
|
using DoomDeathmatch.Component.MVC.View;
|
||||||
|
using DoomDeathmatch.Component.Util;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
|
||||||
|
public class EnemyController : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
public HealthController HealthController => _healthController;
|
||||||
|
|
||||||
|
private GameController _gameController = null!;
|
||||||
|
private HealthController _healthController = null!;
|
||||||
|
private EnemyView _enemyView = null!;
|
||||||
|
private MovementController _movementController = null!;
|
||||||
|
private AttackBehavior _attackBehavior = null!;
|
||||||
|
|
||||||
|
private readonly EnemyData _enemyData;
|
||||||
|
|
||||||
|
public EnemyController(EnemyData parEnemyData)
|
||||||
|
{
|
||||||
|
_enemyData = parEnemyData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Awake()
|
||||||
|
{
|
||||||
|
_gameController = GameObject.Scene!.FindFirstComponent<GameController>()!;
|
||||||
|
_healthController = GameObject.GetComponent<HealthController>()!;
|
||||||
|
_enemyView = GameObject.GetComponent<EnemyView>()!;
|
||||||
|
_movementController = GameObject.GetComponent<MovementController>()!;
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(_gameController);
|
||||||
|
ArgumentNullException.ThrowIfNull(_healthController);
|
||||||
|
ArgumentNullException.ThrowIfNull(_enemyView);
|
||||||
|
ArgumentNullException.ThrowIfNull(_movementController);
|
||||||
|
|
||||||
|
_attackBehavior = _enemyData.AttackBehaviorCreator.Create(this, _gameController.PlayerController.HealthController);
|
||||||
|
|
||||||
|
_healthController.SetMaxHealth(_enemyData.BaseHealth);
|
||||||
|
_healthController.OnDeath += OnDeath;
|
||||||
|
_enemyView.UpdateView(_enemyData);
|
||||||
|
_movementController.Speed = _enemyData.BaseSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
var billboardComponent = GameObject.GetComponentInChildren<BillboardComponent>();
|
||||||
|
if (billboardComponent == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
billboardComponent.Target = _gameController.PlayerController.Camera.GameObject.Transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double parDeltaTime)
|
||||||
|
{
|
||||||
|
var playerPosition = _gameController.PlayerController.GameObject.Transform.Translation;
|
||||||
|
var enemyPosition = GameObject.Transform.Translation;
|
||||||
|
|
||||||
|
var nextPosition = _enemyData.MovementBehavior.GetNextPosition(enemyPosition, playerPosition);
|
||||||
|
|
||||||
|
if (enemyPosition != nextPosition)
|
||||||
|
{
|
||||||
|
var direction = (nextPosition - enemyPosition).Normalized();
|
||||||
|
_movementController.ApplyMovement(direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
_attackBehavior.Attack(parDeltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDeath()
|
||||||
|
{
|
||||||
|
GameObject.Scene!.Remove(GameObject);
|
||||||
|
_gameController.ScoreController.AddScore(_enemyData.BaseScore);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
using DoomDeathmatch.Component.UI;
|
||||||
|
using Engine.Input;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
|
||||||
|
public class GameController : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
public bool IsPaused { get; set; } = false;
|
||||||
|
|
||||||
|
public PlayerController PlayerController => _playerController;
|
||||||
|
public ScoreController ScoreController => _scoreController;
|
||||||
|
|
||||||
|
private ScoreController _scoreController = null!;
|
||||||
|
private TimerController _timerController = null!;
|
||||||
|
private PlayerController _playerController = null!;
|
||||||
|
|
||||||
|
private readonly MenuControllerComponent _menuController;
|
||||||
|
private readonly IInputHandler _inputHandler = Engine.Engine.Instance.InputHandler!;
|
||||||
|
|
||||||
|
public GameController(MenuControllerComponent parMenuController)
|
||||||
|
{
|
||||||
|
_menuController = parMenuController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Awake()
|
||||||
|
{
|
||||||
|
_scoreController = GameObject.GetComponent<ScoreController>()!;
|
||||||
|
_timerController = GameObject.GetComponent<TimerController>()!;
|
||||||
|
_playerController = GameObject.Scene!.FindFirstComponent<PlayerController>()!;
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(_scoreController);
|
||||||
|
ArgumentNullException.ThrowIfNull(_timerController);
|
||||||
|
ArgumentNullException.ThrowIfNull(_playerController);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unpause()
|
||||||
|
{
|
||||||
|
GameObject.Scene!.TimeScale = 1.0f;
|
||||||
|
IsPaused = false;
|
||||||
|
_menuController.SelectMenuItem("play");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
GameObject.Scene!.TimeScale = 0.0f;
|
||||||
|
IsPaused = true;
|
||||||
|
_menuController.SelectMenuItem("escape");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double parDeltaTime)
|
||||||
|
{
|
||||||
|
if (_inputHandler.IsKeyJustPressed(KeyboardButtonCode.Escape))
|
||||||
|
{
|
||||||
|
if (IsPaused)
|
||||||
|
{
|
||||||
|
Unpause();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,11 +5,19 @@ namespace DoomDeathmatch.Component.MVC.Controller;
|
|||||||
|
|
||||||
public class HealthController : Engine.Scene.Component.Component
|
public class HealthController : Engine.Scene.Component.Component
|
||||||
{
|
{
|
||||||
private readonly HealthModel _healthModel = new(100);
|
public event Action? OnDeath;
|
||||||
|
|
||||||
|
private readonly HealthModel _healthModel;
|
||||||
private HealthView? _healthView;
|
private HealthView? _healthView;
|
||||||
|
|
||||||
|
public HealthController(float parHealth = 100)
|
||||||
|
{
|
||||||
|
_healthModel = new HealthModel(parHealth);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Awake()
|
public override void Awake()
|
||||||
{
|
{
|
||||||
|
_healthModel.HealthChanged += OnHealthChanged;
|
||||||
_healthView = GameObject.GetComponent<HealthView>();
|
_healthView = GameObject.GetComponent<HealthView>();
|
||||||
|
|
||||||
if (_healthView != null)
|
if (_healthView != null)
|
||||||
@@ -19,6 +27,12 @@ public class HealthController : Engine.Scene.Component.Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetMaxHealth(float parMaxHealth)
|
||||||
|
{
|
||||||
|
_healthModel.MaxHealth = parMaxHealth;
|
||||||
|
_healthModel.Health = parMaxHealth;
|
||||||
|
}
|
||||||
|
|
||||||
public void TakeDamage(float parDamage)
|
public void TakeDamage(float parDamage)
|
||||||
{
|
{
|
||||||
_healthModel.Health -= parDamage;
|
_healthModel.Health -= parDamage;
|
||||||
@@ -28,4 +42,12 @@ public class HealthController : Engine.Scene.Component.Component
|
|||||||
{
|
{
|
||||||
_healthModel.Health += parHeal;
|
_healthModel.Health += parHeal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnHealthChanged(HealthModel parHealthModel)
|
||||||
|
{
|
||||||
|
if (parHealthModel.Health <= 0)
|
||||||
|
{
|
||||||
|
OnDeath?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using DoomDeathmatch.Component.Util;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
|
||||||
|
public class MovementController : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
public float Speed { get; set; } = 10.0f;
|
||||||
|
|
||||||
|
private RigidbodyComponent _rigidbody = null!;
|
||||||
|
private DragComponent _dragComponent = null!;
|
||||||
|
|
||||||
|
public override void Awake()
|
||||||
|
{
|
||||||
|
_rigidbody = GameObject.GetComponent<RigidbodyComponent>()!;
|
||||||
|
_dragComponent = GameObject.GetComponent<DragComponent>()!;
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(_rigidbody);
|
||||||
|
ArgumentNullException.ThrowIfNull(_dragComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyMovement(Vector3 parDirection)
|
||||||
|
{
|
||||||
|
_rigidbody.AddForce(_dragComponent.Drag * Speed * parDirection);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +1,45 @@
|
|||||||
using DoomDeathmatch.Component.MVC.Model;
|
using DoomDeathmatch.Component.MVC.Model.Weapon;
|
||||||
|
using DoomDeathmatch.Component.Util;
|
||||||
|
using DoomDeathmatch.Component.Util.Collision;
|
||||||
|
using Engine.Graphics.Pipeline;
|
||||||
using Engine.Input;
|
using Engine.Input;
|
||||||
|
using Engine.Scene.Component.BuiltIn;
|
||||||
|
using Engine.Scene.Component.BuiltIn.Renderer;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
namespace DoomDeathmatch.Component.MVC.Controller;
|
namespace DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
|
||||||
public class PlayerController : Engine.Scene.Component.Component
|
public class PlayerController : Engine.Scene.Component.Component
|
||||||
{
|
{
|
||||||
|
public bool IsPaused { get; set; } = false;
|
||||||
|
public HealthController HealthController => _healthController;
|
||||||
|
public PerspectiveCamera Camera => _camera;
|
||||||
|
|
||||||
private readonly IInputHandler _inputHandler = Engine.Engine.Instance.InputHandler!;
|
private readonly IInputHandler _inputHandler = Engine.Engine.Instance.InputHandler!;
|
||||||
|
|
||||||
private HealthController _healthController = null!;
|
private HealthController _healthController = null!;
|
||||||
private WeaponController _weaponController = null!;
|
private WeaponController _weaponController = null!;
|
||||||
private ScoreController _scoreController = null!;
|
private readonly PerspectiveCamera _camera;
|
||||||
|
|
||||||
|
public PlayerController(PerspectiveCamera parCamera)
|
||||||
|
{
|
||||||
|
_camera = parCamera;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Awake()
|
public override void Awake()
|
||||||
{
|
{
|
||||||
_healthController = GameObject.GetComponent<HealthController>()!;
|
_healthController = GameObject.GetComponent<HealthController>()!;
|
||||||
_weaponController = GameObject.GetComponent<WeaponController>()!;
|
_weaponController = GameObject.GetComponent<WeaponController>()!;
|
||||||
_scoreController = GameObject.GetComponent<ScoreController>()!;
|
|
||||||
|
|
||||||
ArgumentNullException.ThrowIfNull(_healthController);
|
ArgumentNullException.ThrowIfNull(_healthController);
|
||||||
ArgumentNullException.ThrowIfNull(_weaponController);
|
ArgumentNullException.ThrowIfNull(_weaponController);
|
||||||
ArgumentNullException.ThrowIfNull(_scoreController);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(double parDeltaTime)
|
public override void Update(double parDeltaTime)
|
||||||
{
|
{
|
||||||
|
if (IsPaused)
|
||||||
|
return;
|
||||||
|
|
||||||
if (_inputHandler.IsKeyJustPressed(KeyboardButtonCode.C))
|
if (_inputHandler.IsKeyJustPressed(KeyboardButtonCode.C))
|
||||||
_weaponController.AddWeapon(WeaponData.Shotgun);
|
_weaponController.AddWeapon(WeaponData.Shotgun);
|
||||||
|
|
||||||
@@ -40,6 +56,42 @@ public class PlayerController : Engine.Scene.Component.Component
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_inputHandler.IsKeyJustPressed(KeyboardButtonCode.Space))
|
if (_inputHandler.IsKeyJustPressed(KeyboardButtonCode.Space))
|
||||||
_weaponController.TryShoot();
|
{
|
||||||
|
if (!_weaponController.TryShoot())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var position = _camera.GameObject.Transform.GetFullTranslation();
|
||||||
|
var forward = (_camera.Forward - position).Normalized();
|
||||||
|
var right = Vector3.Cross(forward, Vector3.UnitZ).Normalized();
|
||||||
|
|
||||||
|
var collisionManager = GameObject.Scene!.FindFirstComponent<CollisionManager>();
|
||||||
|
|
||||||
|
var offsets = _weaponController.WeaponData.ShootPattern.GetShootPattern(forward, Vector3.UnitZ, right);
|
||||||
|
foreach (var offset in offsets)
|
||||||
|
{
|
||||||
|
var direction = forward + offset;
|
||||||
|
if (!collisionManager!.Raycast(position, direction, ["enemy", "wall"], out var result))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var hitDisplayObject = GameObjectUtil.CreateGameObject(GameObject.Scene,
|
||||||
|
new Transform { Translation = result.HitPoint, Size = new Vector3(0.1f) },
|
||||||
|
[
|
||||||
|
new Box2DRenderer { Color = new Vector4(0, 0, 1, 1), RenderLayer = RenderLayer.DEFAULT },
|
||||||
|
new BillboardComponent { Target = _camera.GameObject.Transform }
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
var hitNormalDisplayObject = GameObjectUtil.CreateGameObject(GameObject.Scene,
|
||||||
|
new Transform { Translation = result.HitPoint + result.Normal, Size = new Vector3(0.1f) },
|
||||||
|
[
|
||||||
|
new Box2DRenderer { Color = new Vector4(1, 0, 1, 1), RenderLayer = RenderLayer.DEFAULT },
|
||||||
|
new BillboardComponent { Target = _camera.GameObject.Transform }
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
var enemyController = result.HitObject.GetComponent<EnemyController>();
|
||||||
|
enemyController?.HealthController.TakeDamage(_weaponController.WeaponData.Damage);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@ namespace DoomDeathmatch.Component.MVC.Controller;
|
|||||||
|
|
||||||
public class ScoreController : Engine.Scene.Component.Component
|
public class ScoreController : Engine.Scene.Component.Component
|
||||||
{
|
{
|
||||||
|
public int Score => _scoreModel.Score;
|
||||||
|
|
||||||
private readonly ScoreModel _scoreModel = new();
|
private readonly ScoreModel _scoreModel = new();
|
||||||
private ScoreView _scoreView = null!;
|
private ScoreView _scoreView = null!;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.View;
|
||||||
|
using Engine.Util;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
|
||||||
|
public class TimerController : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
public bool IsPaused { get; set; } = false;
|
||||||
|
public event Action? OnFinished;
|
||||||
|
|
||||||
|
private readonly TickableTimer _tickableTimer = new(60 + 10);
|
||||||
|
private TimerView _timerView = null!;
|
||||||
|
|
||||||
|
public override void Awake()
|
||||||
|
{
|
||||||
|
_timerView = GameObject.GetComponent<TimerView>()!;
|
||||||
|
_timerView.UpdateView(_tickableTimer.CurrentTime);
|
||||||
|
|
||||||
|
_tickableTimer.OnUpdate += OnTimeChanged;
|
||||||
|
_tickableTimer.OnFinished += OnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double parDeltaTime)
|
||||||
|
{
|
||||||
|
if (IsPaused)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_tickableTimer.Update(parDeltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTimeChanged(double parTime)
|
||||||
|
{
|
||||||
|
_timerView.UpdateView(parTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using DoomDeathmatch.Component.MVC.Model;
|
using DoomDeathmatch.Component.MVC.Model;
|
||||||
|
using DoomDeathmatch.Component.MVC.Model.Weapon;
|
||||||
using DoomDeathmatch.Component.MVC.View;
|
using DoomDeathmatch.Component.MVC.View;
|
||||||
|
|
||||||
namespace DoomDeathmatch.Component.MVC.Controller;
|
namespace DoomDeathmatch.Component.MVC.Controller;
|
||||||
@@ -6,6 +7,7 @@ namespace DoomDeathmatch.Component.MVC.Controller;
|
|||||||
public class WeaponController : Engine.Scene.Component.Component
|
public class WeaponController : Engine.Scene.Component.Component
|
||||||
{
|
{
|
||||||
public event Action<WeaponData>? OnWeaponShot;
|
public event Action<WeaponData>? OnWeaponShot;
|
||||||
|
public WeaponData WeaponData => _weaponModel.SelectedWeapon;
|
||||||
|
|
||||||
private readonly WeaponModel _weaponModel = new();
|
private readonly WeaponModel _weaponModel = new();
|
||||||
private WeaponView _weaponView = null!;
|
private WeaponView _weaponView = null!;
|
||||||
@@ -24,7 +26,7 @@ public class WeaponController : Engine.Scene.Component.Component
|
|||||||
if (_weaponModel.SelectedWeapon.Ammo <= 0)
|
if (_weaponModel.SelectedWeapon.Ammo <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_weaponModel.SelectedWeapon.Ammo--;
|
// _weaponModel.SelectedWeapon.Ammo--;
|
||||||
|
|
||||||
OnWeaponShot?.Invoke(_weaponModel.SelectedWeapon);
|
OnWeaponShot?.Invoke(_weaponModel.SelectedWeapon);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
|
||||||
|
|
||||||
|
public abstract class AttackBehavior(EnemyController parEnemyController, HealthController parHealthController)
|
||||||
|
{
|
||||||
|
protected readonly EnemyController _enemyController = parEnemyController;
|
||||||
|
protected readonly HealthController _healthController = parHealthController;
|
||||||
|
|
||||||
|
public abstract bool Attack(double parDeltaTime);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
|
||||||
|
|
||||||
|
public class CloseContinuousAttackBehavior(
|
||||||
|
EnemyController parEnemyController,
|
||||||
|
HealthController parHealthController,
|
||||||
|
float parRadius,
|
||||||
|
float parDamage)
|
||||||
|
: AttackBehavior(parEnemyController, parHealthController)
|
||||||
|
{
|
||||||
|
public override bool Attack(double parDeltaTime)
|
||||||
|
{
|
||||||
|
var distanceSquared =
|
||||||
|
(_enemyController.GameObject.Transform.Translation - _healthController.GameObject.Transform.Translation)
|
||||||
|
.LengthSquared;
|
||||||
|
|
||||||
|
if (distanceSquared <= parRadius * parRadius)
|
||||||
|
{
|
||||||
|
_healthController.TakeDamage(parDamage * (float)parDeltaTime);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
using Engine.Util;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
|
||||||
|
|
||||||
|
public class CloseCooldownAttackBehavior(
|
||||||
|
EnemyController parEnemyController,
|
||||||
|
HealthController parHealthController,
|
||||||
|
float parRadius,
|
||||||
|
float parCooldown,
|
||||||
|
float parDamage)
|
||||||
|
: CooldownAttackBehavior(parEnemyController, parHealthController, parCooldown)
|
||||||
|
{
|
||||||
|
protected override bool CanAttack()
|
||||||
|
{
|
||||||
|
var distanceSquared =
|
||||||
|
(_enemyController.GameObject.Transform.Translation - _healthController.GameObject.Transform.Translation)
|
||||||
|
.LengthSquared;
|
||||||
|
|
||||||
|
return distanceSquared <= parRadius * parRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ActivateAttack()
|
||||||
|
{
|
||||||
|
_healthController.TakeDamage(parDamage);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
|
||||||
|
|
||||||
|
public class CompositeAttackBehavior(
|
||||||
|
EnemyController parEnemyController,
|
||||||
|
HealthController parHealthController,
|
||||||
|
List<AttackBehavior> parBehaviors)
|
||||||
|
: AttackBehavior(parEnemyController, parHealthController)
|
||||||
|
{
|
||||||
|
public override bool Attack(double parDeltaTime)
|
||||||
|
{
|
||||||
|
var result = false;
|
||||||
|
|
||||||
|
foreach (var behavior in parBehaviors)
|
||||||
|
{
|
||||||
|
result |= behavior.Attack(parDeltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
using Engine.Util;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
|
||||||
|
|
||||||
|
public abstract class CooldownAttackBehavior(
|
||||||
|
EnemyController parEnemyController,
|
||||||
|
HealthController parHealthController,
|
||||||
|
float parCooldown)
|
||||||
|
: AttackBehavior(parEnemyController, parHealthController)
|
||||||
|
{
|
||||||
|
private readonly TickableTimer _tickableTimer = new(parCooldown);
|
||||||
|
|
||||||
|
public sealed override bool Attack(double parDeltaTime)
|
||||||
|
{
|
||||||
|
_tickableTimer.Update(parDeltaTime);
|
||||||
|
|
||||||
|
if (CanAttack())
|
||||||
|
{
|
||||||
|
if (!_tickableTimer.IsFinished)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var result = ActivateAttack();
|
||||||
|
|
||||||
|
_tickableTimer.Reset();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract bool CanAttack();
|
||||||
|
protected abstract bool ActivateAttack();
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
|
||||||
|
|
||||||
|
public class FuncAttackBehaviorCreator(Func<EnemyController, HealthController, AttackBehavior> parFunc)
|
||||||
|
: IAttackBehaviorCreator
|
||||||
|
{
|
||||||
|
public AttackBehavior Create(EnemyController parEnemyController, HealthController parHealthController)
|
||||||
|
{
|
||||||
|
return parFunc(parEnemyController, parHealthController);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
|
||||||
|
|
||||||
|
public interface IAttackBehaviorCreator
|
||||||
|
{
|
||||||
|
public AttackBehavior Create(EnemyController parEnemyController, HealthController parHealthController);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
using Engine.Scene;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
|
||||||
|
|
||||||
|
public class ObjectSpawnAttackBehavior(
|
||||||
|
EnemyController parEnemyController,
|
||||||
|
HealthController parHealthController,
|
||||||
|
float parCooldown,
|
||||||
|
Func<EnemyController, HealthController, GameObject> parObjectSpawnFunc
|
||||||
|
)
|
||||||
|
: CooldownAttackBehavior(parEnemyController, parHealthController, parCooldown)
|
||||||
|
{
|
||||||
|
protected override bool CanAttack()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ActivateAttack()
|
||||||
|
{
|
||||||
|
var enemyObject = parObjectSpawnFunc(_enemyController, _healthController);
|
||||||
|
_enemyController.GameObject.Scene!.Add(enemyObject);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
83
DoomDeathmatch/src/Component/MVC/Model/Enemy/EnemyData.cs
Normal file
83
DoomDeathmatch/src/Component/MVC/Model/Enemy/EnemyData.cs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
|
||||||
|
using DoomDeathmatch.Component.MVC.Model.Enemy.Movement;
|
||||||
|
using DoomDeathmatch.Scene.Play;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy;
|
||||||
|
|
||||||
|
public class EnemyData
|
||||||
|
{
|
||||||
|
public static EnemyData Demon =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = "demon",
|
||||||
|
Name = "Демон",
|
||||||
|
Texture = "texture/demon.png",
|
||||||
|
BaseHealth = 150,
|
||||||
|
BaseScore = 50,
|
||||||
|
BaseSpeed = 8,
|
||||||
|
MovementBehavior = new FollowPlayerMovementBehavior(1.5f),
|
||||||
|
AttackBehaviorCreator = new FuncAttackBehaviorCreator(
|
||||||
|
(parEnemyController, parHealthController) =>
|
||||||
|
new CloseCooldownAttackBehavior(parEnemyController, parHealthController, 1.75f, 2.5f, 10)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
public static EnemyData Imp =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = "imp",
|
||||||
|
Name = "Имп",
|
||||||
|
Texture = "texture/imp.png",
|
||||||
|
BaseHealth = 300,
|
||||||
|
BaseScore = 200,
|
||||||
|
BaseSpeed = 7,
|
||||||
|
MovementBehavior = new FollowPlayerMovementBehavior(10f),
|
||||||
|
AttackBehaviorCreator = new FuncAttackBehaviorCreator(
|
||||||
|
(parEnemyController, parHealthController) =>
|
||||||
|
new CompositeAttackBehavior(parEnemyController, parHealthController,
|
||||||
|
[
|
||||||
|
new CloseContinuousAttackBehavior(parEnemyController, parHealthController, 1.75f, 10f),
|
||||||
|
new ObjectSpawnAttackBehavior(parEnemyController, parHealthController, 4f,
|
||||||
|
(parEnemyController, parHealthController) =>
|
||||||
|
{
|
||||||
|
var direction =
|
||||||
|
(parHealthController.GameObject.Transform.Translation -
|
||||||
|
parEnemyController.GameObject.Transform.Translation).Normalized();
|
||||||
|
|
||||||
|
var fireballObject = EnemyObject.CreateImpFireball(parEnemyController.GameObject.Scene!,
|
||||||
|
parEnemyController.GameObject.Transform.Translation + new Vector3(0, 0f, 1.75f),
|
||||||
|
direction * 25,
|
||||||
|
35,
|
||||||
|
parHealthController.GameObject.Transform
|
||||||
|
);
|
||||||
|
|
||||||
|
return fireballObject;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
public string Id { get; private init; } = "";
|
||||||
|
public string Name { get; private init; } = "";
|
||||||
|
public string Texture { get; private init; } = "";
|
||||||
|
public float BaseHealth { get; private init; }
|
||||||
|
public int BaseScore { get; private init; }
|
||||||
|
public float BaseSpeed { get; private init; }
|
||||||
|
public IMovementBehavior MovementBehavior { get; private init; }
|
||||||
|
public IAttackBehaviorCreator AttackBehaviorCreator { get; private init; }
|
||||||
|
|
||||||
|
private EnemyData() { }
|
||||||
|
|
||||||
|
public override bool Equals(object? parObj)
|
||||||
|
{
|
||||||
|
return parObj is EnemyData enemyData && Id == enemyData.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Movement;
|
||||||
|
|
||||||
|
public class FollowPlayerMovementBehavior(float parRadius) : IMovementBehavior
|
||||||
|
{
|
||||||
|
public Vector3 GetNextPosition(Vector3 parPosition, Vector3 parPlayerPosition)
|
||||||
|
{
|
||||||
|
var direction = (parPosition - parPlayerPosition).Normalized();
|
||||||
|
return parPlayerPosition + parRadius * direction;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Movement;
|
||||||
|
|
||||||
|
public interface IMovementBehavior
|
||||||
|
{
|
||||||
|
public Vector3 GetNextPosition(Vector3 parPosition, Vector3 parPlayerPosition);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Enemy.Movement;
|
||||||
|
|
||||||
|
public class StandingMovementBehavior : IMovementBehavior
|
||||||
|
{
|
||||||
|
public Vector3 GetNextPosition(Vector3 parPosition, Vector3 parPlayerPosition)
|
||||||
|
{
|
||||||
|
return parPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ public class HealthModel
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_maxHealth = Math.Max(value, 1);
|
_maxHealth = Math.Max(value, 1);
|
||||||
|
_health = Math.Clamp(_health, 0, _maxHealth);
|
||||||
HealthChanged?.Invoke(this);
|
HealthChanged?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +18,11 @@ public class HealthModel
|
|||||||
get => _health;
|
get => _health;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_health = Math.Clamp(value, 0, MaxHealth);
|
value = Math.Clamp(value, 0, MaxHealth);
|
||||||
|
if (Math.Abs(_health - value) < float.Epsilon)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_health = value;
|
||||||
HealthChanged?.Invoke(this);
|
HealthChanged?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Weapon;
|
||||||
|
|
||||||
|
public interface IShootPattern
|
||||||
|
{
|
||||||
|
public IEnumerable<Vector3> GetShootPattern(Vector3 parForward, Vector3 parUp, Vector3 parRight);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Weapon;
|
||||||
|
|
||||||
|
public class LineShootPattern : IShootPattern
|
||||||
|
{
|
||||||
|
public IEnumerable<Vector3> GetShootPattern(Vector3 parForward, Vector3 parUp, Vector3 parRight)
|
||||||
|
{
|
||||||
|
return [Vector3.Zero];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Weapon;
|
||||||
|
|
||||||
|
public class RandomFlatSpreadShootPattern(float parAngle, uint parCount) : IShootPattern
|
||||||
|
{
|
||||||
|
private readonly Random _random = new();
|
||||||
|
|
||||||
|
public IEnumerable<Vector3> GetShootPattern(Vector3 parForward, Vector3 parUp, Vector3 parRight)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < parCount; i++)
|
||||||
|
{
|
||||||
|
var angle = parAngle * ((float)_random.NextDouble() * 2 - 1);
|
||||||
|
var delta = MathF.Tan(angle);
|
||||||
|
|
||||||
|
var offset = parRight * delta;
|
||||||
|
|
||||||
|
yield return offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,35 @@
|
|||||||
namespace DoomDeathmatch.Component.MVC.Model;
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model.Weapon;
|
||||||
|
|
||||||
public class WeaponData
|
public class WeaponData
|
||||||
{
|
{
|
||||||
public static WeaponData Pistol =>
|
public static WeaponData Pistol =>
|
||||||
new(30) { Id = "pistol", Name = "Пистолет", Texture = "texture/pistol.png", Damage = 10 };
|
new(30)
|
||||||
|
{
|
||||||
|
Id = "pistol",
|
||||||
|
Name = "Пистолет",
|
||||||
|
Texture = "texture/pistol.png",
|
||||||
|
Damage = 30,
|
||||||
|
ShootPattern = new LineShootPattern()
|
||||||
|
};
|
||||||
|
|
||||||
public static WeaponData Shotgun =>
|
public static WeaponData Shotgun =>
|
||||||
new(10) { Id = "shotgun", Name = "Дробовик", Texture = "texture/shotgun.png", Damage = 50 };
|
new(10)
|
||||||
|
{
|
||||||
|
Id = "shotgun",
|
||||||
|
Name = "Дробовик",
|
||||||
|
Texture = "texture/shotgun.png",
|
||||||
|
Damage = 5,
|
||||||
|
ShootPattern = new RandomFlatSpreadShootPattern(MathHelper.DegreesToRadians(20), 40)
|
||||||
|
};
|
||||||
|
|
||||||
public string Id { get; private init; } = "";
|
public string Id { get; private init; } = "";
|
||||||
public string Name { get; private init; } = "";
|
public string Name { get; private init; } = "";
|
||||||
public string Texture { get; private init; } = "";
|
public string Texture { get; private init; } = "";
|
||||||
public int Damage { get; private init; }
|
public int Damage { get; private init; }
|
||||||
public int MaxAmmo { get; }
|
public int MaxAmmo { get; }
|
||||||
|
public IShootPattern ShootPattern { get; private init; }
|
||||||
|
|
||||||
public int Ammo
|
public int Ammo
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace DoomDeathmatch.Component.MVC.Model;
|
using DoomDeathmatch.Component.MVC.Model.Weapon;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.Model;
|
||||||
|
|
||||||
public class WeaponModel
|
public class WeaponModel
|
||||||
{
|
{
|
||||||
|
|||||||
16
DoomDeathmatch/src/Component/MVC/View/EnemyHealthView.cs
Normal file
16
DoomDeathmatch/src/Component/MVC/View/EnemyHealthView.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Model;
|
||||||
|
using Engine.Scene.Component.BuiltIn.Renderer;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.View;
|
||||||
|
|
||||||
|
public class EnemyHealthView : HealthView
|
||||||
|
{
|
||||||
|
public EnemyHealthView(TextRenderer parHealthTextRenderer) : base(parHealthTextRenderer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateView(HealthModel parHealthModel)
|
||||||
|
{
|
||||||
|
_healthTextRenderer.Text = $"Здоровье: {parHealthModel.Health:000}";
|
||||||
|
}
|
||||||
|
}
|
||||||
20
DoomDeathmatch/src/Component/MVC/View/EnemyView.cs
Normal file
20
DoomDeathmatch/src/Component/MVC/View/EnemyView.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Model.Enemy;
|
||||||
|
using Engine.Graphics.Texture;
|
||||||
|
using Engine.Scene.Component.BuiltIn.Renderer;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.View;
|
||||||
|
|
||||||
|
public class EnemyView : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
private readonly Box2DRenderer _box2DRenderer;
|
||||||
|
|
||||||
|
public EnemyView(Box2DRenderer parBox2DRenderer)
|
||||||
|
{
|
||||||
|
_box2DRenderer = parBox2DRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateView(EnemyData parEnemyData)
|
||||||
|
{
|
||||||
|
_box2DRenderer.Texture = Engine.Engine.Instance.AssetResourceManager.Load<Texture>(parEnemyData.Texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,14 +5,14 @@ namespace DoomDeathmatch.Component.MVC.View;
|
|||||||
|
|
||||||
public class HealthView : Engine.Scene.Component.Component
|
public class HealthView : Engine.Scene.Component.Component
|
||||||
{
|
{
|
||||||
private readonly TextRenderer _healthTextRenderer;
|
protected readonly TextRenderer _healthTextRenderer;
|
||||||
|
|
||||||
public HealthView(TextRenderer parHealthTextRenderer)
|
public HealthView(TextRenderer parHealthTextRenderer)
|
||||||
{
|
{
|
||||||
_healthTextRenderer = parHealthTextRenderer;
|
_healthTextRenderer = parHealthTextRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateView(HealthModel parHealthModel)
|
public virtual void UpdateView(HealthModel parHealthModel)
|
||||||
{
|
{
|
||||||
var percentage = parHealthModel.Health / parHealthModel.MaxHealth * 100;
|
var percentage = parHealthModel.Health / parHealthModel.MaxHealth * 100;
|
||||||
if (parHealthModel.Health != 0)
|
if (parHealthModel.Health != 0)
|
||||||
|
|||||||
21
DoomDeathmatch/src/Component/MVC/View/TimerView.cs
Normal file
21
DoomDeathmatch/src/Component/MVC/View/TimerView.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using Engine.Scene.Component.BuiltIn.Renderer;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.MVC.View;
|
||||||
|
|
||||||
|
public class TimerView : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
private readonly TextRenderer _timerTextRenderer;
|
||||||
|
|
||||||
|
public TimerView(TextRenderer parTimerTextRenderer)
|
||||||
|
{
|
||||||
|
_timerTextRenderer = parTimerTextRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateView(double parTime)
|
||||||
|
{
|
||||||
|
var seconds = Math.Floor(parTime) % 60;
|
||||||
|
var minutes = Math.Floor(parTime / 60) % 60;
|
||||||
|
|
||||||
|
_timerTextRenderer.Text = $"Время: {minutes:00}:{seconds:00}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using DoomDeathmatch.Component.MVC.Model;
|
using DoomDeathmatch.Component.MVC.Model;
|
||||||
|
using DoomDeathmatch.Component.MVC.Model.Weapon;
|
||||||
using Engine.Graphics.Texture;
|
using Engine.Graphics.Texture;
|
||||||
using Engine.Scene.Component.BuiltIn.Renderer;
|
using Engine.Scene.Component.BuiltIn.Renderer;
|
||||||
|
|
||||||
|
|||||||
26
DoomDeathmatch/src/Component/UI/MenuControllerComponent.cs
Normal file
26
DoomDeathmatch/src/Component/UI/MenuControllerComponent.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using Engine.Scene;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.UI;
|
||||||
|
|
||||||
|
public class MenuControllerComponent : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, GameObject> _menuItems = new();
|
||||||
|
|
||||||
|
public void AddMenuItem(string parName, GameObject parGameObject)
|
||||||
|
{
|
||||||
|
_menuItems.Add(parName, parGameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveMenuItem(string parName)
|
||||||
|
{
|
||||||
|
_menuItems.Remove(parName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectMenuItem(string parName)
|
||||||
|
{
|
||||||
|
foreach (var (name, menuItem) in _menuItems)
|
||||||
|
{
|
||||||
|
menuItem.IsEnabled = name == parName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,10 +15,11 @@ public class BillboardComponent : Engine.Scene.Component.Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetPosition = Target.TransformMatrix.ExtractTranslation();
|
var targetPosition = Target.GetFullTranslation();
|
||||||
var currentPosition = GameObject.Transform.Translation;
|
var currentPosition = GameObject.Transform.GetFullTranslation();
|
||||||
|
|
||||||
var forward = targetPosition - currentPosition;
|
var forward = targetPosition - currentPosition;
|
||||||
|
forward -= Vector3.Dot(forward, Up) * Up;
|
||||||
if (forward.LengthSquared > 0)
|
if (forward.LengthSquared > 0)
|
||||||
forward.Normalize();
|
forward.Normalize();
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ public class BillboardComponent : Engine.Scene.Component.Component
|
|||||||
if (right.LengthSquared > 0)
|
if (right.LengthSquared > 0)
|
||||||
right.Normalize();
|
right.Normalize();
|
||||||
|
|
||||||
var recalculatedUp = Vector3.Cross(forward, right);
|
var recalculatedUp = Vector3.Cross(forward, right).Normalized();
|
||||||
|
|
||||||
var rotationMatrix = new Matrix3(
|
var rotationMatrix = new Matrix3(
|
||||||
right.X, recalculatedUp.X, forward.X,
|
right.X, recalculatedUp.X, forward.X,
|
||||||
@@ -34,8 +35,6 @@ public class BillboardComponent : Engine.Scene.Component.Component
|
|||||||
right.Z, recalculatedUp.Z, forward.Z
|
right.Z, recalculatedUp.Z, forward.Z
|
||||||
);
|
);
|
||||||
|
|
||||||
var rotation = Quaternion.FromMatrix(rotationMatrix);
|
GameObject.Transform.Rotation = Quaternion.FromMatrix(rotationMatrix);
|
||||||
|
|
||||||
GameObject.Transform.Rotation = rotation;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
53
DoomDeathmatch/src/Component/Util/Collision/AABBCollider.cs
Normal file
53
DoomDeathmatch/src/Component/Util/Collision/AABBCollider.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.Util.Collision;
|
||||||
|
|
||||||
|
public class AABBCollider
|
||||||
|
{
|
||||||
|
public Vector3 Size { get; set; }
|
||||||
|
public Vector3 Position { get; set; }
|
||||||
|
|
||||||
|
public Vector3 Max => Position + Size / 2;
|
||||||
|
public Vector3 Min => Position - Size / 2;
|
||||||
|
|
||||||
|
public bool Intersects(AABBCollider parCollider)
|
||||||
|
{
|
||||||
|
var max = Max;
|
||||||
|
var min = Min;
|
||||||
|
var otherMax = parCollider.Max;
|
||||||
|
var otherMin = parCollider.Min;
|
||||||
|
|
||||||
|
return max.X >= otherMin.X && min.X <= otherMax.X && max.Y >= otherMin.Y && min.Y <= otherMax.Y &&
|
||||||
|
max.Z >= otherMin.Z && min.Z <= otherMax.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 GetCollisionNormal(AABBCollider parOther)
|
||||||
|
{
|
||||||
|
var normal = Vector3.Zero;
|
||||||
|
var diff = parOther.Position - Position;
|
||||||
|
|
||||||
|
// Calculate penetration depths for each axis
|
||||||
|
var penX = (Size.X / 2 + parOther.Size.X / 2) - Math.Abs(diff.X);
|
||||||
|
var penY = (Size.Y / 2 + parOther.Size.Y / 2) - Math.Abs(diff.Y);
|
||||||
|
var penZ = (Size.Z / 2 + parOther.Size.Z / 2) - Math.Abs(diff.Z);
|
||||||
|
|
||||||
|
// Use the axis with the smallest penetration
|
||||||
|
if (penX < penY && penX < penZ)
|
||||||
|
{
|
||||||
|
var sign = Math.Sign(diff.X);
|
||||||
|
normal.X = sign == 0 ? 1 : sign;
|
||||||
|
}
|
||||||
|
else if (penY < penX && penY < penZ)
|
||||||
|
{
|
||||||
|
var sign = Math.Sign(diff.Y);
|
||||||
|
normal.Y = sign == 0 ? 1 : sign;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var sign = Math.Sign(diff.Z);
|
||||||
|
normal.Z = sign == 0 ? 1 : sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normal.Normalized();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.Util.Collision;
|
||||||
|
|
||||||
|
public class AABBColliderComponent : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
public event Action<AABBColliderComponent>? OnCollision;
|
||||||
|
|
||||||
|
public AABBCollider Collider { get; set; } = new();
|
||||||
|
public Vector3 Offset { get; set; } = Vector3.Zero;
|
||||||
|
public ISet<string> ColliderGroups => _colliderGroups;
|
||||||
|
public ISet<string> ExcludeColliderCollideGroups => _excludeColliderCollideGroups;
|
||||||
|
|
||||||
|
private readonly HashSet<string> _colliderGroups = ["default"];
|
||||||
|
private readonly HashSet<string> _excludeColliderCollideGroups = [];
|
||||||
|
|
||||||
|
public override void Update(double parDeltaTime)
|
||||||
|
{
|
||||||
|
Collider.Position = GameObject.Transform.GetFullTranslation() + Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CollideWith(AABBColliderComponent parCollider)
|
||||||
|
{
|
||||||
|
OnCollision?.Invoke(parCollider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool InColliderGroup(string parGroup)
|
||||||
|
{
|
||||||
|
return ColliderGroups.Contains(parGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.Util.Collision;
|
||||||
|
|
||||||
|
public class ColliderForceFieldComponent : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
private AABBColliderComponent _collider = null!;
|
||||||
|
|
||||||
|
public override void Awake()
|
||||||
|
{
|
||||||
|
_collider = GameObject.GetComponent<AABBColliderComponent>()!;
|
||||||
|
_collider.OnCollision += OnCollision;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCollision(AABBColliderComponent parCollider)
|
||||||
|
{
|
||||||
|
var rigidbody = parCollider.GameObject.GetComponent<RigidbodyComponent>();
|
||||||
|
if (rigidbody == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var normal = _collider.Collider.GetCollisionNormal(parCollider.Collider);
|
||||||
|
var speedAlongNormal = Vector3.Dot(rigidbody.Velocity, normal);
|
||||||
|
if (speedAlongNormal >= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rigidbody.AddVelocity(-normal * speedAlongNormal);
|
||||||
|
}
|
||||||
|
}
|
||||||
164
DoomDeathmatch/src/Component/Util/Collision/CollisionManager.cs
Normal file
164
DoomDeathmatch/src/Component/Util/Collision/CollisionManager.cs
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.Util.Collision;
|
||||||
|
|
||||||
|
public class CollisionManager : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
private List<AABBColliderComponent> _colliders = [];
|
||||||
|
|
||||||
|
public override void PreUpdate()
|
||||||
|
{
|
||||||
|
_colliders = GameObject.Scene!.FindAllComponents<AABBColliderComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double parDeltaTime)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _colliders.Count; i++)
|
||||||
|
{
|
||||||
|
var colliderA = _colliders[i];
|
||||||
|
|
||||||
|
for (var j = i + 1; j < _colliders.Count; j++)
|
||||||
|
{
|
||||||
|
var colliderB = _colliders[j];
|
||||||
|
|
||||||
|
var canCollideAB = colliderA.ExcludeColliderCollideGroups.Count == 0 ||
|
||||||
|
!colliderA.ExcludeColliderCollideGroups.IsSubsetOf(colliderB.ColliderGroups);
|
||||||
|
var canCollideBA = colliderB.ExcludeColliderCollideGroups.Count == 0 ||
|
||||||
|
!colliderB.ExcludeColliderCollideGroups.IsSubsetOf(colliderA.ColliderGroups);
|
||||||
|
|
||||||
|
if (!canCollideAB && !canCollideBA)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!colliderA.Collider.Intersects(colliderB.Collider))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (canCollideAB)
|
||||||
|
colliderA.CollideWith(colliderB);
|
||||||
|
|
||||||
|
if (canCollideBA)
|
||||||
|
colliderB.CollideWith(colliderA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Raycast(Vector3 parStart, Vector3 parDirection, HashSet<string> parColliderGroups,
|
||||||
|
[MaybeNullWhen(false)] out RaycastResult parResult)
|
||||||
|
{
|
||||||
|
var start = parStart;
|
||||||
|
var direction = parDirection.Normalized();
|
||||||
|
|
||||||
|
var closestDistance = float.MaxValue;
|
||||||
|
|
||||||
|
parResult = null;
|
||||||
|
foreach (var collider in _colliders)
|
||||||
|
{
|
||||||
|
if (!collider.ColliderGroups.Overlaps(parColliderGroups))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!RaycastAABB(start, direction, collider.Collider, out var hitPoint, out var normal))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var distance = (start - hitPoint).Length;
|
||||||
|
if (distance > closestDistance)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
closestDistance = distance;
|
||||||
|
|
||||||
|
parResult = new RaycastResult
|
||||||
|
{
|
||||||
|
HitPoint = hitPoint, Normal = normal, Distance = distance, HitObject = collider.GameObject
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return parResult != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool RaycastAABB(Vector3 parOrigin, Vector3 parDirection, AABBCollider parCollider,
|
||||||
|
out Vector3 parHitPoint,
|
||||||
|
out Vector3 parHitNormal)
|
||||||
|
{
|
||||||
|
const int RIGHT = 0;
|
||||||
|
const int LEFT = 1;
|
||||||
|
const int MIDDLE = 2;
|
||||||
|
|
||||||
|
parHitPoint = Vector3.Zero;
|
||||||
|
parHitNormal = Vector3.Zero;
|
||||||
|
|
||||||
|
var minB = parCollider.Min;
|
||||||
|
var maxB = parCollider.Max;
|
||||||
|
|
||||||
|
// Initialize arrays to store the 3D components
|
||||||
|
var inside = true;
|
||||||
|
var quadrant = new int[3];
|
||||||
|
var maxT = new float[3];
|
||||||
|
var candidatePlane = new float[3];
|
||||||
|
|
||||||
|
// Find candidate planes
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (parOrigin[i] < minB[i])
|
||||||
|
{
|
||||||
|
quadrant[i] = LEFT;
|
||||||
|
candidatePlane[i] = minB[i];
|
||||||
|
inside = false;
|
||||||
|
}
|
||||||
|
else if (parOrigin[i] > maxB[i])
|
||||||
|
{
|
||||||
|
quadrant[i] = RIGHT;
|
||||||
|
candidatePlane[i] = maxB[i];
|
||||||
|
inside = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
quadrant[i] = MIDDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ray origin inside bounding box
|
||||||
|
if (inside)
|
||||||
|
{
|
||||||
|
parHitPoint = parOrigin;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate T distances to candidate planes
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (quadrant[i] != MIDDLE && parDirection[i] != 0.0f)
|
||||||
|
maxT[i] = (candidatePlane[i] - parOrigin[i]) / parDirection[i];
|
||||||
|
else
|
||||||
|
maxT[i] = -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get largest of the maxT's for final choice of intersection
|
||||||
|
var whichPlane = 0;
|
||||||
|
for (var i = 1; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (maxT[whichPlane] < maxT[i])
|
||||||
|
whichPlane = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check final candidate actually inside box
|
||||||
|
if (maxT[whichPlane] < 0.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (whichPlane != i)
|
||||||
|
{
|
||||||
|
parHitPoint[i] = parOrigin[i] + maxT[whichPlane] * parDirection[i];
|
||||||
|
if (parHitPoint[i] < minB[i] || parHitPoint[i] > maxB[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parHitPoint[i] = candidatePlane[i];
|
||||||
|
// Calculate normal for the intersection plane
|
||||||
|
parHitNormal[i] = (quadrant[i] == LEFT) ? -1.0f : 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
DoomDeathmatch/src/Component/Util/Collision/RaycastResult.cs
Normal file
12
DoomDeathmatch/src/Component/Util/Collision/RaycastResult.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Engine.Scene;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.Util.Collision;
|
||||||
|
|
||||||
|
public class RaycastResult
|
||||||
|
{
|
||||||
|
public float Distance { get; init; }
|
||||||
|
public Vector3 HitPoint { get; init; }
|
||||||
|
public Vector3 Normal { get; init; }
|
||||||
|
public GameObject HitObject { get; init; }
|
||||||
|
}
|
||||||
@@ -1,19 +1,21 @@
|
|||||||
using Engine.Input;
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
using Engine.Input;
|
||||||
using OpenTK.Mathematics;
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
namespace DoomDeathmatch.Component.Util;
|
namespace DoomDeathmatch.Component.Util;
|
||||||
|
|
||||||
public class ControllerComponent : Engine.Scene.Component.Component
|
public class ControllerComponent : Engine.Scene.Component.Component
|
||||||
{
|
{
|
||||||
public float Speed { get; set; } = 10.0f;
|
|
||||||
public float RotationSpeed { get; set; } = 70.0f;
|
public float RotationSpeed { get; set; } = 70.0f;
|
||||||
|
|
||||||
private readonly IInputHandler _inputHandler = Engine.Engine.Instance.InputHandler!;
|
private readonly IInputHandler _inputHandler = Engine.Engine.Instance.InputHandler!;
|
||||||
private RigidbodyComponent _rigidbody;
|
private MovementController _movementController = null!;
|
||||||
|
|
||||||
public override void Awake()
|
public override void Awake()
|
||||||
{
|
{
|
||||||
_rigidbody = GameObject.GetComponent<RigidbodyComponent>()!;
|
_movementController = GameObject.GetComponent<MovementController>()!;
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(_movementController);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(double parDeltaTime)
|
public override void Update(double parDeltaTime)
|
||||||
@@ -40,14 +42,7 @@ public class ControllerComponent : Engine.Scene.Component.Component
|
|||||||
movement.Normalize();
|
movement.Normalize();
|
||||||
movement = GameObject.Transform.Rotation * movement;
|
movement = GameObject.Transform.Rotation * movement;
|
||||||
|
|
||||||
_rigidbody.AddVelocity(Speed * movement);
|
_movementController.ApplyMovement(movement);
|
||||||
}
|
|
||||||
|
|
||||||
var velocityXy = _rigidbody.Velocity.Xy;
|
|
||||||
if (velocityXy.LengthSquared > Speed * Speed)
|
|
||||||
{
|
|
||||||
var length = velocityXy.Length;
|
|
||||||
_rigidbody.AddVelocity(new Vector3(-(length - Speed) / length * velocityXy));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GameObject.Transform.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitZ, MathHelper.DegreesToRadians(rotation) *
|
GameObject.Transform.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitZ, MathHelper.DegreesToRadians(rotation) *
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ public class DragComponent : Engine.Scene.Component.Component
|
|||||||
public float Drag { get; set; } = 1f;
|
public float Drag { get; set; } = 1f;
|
||||||
public Vector3 Coefficient { get; set; } = Vector3.One;
|
public Vector3 Coefficient { get; set; } = Vector3.One;
|
||||||
|
|
||||||
private RigidbodyComponent _rigidbody;
|
private RigidbodyComponent _rigidbody = null!;
|
||||||
|
|
||||||
public override void Awake()
|
public override void Awake()
|
||||||
{
|
{
|
||||||
_rigidbody = GameObject.GetComponent<RigidbodyComponent>()!;
|
_rigidbody = GameObject.GetComponent<RigidbodyComponent>()!;
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(_rigidbody);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(double parDeltaTime)
|
public override void Update(double parDeltaTime)
|
||||||
|
|||||||
26
DoomDeathmatch/src/Component/Util/FireballComponent.cs
Normal file
26
DoomDeathmatch/src/Component/Util/FireballComponent.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
using DoomDeathmatch.Component.Util.Collision;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Component.Util;
|
||||||
|
|
||||||
|
public class FireballComponent : Engine.Scene.Component.Component
|
||||||
|
{
|
||||||
|
public float Damage { get; set; }
|
||||||
|
|
||||||
|
public override void Awake()
|
||||||
|
{
|
||||||
|
var collider = GameObject.GetComponent<AABBColliderComponent>()!;
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(collider);
|
||||||
|
|
||||||
|
collider.OnCollision += OnCollision;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCollision(AABBColliderComponent parCollider)
|
||||||
|
{
|
||||||
|
var healthController = parCollider.GameObject.GetComponent<HealthController>();
|
||||||
|
healthController?.TakeDamage(Damage);
|
||||||
|
|
||||||
|
GameObject.Scene!.Remove(GameObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,12 +16,14 @@ public class GravityComponent : Engine.Scene.Component.Component
|
|||||||
|
|
||||||
public bool IsInAir { get; private set; } = false;
|
public bool IsInAir { get; private set; } = false;
|
||||||
|
|
||||||
private RigidbodyComponent _rigidbody;
|
private RigidbodyComponent _rigidbody = null!;
|
||||||
private Vector3 _direction = -Vector3.UnitZ;
|
private Vector3 _direction = -Vector3.UnitZ;
|
||||||
|
|
||||||
public override void Awake()
|
public override void Awake()
|
||||||
{
|
{
|
||||||
_rigidbody = GameObject.GetComponent<RigidbodyComponent>()!;
|
_rigidbody = GameObject.GetComponent<RigidbodyComponent>()!;
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(_rigidbody);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(double parDeltaTime)
|
public override void Update(double parDeltaTime)
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
using Engine.Input;
|
|
||||||
using OpenTK.Mathematics;
|
|
||||||
|
|
||||||
namespace DoomDeathmatch.Component.Util;
|
|
||||||
|
|
||||||
public class RotateComponent : Engine.Scene.Component.Component
|
|
||||||
{
|
|
||||||
private readonly IInputHandler _inputHandler = Engine.Engine.Instance.InputHandler!;
|
|
||||||
|
|
||||||
public override void Update(double parDeltaTime)
|
|
||||||
{
|
|
||||||
if (_inputHandler.IsKeyPressed(KeyboardButtonCode.Q))
|
|
||||||
GameObject.Transform.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitY, (float)parDeltaTime * 0.5f);
|
|
||||||
else if (_inputHandler.IsKeyPressed(KeyboardButtonCode.E))
|
|
||||||
GameObject.Transform.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitY, -(float)parDeltaTime * 0.5f);
|
|
||||||
|
|
||||||
if (_inputHandler.IsMouseButtonPressed(MouseButtonCode.Left))
|
|
||||||
GameObject.Transform.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitZ, (float)parDeltaTime * 0.5f);
|
|
||||||
else if (_inputHandler.IsMouseButtonPressed(MouseButtonCode.Right))
|
|
||||||
GameObject.Transform.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitZ, -(float)parDeltaTime * 0.5f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,4 @@
|
|||||||
using System.Text.Json;
|
using DoomDeathmatch.Scene;
|
||||||
using DoomDeathmatch.Component;
|
|
||||||
using DoomDeathmatch.Component.UI;
|
|
||||||
using DoomDeathmatch.Scene.Main;
|
|
||||||
using DoomDeathmatch.Scene.Rules;
|
|
||||||
using Engine.Asset.Font;
|
|
||||||
using Engine.Asset.Font.Metadata;
|
|
||||||
using Engine.Asset.Mesh;
|
|
||||||
using Engine.Asset.Mesh.Loader;
|
|
||||||
using Engine.Graphics.Camera;
|
|
||||||
using Engine.Graphics.Pipeline;
|
|
||||||
using Engine.Graphics.Texture;
|
|
||||||
using Engine.Scene;
|
|
||||||
using Engine.Scene.Component.BuiltIn;
|
|
||||||
using Engine.Scene.Component.BuiltIn.Renderer;
|
|
||||||
using OpenTK.Mathematics;
|
|
||||||
|
|
||||||
namespace DoomDeathmatch;
|
namespace DoomDeathmatch;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,31 @@
|
|||||||
using Engine.Scene;
|
using DoomDeathmatch.Component.Util.Collision;
|
||||||
|
using Engine.Scene;
|
||||||
using Engine.Scene.Component.BuiltIn;
|
using Engine.Scene.Component.BuiltIn;
|
||||||
|
using Engine.Scene.Component.BuiltIn.Renderer;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
namespace DoomDeathmatch;
|
namespace DoomDeathmatch;
|
||||||
|
|
||||||
public static class GameObjectUtil
|
public static class GameObjectUtil
|
||||||
{
|
{
|
||||||
|
public static GameObject CreateGameObject(Engine.Scene.Scene parScene)
|
||||||
|
{
|
||||||
|
var gameObject = new GameObject();
|
||||||
|
|
||||||
|
parScene.Add(gameObject);
|
||||||
|
|
||||||
|
return gameObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameObject CreateGameObject(Engine.Scene.Scene parScene, Transform parTransform)
|
||||||
|
{
|
||||||
|
var gameObject = new GameObject(parTransform);
|
||||||
|
|
||||||
|
parScene.Add(gameObject);
|
||||||
|
|
||||||
|
return gameObject;
|
||||||
|
}
|
||||||
|
|
||||||
public static GameObject CreateGameObject(Engine.Scene.Scene parScene,
|
public static GameObject CreateGameObject(Engine.Scene.Scene parScene,
|
||||||
List<Engine.Scene.Component.Component> parComponents)
|
List<Engine.Scene.Component.Component> parComponents)
|
||||||
{
|
{
|
||||||
@@ -32,4 +53,92 @@ public static class GameObjectUtil
|
|||||||
|
|
||||||
return gameObject;
|
return gameObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GameObject CreateColliderForceField(Engine.Scene.Scene parScene, AABBColliderComponent parCollider)
|
||||||
|
{
|
||||||
|
var offset = parCollider.Offset;
|
||||||
|
parCollider.Offset = Vector3.Zero;
|
||||||
|
|
||||||
|
var forceFieldObject = CreateGameObject(parScene,
|
||||||
|
new Transform { Translation = offset, Size = parCollider.Collider.Size },
|
||||||
|
[
|
||||||
|
parCollider,
|
||||||
|
new ColliderForceFieldComponent()
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// var color = new Vector4(1, 0, 0, 0.5f);
|
||||||
|
// var size = parCollider.Collider.Size;
|
||||||
|
//
|
||||||
|
// var frontPlaneObject = CreateGameObject(parScene,
|
||||||
|
// new Transform
|
||||||
|
// {
|
||||||
|
// Translation = new Vector3(0, -size.Y / 2, 0),
|
||||||
|
// Size = new Vector3(size.X, size.Z, 0),
|
||||||
|
// Rotation = Quaternion.FromAxisAngle(Vector3.UnitX, MathF.PI / 2)
|
||||||
|
// },
|
||||||
|
// [
|
||||||
|
// new Box2DRenderer { Color = color }
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// var backPlaneObject = CreateGameObject(parScene,
|
||||||
|
// new Transform
|
||||||
|
// {
|
||||||
|
// Translation = new Vector3(0, size.Y / 2, 0),
|
||||||
|
// Size = new Vector3(size.X, size.Z, 0),
|
||||||
|
// Rotation = Quaternion.FromAxisAngle(Vector3.UnitX, -MathF.PI / 2)
|
||||||
|
// },
|
||||||
|
// [
|
||||||
|
// new Box2DRenderer { Color = color }
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// var leftPlaneObject = CreateGameObject(parScene,
|
||||||
|
// new Transform
|
||||||
|
// {
|
||||||
|
// Translation = new Vector3(-size.X / 2, 0, 0),
|
||||||
|
// Size = new Vector3(size.Z, size.Y, 0),
|
||||||
|
// Rotation = Quaternion.FromAxisAngle(Vector3.UnitY, MathF.PI / 2)
|
||||||
|
// },
|
||||||
|
// [
|
||||||
|
// new Box2DRenderer { Color = color }
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// var rightPlaneObject = CreateGameObject(parScene,
|
||||||
|
// new Transform
|
||||||
|
// {
|
||||||
|
// Translation = new Vector3(size.X / 2, 0, 0),
|
||||||
|
// Size = new Vector3(size.Z, size.Y, 0),
|
||||||
|
// Rotation = Quaternion.FromAxisAngle(Vector3.UnitY, -MathF.PI / 2)
|
||||||
|
// },
|
||||||
|
// [
|
||||||
|
// new Box2DRenderer { Color = color }
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// var topPlaneObject = CreateGameObject(parScene,
|
||||||
|
// new Transform { Translation = new Vector3(0, 0, size.Z / 2), Size = new Vector3(size.X, size.Y, 0) },
|
||||||
|
// [
|
||||||
|
// new Box2DRenderer { Color = color }
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// var bottomPlaneObject = CreateGameObject(parScene,
|
||||||
|
// new Transform { Translation = new Vector3(0, 0, -size.Z / 2), Size = new Vector3(size.X, size.Y, 0) },
|
||||||
|
// [
|
||||||
|
// new Box2DRenderer { Color = color }
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// parScene.AddChild(forceFieldObject, frontPlaneObject);
|
||||||
|
// parScene.AddChild(forceFieldObject, backPlaneObject);
|
||||||
|
// parScene.AddChild(forceFieldObject, leftPlaneObject);
|
||||||
|
// parScene.AddChild(forceFieldObject, rightPlaneObject);
|
||||||
|
// parScene.AddChild(forceFieldObject, topPlaneObject);
|
||||||
|
// parScene.AddChild(forceFieldObject, bottomPlaneObject);
|
||||||
|
|
||||||
|
return forceFieldObject;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using DoomDeathmatch.Component.UI;
|
|
||||||
using DoomDeathmatch.Scene.Main;
|
|
||||||
using Engine.Asset.Font;
|
|
||||||
using Engine.Input;
|
|
||||||
using Engine.Scene;
|
|
||||||
using Engine.Scene.Component.BuiltIn.Renderer;
|
|
||||||
using OpenTK.Mathematics;
|
|
||||||
|
|
||||||
namespace DoomDeathmatch.Scene.Leaders;
|
|
||||||
|
|
||||||
public static class LeadersScene
|
|
||||||
{
|
|
||||||
public static Engine.Scene.Scene Create(Engine.Engine parEngine)
|
|
||||||
{
|
|
||||||
var scene = new Engine.Scene.Scene();
|
|
||||||
|
|
||||||
var (cameraObject, camera) = UiUtil.CreateOrthographicCamera(scene);
|
|
||||||
|
|
||||||
var (uiContainerObject, uiContainer) = UiUtil.CreateBackgroundUi(scene, new UiContainerComponent { Camera = camera });
|
|
||||||
|
|
||||||
var (logoObject, logoUi) = UiUtil.CreateLogoUi(parEngine, scene, uiContainer);
|
|
||||||
logoUi.Offset = new Vector2(0, 3f);
|
|
||||||
|
|
||||||
var (backUiObject, backUi, _) = UiUtil.CreateTextUi(scene, uiContainer,
|
|
||||||
UiUtil.GetDoomFont(parEngine), "Назад");
|
|
||||||
backUi.OnClick += _ => parEngine.SceneManager.TransitionTo(() => MainScene.Create(parEngine));
|
|
||||||
|
|
||||||
var (stackObject, stack) = UiUtil.CreateStackUi(scene,
|
|
||||||
new StackComponent { Offset = new Vector2(0, -1f), Container = uiContainer, Children = { backUi } });
|
|
||||||
stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
|
|
||||||
|
|
||||||
var (selectorObject, selector) = UiUtil.CreateSelectorUi(scene, new SelectorComponent { Children = { backUi } });
|
|
||||||
|
|
||||||
scene.AddChild(uiContainerObject, selectorObject);
|
|
||||||
scene.AddChild(uiContainerObject, logoObject);
|
|
||||||
scene.AddChild(uiContainerObject, stackObject);
|
|
||||||
scene.AddChild(stackObject, backUiObject);
|
|
||||||
|
|
||||||
return scene;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
using DoomDeathmatch.Component.UI;
|
|
||||||
using DoomDeathmatch.Scene.Leaders;
|
|
||||||
using DoomDeathmatch.Scene.Play;
|
|
||||||
using DoomDeathmatch.Scene.Rules;
|
|
||||||
using Engine.Scene.Component.BuiltIn;
|
|
||||||
using OpenTK.Mathematics;
|
|
||||||
|
|
||||||
namespace DoomDeathmatch.Scene.Main;
|
|
||||||
|
|
||||||
public static class MainScene
|
|
||||||
{
|
|
||||||
public static Engine.Scene.Scene Create(Engine.Engine parEngine)
|
|
||||||
{
|
|
||||||
var scene = new Engine.Scene.Scene();
|
|
||||||
|
|
||||||
var (cameraObject, camera) = UiUtil.CreateOrthographicCamera(scene);
|
|
||||||
|
|
||||||
var (uiContainerObject, uiContainer) =
|
|
||||||
UiUtil.CreateBackgroundUi(scene, new UiContainerComponent { Camera = camera });
|
|
||||||
|
|
||||||
var (playUiObject, playUi, _) =
|
|
||||||
UiUtil.CreateTextUi(scene, uiContainer, UiUtil.GetDoomFont(parEngine), "Играть");
|
|
||||||
|
|
||||||
var (leadersUiObject, leadersUi, _) =
|
|
||||||
UiUtil.CreateTextUi(scene, uiContainer, UiUtil.GetDoomFont(parEngine), "Лидеры");
|
|
||||||
|
|
||||||
var (rulesUiObject, rulesUi, _) =
|
|
||||||
UiUtil.CreateTextUi(scene, uiContainer, UiUtil.GetDoomFont(parEngine), "Правила");
|
|
||||||
|
|
||||||
var (exitUiObject, exitUi, _) =
|
|
||||||
UiUtil.CreateTextUi(scene, uiContainer, UiUtil.GetDoomFont(parEngine), "Выход");
|
|
||||||
|
|
||||||
var (stackObject, stack) = UiUtil.CreateStackUi(scene,
|
|
||||||
new StackComponent
|
|
||||||
{
|
|
||||||
Offset = new Vector2(0, -1f), Container = uiContainer, Children = { playUi, leadersUi, rulesUi, exitUi }
|
|
||||||
});
|
|
||||||
stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
|
|
||||||
|
|
||||||
playUi.OnClick += _ => parEngine.SceneManager.TransitionTo(() => PlayScene.Create(parEngine));
|
|
||||||
leadersUi.OnClick += _ => parEngine.SceneManager.TransitionTo(() => LeadersScene.Create(parEngine));
|
|
||||||
rulesUi.OnClick += _ => parEngine.SceneManager.TransitionTo(() => RulesScene.Create(parEngine));
|
|
||||||
exitUi.OnClick += _ => parEngine.Close();
|
|
||||||
|
|
||||||
var (logoObject, logoUi) = UiUtil.CreateLogoUi(parEngine, scene, uiContainer);
|
|
||||||
logoUi.Offset = new Vector2(0, 3f);
|
|
||||||
|
|
||||||
var (selectorObject, selector) = UiUtil.CreateSelectorUi(scene,
|
|
||||||
new SelectorComponent { Children = { playUi, leadersUi, rulesUi, exitUi } });
|
|
||||||
|
|
||||||
scene.AddChild(uiContainerObject, selectorObject);
|
|
||||||
|
|
||||||
scene.AddChild(uiContainerObject, stackObject);
|
|
||||||
scene.AddChild(uiContainerObject, logoObject);
|
|
||||||
|
|
||||||
scene.AddChild(stackObject, playUiObject);
|
|
||||||
scene.AddChild(stackObject, leadersUiObject);
|
|
||||||
scene.AddChild(stackObject, rulesUiObject);
|
|
||||||
scene.AddChild(stackObject, exitUiObject);
|
|
||||||
|
|
||||||
return scene;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
138
DoomDeathmatch/src/Scene/MainScene.cs
Normal file
138
DoomDeathmatch/src/Scene/MainScene.cs
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
using DoomDeathmatch.Component.UI;
|
||||||
|
using DoomDeathmatch.Scene.Play;
|
||||||
|
using Engine.Scene;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Scene;
|
||||||
|
|
||||||
|
public static class MainScene
|
||||||
|
{
|
||||||
|
public static Engine.Scene.Scene Create(Engine.Engine parEngine)
|
||||||
|
{
|
||||||
|
var scene = new Engine.Scene.Scene();
|
||||||
|
|
||||||
|
var (cameraObject, camera) = UiUtil.CreateOrthographicCamera(scene);
|
||||||
|
|
||||||
|
var (uiContainerObject, uiContainer) =
|
||||||
|
UiUtil.CreateBackgroundUi(scene, new UiContainerComponent { Camera = camera });
|
||||||
|
|
||||||
|
var (logoObject, logoUi) = UiUtil.CreateLogoUi(parEngine, scene, uiContainer);
|
||||||
|
logoUi.Offset = new Vector2(0, 3f);
|
||||||
|
scene.AddChild(uiContainerObject, logoObject);
|
||||||
|
|
||||||
|
var menuController = new MenuControllerComponent();
|
||||||
|
var menuControllerObject = GameObjectUtil.CreateGameObject(scene, [
|
||||||
|
menuController
|
||||||
|
]);
|
||||||
|
|
||||||
|
var mainMenu = CreateMainMenu(parEngine, scene, uiContainer, menuController);
|
||||||
|
menuController.AddMenuItem("main", mainMenu);
|
||||||
|
|
||||||
|
var leadersMenu = CreateLeadersMenu(parEngine, scene, uiContainer, menuController);
|
||||||
|
leadersMenu.IsEnabled = false;
|
||||||
|
menuController.AddMenuItem("leaders", leadersMenu);
|
||||||
|
|
||||||
|
var rulesMenu = CreateRulesMenu(parEngine, scene, uiContainer, menuController);
|
||||||
|
rulesMenu.IsEnabled = false;
|
||||||
|
menuController.AddMenuItem("rules", rulesMenu);
|
||||||
|
|
||||||
|
scene.AddChild(uiContainerObject, mainMenu);
|
||||||
|
scene.AddChild(uiContainerObject, leadersMenu);
|
||||||
|
scene.AddChild(uiContainerObject, rulesMenu);
|
||||||
|
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GameObject CreateMainMenu(Engine.Engine parEngine, Engine.Scene.Scene parScene,
|
||||||
|
UiContainerComponent parUiContainer, MenuControllerComponent parMenuController)
|
||||||
|
{
|
||||||
|
var parentObject = GameObjectUtil.CreateGameObject(parScene);
|
||||||
|
|
||||||
|
var (playUiObject, playUi, _) =
|
||||||
|
UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(parEngine), "Играть");
|
||||||
|
|
||||||
|
var (leadersUiObject, leadersUi, _) =
|
||||||
|
UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(parEngine), "Лидеры");
|
||||||
|
|
||||||
|
var (rulesUiObject, rulesUi, _) =
|
||||||
|
UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(parEngine), "Правила");
|
||||||
|
|
||||||
|
var (exitUiObject, exitUi, _) =
|
||||||
|
UiUtil.CreateTextUi(parScene, parUiContainer, UiUtil.GetDoomFont(parEngine), "Выход");
|
||||||
|
|
||||||
|
var (stackObject, stack) = UiUtil.CreateStackUi(parScene,
|
||||||
|
new StackComponent
|
||||||
|
{
|
||||||
|
Offset = new Vector2(0, -1f), Container = parUiContainer, Children = { playUi, leadersUi, rulesUi, exitUi }
|
||||||
|
});
|
||||||
|
stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
|
||||||
|
|
||||||
|
playUi.OnClick += _ => parEngine.SceneManager.TransitionTo(() => PlayScene.Create(parEngine));
|
||||||
|
leadersUi.OnClick += _ => parMenuController.SelectMenuItem("leaders");
|
||||||
|
rulesUi.OnClick += _ => parMenuController.SelectMenuItem("rules");
|
||||||
|
exitUi.OnClick += _ => parEngine.Close();
|
||||||
|
|
||||||
|
var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene,
|
||||||
|
new SelectorComponent { Children = { playUi, leadersUi, rulesUi, exitUi } });
|
||||||
|
|
||||||
|
parScene.AddChild(parentObject, selectorObject);
|
||||||
|
parScene.AddChild(parentObject, stackObject);
|
||||||
|
|
||||||
|
parScene.AddChild(stackObject, playUiObject);
|
||||||
|
parScene.AddChild(stackObject, leadersUiObject);
|
||||||
|
parScene.AddChild(stackObject, rulesUiObject);
|
||||||
|
parScene.AddChild(stackObject, exitUiObject);
|
||||||
|
|
||||||
|
return parentObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GameObject CreateLeadersMenu(Engine.Engine parEngine, Engine.Scene.Scene parScene,
|
||||||
|
UiContainerComponent parUiContainer, MenuControllerComponent parMenuController)
|
||||||
|
{
|
||||||
|
var parentObject = GameObjectUtil.CreateGameObject(parScene);
|
||||||
|
|
||||||
|
var (backUiObject, backUi, _) = UiUtil.CreateTextUi(parScene, parUiContainer,
|
||||||
|
UiUtil.GetDoomFont(parEngine), "Назад");
|
||||||
|
backUi.OnClick += _ => parMenuController.SelectMenuItem("main");
|
||||||
|
|
||||||
|
var (stackObject, stack) = UiUtil.CreateStackUi(parScene,
|
||||||
|
new StackComponent { Offset = new Vector2(0, -1f), Container = parUiContainer, Children = { backUi } });
|
||||||
|
stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
|
||||||
|
|
||||||
|
var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene, new SelectorComponent { Children = { backUi } });
|
||||||
|
|
||||||
|
parScene.AddChild(parentObject, selectorObject);
|
||||||
|
parScene.AddChild(parentObject, stackObject);
|
||||||
|
parScene.AddChild(stackObject, backUiObject);
|
||||||
|
|
||||||
|
return parentObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GameObject CreateRulesMenu(Engine.Engine parEngine, Engine.Scene.Scene parScene,
|
||||||
|
UiContainerComponent parUiContainer, MenuControllerComponent parMenuController)
|
||||||
|
{
|
||||||
|
var parentObject = GameObjectUtil.CreateGameObject(parScene);
|
||||||
|
|
||||||
|
var (backUiObject, backUi, _) = UiUtil.CreateTextUi(parScene, parUiContainer,
|
||||||
|
UiUtil.GetDoomFont(parEngine), "Назад");
|
||||||
|
backUi.OnClick += _ => parMenuController.SelectMenuItem("main");
|
||||||
|
|
||||||
|
var (rulesObject, rulesUi, _) = UiUtil.CreateTextUi(parScene, parUiContainer,
|
||||||
|
UiUtil.GetDoomFont(parEngine), "Правила");
|
||||||
|
|
||||||
|
var (stackObject, stack) = UiUtil.CreateStackUi(parScene,
|
||||||
|
new StackComponent { Offset = new Vector2(0, -1f), Container = parUiContainer, Children = { rulesUi, backUi } });
|
||||||
|
stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
|
||||||
|
|
||||||
|
var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene, new SelectorComponent { Children = { backUi } });
|
||||||
|
|
||||||
|
parScene.AddChild(parentObject, selectorObject);
|
||||||
|
|
||||||
|
parScene.AddChild(parentObject, stackObject);
|
||||||
|
|
||||||
|
parScene.AddChild(stackObject, rulesObject);
|
||||||
|
parScene.AddChild(stackObject, backUiObject);
|
||||||
|
|
||||||
|
return parentObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
90
DoomDeathmatch/src/Scene/Play/EnemyObject.cs
Normal file
90
DoomDeathmatch/src/Scene/Play/EnemyObject.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
|
using DoomDeathmatch.Component.MVC.Model.Enemy;
|
||||||
|
using DoomDeathmatch.Component.MVC.View;
|
||||||
|
using DoomDeathmatch.Component.UI;
|
||||||
|
using DoomDeathmatch.Component.Util;
|
||||||
|
using DoomDeathmatch.Component.Util.Collision;
|
||||||
|
using Engine.Graphics.Texture;
|
||||||
|
using Engine.Scene;
|
||||||
|
using Engine.Scene.Component.BuiltIn;
|
||||||
|
using Engine.Scene.Component.BuiltIn.Renderer;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace DoomDeathmatch.Scene.Play;
|
||||||
|
|
||||||
|
public static class EnemyObject
|
||||||
|
{
|
||||||
|
public static GameObject CreateEnemy(Engine.Engine parEngine, Engine.Scene.Scene parScene, EnemyData parEnemyData)
|
||||||
|
{
|
||||||
|
var enemyHealthTextRenderer = new TextRenderer { Font = UiUtil.GetDoomFont(parEngine), Text = "Здоровье: 000" };
|
||||||
|
var displayBox2DRenderer = new Box2DRenderer();
|
||||||
|
|
||||||
|
var demonObject = GameObjectUtil.CreateGameObject(parScene,
|
||||||
|
[
|
||||||
|
new EnemyController(parEnemyData),
|
||||||
|
new EnemyView(displayBox2DRenderer),
|
||||||
|
|
||||||
|
new HealthController(parEnemyData.BaseHealth),
|
||||||
|
new EnemyHealthView(enemyHealthTextRenderer),
|
||||||
|
|
||||||
|
new MovementController(),
|
||||||
|
new RigidbodyComponent(),
|
||||||
|
new DragComponent { Drag = 5f, Coefficient = new Vector3(1, 1, 0) },
|
||||||
|
|
||||||
|
new AABBColliderComponent
|
||||||
|
{
|
||||||
|
Collider = new AABBCollider { Size = new Vector3(1, 1, 2) },
|
||||||
|
Offset = new Vector3(0, 0f, 1f),
|
||||||
|
ColliderGroups = { "enemy" },
|
||||||
|
ExcludeColliderCollideGroups = { "enemy" }
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
var demonHealthContainer = GameObjectUtil.CreateGameObject(parScene,
|
||||||
|
new Transform { Translation = new Vector3(0, 1.25f, 0f), Scale = new Vector3(0.2f) }
|
||||||
|
);
|
||||||
|
|
||||||
|
var demonHealthObject = GameObjectUtil.CreateGameObject(parScene, [
|
||||||
|
enemyHealthTextRenderer,
|
||||||
|
new TextAlignComponent { Alignment = TextAlignComponent.Align.Center }
|
||||||
|
]
|
||||||
|
);
|
||||||
|
var demonVisualObject = GameObjectUtil.CreateGameObject(parScene,
|
||||||
|
new Transform { Translation = new Vector3(0, 0f, 1f), Size = new Vector3(1, 2, 1) }, [
|
||||||
|
displayBox2DRenderer,
|
||||||
|
new BillboardComponent(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
parScene.AddChild(demonObject, demonVisualObject);
|
||||||
|
parScene.AddChild(demonVisualObject, demonHealthContainer);
|
||||||
|
parScene.AddChild(demonHealthContainer, demonHealthObject);
|
||||||
|
|
||||||
|
return demonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameObject CreateImpFireball(Engine.Scene.Scene parScene, Vector3 parPosition,
|
||||||
|
Vector3 parVelocity, float parDamage, Transform? parBillboardTarget = null)
|
||||||
|
{
|
||||||
|
var rigidbodyComponent = new RigidbodyComponent();
|
||||||
|
rigidbodyComponent.AddVelocity(parVelocity);
|
||||||
|
|
||||||
|
var fireballObject = GameObjectUtil.CreateGameObject(parScene,
|
||||||
|
new Transform { Translation = parPosition, Size = new Vector3(0.5f) },
|
||||||
|
[
|
||||||
|
rigidbodyComponent,
|
||||||
|
new Box2DRenderer
|
||||||
|
{
|
||||||
|
Texture = Engine.Engine.Instance.AssetResourceManager.Load<Texture>("texture/fireball.png")
|
||||||
|
},
|
||||||
|
new BillboardComponent { Target = parBillboardTarget },
|
||||||
|
new FireballComponent { Damage = parDamage },
|
||||||
|
new AABBColliderComponent
|
||||||
|
{
|
||||||
|
Collider = new AABBCollider { Size = new Vector3(0.25f) }, ExcludeColliderCollideGroups = { "enemy" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return fireballObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
using DoomDeathmatch.Component;
|
using DoomDeathmatch.Component.MVC.Controller;
|
||||||
using DoomDeathmatch.Component.MVC.Controller;
|
using DoomDeathmatch.Component.MVC.Model.Enemy;
|
||||||
using DoomDeathmatch.Component.MVC.View;
|
using DoomDeathmatch.Component.MVC.View;
|
||||||
using DoomDeathmatch.Component.UI;
|
using DoomDeathmatch.Component.UI;
|
||||||
using DoomDeathmatch.Component.Util;
|
using DoomDeathmatch.Component.Util;
|
||||||
|
using DoomDeathmatch.Component.Util.Collision;
|
||||||
using Engine.Asset.Mesh;
|
using Engine.Asset.Mesh;
|
||||||
using Engine.Graphics.Pipeline;
|
using Engine.Graphics.Pipeline;
|
||||||
using Engine.Graphics.Texture;
|
using Engine.Graphics.Texture;
|
||||||
using Engine.Scene;
|
using Engine.Scene;
|
||||||
using Engine.Scene.Component.BuiltIn;
|
|
||||||
using Engine.Scene.Component.BuiltIn.Renderer;
|
using Engine.Scene.Component.BuiltIn.Renderer;
|
||||||
using OpenTK.Mathematics;
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
@@ -23,8 +23,141 @@ public static class PlayScene
|
|||||||
var (uiContainerObject, uiContainer) =
|
var (uiContainerObject, uiContainer) =
|
||||||
UiUtil.CreateContainerUi(scene, new UiContainerComponent { Camera = hudCamera });
|
UiUtil.CreateContainerUi(scene, new UiContainerComponent { Camera = hudCamera });
|
||||||
|
|
||||||
|
var menuController = new MenuControllerComponent();
|
||||||
|
var menuControllerObject = GameObjectUtil.CreateGameObject(scene, [
|
||||||
|
menuController
|
||||||
|
]);
|
||||||
|
|
||||||
|
var (playUiObject, (playWeaponView, playHealthView, playScoreView, plaTimerView)) =
|
||||||
|
CreateGameUi(parEngine, scene, uiContainer, menuController);
|
||||||
|
menuController.AddMenuItem("play", playUiObject);
|
||||||
|
scene.AddChild(uiContainerObject, playUiObject);
|
||||||
|
|
||||||
|
var escapeUiObject = CreateEscapeMenu(parEngine, scene, uiContainer, menuController);
|
||||||
|
escapeUiObject.IsEnabled = false;
|
||||||
|
menuController.AddMenuItem("escape", escapeUiObject);
|
||||||
|
scene.AddChild(uiContainerObject, escapeUiObject);
|
||||||
|
|
||||||
|
var (perspectiveCameraObject, perspectiveCamera) = UiUtil.CreatePerspectiveCamera(scene);
|
||||||
|
perspectiveCameraObject.Transform.Translation.Z = 2;
|
||||||
|
var playerObject = GameObjectUtil.CreateGameObject(scene, [
|
||||||
|
new ControllerComponent(),
|
||||||
|
|
||||||
|
new MovementController { Speed = 10f },
|
||||||
|
new RigidbodyComponent(),
|
||||||
|
new DragComponent { Drag = 10f, Coefficient = new Vector3(1, 1, 0) },
|
||||||
|
|
||||||
|
new AABBColliderComponent
|
||||||
|
{
|
||||||
|
Collider = new AABBCollider { Size = new Vector3(1, 1, 2) },
|
||||||
|
Offset = new Vector3(0, 0f, 1f),
|
||||||
|
ColliderGroups = { "player" },
|
||||||
|
ExcludeColliderCollideGroups = { "player" }
|
||||||
|
},
|
||||||
|
|
||||||
|
new PlayerController(perspectiveCamera),
|
||||||
|
|
||||||
|
new WeaponController(),
|
||||||
|
playWeaponView,
|
||||||
|
|
||||||
|
new HealthController(),
|
||||||
|
playHealthView,
|
||||||
|
]);
|
||||||
|
playerObject.Transform.Translation.X = -3;
|
||||||
|
var gameControllerObject = GameObjectUtil.CreateGameObject(scene, [
|
||||||
|
new GameController(menuController),
|
||||||
|
|
||||||
|
new TimerController(),
|
||||||
|
plaTimerView,
|
||||||
|
|
||||||
|
new ScoreController(),
|
||||||
|
playScoreView,
|
||||||
|
|
||||||
|
new CollisionManager(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
scene.AddChild(playerObject, perspectiveCameraObject);
|
||||||
|
|
||||||
|
var mapObject = LoadMap(parEngine, scene, "default");
|
||||||
|
var impObject = EnemyObject.CreateEnemy(parEngine, scene, EnemyData.Imp);
|
||||||
|
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GameObject LoadMap(Engine.Engine parEngine, Engine.Scene.Scene parScene, string parMapName)
|
||||||
|
{
|
||||||
|
var mapObject = GameObjectUtil.CreateGameObject(parScene, [
|
||||||
|
new MeshRenderer
|
||||||
|
{
|
||||||
|
Mesh = parEngine.AssetResourceManager.Load<Mesh>($"map/{parMapName}/mesh.obj"),
|
||||||
|
Albedo = parEngine.AssetResourceManager.Load<Texture>($"map/{parMapName}/texture.png")
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
var colliders = parEngine.AssetResourceManager.Load<Mesh>($"map/{parMapName}/colliders.obj");
|
||||||
|
var collidersObject = MeshToColliders(parScene, colliders);
|
||||||
|
|
||||||
|
var monsterSpawnPoints = MeshToSpawnPoints(
|
||||||
|
parEngine.AssetResourceManager.Load<Mesh>($"map/{parMapName}/monster_spawners.obj"));
|
||||||
|
|
||||||
|
var valuableSpawnPoints = MeshToSpawnPoints(
|
||||||
|
parEngine.AssetResourceManager.Load<Mesh>($"map/{parMapName}/valuable_spawners.obj"));
|
||||||
|
|
||||||
|
parScene.AddChild(mapObject, collidersObject);
|
||||||
|
|
||||||
|
return mapObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Vector3> MeshToSpawnPoints(Mesh parMesh)
|
||||||
|
{
|
||||||
|
return parMesh.Indices.Select(parIndex => parMesh.Vertices[(int)parIndex]._position).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GameObject MeshToColliders(Engine.Scene.Scene parScene, Mesh parMesh)
|
||||||
|
{
|
||||||
|
var allCollidersObject = GameObjectUtil.CreateGameObject(parScene);
|
||||||
|
|
||||||
|
if (parMesh.Indices.Count % (4 * 6) != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Mesh is not an AABB collider");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < parMesh.Indices.Count; i += 24)
|
||||||
|
{
|
||||||
|
var max = new Vector3(float.MinValue);
|
||||||
|
var min = new Vector3(float.MaxValue);
|
||||||
|
for (var j = 0; j < 24; j++)
|
||||||
|
{
|
||||||
|
var position = parMesh.Vertices[(int)parMesh.Indices[i + j]]._position;
|
||||||
|
max = Vector3.ComponentMax(max, position);
|
||||||
|
min = Vector3.ComponentMin(min, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
var size = max - min;
|
||||||
|
var offset = min + size / 2;
|
||||||
|
|
||||||
|
var colliderObject = GameObjectUtil.CreateColliderForceField(
|
||||||
|
parScene,
|
||||||
|
new AABBColliderComponent
|
||||||
|
{
|
||||||
|
Collider = new AABBCollider { Size = size }, Offset = offset, ColliderGroups = { "wall" }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
parScene.AddChild(allCollidersObject, colliderObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allCollidersObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (GameObject, (WeaponView, HealthView, ScoreView, TimerView)) CreateGameUi(Engine.Engine parEngine,
|
||||||
|
Engine.Scene.Scene parScene,
|
||||||
|
UiContainerComponent parUiContainer, MenuControllerComponent parMenuController)
|
||||||
|
{
|
||||||
|
var parentObject = GameObjectUtil.CreateGameObject(parScene);
|
||||||
|
|
||||||
var (bottomContainerObject, bottomContainer) =
|
var (bottomContainerObject, bottomContainer) =
|
||||||
UiUtil.CreateContainerUi(scene, new UiContainerComponent { Container = uiContainer });
|
UiUtil.CreateContainerUi(parScene, new UiContainerComponent { Container = parUiContainer });
|
||||||
bottomContainer.Anchor = Anchor.BottomCenter;
|
bottomContainer.Anchor = Anchor.BottomCenter;
|
||||||
bottomContainer.Center = Anchor.BottomCenter;
|
bottomContainer.Center = Anchor.BottomCenter;
|
||||||
bottomContainerObject.AddComponent(new Box2DRenderer
|
bottomContainerObject.AddComponent(new Box2DRenderer
|
||||||
@@ -33,104 +166,121 @@ public static class PlayScene
|
|||||||
});
|
});
|
||||||
bottomContainerObject.AddComponent(new CopySizeComponent
|
bottomContainerObject.AddComponent(new CopySizeComponent
|
||||||
{
|
{
|
||||||
Target = uiContainerObject.Transform, Coefficient = new Vector3(1, 0, 1)
|
Target = parUiContainer.GameObject.Transform, Coefficient = new Vector3(1, 0, 1)
|
||||||
});
|
});
|
||||||
bottomContainerObject.Transform.Size.Y = 1.5f;
|
bottomContainerObject.Transform.Size.Y = 1.5f;
|
||||||
scene.AddChild(uiContainerObject, bottomContainerObject);
|
parScene.AddChild(parentObject, bottomContainerObject);
|
||||||
|
|
||||||
var (gunObject, (gunUi, gunSprite)) = UiUtil.CreateSpriteUi(scene, bottomContainer,
|
var (gunObject, (gunUi, gunSprite)) = UiUtil.CreateSpriteUi(parScene, bottomContainer,
|
||||||
parEngine.AssetResourceManager.Load<Texture>("texture/pistol.png"), RenderLayer.HUD);
|
null, RenderLayer.HUD);
|
||||||
gunObject.Transform.Scale = new Vector3(5);
|
gunObject.Transform.Scale = new Vector3(5);
|
||||||
gunUi.Anchor = Anchor.TopCenter;
|
gunUi.Anchor = Anchor.TopCenter;
|
||||||
gunUi.Center = Anchor.BottomCenter;
|
gunUi.Center = Anchor.BottomCenter;
|
||||||
scene.AddChild(bottomContainerObject, gunObject);
|
gunUi.Offset = new Vector2(0, -0.05f);
|
||||||
|
parScene.AddChild(bottomContainerObject, gunObject);
|
||||||
|
|
||||||
var (healthObject, healthUi, (_, healthTextRenderer)) =
|
var (healthObject, healthUi, (_, healthTextRenderer)) =
|
||||||
UiUtil.CreateTextUi(scene, bottomContainer, UiUtil.GetDoomFont(parEngine), "Здоровье: 000",
|
UiUtil.CreateTextUi(parScene, bottomContainer, UiUtil.GetDoomFont(parEngine), "Здоровье: 000",
|
||||||
TextAlignComponent.Align.Center,
|
TextAlignComponent.Align.Center,
|
||||||
RenderLayer.HUD);
|
RenderLayer.HUD);
|
||||||
healthObject.Transform.Scale = new Vector3(0.75f);
|
healthObject.Transform.Scale = new Vector3(0.75f);
|
||||||
healthUi.Anchor = Anchor.CenterLeft;
|
healthUi.Anchor = Anchor.CenterLeft;
|
||||||
healthUi.Center = Anchor.CenterLeft;
|
healthUi.Center = Anchor.CenterLeft;
|
||||||
scene.AddChild(bottomContainerObject, healthObject);
|
parScene.AddChild(bottomContainerObject, healthObject);
|
||||||
|
|
||||||
var (ammoObject, ammoUi, (_, ammoTextRenderer)) =
|
var (ammoObject, ammoUi, (_, ammoTextRenderer)) =
|
||||||
UiUtil.CreateTextUi(scene, bottomContainer, UiUtil.GetDoomFont(parEngine), "Патроны: 00/00",
|
UiUtil.CreateTextUi(parScene, bottomContainer, UiUtil.GetDoomFont(parEngine), "Патроны: 00/00",
|
||||||
TextAlignComponent.Align.Center,
|
TextAlignComponent.Align.Center,
|
||||||
RenderLayer.HUD);
|
RenderLayer.HUD);
|
||||||
ammoObject.Transform.Scale = new Vector3(0.75f);
|
ammoObject.Transform.Scale = new Vector3(0.75f);
|
||||||
ammoUi.Anchor = Anchor.TopRight;
|
ammoUi.Anchor = Anchor.TopRight;
|
||||||
ammoUi.Center = Anchor.TopRight;
|
ammoUi.Center = Anchor.TopRight;
|
||||||
scene.AddChild(bottomContainerObject, ammoObject);
|
parScene.AddChild(bottomContainerObject, ammoObject);
|
||||||
|
|
||||||
var (weaponObject, weaponUi, (_, weaponTextRenderer)) =
|
var (weaponObject, weaponUi, (_, weaponTextRenderer)) =
|
||||||
UiUtil.CreateTextUi(scene, bottomContainer, UiUtil.GetDoomFont(parEngine), "Оружие: ОРУЖИЕОР",
|
UiUtil.CreateTextUi(parScene, bottomContainer, UiUtil.GetDoomFont(parEngine), "Оружие: ОРУЖИЕОР",
|
||||||
TextAlignComponent.Align.Center,
|
TextAlignComponent.Align.Center,
|
||||||
RenderLayer.HUD);
|
RenderLayer.HUD);
|
||||||
weaponObject.Transform.Scale = new Vector3(0.75f);
|
weaponObject.Transform.Scale = new Vector3(0.75f);
|
||||||
weaponUi.Anchor = Anchor.BottomRight;
|
weaponUi.Anchor = Anchor.BottomRight;
|
||||||
weaponUi.Center = Anchor.BottomRight;
|
weaponUi.Center = Anchor.BottomRight;
|
||||||
scene.AddChild(bottomContainerObject, weaponObject);
|
parScene.AddChild(bottomContainerObject, weaponObject);
|
||||||
|
|
||||||
var (topContainerObject, topContainer) =
|
var (topContainerObject, topContainer) =
|
||||||
UiUtil.CreateContainerUi(scene, new UiContainerComponent { Container = uiContainer });
|
UiUtil.CreateContainerUi(parScene, new UiContainerComponent { Container = parUiContainer });
|
||||||
topContainer.Anchor = Anchor.TopCenter;
|
topContainer.Anchor = Anchor.TopCenter;
|
||||||
topContainer.Center = Anchor.TopCenter;
|
topContainer.Center = Anchor.TopCenter;
|
||||||
topContainerObject.AddComponent(
|
topContainerObject.AddComponent(
|
||||||
new Box2DRenderer { Color = new Vector4(1, 0, 0, 1), RenderLayer = RenderLayer.HUD });
|
new Box2DRenderer { Color = new Vector4(1, 0, 0, 1), RenderLayer = RenderLayer.HUD });
|
||||||
topContainerObject.AddComponent(new CopySizeComponent
|
topContainerObject.AddComponent(new CopySizeComponent
|
||||||
{
|
{
|
||||||
Target = uiContainerObject.Transform, Coefficient = new Vector3(1, 0, 1)
|
Target = parUiContainer.GameObject.Transform, Coefficient = new Vector3(1, 0, 1)
|
||||||
});
|
});
|
||||||
topContainerObject.Transform.Size.Y = 1f;
|
topContainerObject.Transform.Size.Y = 1f;
|
||||||
scene.AddChild(uiContainerObject, topContainerObject);
|
parScene.AddChild(parentObject, topContainerObject);
|
||||||
|
|
||||||
var (timerObject, timerUi, _) =
|
var (timerObject, timerUi, (_, timerTextRenderer)) =
|
||||||
UiUtil.CreateTextUi(scene, topContainer, UiUtil.GetDoomFont(parEngine), "Время: 00:00",
|
UiUtil.CreateTextUi(parScene, topContainer, UiUtil.GetDoomFont(parEngine), "Время: 00:00",
|
||||||
parRenderLayer: RenderLayer.HUD);
|
parRenderLayer: RenderLayer.HUD);
|
||||||
timerUi.Anchor = Anchor.CenterLeft;
|
timerUi.Anchor = Anchor.CenterLeft;
|
||||||
timerUi.Center = Anchor.CenterLeft;
|
timerUi.Center = Anchor.CenterLeft;
|
||||||
scene.AddChild(topContainerObject, timerObject);
|
parScene.AddChild(topContainerObject, timerObject);
|
||||||
|
|
||||||
var (scoreObject, scoreUi, (_, scoreTextRenderer)) =
|
var (scoreObject, scoreUi, (_, scoreTextRenderer)) =
|
||||||
UiUtil.CreateTextUi(scene, topContainer, UiUtil.GetDoomFont(parEngine), "Счет: 00000",
|
UiUtil.CreateTextUi(parScene, topContainer, UiUtil.GetDoomFont(parEngine), "Счет: 00000",
|
||||||
parRenderLayer: RenderLayer.HUD);
|
parRenderLayer: RenderLayer.HUD);
|
||||||
scoreUi.Anchor = Anchor.CenterRight;
|
scoreUi.Anchor = Anchor.CenterRight;
|
||||||
scoreUi.Center = Anchor.CenterRight;
|
scoreUi.Center = Anchor.CenterRight;
|
||||||
scene.AddChild(topContainerObject, scoreObject);
|
parScene.AddChild(topContainerObject, scoreObject);
|
||||||
|
|
||||||
var playerObject = GameObjectUtil.CreateGameObject(scene, [
|
var weaponView = new WeaponView(weaponTextRenderer, ammoTextRenderer, gunSprite);
|
||||||
new RigidbodyComponent(),
|
var healthView = new HealthView(healthTextRenderer);
|
||||||
new ControllerComponent { Speed = 5f },
|
var scoreView = new ScoreView(scoreTextRenderer);
|
||||||
new DragComponent { Drag = 5f, Coefficient = new Vector3(1, 1, 0) },
|
var timerView = new TimerView(timerTextRenderer);
|
||||||
|
|
||||||
new PlayerController(),
|
return (parentObject, (weaponView, healthView, scoreView, timerView));
|
||||||
|
}
|
||||||
|
|
||||||
new WeaponController(),
|
private static GameObject CreateEscapeMenu(Engine.Engine parEngine, Engine.Scene.Scene parScene,
|
||||||
new WeaponView(weaponTextRenderer, ammoTextRenderer, gunSprite),
|
UiContainerComponent parUiContainer, MenuControllerComponent parMenuController)
|
||||||
|
{
|
||||||
|
var parentObject = GameObjectUtil.CreateGameObject(parScene);
|
||||||
|
|
||||||
new HealthController(),
|
var (backgroundObject, backgroundUiContainer) = UiUtil.CreateBackgroundUi(parScene,
|
||||||
new HealthView(healthTextRenderer),
|
new UiContainerComponent { Container = parUiContainer }, new Vector4(0, 0, 0, 0.9f), RenderLayer.HUD);
|
||||||
|
backgroundObject.AddComponent(new CopySizeComponent { Target = parUiContainer.GameObject.Transform });
|
||||||
|
parScene.AddChild(parentObject, backgroundObject);
|
||||||
|
|
||||||
new ScoreController(),
|
var (logoObject, logoUi) = UiUtil.CreateLogoUi(parEngine, parScene, backgroundUiContainer, RenderLayer.HUD);
|
||||||
new ScoreView(scoreTextRenderer),
|
logoUi.Offset = new Vector2(0, 3f);
|
||||||
]);
|
parScene.AddChild(parentObject, logoObject);
|
||||||
|
|
||||||
var (perspectiveCameraObject, perspectiveCamera) = UiUtil.CreatePerspectiveCamera(scene);
|
var (backUiObject, backUi, _) = UiUtil.CreateTextUi(parScene, backgroundUiContainer,
|
||||||
perspectiveCameraObject.Transform.Translation.Z = 2;
|
UiUtil.GetDoomFont(parEngine), "Назад",
|
||||||
|
parRenderLayer: RenderLayer.HUD);
|
||||||
|
backUi.OnClick += parUiComponent =>
|
||||||
|
parUiComponent.GameObject.Scene!.FindFirstComponent<GameController>()!.Unpause();
|
||||||
|
|
||||||
var mapObject = GameObjectUtil.CreateGameObject(scene, [
|
var (exitUiObject, exitUi, _) = UiUtil.CreateTextUi(parScene, backgroundUiContainer,
|
||||||
new MeshRenderer { Mesh = parEngine.AssetResourceManager.Load<Mesh>("model/map.obj") },
|
UiUtil.GetDoomFont(parEngine), "Выход",
|
||||||
]);
|
parRenderLayer: RenderLayer.HUD);
|
||||||
|
exitUi.OnClick += _ => parEngine.SceneManager.TransitionTo(() => MainScene.Create(parEngine));
|
||||||
|
|
||||||
var impObject = GameObjectUtil.CreateGameObject(scene,
|
var (stackObject, stack) = UiUtil.CreateStackUi(parScene,
|
||||||
new Transform { Translation = new Vector3(0, 0, 1), Scale = new Vector3(1, 2, 1), }, [
|
new StackComponent
|
||||||
new Box2DRenderer { Texture = parEngine.AssetResourceManager.Load<Texture>("texture/imp.png") },
|
{
|
||||||
new BillboardComponent { Target = perspectiveCameraObject.Transform }
|
Offset = new Vector2(0, -1f), Container = backgroundUiContainer, Children = { backUi, exitUi }
|
||||||
]);
|
});
|
||||||
|
stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
|
||||||
|
|
||||||
scene.AddChild(playerObject, perspectiveCameraObject);
|
var (selectorObject, selector) = UiUtil.CreateSelectorUi(parScene,
|
||||||
|
new SelectorComponent { Children = { backUi, exitUi } }, RenderLayer.HUD);
|
||||||
|
|
||||||
return scene;
|
parScene.AddChild(parentObject, selectorObject);
|
||||||
|
parScene.AddChild(parentObject, stackObject);
|
||||||
|
parScene.AddChild(stackObject, backUiObject);
|
||||||
|
parScene.AddChild(stackObject, exitUiObject);
|
||||||
|
|
||||||
|
return parentObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using DoomDeathmatch.Component.UI;
|
|
||||||
using DoomDeathmatch.Scene.Main;
|
|
||||||
using OpenTK.Mathematics;
|
|
||||||
|
|
||||||
namespace DoomDeathmatch.Scene.Rules;
|
|
||||||
|
|
||||||
public static class RulesScene
|
|
||||||
{
|
|
||||||
public static Engine.Scene.Scene Create(Engine.Engine parEngine)
|
|
||||||
{
|
|
||||||
var scene = new Engine.Scene.Scene();
|
|
||||||
|
|
||||||
var (cameraObject, camera) = UiUtil.CreateOrthographicCamera(scene);
|
|
||||||
|
|
||||||
var (uiContainerObject, uiContainer) = UiUtil.CreateBackgroundUi(scene, new UiContainerComponent { Camera = camera });
|
|
||||||
|
|
||||||
var (logoObject, logoUi) = UiUtil.CreateLogoUi(parEngine, scene, uiContainer);
|
|
||||||
logoUi.Offset = new Vector2(0, 3f);
|
|
||||||
|
|
||||||
var (backUiObject, backUi, _) = UiUtil.CreateTextUi(scene, uiContainer,
|
|
||||||
UiUtil.GetDoomFont(parEngine), "Назад");
|
|
||||||
backUi.OnClick += _ => parEngine.SceneManager.TransitionTo(() => MainScene.Create(parEngine));
|
|
||||||
|
|
||||||
var (rulesObject, rulesUi, _) = UiUtil.CreateTextUi(scene, uiContainer,
|
|
||||||
UiUtil.GetDoomFont(parEngine), "Правила");
|
|
||||||
|
|
||||||
var (stackObject, stack) = UiUtil.CreateStackUi(scene,
|
|
||||||
new StackComponent { Offset = new Vector2(0, -1f), Container = uiContainer, Children = { rulesUi, backUi } });
|
|
||||||
stackObject.Transform.Size.Xy = new Vector2(1f, 6f);
|
|
||||||
|
|
||||||
var (selectorObject, selector) = UiUtil.CreateSelectorUi(scene, new SelectorComponent { Children = { backUi } });
|
|
||||||
|
|
||||||
scene.AddChild(uiContainerObject, selectorObject);
|
|
||||||
|
|
||||||
scene.AddChild(uiContainerObject, logoObject);
|
|
||||||
scene.AddChild(uiContainerObject, stackObject);
|
|
||||||
|
|
||||||
scene.AddChild(stackObject, rulesObject);
|
|
||||||
scene.AddChild(stackObject, backUiObject);
|
|
||||||
|
|
||||||
return scene;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -155,7 +155,7 @@ public static class UiUtil
|
|||||||
selectorObject.AddComponent(parSelectorComponent);
|
selectorObject.AddComponent(parSelectorComponent);
|
||||||
var innerSelectorObject = new GameObject
|
var innerSelectorObject = new GameObject
|
||||||
{
|
{
|
||||||
Transform = { Translation = new Vector3(-0.5f, 0, 0), Size = new Vector3(0.25f, 0.5f, 1f) }
|
Transform = { Translation = new Vector3(-0.5f, 0, -1), Size = new Vector3(0.25f, 0.5f, 1f) }
|
||||||
};
|
};
|
||||||
innerSelectorObject.AddComponent(new Box2DRenderer
|
innerSelectorObject.AddComponent(new Box2DRenderer
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ uniform mat4 uViewMatrix;
|
|||||||
layout (location = 0) in vec3 aPosition;
|
layout (location = 0) in vec3 aPosition;
|
||||||
layout (location = 1) in vec2 aUV;
|
layout (location = 1) in vec2 aUV;
|
||||||
layout (location = 2) in vec4 aColor;
|
layout (location = 2) in vec4 aColor;
|
||||||
layout (location = 3) in int aTextureId;
|
layout (location = 3) in float aTextureId;
|
||||||
layout (location = 4) in mat4 aModel;
|
layout (location = 4) in mat4 aModel;
|
||||||
|
|
||||||
layout (location = 0) out vec4 oColor;
|
layout (location = 0) out vec4 oColor;
|
||||||
layout (location = 1) out vec2 oUV;
|
layout (location = 1) out vec2 oUV;
|
||||||
layout (location = 2) flat out int oTextureId;
|
layout (location = 2) flat out float oTextureId;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
@@ -30,7 +30,7 @@ uniform sampler2D uTexture[16];
|
|||||||
|
|
||||||
layout (location = 0) in vec4 iColor;
|
layout (location = 0) in vec4 iColor;
|
||||||
layout (location = 1) in vec2 iUV;
|
layout (location = 1) in vec2 iUV;
|
||||||
layout (location = 2) flat in int iTextureId;
|
layout (location = 2) flat in float iTextureId;
|
||||||
|
|
||||||
layout (location = 0) out vec4 FragColor;
|
layout (location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ void main()
|
|||||||
FragColor = iColor;
|
FragColor = iColor;
|
||||||
|
|
||||||
if (iTextureId >= 0)
|
if (iTextureId >= 0)
|
||||||
FragColor *= texture(uTexture[iTextureId], iUV);
|
FragColor *= texture(uTexture[int(iTextureId)], iUV);
|
||||||
|
|
||||||
if (FragColor.a == 0.0)
|
if (FragColor.a == 0.0)
|
||||||
discard;
|
discard;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using OpenTK.Mathematics;
|
|
||||||
|
|
||||||
namespace Engine.Asset.Font.Metadata;
|
namespace Engine.Asset.Font.Metadata;
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ namespace Engine.Asset.Mesh.Loader;
|
|||||||
|
|
||||||
public class ObjMeshLoader : IMeshLoader
|
public class ObjMeshLoader : IMeshLoader
|
||||||
{
|
{
|
||||||
private static readonly ObjMeshLoader _instance = new();
|
private static readonly ObjMeshLoader INSTANCE = new();
|
||||||
|
|
||||||
public static Mesh Load(TextReader parReader, MeshLoaderParameters parParameters = MeshLoaderParameters.Default)
|
public static Mesh Load(TextReader parReader, MeshLoaderParameters parParameters = MeshLoaderParameters.Default)
|
||||||
{
|
{
|
||||||
return _instance.LoadMesh(parReader, parParameters);
|
return INSTANCE.LoadMesh(parReader, parParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjMeshLoader()
|
private ObjMeshLoader()
|
||||||
@@ -62,7 +62,7 @@ public class ObjMeshLoader : IMeshLoader
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "f":
|
case "f":
|
||||||
for (var i = 1; i <= 3; i++)
|
for (var i = 1; i < parts.Length; i++)
|
||||||
{
|
{
|
||||||
var faceComponents = parts[i].Split('/');
|
var faceComponents = parts[i].Split('/');
|
||||||
var meshVertex = new Mesh.Vertex { _position = tempVertices[int.Parse(faceComponents[0]) - 1] };
|
var meshVertex = new Mesh.Vertex { _position = tempVertices[int.Parse(faceComponents[0]) - 1] };
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ namespace Engine.Asset.Mesh.Loader;
|
|||||||
|
|
||||||
public class StlMeshLoader : IMeshLoader
|
public class StlMeshLoader : IMeshLoader
|
||||||
{
|
{
|
||||||
private static readonly StlMeshLoader _instance = new();
|
private static readonly StlMeshLoader INSTANCE = new();
|
||||||
|
|
||||||
public static Mesh Load(TextReader parReader, MeshLoaderParameters parParameters = MeshLoaderParameters.Default)
|
public static Mesh Load(TextReader parReader, MeshLoaderParameters parParameters = MeshLoaderParameters.Default)
|
||||||
{
|
{
|
||||||
return _instance.LoadMesh(parReader, parParameters);
|
return INSTANCE.LoadMesh(parReader, parParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StlMeshLoader()
|
private StlMeshLoader()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace Engine.Graphics.Render.Quad;
|
|||||||
public struct QuadInstanceVertex : IVertex
|
public struct QuadInstanceVertex : IVertex
|
||||||
{
|
{
|
||||||
[Vertex(VertexAttribType.Float, 4)] public Vector4 _color;
|
[Vertex(VertexAttribType.Float, 4)] public Vector4 _color;
|
||||||
[Vertex(VertexAttribType.Int)] public int _textureId;
|
[Vertex(VertexAttribType.Float)] public float _textureId;
|
||||||
[Vertex(VertexAttribType.Float, 4, 4)] public Matrix4 _modelMatrix;
|
[Vertex(VertexAttribType.Float, 4, 4)] public Matrix4 _modelMatrix;
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class QuadRenderer : InstancedRenderer<QuadCommonVertex, QuadInstanceVert
|
|||||||
|
|
||||||
_instanceVertices[_queuedInstanceCount]._modelMatrix = parModelMatrix;
|
_instanceVertices[_queuedInstanceCount]._modelMatrix = parModelMatrix;
|
||||||
_instanceVertices[_queuedInstanceCount]._color = parColor;
|
_instanceVertices[_queuedInstanceCount]._color = parColor;
|
||||||
_instanceVertices[_queuedInstanceCount]._textureId = textureId;
|
_instanceVertices[_queuedInstanceCount]._textureId = textureId + 0.01f;
|
||||||
|
|
||||||
_frameHash = HashCode.Combine(_frameHash, _instanceVertices[_queuedInstanceCount]);
|
_frameHash = HashCode.Combine(_frameHash, _instanceVertices[_queuedInstanceCount]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using Engine.Graphics.Pipeline;
|
||||||
using Engine.Graphics.Pipeline;
|
|
||||||
using Engine.Graphics.Pixel;
|
using Engine.Graphics.Pixel;
|
||||||
using Engine.Graphics.Render.Quad;
|
using Engine.Graphics.Render.Quad;
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using OpenTK.Mathematics;
|
using OpenTK.Mathematics;
|
||||||
using OpenTK.Windowing.Desktop;
|
using OpenTK.Windowing.Desktop;
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace Engine.Graphics;
|
namespace Engine.Graphics;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using System.Collections;
|
namespace Engine.Graphics.Texture;
|
||||||
|
|
||||||
namespace Engine.Graphics.Texture;
|
|
||||||
|
|
||||||
public class TextureUnitMap(int parCapacity)
|
public class TextureUnitMap(int parCapacity)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Engine.Graphics.Pixel;
|
using Engine.Graphics.Pixel;
|
||||||
using SixLabors.ImageSharp;
|
|
||||||
using SixLabors.ImageSharp.Formats;
|
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
|
||||||
|
|||||||
5
Engine/src/Resource/ShaderResource.Designer.cs
generated
5
Engine/src/Resource/ShaderResource.Designer.cs
generated
@@ -7,10 +7,7 @@
|
|||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace Engine {
|
namespace Engine.Resource {
|
||||||
using System;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Engine.Graphics.Camera;
|
using Engine.Graphics.Camera;
|
||||||
using Engine.Graphics.Pipeline;
|
using Engine.Graphics.Pipeline;
|
||||||
using OpenTK.Mathematics;
|
using OpenTK.Mathematics;
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace Engine.Scene.Component.BuiltIn;
|
namespace Engine.Scene.Component.BuiltIn;
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ public class PerspectiveCamera(
|
|||||||
{
|
{
|
||||||
public float FieldOfView { get; set; } = parFieldOfView;
|
public float FieldOfView { get; set; } = parFieldOfView;
|
||||||
|
|
||||||
|
public Vector3 Forward => new Vector4(0, 1, 0, 1).MulProject(GameObject.Transform.TransformMatrix).Xyz;
|
||||||
public override Matrix4 View
|
public override Matrix4 View
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ public class Transform : Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector3 GetFullTranslation()
|
||||||
|
{
|
||||||
|
return FullTransformMatrix.ExtractTranslation();
|
||||||
|
}
|
||||||
|
|
||||||
public Transform Clone()
|
public Transform Clone()
|
||||||
{
|
{
|
||||||
var clone =
|
var clone =
|
||||||
@@ -38,4 +43,15 @@ public class Transform : Component
|
|||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float SquaredDistanceTo(Transform parTransform)
|
||||||
|
{
|
||||||
|
var translation = GetFullTranslation();
|
||||||
|
var otherTranslation = parTransform.GetFullTranslation();
|
||||||
|
|
||||||
|
var difference = translation - otherTranslation;
|
||||||
|
var squaredDistance = difference.LengthSquared;
|
||||||
|
|
||||||
|
return squaredDistance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,10 @@ public abstract class Component : IUpdate, IRender
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void PreUpdate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void Update(double parDeltaTime)
|
public virtual void Update(double parDeltaTime)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,22 +11,26 @@ public sealed class GameObject : IUpdate, IRender
|
|||||||
public bool IsEnabled
|
public bool IsEnabled
|
||||||
{
|
{
|
||||||
get => IsSelfEnabled && IsParentEnabled;
|
get => IsSelfEnabled && IsParentEnabled;
|
||||||
set => IsSelfEnabled = value;
|
set => _nextIsSelfEnabled = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsSelfEnabled { get; set; } = true;
|
private bool IsSelfEnabled { get; set; } = true;
|
||||||
private bool _prevIsSelfEnabled = true;
|
private bool _prevIsSelfEnabled = true;
|
||||||
|
private bool _nextIsSelfEnabled = true;
|
||||||
private bool IsParentEnabled => Scene?.Hierarchy.GetParent(this)?.IsEnabled ?? true;
|
private bool IsParentEnabled => Scene?.Hierarchy.GetParent(this)?.IsEnabled ?? true;
|
||||||
|
|
||||||
public Transform Transform { get; }
|
public Transform Transform { get; }
|
||||||
|
|
||||||
internal Scene? Scene { get; set; }
|
public Scene? Scene { get; set; }
|
||||||
|
|
||||||
private readonly Queue<Action> _componentActions = new();
|
private readonly Queue<Action> _componentActions = new();
|
||||||
|
|
||||||
private readonly List<Component.Component> _components = [];
|
private readonly List<Component.Component> _components = [];
|
||||||
private readonly HashSet<Type> _addedComponentTypes = [];
|
private readonly HashSet<Type> _addedComponentTypes = [];
|
||||||
|
|
||||||
|
private readonly HashSet<Component.Component> _addedComponents = [];
|
||||||
|
private readonly HashSet<Component.Component> _removedComponents = [];
|
||||||
|
|
||||||
public GameObject()
|
public GameObject()
|
||||||
{
|
{
|
||||||
AddComponent<Transform>();
|
AddComponent<Transform>();
|
||||||
@@ -43,20 +47,37 @@ public sealed class GameObject : IUpdate, IRender
|
|||||||
Transform = GetComponent<Transform>()!;
|
Transform = GetComponent<Transform>()!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Awake()
|
public void PreUpdate()
|
||||||
{
|
{
|
||||||
|
ProcessAddedComponents();
|
||||||
|
ProcessRemovedComponents();
|
||||||
|
|
||||||
foreach (var component in _components)
|
foreach (var component in _components)
|
||||||
{
|
{
|
||||||
component.Awake();
|
component.PreUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
private void ProcessAddedComponents()
|
||||||
{
|
{
|
||||||
foreach (var component in _components)
|
foreach (var component in _addedComponents)
|
||||||
{
|
{
|
||||||
|
component.Awake();
|
||||||
component.Start();
|
component.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_addedComponents.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessRemovedComponents()
|
||||||
|
{
|
||||||
|
foreach (var component in _removedComponents)
|
||||||
|
{
|
||||||
|
component.Destroy();
|
||||||
|
component.GameObject = null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
_removedComponents.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(double parDeltaTime)
|
public void Update(double parDeltaTime)
|
||||||
@@ -112,7 +133,44 @@ public sealed class GameObject : IUpdate, IRender
|
|||||||
|
|
||||||
public T? GetComponent<T>() where T : Component.Component
|
public T? GetComponent<T>() where T : Component.Component
|
||||||
{
|
{
|
||||||
return !HasComponent<T>() ? null : _components.OfType<T>().First();
|
if (!HasComponent<T>())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
foreach (var component in _components)
|
||||||
|
{
|
||||||
|
if (component is T result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T? GetComponentAny<T>() where T : Component.Component
|
||||||
|
{
|
||||||
|
var component = GetComponent<T>();
|
||||||
|
if (component != null)
|
||||||
|
return component;
|
||||||
|
|
||||||
|
component = GetComponentInChildren<T>();
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T? GetComponentInChildren<T>() where T : Component.Component
|
||||||
|
{
|
||||||
|
var children = Scene!.Hierarchy.GetChildren(this);
|
||||||
|
|
||||||
|
foreach (var child in children)
|
||||||
|
{
|
||||||
|
var component = child.GetComponent<T>();
|
||||||
|
if (component != null)
|
||||||
|
return component;
|
||||||
|
|
||||||
|
var childComponent = child.GetComponentInChildren<T>();
|
||||||
|
if (childComponent != null)
|
||||||
|
return childComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddComponent<T>() where T : Component.Component, new()
|
public void AddComponent<T>() where T : Component.Component, new()
|
||||||
@@ -142,6 +200,8 @@ public sealed class GameObject : IUpdate, IRender
|
|||||||
|
|
||||||
public void AddComponent<T>(T parComponent) where T : Component.Component
|
public void AddComponent<T>(T parComponent) where T : Component.Component
|
||||||
{
|
{
|
||||||
|
parComponent.GameObject = this;
|
||||||
|
|
||||||
_componentActions.Enqueue(() =>
|
_componentActions.Enqueue(() =>
|
||||||
{
|
{
|
||||||
if (HasComponent<T>())
|
if (HasComponent<T>())
|
||||||
@@ -149,9 +209,9 @@ public sealed class GameObject : IUpdate, IRender
|
|||||||
throw new ArgumentException($"GameObject already has component of type {typeof(T)}");
|
throw new ArgumentException($"GameObject already has component of type {typeof(T)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
parComponent.GameObject = this;
|
|
||||||
_components.Add(parComponent);
|
_components.Add(parComponent);
|
||||||
_addedComponentTypes.Add(parComponent.GetType().GetComponentBaseType());
|
_addedComponentTypes.Add(parComponent.GetType().GetComponentBaseType());
|
||||||
|
_addedComponents.Add(parComponent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,6 +237,7 @@ public sealed class GameObject : IUpdate, IRender
|
|||||||
|
|
||||||
_components.Remove(component);
|
_components.Remove(component);
|
||||||
_addedComponentTypes.Remove(typeof(T));
|
_addedComponentTypes.Remove(typeof(T));
|
||||||
|
_removedComponents.Add(component);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,9 +249,26 @@ public sealed class GameObject : IUpdate, IRender
|
|||||||
|
|
||||||
internal void ProcessChanges()
|
internal void ProcessChanges()
|
||||||
{
|
{
|
||||||
|
IsSelfEnabled = _nextIsSelfEnabled;
|
||||||
|
|
||||||
while (_componentActions.TryDequeue(out var action))
|
while (_componentActions.TryDequeue(out var action))
|
||||||
{
|
{
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Id.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? parObj)
|
||||||
|
{
|
||||||
|
return parObj is GameObject gameObject && Id == gameObject.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -50,6 +50,9 @@ public class Hierarchy<T>
|
|||||||
|
|
||||||
_hierarchyActions.Enqueue(() =>
|
_hierarchyActions.Enqueue(() =>
|
||||||
{
|
{
|
||||||
|
if (!Contains(parObj))
|
||||||
|
return;
|
||||||
|
|
||||||
var parent = GetParent(parObj);
|
var parent = GetParent(parObj);
|
||||||
_childrenLookup[parent].Remove(parObj);
|
_childrenLookup[parent].Remove(parObj);
|
||||||
|
|
||||||
@@ -97,9 +100,24 @@ public class Hierarchy<T>
|
|||||||
: throw new InvalidOperationException($"Child {parChild} is not in hierarchy");
|
: throw new InvalidOperationException($"Child {parChild} is not in hierarchy");
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<T> GetChildren(T? parObj = null)
|
public IEnumerable<T> GetChildren(T? parParent = null)
|
||||||
{
|
{
|
||||||
return _childrenLookup.TryGetValue(parObj, out IList<T>? children) ? children : Enumerable.Empty<T>();
|
return _childrenLookup.TryGetValue(parParent, out var children) ? children : Enumerable.Empty<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<T> GetAllChildren(T? parParent = null)
|
||||||
|
{
|
||||||
|
var children = GetChildren(parParent);
|
||||||
|
|
||||||
|
foreach (var child in children)
|
||||||
|
{
|
||||||
|
foreach (var descendant in GetAllChildren(child))
|
||||||
|
{
|
||||||
|
yield return descendant;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsInHierarchy(T? parAncestor, T? parChild)
|
public bool IsInHierarchy(T? parAncestor, T? parChild)
|
||||||
@@ -133,19 +151,4 @@ public class Hierarchy<T>
|
|||||||
|
|
||||||
return IsInHierarchy(parAncestor, parent);
|
return IsInHierarchy(parAncestor, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<T> GetAllChildren(T? parObj = null)
|
|
||||||
{
|
|
||||||
IEnumerable<T>? children = GetChildren(parObj);
|
|
||||||
|
|
||||||
foreach (var child in children)
|
|
||||||
{
|
|
||||||
yield return child;
|
|
||||||
|
|
||||||
foreach (var descendant in GetAllChildren(child))
|
|
||||||
{
|
|
||||||
yield return descendant;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,8 @@ public class Scene : IUpdate, IRender
|
|||||||
{
|
{
|
||||||
public bool IsPlaying { get; private set; }
|
public bool IsPlaying { get; private set; }
|
||||||
public IReadOnlyDictionary<RenderLayer, ICamera> Cameras => _cameras;
|
public IReadOnlyDictionary<RenderLayer, ICamera> Cameras => _cameras;
|
||||||
|
public float TimeScale { get; set; } = 1.0f;
|
||||||
|
|
||||||
private readonly Dictionary<RenderLayer, ICamera> _cameras = new();
|
private readonly Dictionary<RenderLayer, ICamera> _cameras = new();
|
||||||
|
|
||||||
internal Hierarchy<GameObject> Hierarchy { get; } = new();
|
internal Hierarchy<GameObject> Hierarchy { get; } = new();
|
||||||
@@ -32,9 +34,11 @@ public class Scene : IUpdate, IRender
|
|||||||
IsPlaying = true;
|
IsPlaying = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<T> FindAllComponents<T>() where T : Component.Component
|
public List<T> FindAllComponents<T>(bool parOnlyEnabled = true) where T : Component.Component
|
||||||
{
|
{
|
||||||
return Hierarchy.Objects.Select(parGameObject => parGameObject.GetComponent<T>())
|
return Hierarchy.Objects
|
||||||
|
.Where(parGameObject => !parOnlyEnabled || parGameObject.IsEnabled)
|
||||||
|
.Select(parGameObject => parGameObject.GetComponent<T>())
|
||||||
.Where(parComponent => parComponent != null).ToList()!;
|
.Where(parComponent => parComponent != null).ToList()!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,9 +57,16 @@ public class Scene : IUpdate, IRender
|
|||||||
|
|
||||||
ProcessChanges();
|
ProcessChanges();
|
||||||
|
|
||||||
foreach (var gameObject in Hierarchy.Objects)
|
var hierarchyObjects = Hierarchy.Objects;
|
||||||
|
|
||||||
|
foreach (var gameObject in hierarchyObjects)
|
||||||
{
|
{
|
||||||
gameObject.Update(parDeltaTime);
|
gameObject.PreUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var gameObject in hierarchyObjects)
|
||||||
|
{
|
||||||
|
gameObject.Update(parDeltaTime * TimeScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,16 +99,9 @@ public class Scene : IUpdate, IRender
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Add(GameObject parGameObject)
|
public void Add(GameObject parGameObject)
|
||||||
{
|
|
||||||
Hierarchy.Add(parGameObject);
|
|
||||||
|
|
||||||
_sceneActions.Enqueue(() =>
|
|
||||||
{
|
{
|
||||||
parGameObject.Scene = this;
|
parGameObject.Scene = this;
|
||||||
|
Hierarchy.Add(parGameObject);
|
||||||
parGameObject.Awake();
|
|
||||||
parGameObject.Start();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddChild(GameObject parParent, GameObject parChild)
|
public void AddChild(GameObject parParent, GameObject parChild)
|
||||||
@@ -108,11 +112,12 @@ public class Scene : IUpdate, IRender
|
|||||||
|
|
||||||
public void Remove(GameObject parGameObject)
|
public void Remove(GameObject parGameObject)
|
||||||
{
|
{
|
||||||
|
var children = Hierarchy.GetAllChildren(parGameObject).ToList();
|
||||||
Hierarchy.Remove(parGameObject);
|
Hierarchy.Remove(parGameObject);
|
||||||
|
|
||||||
_sceneActions.Enqueue(() =>
|
_sceneActions.Enqueue(() =>
|
||||||
{
|
{
|
||||||
foreach (var child in Hierarchy.GetAllChildren(parGameObject))
|
foreach (var child in children)
|
||||||
{
|
{
|
||||||
child.Destroy();
|
child.Destroy();
|
||||||
child.Scene = null;
|
child.Scene = null;
|
||||||
@@ -124,6 +129,11 @@ public class Scene : IUpdate, IRender
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<GameObject> GetChildren(GameObject parParent, bool parRecursive = false)
|
||||||
|
{
|
||||||
|
return parRecursive ? Hierarchy.GetAllChildren(parParent) : Hierarchy.GetChildren(parParent);
|
||||||
|
}
|
||||||
|
|
||||||
private void ProcessChanges()
|
private void ProcessChanges()
|
||||||
{
|
{
|
||||||
Hierarchy.ProcessChanges();
|
Hierarchy.ProcessChanges();
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ public class SceneManager : IUpdate, IRender
|
|||||||
public Scene? CurrentScene => _currentScene;
|
public Scene? CurrentScene => _currentScene;
|
||||||
|
|
||||||
private Scene? _currentScene;
|
private Scene? _currentScene;
|
||||||
// private Scene? _nextScene;
|
|
||||||
private Func<Scene>? _nextScene;
|
private Func<Scene>? _nextScene;
|
||||||
|
|
||||||
public void TransitionTo(Func<Scene>? parScene)
|
public void TransitionTo(Func<Scene>? parScene)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace Engine.Util;
|
namespace Engine.Util;
|
||||||
|
|
||||||
public class Timer
|
public class TickableTimer
|
||||||
{
|
{
|
||||||
public event Action? OnFinished;
|
public event Action? OnFinished;
|
||||||
public event Action<double>? OnUpdate;
|
public event Action<double>? OnUpdate;
|
||||||
@@ -41,7 +41,7 @@ public class Timer
|
|||||||
private double _totalTime;
|
private double _totalTime;
|
||||||
private double _currentTime;
|
private double _currentTime;
|
||||||
|
|
||||||
public Timer(double parTotalTime)
|
public TickableTimer(double parTotalTime)
|
||||||
{
|
{
|
||||||
if (parTotalTime <= 0)
|
if (parTotalTime <= 0)
|
||||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parTotalTime);
|
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parTotalTime);
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using Engine.Graphics;
|
using Engine.Graphics;
|
||||||
using Engine.Graphics.Texture;
|
using Engine.Graphics.Texture;
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using OpenTK.Mathematics;
|
|
||||||
using OpenTK.Windowing.Common;
|
using OpenTK.Windowing.Common;
|
||||||
using OpenTK.Windowing.Desktop;
|
using OpenTK.Windowing.Desktop;
|
||||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using Engine.Resource;
|
|||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using OpenTK.Mathematics;
|
using OpenTK.Mathematics;
|
||||||
using OpenTK.Windowing.Common;
|
using OpenTK.Windowing.Common;
|
||||||
using PresenterConsole.Resource;
|
using ShaderResource = PresenterConsole.Resource.ShaderResource;
|
||||||
|
|
||||||
namespace PresenterConsole;
|
namespace PresenterConsole;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using System.Configuration;
|
using System.IO;
|
||||||
using System.Data;
|
|
||||||
using System.IO;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using Engine;
|
using Engine;
|
||||||
using Engine.Graphics;
|
using Engine.Graphics;
|
||||||
|
|||||||
Reference in New Issue
Block a user