diff --git a/DoomDeathmatch/DoomDeathmatch.csproj b/DoomDeathmatch/DoomDeathmatch.csproj index 3d2f171..e1baa34 100644 --- a/DoomDeathmatch/DoomDeathmatch.csproj +++ b/DoomDeathmatch/DoomDeathmatch.csproj @@ -10,8 +10,4 @@ - - - - diff --git a/DoomDeathmatch/asset/font/doom/atlas.png b/DoomDeathmatch/asset/font/doom/atlas.png index 7c76c05..83f3349 100644 Binary files a/DoomDeathmatch/asset/font/doom/atlas.png and b/DoomDeathmatch/asset/font/doom/atlas.png differ diff --git a/DoomDeathmatch/asset/font/doom/metadata.json b/DoomDeathmatch/asset/font/doom/metadata.json index d4e15d3..53caf9d 100644 --- a/DoomDeathmatch/asset/font/doom/metadata.json +++ b/DoomDeathmatch/asset/font/doom/metadata.json @@ -4,8 +4,8 @@ "distanceRange": 2, "distanceRangeMiddle": 0, "size": 32.875, - "width": 184, - "height": 184, + "width": 248, + "height": 248, "yOrigin": "bottom" }, "metrics": { @@ -31,10 +31,10 @@ "top": 0.95817490494296575 }, "atlasBounds": { - "left": 31.5, - "bottom": 153.5, - "right": 38.5, - "top": 183.5 + "left": 91.5, + "bottom": 217.5, + "right": 98.5, + "top": 247.5 } }, { @@ -47,10 +47,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 138.5, - "bottom": 17.5, - "right": 150.5, - "top": 28.5 + "left": 36.5, + "bottom": 1.5, + "right": 48.5, + "top": 12.5 } }, { @@ -63,10 +63,10 @@ "top": 1.0494296577946769 }, "atlasBounds": { - "left": 39.5, - "bottom": 153.5, - "right": 51.5, - "top": 183.5 + "left": 99.5, + "bottom": 217.5, + "right": 111.5, + "top": 247.5 } }, { @@ -79,10 +79,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 110.5, - "bottom": 30.5, - "right": 132.5, - "top": 53.5 + "left": 0.5, + "bottom": 13.5, + "right": 22.5, + "top": 36.5 } }, { @@ -95,10 +95,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 176.5, - "bottom": 172.5, - "right": 183.5, - "top": 183.5 + "left": 240.5, + "bottom": 135.5, + "right": 247.5, + "top": 146.5 } }, { @@ -111,10 +111,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 58.5, - "bottom": 115.5, - "right": 66.5, - "top": 144.5 + "left": 32.5, + "bottom": 148.5, + "right": 40.5, + "top": 177.5 } }, { @@ -127,10 +127,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 67.5, - "bottom": 115.5, - "right": 75.5, - "top": 144.5 + "left": 146.5, + "bottom": 148.5, + "right": 154.5, + "top": 177.5 } }, { @@ -143,10 +143,10 @@ "top": 0.92775665399239526 }, "atlasBounds": { - "left": 172.5, - "bottom": 33.5, - "right": 183.5, - "top": 45.5 + "left": 236.5, + "bottom": 235.5, + "right": 247.5, + "top": 247.5 } }, { @@ -159,10 +159,10 @@ "top": 0.80608365019011397 }, "atlasBounds": { - "left": 90.5, - "bottom": 15.5, - "right": 101.5, - "top": 28.5 + "left": 236.5, + "bottom": 221.5, + "right": 247.5, + "top": 234.5 } }, { @@ -175,10 +175,10 @@ "top": 0.38022813688212925 }, "atlasBounds": { - "left": 176.5, - "bottom": 158.5, - "right": 183.5, - "top": 171.5 + "left": 229.5, + "bottom": 23.5, + "right": 236.5, + "top": 36.5 } }, { @@ -191,10 +191,10 @@ "top": 0.71482889733840294 }, "atlasBounds": { - "left": 160.5, - "bottom": 21.5, - "right": 171.5, - "top": 28.5 + "left": 90.5, + "bottom": 5.5, + "right": 101.5, + "top": 12.5 } }, { @@ -207,10 +207,10 @@ "top": 0.3802281368821292 }, "atlasBounds": { - "left": 176.5, - "bottom": 103.5, - "right": 183.5, - "top": 113.5 + "left": 49.5, + "bottom": 2.5, + "right": 56.5, + "top": 12.5 } }, { @@ -223,10 +223,10 @@ "top": 0.95817490494296575 }, "atlasBounds": { - "left": 52.5, - "bottom": 153.5, - "right": 64.5, - "top": 183.5 + "left": 112.5, + "bottom": 217.5, + "right": 124.5, + "top": 247.5 } }, { @@ -239,10 +239,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 76.5, - "bottom": 115.5, - "right": 89.5, - "top": 144.5 + "left": 183.5, + "bottom": 148.5, + "right": 196.5, + "top": 177.5 } }, { @@ -255,10 +255,10 @@ "top": 0.95817490494296575 }, "atlasBounds": { - "left": 65.5, - "bottom": 153.5, - "right": 75.5, - "top": 183.5 + "left": 125.5, + "bottom": 217.5, + "right": 135.5, + "top": 247.5 } }, { @@ -271,10 +271,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 90.5, - "bottom": 115.5, - "right": 103.5, - "top": 144.5 + "left": 210.5, + "bottom": 148.5, + "right": 223.5, + "top": 177.5 } }, { @@ -287,10 +287,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 104.5, - "bottom": 115.5, - "right": 117.5, - "top": 144.5 + "left": 224.5, + "bottom": 148.5, + "right": 237.5, + "top": 177.5 } }, { @@ -303,10 +303,10 @@ "top": 0.95817490494296575 }, "atlasBounds": { - "left": 76.5, - "bottom": 153.5, - "right": 89.5, - "top": 183.5 + "left": 136.5, + "bottom": 217.5, + "right": 149.5, + "top": 247.5 } }, { @@ -319,10 +319,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 118.5, - "bottom": 115.5, - "right": 131.5, - "top": 144.5 + "left": 0.5, + "bottom": 117.5, + "right": 13.5, + "top": 146.5 } }, { @@ -335,10 +335,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 132.5, - "bottom": 115.5, - "right": 145.5, - "top": 144.5 + "left": 14.5, + "bottom": 117.5, + "right": 27.5, + "top": 146.5 } }, { @@ -351,10 +351,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 146.5, - "bottom": 115.5, - "right": 159.5, - "top": 144.5 + "left": 56.5, + "bottom": 117.5, + "right": 69.5, + "top": 146.5 } }, { @@ -367,10 +367,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 160.5, - "bottom": 115.5, - "right": 173.5, - "top": 144.5 + "left": 84.5, + "bottom": 117.5, + "right": 97.5, + "top": 146.5 } }, { @@ -383,10 +383,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 0.5, - "bottom": 84.5, - "right": 14.5, - "top": 113.5 + "left": 98.5, + "bottom": 117.5, + "right": 112.5, + "top": 146.5 } }, { @@ -399,10 +399,10 @@ "top": 0.92775665399239526 }, "atlasBounds": { - "left": 176.5, - "bottom": 85.5, - "right": 183.5, - "top": 102.5 + "left": 240.5, + "bottom": 117.5, + "right": 247.5, + "top": 134.5 } }, { @@ -415,10 +415,10 @@ "top": 0.92775665399239537 }, "atlasBounds": { - "left": 82.5, - "bottom": 9.5, - "right": 89.5, - "top": 28.5 + "left": 221.5, + "bottom": 17.5, + "right": 228.5, + "top": 36.5 } }, { @@ -431,10 +431,10 @@ "top": 0.7756653992395437 }, "atlasBounds": { - "left": 102.5, - "bottom": 16.5, - "right": 113.5, - "top": 28.5 + "left": 12.5, + "bottom": 0.5, + "right": 23.5, + "top": 12.5 } }, { @@ -447,10 +447,10 @@ "top": 0.7756653992395437 }, "atlasBounds": { - "left": 114.5, - "bottom": 16.5, - "right": 125.5, - "top": 28.5 + "left": 24.5, + "bottom": 0.5, + "right": 35.5, + "top": 12.5 } }, { @@ -463,10 +463,10 @@ "top": 0.7756653992395437 }, "atlasBounds": { - "left": 126.5, - "bottom": 16.5, - "right": 137.5, - "top": 28.5 + "left": 0.5, + "bottom": 0.5, + "right": 11.5, + "top": 12.5 } }, { @@ -479,10 +479,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 15.5, - "bottom": 84.5, - "right": 28.5, - "top": 113.5 + "left": 142.5, + "bottom": 117.5, + "right": 155.5, + "top": 146.5 } }, { @@ -495,10 +495,10 @@ "top": 0.95817490494296575 }, "atlasBounds": { - "left": 90.5, - "bottom": 153.5, - "right": 103.5, - "top": 183.5 + "left": 150.5, + "bottom": 217.5, + "right": 163.5, + "top": 247.5 } }, { @@ -511,10 +511,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 66.5, - "bottom": 84.5, - "right": 79.5, - "top": 113.5 + "left": 156.5, + "bottom": 117.5, + "right": 169.5, + "top": 146.5 } }, { @@ -527,10 +527,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 80.5, - "bottom": 84.5, - "right": 93.5, - "top": 113.5 + "left": 170.5, + "bottom": 117.5, + "right": 183.5, + "top": 146.5 } }, { @@ -543,10 +543,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 121.5, - "bottom": 84.5, - "right": 134.5, - "top": 113.5 + "left": 184.5, + "bottom": 117.5, + "right": 197.5, + "top": 146.5 } }, { @@ -559,10 +559,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 149.5, - "bottom": 84.5, - "right": 162.5, - "top": 113.5 + "left": 198.5, + "bottom": 117.5, + "right": 211.5, + "top": 146.5 } }, { @@ -575,10 +575,10 @@ "top": 0.95817490494296575 }, "atlasBounds": { - "left": 104.5, - "bottom": 153.5, - "right": 117.5, - "top": 183.5 + "left": 164.5, + "bottom": 217.5, + "right": 177.5, + "top": 247.5 } }, { @@ -591,10 +591,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 55.5, - "bottom": 54.5, - "right": 68.5, - "top": 83.5 + "left": 212.5, + "bottom": 117.5, + "right": 225.5, + "top": 146.5 } }, { @@ -607,10 +607,10 @@ "top": 0.95817490494296575 }, "atlasBounds": { - "left": 118.5, - "bottom": 153.5, - "right": 131.5, - "top": 183.5 + "left": 178.5, + "bottom": 217.5, + "right": 191.5, + "top": 247.5 } }, { @@ -623,10 +623,10 @@ "top": 1.0798479087452473 }, "atlasBounds": { - "left": 8.5, - "bottom": 149.5, - "right": 15.5, - "top": 183.5 + "left": 22.5, + "bottom": 213.5, + "right": 29.5, + "top": 247.5 } }, { @@ -639,10 +639,10 @@ "top": 1.0798479087452471 }, "atlasBounds": { - "left": 16.5, - "bottom": 150.5, - "right": 30.5, - "top": 183.5 + "left": 30.5, + "bottom": 214.5, + "right": 44.5, + "top": 247.5 } }, { @@ -655,10 +655,10 @@ "top": 0.95817490494296575 }, "atlasBounds": { - "left": 132.5, - "bottom": 153.5, - "right": 145.5, - "top": 183.5 + "left": 192.5, + "bottom": 217.5, + "right": 205.5, + "top": 247.5 } }, { @@ -671,10 +671,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 27.5, - "bottom": 54.5, - "right": 40.5, - "top": 83.5 + "left": 226.5, + "bottom": 117.5, + "right": 239.5, + "top": 146.5 } }, { @@ -687,10 +687,10 @@ "top": 0.95817490494296575 }, "atlasBounds": { - "left": 146.5, - "bottom": 153.5, - "right": 161.5, - "top": 183.5 + "left": 206.5, + "bottom": 217.5, + "right": 221.5, + "top": 247.5 } }, { @@ -703,10 +703,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 13.5, - "bottom": 54.5, - "right": 26.5, - "top": 83.5 + "left": 0.5, + "bottom": 87.5, + "right": 13.5, + "top": 116.5 } }, { @@ -719,10 +719,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 0.5, - "bottom": 54.5, - "right": 12.5, - "top": 83.5 + "left": 14.5, + "bottom": 87.5, + "right": 26.5, + "top": 116.5 } }, { @@ -735,10 +735,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 41.5, - "bottom": 54.5, - "right": 54.5, - "top": 83.5 + "left": 27.5, + "bottom": 87.5, + "right": 40.5, + "top": 116.5 } }, { @@ -751,10 +751,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 163.5, - "bottom": 84.5, - "right": 175.5, - "top": 113.5 + "left": 41.5, + "bottom": 87.5, + "right": 53.5, + "top": 116.5 } }, { @@ -767,10 +767,10 @@ "top": 0.95817490494296575 }, "atlasBounds": { - "left": 162.5, - "bottom": 153.5, - "right": 175.5, - "top": 183.5 + "left": 222.5, + "bottom": 217.5, + "right": 235.5, + "top": 247.5 } }, { @@ -783,10 +783,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 135.5, - "bottom": 84.5, - "right": 148.5, - "top": 113.5 + "left": 54.5, + "bottom": 87.5, + "right": 67.5, + "top": 116.5 } }, { @@ -800,9 +800,9 @@ }, "atlasBounds": { "left": 0.5, - "bottom": 114.5, + "bottom": 178.5, "right": 14.5, - "top": 144.5 + "top": 208.5 } }, { @@ -815,10 +815,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 108.5, - "bottom": 84.5, - "right": 120.5, - "top": 113.5 + "left": 68.5, + "bottom": 87.5, + "right": 80.5, + "top": 116.5 } }, { @@ -831,10 +831,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 94.5, - "bottom": 84.5, - "right": 107.5, - "top": 113.5 + "left": 81.5, + "bottom": 87.5, + "right": 94.5, + "top": 116.5 } }, { @@ -848,9 +848,9 @@ }, "atlasBounds": { "left": 15.5, - "bottom": 114.5, + "bottom": 178.5, "right": 30.5, - "top": 144.5 + "top": 208.5 } }, { @@ -864,9 +864,9 @@ }, "atlasBounds": { "left": 31.5, - "bottom": 114.5, + "bottom": 178.5, "right": 44.5, - "top": 144.5 + "top": 208.5 } }, { @@ -879,10 +879,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 52.5, - "bottom": 84.5, - "right": 65.5, - "top": 113.5 + "left": 95.5, + "bottom": 87.5, + "right": 108.5, + "top": 116.5 } }, { @@ -895,10 +895,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 38.5, - "bottom": 84.5, - "right": 51.5, - "top": 113.5 + "left": 109.5, + "bottom": 87.5, + "right": 122.5, + "top": 116.5 } }, { @@ -911,10 +911,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 174.5, - "bottom": 115.5, - "right": 182.5, - "top": 144.5 + "left": 238.5, + "bottom": 148.5, + "right": 246.5, + "top": 177.5 } }, { @@ -928,9 +928,9 @@ }, "atlasBounds": { "left": 45.5, - "bottom": 114.5, + "bottom": 178.5, "right": 57.5, - "top": 144.5 + "top": 208.5 } }, { @@ -943,10 +943,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 29.5, - "bottom": 84.5, - "right": 37.5, - "top": 113.5 + "left": 123.5, + "bottom": 87.5, + "right": 131.5, + "top": 116.5 } }, { @@ -959,10 +959,10 @@ "top": 0.38022813688212925 }, "atlasBounds": { - "left": 172.5, - "bottom": 46.5, - "right": 183.5, - "top": 53.5 + "left": 78.5, + "bottom": 5.5, + "right": 89.5, + "top": 12.5 } }, { @@ -975,10 +975,10 @@ "top": 0.71482889733840305 }, "atlasBounds": { - "left": 151.5, - "bottom": 20.5, - "right": 159.5, - "top": 28.5 + "left": 57.5, + "bottom": 4.5, + "right": 65.5, + "top": 12.5 } }, { @@ -991,10 +991,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 133.5, - "bottom": 30.5, - "right": 145.5, - "top": 53.5 + "left": 178.5, + "bottom": 13.5, + "right": 190.5, + "top": 36.5 } }, { @@ -1007,10 +1007,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 66.5, - "bottom": 29.5, - "right": 78.5, - "top": 53.5 + "left": 14.5, + "bottom": 62.5, + "right": 26.5, + "top": 86.5 } }, { @@ -1023,10 +1023,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 53.5, - "bottom": 29.5, - "right": 65.5, - "top": 53.5 + "left": 27.5, + "bottom": 62.5, + "right": 39.5, + "top": 86.5 } }, { @@ -1039,10 +1039,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 39.5, - "bottom": 29.5, - "right": 52.5, - "top": 53.5 + "left": 0.5, + "bottom": 62.5, + "right": 13.5, + "top": 86.5 } }, { @@ -1055,10 +1055,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 13.5, - "bottom": 29.5, - "right": 25.5, - "top": 53.5 + "left": 222.5, + "bottom": 92.5, + "right": 234.5, + "top": 116.5 } }, { @@ -1071,10 +1071,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 56.5, - "bottom": 5.5, - "right": 68.5, - "top": 28.5 + "left": 52.5, + "bottom": 38.5, + "right": 64.5, + "top": 61.5 } }, { @@ -1087,10 +1087,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 90.5, - "bottom": 59.5, - "right": 102.5, - "top": 83.5 + "left": 196.5, + "bottom": 92.5, + "right": 208.5, + "top": 116.5 } }, { @@ -1103,10 +1103,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 146.5, - "bottom": 30.5, - "right": 158.5, - "top": 53.5 + "left": 139.5, + "bottom": 13.5, + "right": 151.5, + "top": 36.5 } }, { @@ -1119,10 +1119,10 @@ "top": 1.0798479087452471 }, "atlasBounds": { - "left": 82.5, - "bottom": 56.5, - "right": 89.5, - "top": 83.5 + "left": 171.5, + "bottom": 89.5, + "right": 178.5, + "top": 116.5 } }, { @@ -1135,10 +1135,10 @@ "top": 1.0798479087452471 }, "atlasBounds": { - "left": 69.5, - "bottom": 55.5, - "right": 81.5, - "top": 83.5 + "left": 145.5, + "bottom": 88.5, + "right": 157.5, + "top": 116.5 } }, { @@ -1151,10 +1151,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 43.5, - "bottom": 5.5, - "right": 55.5, - "top": 28.5 + "left": 161.5, + "bottom": 38.5, + "right": 173.5, + "top": 61.5 } }, { @@ -1167,10 +1167,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 103.5, - "bottom": 59.5, - "right": 115.5, - "top": 83.5 + "left": 66.5, + "bottom": 62.5, + "right": 78.5, + "top": 86.5 } }, { @@ -1183,10 +1183,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 13.5, - "bottom": 5.5, - "right": 29.5, - "top": 28.5 + "left": 79.5, + "bottom": 13.5, + "right": 95.5, + "top": 36.5 } }, { @@ -1199,10 +1199,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 69.5, - "bottom": 5.5, - "right": 81.5, - "top": 28.5 + "left": 49.5, + "bottom": 13.5, + "right": 61.5, + "top": 36.5 } }, { @@ -1215,10 +1215,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 129.5, - "bottom": 59.5, - "right": 141.5, - "top": 83.5 + "left": 160.5, + "bottom": 62.5, + "right": 172.5, + "top": 86.5 } }, { @@ -1231,10 +1231,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 0.5, - "bottom": 5.5, - "right": 12.5, - "top": 28.5 + "left": 148.5, + "bottom": 38.5, + "right": 160.5, + "top": 61.5 } }, { @@ -1247,10 +1247,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 155.5, - "bottom": 59.5, - "right": 167.5, - "top": 83.5 + "left": 199.5, + "bottom": 62.5, + "right": 211.5, + "top": 86.5 } }, { @@ -1263,10 +1263,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 30.5, - "bottom": 5.5, - "right": 42.5, - "top": 28.5 + "left": 92.5, + "bottom": 38.5, + "right": 104.5, + "top": 61.5 } }, { @@ -1279,10 +1279,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 168.5, - "bottom": 59.5, - "right": 180.5, - "top": 83.5 + "left": 0.5, + "bottom": 37.5, + "right": 12.5, + "top": 61.5 } }, { @@ -1295,10 +1295,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 159.5, - "bottom": 30.5, - "right": 171.5, - "top": 53.5 + "left": 204.5, + "bottom": 38.5, + "right": 216.5, + "top": 61.5 } }, { @@ -1312,9 +1312,9 @@ }, "atlasBounds": { "left": 26.5, - "bottom": 29.5, + "bottom": 37.5, "right": 38.5, - "top": 53.5 + "top": 61.5 } }, { @@ -1327,10 +1327,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 142.5, - "bottom": 59.5, - "right": 154.5, - "top": 83.5 + "left": 121.5, + "bottom": 62.5, + "right": 133.5, + "top": 86.5 } }, { @@ -1343,10 +1343,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 93.5, - "bottom": 30.5, - "right": 109.5, - "top": 53.5 + "left": 230.5, + "bottom": 38.5, + "right": 246.5, + "top": 61.5 } }, { @@ -1359,10 +1359,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 79.5, - "bottom": 30.5, - "right": 92.5, - "top": 53.5 + "left": 65.5, + "bottom": 38.5, + "right": 78.5, + "top": 61.5 } }, { @@ -1375,10 +1375,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 116.5, - "bottom": 59.5, - "right": 128.5, - "top": 83.5 + "left": 186.5, + "bottom": 62.5, + "right": 198.5, + "top": 86.5 } }, { @@ -1391,10 +1391,10 @@ "top": 0.95817490494296564 }, "atlasBounds": { - "left": 0.5, - "bottom": 29.5, - "right": 12.5, - "top": 53.5 + "left": 147.5, + "bottom": 62.5, + "right": 159.5, + "top": 86.5 } }, { @@ -1408,9 +1408,1101 @@ }, "atlasBounds": { "left": 0.5, - "bottom": 145.5, + "bottom": 209.5, "right": 7.5, - "top": 183.5 + "top": 247.5 + } + }, + { + "unicode": 160, + "advance": 0.248 + }, + { + "unicode": 165, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.059218631178707237, + "bottom": 0.045627376425855508, + "right": 0.33621863117870721, + "top": 1.1102661596958174 + }, + "atlasBounds": { + "left": 8.5, + "bottom": 212.5, + "right": 21.5, + "top": 247.5 + } + }, + { + "unicode": 173, + "advance": 0.25, + "planeBounds": { + "left": -0.056800380228136882, + "bottom": 0.50190114068441061, + "right": 0.2778003802281368, + "top": 0.71482889733840294 + }, + "atlasBounds": { + "left": 66.5, + "bottom": 5.5, + "right": 77.5, + "top": 12.5 + } + }, + { + "unicode": 1025, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.054718631178707219, + "bottom": 0.076045627376425839, + "right": 0.34071863117870721, + "top": 1.0798479087452471 + }, + "atlasBounds": { + "left": 45.5, + "bottom": 214.5, + "right": 58.5, + "top": 247.5 + } + }, + { + "unicode": 1040, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.055718631178707248, + "bottom": 0.045627376425855508, + "right": 0.33971863117870715, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 58.5, + "bottom": 178.5, + "right": 71.5, + "top": 208.5 + } + }, + { + "unicode": 1041, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.060927756653992415, + "bottom": 0.076045627376425839, + "right": 0.36492775665399235, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 127.5, + "bottom": 117.5, + "right": 141.5, + "top": 146.5 + } + }, + { + "unicode": 1042, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.054718631178707219, + "bottom": 0.076045627376425839, + "right": 0.34071863117870721, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 113.5, + "bottom": 117.5, + "right": 126.5, + "top": 146.5 + } + }, + { + "unicode": 1043, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.059218631178707237, + "bottom": 0.045627376425855508, + "right": 0.33621863117870721, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 72.5, + "bottom": 178.5, + "right": 85.5, + "top": 208.5 + } + }, + { + "unicode": 1044, + "advance": 0.44800000000000001, + "planeBounds": { + "left": -0.052555133079847931, + "bottom": -0.015209125475285169, + "right": 0.4645551330798478, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 73.5, + "bottom": 215.5, + "right": 90.5, + "top": 247.5 + } + }, + { + "unicode": 1045, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.054718631178707219, + "bottom": 0.076045627376425839, + "right": 0.34071863117870721, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 70.5, + "bottom": 117.5, + "right": 83.5, + "top": 146.5 + } + }, + { + "unicode": 1046, + "advance": 0.38500000000000001, + "planeBounds": { + "left": -0.051636882129277577, + "bottom": 0.045627376425855508, + "right": 0.40463688212927751, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 86.5, + "bottom": 178.5, + "right": 101.5, + "top": 208.5 + } + }, + { + "unicode": 1047, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.054718631178707219, + "bottom": 0.076045627376425839, + "right": 0.34071863117870721, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 42.5, + "bottom": 117.5, + "right": 55.5, + "top": 146.5 + } + }, + { + "unicode": 1048, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.056218631178707221, + "bottom": 0.076045627376425839, + "right": 0.33921863117870721, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 28.5, + "bottom": 117.5, + "right": 41.5, + "top": 146.5 + } + }, + { + "unicode": 1049, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.055718631178707248, + "bottom": 0.076045627376425839, + "right": 0.33971863117870715, + "top": 1.0798479087452471 + }, + "atlasBounds": { + "left": 59.5, + "bottom": 214.5, + "right": 72.5, + "top": 247.5 + } + }, + { + "unicode": 1050, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.055218631178707234, + "bottom": 0.045627376425855508, + "right": 0.34021863117870721, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 102.5, + "bottom": 178.5, + "right": 115.5, + "top": 208.5 + } + }, + { + "unicode": 1051, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.048718631178707228, + "bottom": 0.045627376425855508, + "right": 0.34671863117870722, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 116.5, + "bottom": 178.5, + "right": 129.5, + "top": 208.5 + } + }, + { + "unicode": 1052, + "advance": 0.38500000000000001, + "planeBounds": { + "left": -0.058136882129277576, + "bottom": 0.045627376425855508, + "right": 0.39813688212927756, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 130.5, + "bottom": 178.5, + "right": 145.5, + "top": 208.5 + } + }, + { + "unicode": 1053, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.055718631178707248, + "bottom": 0.045627376425855508, + "right": 0.33971863117870715, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 146.5, + "bottom": 178.5, + "right": 159.5, + "top": 208.5 + } + }, + { + "unicode": 1054, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.035509505703422074, + "bottom": 0.076045627376425839, + "right": 0.32950950570342202, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 197.5, + "bottom": 148.5, + "right": 209.5, + "top": 177.5 + } + }, + { + "unicode": 1055, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.054718631178707219, + "bottom": 0.045627376425855508, + "right": 0.34071863117870721, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 160.5, + "bottom": 178.5, + "right": 173.5, + "top": 208.5 + } + }, + { + "unicode": 1056, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.059218631178707237, + "bottom": 0.076045627376425839, + "right": 0.33621863117870721, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 169.5, + "bottom": 148.5, + "right": 182.5, + "top": 177.5 + } + }, + { + "unicode": 1057, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.054718631178707219, + "bottom": 0.076045627376425839, + "right": 0.34071863117870721, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 155.5, + "bottom": 148.5, + "right": 168.5, + "top": 177.5 + } + }, + { + "unicode": 1058, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.064427756653992391, + "bottom": 0.045627376425855508, + "right": 0.36142775665399235, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 174.5, + "bottom": 178.5, + "right": 188.5, + "top": 208.5 + } + }, + { + "unicode": 1059, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.054718631178707219, + "bottom": 0.076045627376425839, + "right": 0.34071863117870721, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 132.5, + "bottom": 148.5, + "right": 145.5, + "top": 177.5 + } + }, + { + "unicode": 1060, + "advance": 0.39900000000000002, + "planeBounds": { + "left": -0.030927756653992396, + "bottom": 0.076045627376425839, + "right": 0.39492775665399232, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 117.5, + "bottom": 148.5, + "right": 131.5, + "top": 177.5 + } + }, + { + "unicode": 1061, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.054718631178707219, + "bottom": 0.045627376425855508, + "right": 0.34071863117870721, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 189.5, + "bottom": 178.5, + "right": 202.5, + "top": 208.5 + } + }, + { + "unicode": 1062, + "advance": 0.32300000000000001, + "planeBounds": { + "left": -0.055718631178707248, + "bottom": 0.076045627376425839, + "right": 0.33971863117870715, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 89.5, + "bottom": 148.5, + "right": 102.5, + "top": 177.5 + } + }, + { + "unicode": 1063, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.051218631178707237, + "bottom": 0.045627376425855508, + "right": 0.34421863117870721, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 234.5, + "bottom": 178.5, + "right": 247.5, + "top": 208.5 + } + }, + { + "unicode": 1064, + "advance": 0.38500000000000001, + "planeBounds": { + "left": -0.057636882129277561, + "bottom": 0.045627376425855508, + "right": 0.39863688212927756, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 0.5, + "bottom": 147.5, + "right": 15.5, + "top": 177.5 + } + }, + { + "unicode": 1065, + "advance": 0.38500000000000001, + "planeBounds": { + "left": -0.058136882129277576, + "bottom": 0.045627376425855508, + "right": 0.39813688212927756, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 16.5, + "bottom": 147.5, + "right": 31.5, + "top": 177.5 + } + }, + { + "unicode": 1066, + "advance": 0.39300000000000002, + "planeBounds": { + "left": -0.055136882129277559, + "bottom": 0.076045627376425839, + "right": 0.40113688212927751, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 41.5, + "bottom": 148.5, + "right": 56.5, + "top": 177.5 + } + }, + { + "unicode": 1067, + "advance": 0.42899999999999999, + "planeBounds": { + "left": -0.057055133079847928, + "bottom": 0.076045627376425839, + "right": 0.4600551330798478, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 57.5, + "bottom": 148.5, + "right": 74.5, + "top": 177.5 + } + }, + { + "unicode": 1068, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.054718631178707219, + "bottom": 0.076045627376425839, + "right": 0.34071863117870721, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 75.5, + "bottom": 148.5, + "right": 88.5, + "top": 177.5 + } + }, + { + "unicode": 1069, + "advance": 0.33300000000000002, + "planeBounds": { + "left": -0.054718631178707219, + "bottom": 0.076045627376425839, + "right": 0.34071863117870721, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 103.5, + "bottom": 148.5, + "right": 116.5, + "top": 177.5 + } + }, + { + "unicode": 1070, + "advance": 0.41799999999999998, + "planeBounds": { + "left": -0.053846007604562734, + "bottom": 0.045627376425855508, + "right": 0.43284600760456271, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 217.5, + "bottom": 178.5, + "right": 233.5, + "top": 208.5 + } + }, + { + "unicode": 1071, + "advance": 0.32400000000000001, + "planeBounds": { + "left": -0.056718631178707235, + "bottom": 0.045627376425855508, + "right": 0.33871863117870721, + "top": 0.95817490494296575 + }, + "atlasBounds": { + "left": 203.5, + "bottom": 178.5, + "right": 216.5, + "top": 208.5 + } + }, + { + "unicode": 1072, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 23.5, + "bottom": 13.5, + "right": 35.5, + "top": 36.5 + } + }, + { + "unicode": 1073, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 209.5, + "bottom": 92.5, + "right": 221.5, + "top": 116.5 + } + }, + { + "unicode": 1074, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 40.5, + "bottom": 62.5, + "right": 52.5, + "top": 86.5 + } + }, + { + "unicode": 1075, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 126.5, + "bottom": 13.5, + "right": 138.5, + "top": 36.5 + } + }, + { + "unicode": 1076, + "advance": 0.40400000000000003, + "planeBounds": { + "left": -0.036136882129277591, + "bottom": 0.2585551330798479, + "right": 0.42013688212927747, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 110.5, + "bottom": 13.5, + "right": 125.5, + "top": 36.5 + } + }, + { + "unicode": 1077, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 95.5, + "bottom": 62.5, + "right": 107.5, + "top": 86.5 + } + }, + { + "unicode": 1078, + "advance": 0.44600000000000001, + "planeBounds": { + "left": -0.036346007604562761, + "bottom": 0.2585551330798479, + "right": 0.45034600760456273, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 62.5, + "bottom": 13.5, + "right": 78.5, + "top": 36.5 + } + }, + { + "unicode": 1079, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 108.5, + "bottom": 62.5, + "right": 120.5, + "top": 86.5 + } + }, + { + "unicode": 1080, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 36.5, + "bottom": 13.5, + "right": 48.5, + "top": 36.5 + } + }, + { + "unicode": 1081, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 1.0798479087452471 + }, + "atlasBounds": { + "left": 158.5, + "bottom": 89.5, + "right": 170.5, + "top": 116.5 + } + }, + { + "unicode": 1082, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 152.5, + "bottom": 13.5, + "right": 164.5, + "top": 36.5 + } + }, + { + "unicode": 1083, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 217.5, + "bottom": 38.5, + "right": 229.5, + "top": 61.5 + } + }, + { + "unicode": 1084, + "advance": 0.44600000000000001, + "planeBounds": { + "left": -0.036346007604562761, + "bottom": 0.2585551330798479, + "right": 0.45034600760456273, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 131.5, + "bottom": 38.5, + "right": 147.5, + "top": 61.5 + } + }, + { + "unicode": 1085, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 191.5, + "bottom": 13.5, + "right": 203.5, + "top": 36.5 + } + }, + { + "unicode": 1086, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 235.5, + "bottom": 92.5, + "right": 247.5, + "top": 116.5 + } + }, + { + "unicode": 1087, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 118.5, + "bottom": 38.5, + "right": 130.5, + "top": 61.5 + } + }, + { + "unicode": 1088, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 79.5, + "bottom": 38.5, + "right": 91.5, + "top": 61.5 + } + }, + { + "unicode": 1089, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 39.5, + "bottom": 37.5, + "right": 51.5, + "top": 61.5 + } + }, + { + "unicode": 1090, + "advance": 0.32000000000000001, + "planeBounds": { + "left": -0.035009505703422074, + "bottom": 0.2585551330798479, + "right": 0.33000950570342202, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 105.5, + "bottom": 38.5, + "right": 117.5, + "top": 61.5 + } + }, + { + "unicode": 1091, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 173.5, + "bottom": 62.5, + "right": 185.5, + "top": 86.5 + } + }, + { + "unicode": 1092, + "advance": 0.50900000000000001, + "planeBounds": { + "left": -0.029764258555133004, + "bottom": 0.2585551330798479, + "right": 0.51776425855513308, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 229.5, + "bottom": 63.5, + "right": 247.5, + "top": 86.5 + } + }, + { + "unicode": 1093, + "advance": 0.33200000000000002, + "planeBounds": { + "left": -0.042718631178707223, + "bottom": 0.2585551330798479, + "right": 0.35271863117870722, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 96.5, + "bottom": 13.5, + "right": 109.5, + "top": 36.5 + } + }, + { + "unicode": 1094, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 53.5, + "bottom": 62.5, + "right": 65.5, + "top": 86.5 + } + }, + { + "unicode": 1095, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 165.5, + "bottom": 13.5, + "right": 177.5, + "top": 36.5 + } + }, + { + "unicode": 1096, + "advance": 0.44600000000000001, + "planeBounds": { + "left": -0.036346007604562761, + "bottom": 0.2585551330798479, + "right": 0.45034600760456273, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 187.5, + "bottom": 38.5, + "right": 203.5, + "top": 61.5 + } + }, + { + "unicode": 1097, + "advance": 0.44600000000000001, + "planeBounds": { + "left": -0.036346007604562761, + "bottom": 0.22813688212927755, + "right": 0.45034600760456273, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 179.5, + "bottom": 92.5, + "right": 195.5, + "top": 116.5 + } + }, + { + "unicode": 1098, + "advance": 0.39500000000000002, + "planeBounds": { + "left": -0.042136882129277575, + "bottom": 0.22813688212927755, + "right": 0.41413688212927752, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 79.5, + "bottom": 62.5, + "right": 94.5, + "top": 86.5 + } + }, + { + "unicode": 1099, + "advance": 0.44600000000000001, + "planeBounds": { + "left": -0.036346007604562761, + "bottom": 0.28897338403041822, + "right": 0.45034600760456273, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 204.5, + "bottom": 14.5, + "right": 220.5, + "top": 36.5 + } + }, + { + "unicode": 1100, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 134.5, + "bottom": 62.5, + "right": 146.5, + "top": 86.5 + } + }, + { + "unicode": 1101, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 13.5, + "bottom": 37.5, + "right": 25.5, + "top": 61.5 + } + }, + { + "unicode": 1102, + "advance": 0.42999999999999999, + "planeBounds": { + "left": -0.042346007604562752, + "bottom": 0.22813688212927755, + "right": 0.44434600760456272, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 212.5, + "bottom": 62.5, + "right": 228.5, + "top": 86.5 + } + }, + { + "unicode": 1103, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.2585551330798479, + "right": 0.33350950570342208, + "top": 0.95817490494296564 + }, + "atlasBounds": { + "left": 174.5, + "bottom": 38.5, + "right": 186.5, + "top": 61.5 + } + }, + { + "unicode": 1105, + "advance": 0.32500000000000001, + "planeBounds": { + "left": -0.031509505703422057, + "bottom": 0.22813688212927755, + "right": 0.33350950570342208, + "top": 1.0798479087452471 + }, + "atlasBounds": { + "left": 132.5, + "bottom": 88.5, + "right": 144.5, + "top": 116.5 } } ], diff --git a/DoomDeathmatch/asset/model/map.obj b/DoomDeathmatch/asset/model/map.obj new file mode 100644 index 0000000..fdd2d0b --- /dev/null +++ b/DoomDeathmatch/asset/model/map.obj @@ -0,0 +1,101 @@ +# 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 diff --git a/DoomDeathmatch/asset/texture/demon.png b/DoomDeathmatch/asset/texture/demon.png new file mode 100644 index 0000000..56b96ca Binary files /dev/null and b/DoomDeathmatch/asset/texture/demon.png differ diff --git a/DoomDeathmatch/asset/texture/imp.png b/DoomDeathmatch/asset/texture/imp.png new file mode 100644 index 0000000..f900685 Binary files /dev/null and b/DoomDeathmatch/asset/texture/imp.png differ diff --git a/DoomDeathmatch/asset/texture/pistol.png b/DoomDeathmatch/asset/texture/pistol.png new file mode 100644 index 0000000..a5f2b76 Binary files /dev/null and b/DoomDeathmatch/asset/texture/pistol.png differ diff --git a/DoomDeathmatch/asset/texture/shotgun.png b/DoomDeathmatch/asset/texture/shotgun.png new file mode 100644 index 0000000..adeac1f Binary files /dev/null and b/DoomDeathmatch/asset/texture/shotgun.png differ diff --git a/DoomDeathmatch/src/Component/HealthComponent.cs b/DoomDeathmatch/src/Component/HealthComponent.cs deleted file mode 100644 index 9ebc517..0000000 --- a/DoomDeathmatch/src/Component/HealthComponent.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace DoomDeathmatch.Component; - -public class HealthComponent : Engine.Scene.Component.Component -{ - public float MaxHealth { get; set; } = 100; - public float Health { get; private set; } = 100; - public event Action? HealthChanged; - public event Action? Died; - - public void TakeDamage(float parDamage) - { - Health -= parDamage; - if (Health <= 0) - { - Died?.Invoke(this); - } - else - { - HealthChanged?.Invoke(this); - } - } - - public void Heal(float parHeal) - { - Health += parHeal; - if (Health > MaxHealth) - { - Health = MaxHealth; - } - - HealthChanged?.Invoke(this); - } -} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/Controller/HealthController.cs b/DoomDeathmatch/src/Component/MVC/Controller/HealthController.cs new file mode 100644 index 0000000..3fb7408 --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/Controller/HealthController.cs @@ -0,0 +1,31 @@ +using DoomDeathmatch.Component.MVC.Model; +using DoomDeathmatch.Component.MVC.View; + +namespace DoomDeathmatch.Component.MVC.Controller; + +public class HealthController : Engine.Scene.Component.Component +{ + private readonly HealthModel _healthModel = new(100); + private HealthView? _healthView; + + public override void Awake() + { + _healthView = GameObject.GetComponent(); + + if (_healthView != null) + { + _healthView.UpdateView(_healthModel); + _healthModel.HealthChanged += _healthView.UpdateView; + } + } + + public void TakeDamage(float parDamage) + { + _healthModel.Health -= parDamage; + } + + public void Heal(float parHeal) + { + _healthModel.Health += parHeal; + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/Controller/PlayerController.cs b/DoomDeathmatch/src/Component/MVC/Controller/PlayerController.cs new file mode 100644 index 0000000..f388ea0 --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/Controller/PlayerController.cs @@ -0,0 +1,45 @@ +using DoomDeathmatch.Component.MVC.Model; +using Engine.Input; + +namespace DoomDeathmatch.Component.MVC.Controller; + +public class PlayerController : Engine.Scene.Component.Component +{ + private readonly IInputHandler _inputHandler = Engine.Engine.Instance.InputHandler!; + + private HealthController _healthController = null!; + private WeaponController _weaponController = null!; + private ScoreController _scoreController = null!; + + public override void Awake() + { + _healthController = GameObject.GetComponent()!; + _weaponController = GameObject.GetComponent()!; + _scoreController = GameObject.GetComponent()!; + + ArgumentNullException.ThrowIfNull(_healthController); + ArgumentNullException.ThrowIfNull(_weaponController); + ArgumentNullException.ThrowIfNull(_scoreController); + } + + public override void Update(double parDeltaTime) + { + if (_inputHandler.IsKeyJustPressed(KeyboardButtonCode.C)) + _weaponController.AddWeapon(WeaponData.Shotgun); + + for (var i = 0; i < 10; i++) + { + if (KeyboardButtonCode.D1 + i > KeyboardButtonCode.D0) + break; + + if (!_inputHandler.IsKeyJustPressed(KeyboardButtonCode.D1 + i)) + continue; + + _weaponController.SelectWeapon(i); + break; + } + + if (_inputHandler.IsKeyJustPressed(KeyboardButtonCode.Space)) + _weaponController.TryShoot(); + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/Controller/ScoreController.cs b/DoomDeathmatch/src/Component/MVC/Controller/ScoreController.cs new file mode 100644 index 0000000..3140b48 --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/Controller/ScoreController.cs @@ -0,0 +1,22 @@ +using DoomDeathmatch.Component.MVC.Model; +using DoomDeathmatch.Component.MVC.View; + +namespace DoomDeathmatch.Component.MVC.Controller; + +public class ScoreController : Engine.Scene.Component.Component +{ + private readonly ScoreModel _scoreModel = new(); + private ScoreView _scoreView = null!; + + public override void Awake() + { + _scoreView = GameObject.GetComponent()!; + _scoreView.UpdateView(_scoreModel); + _scoreModel.ScoreChanged += _scoreView.UpdateView; + } + + public void AddScore(int parScore) + { + _scoreModel.Score += parScore; + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/Controller/WeaponController.cs b/DoomDeathmatch/src/Component/MVC/Controller/WeaponController.cs new file mode 100644 index 0000000..a2a4a30 --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/Controller/WeaponController.cs @@ -0,0 +1,74 @@ +using DoomDeathmatch.Component.MVC.Model; +using DoomDeathmatch.Component.MVC.View; + +namespace DoomDeathmatch.Component.MVC.Controller; + +public class WeaponController : Engine.Scene.Component.Component +{ + public event Action? OnWeaponShot; + + private readonly WeaponModel _weaponModel = new(); + private WeaponView _weaponView = null!; + + public override void Awake() + { + _weaponView = GameObject.GetComponent()!; + _weaponView.UpdateView(_weaponModel.SelectedWeapon); + + _weaponModel.OnWeaponSelected += WeaponSelected; + WeaponSelected(null, _weaponModel.SelectedWeapon); + } + + public bool TryShoot() + { + if (_weaponModel.SelectedWeapon.Ammo <= 0) + return false; + + _weaponModel.SelectedWeapon.Ammo--; + + OnWeaponShot?.Invoke(_weaponModel.SelectedWeapon); + + return true; + } + + public void Reload() + { + _weaponModel.SelectedWeapon.Ammo = _weaponModel.SelectedWeapon.MaxAmmo; + } + + public void AddWeapon(WeaponData parWeaponData) + { + if (_weaponModel.Weapons.Contains(parWeaponData)) + return; + + _weaponModel.Weapons.Add(parWeaponData); + } + + public void RemoveWeapon(int parIndex) + { + if (parIndex <= 0 || parIndex >= _weaponModel.Weapons.Count) + return; + + var newSelectedIndex = parIndex >= _weaponModel.SelectedWeaponIndex ? _weaponModel.SelectedWeaponIndex : 0; + + _weaponModel.SelectedWeaponIndex = newSelectedIndex; + _weaponModel.Weapons.RemoveAt(parIndex); + } + + public void SelectWeapon(int parIndex) + { + if (parIndex >= _weaponModel.Weapons.Count) + return; + + _weaponModel.SelectedWeaponIndex = parIndex; + } + + private void WeaponSelected(WeaponData? parOldWeapon, WeaponData parNewWeapon) + { + if (parOldWeapon != null) + parOldWeapon.OnAmmoChanged -= _weaponView.UpdateAmmoView; + + parNewWeapon.OnAmmoChanged += _weaponView.UpdateAmmoView; + _weaponView.UpdateView(parNewWeapon); + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/Model/HealthModel.cs b/DoomDeathmatch/src/Component/MVC/Model/HealthModel.cs new file mode 100644 index 0000000..cc492ba --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/Model/HealthModel.cs @@ -0,0 +1,35 @@ +namespace DoomDeathmatch.Component.MVC.Model; + +public class HealthModel +{ + public float MaxHealth + { + get => _maxHealth; + set + { + _maxHealth = Math.Max(value, 1); + HealthChanged?.Invoke(this); + } + } + + public float Health + { + get => _health; + set + { + _health = Math.Clamp(value, 0, MaxHealth); + HealthChanged?.Invoke(this); + } + } + + public event Action? HealthChanged; + + private float _health; + private float _maxHealth; + + public HealthModel(float parMaxHealth) + { + MaxHealth = parMaxHealth; + Health = parMaxHealth; + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/Model/ScoreModel.cs b/DoomDeathmatch/src/Component/MVC/Model/ScoreModel.cs new file mode 100644 index 0000000..994d5c3 --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/Model/ScoreModel.cs @@ -0,0 +1,18 @@ +namespace DoomDeathmatch.Component.MVC.Model; + +public class ScoreModel +{ + public event Action? ScoreChanged; + + public int Score + { + get => _score; + set + { + _score = Math.Max(value, 0); + ScoreChanged?.Invoke(this); + } + } + + private int _score; +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/Model/WeaponData.cs b/DoomDeathmatch/src/Component/MVC/Model/WeaponData.cs new file mode 100644 index 0000000..d2a060b --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/Model/WeaponData.cs @@ -0,0 +1,54 @@ +namespace DoomDeathmatch.Component.MVC.Model; + +public class WeaponData +{ + public static WeaponData Pistol => + new(30) { Id = "pistol", Name = "Пистолет", Texture = "texture/pistol.png", Damage = 10 }; + + public static WeaponData Shotgun => + new(10) { Id = "shotgun", Name = "Дробовик", Texture = "texture/shotgun.png", Damage = 50 }; + + public string Id { get; private init; } = ""; + public string Name { get; private init; } = ""; + public string Texture { get; private init; } = ""; + public int Damage { get; private init; } + public int MaxAmmo { get; } + + public int Ammo + { + get => _ammo; + set + { + if (value < 0) + value = 0; + if (value > MaxAmmo) + value = MaxAmmo; + + if (_ammo == value) + return; + + _ammo = value; + OnAmmoChanged?.Invoke(this); + } + } + + public event Action? OnAmmoChanged; + + private int _ammo; + + private WeaponData(int parMaxAmmo) + { + MaxAmmo = parMaxAmmo; + Ammo = MaxAmmo; + } + + public override bool Equals(object? parObj) + { + return parObj is WeaponData weaponModel && Id == weaponModel.Id; + } + + public override int GetHashCode() + { + return HashCode.Combine(Id); + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/Model/WeaponModel.cs b/DoomDeathmatch/src/Component/MVC/Model/WeaponModel.cs new file mode 100644 index 0000000..b5190d5 --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/Model/WeaponModel.cs @@ -0,0 +1,29 @@ +namespace DoomDeathmatch.Component.MVC.Model; + +public class WeaponModel +{ + public event Action? OnWeaponSelected; + + public IList Weapons => _weapons; + + public WeaponData SelectedWeapon => _weapons[_selectedWeaponIndex]; + + public int SelectedWeaponIndex + { + get => _selectedWeaponIndex; + set + { + value = Math.Clamp(value, 0, _weapons.Count - 1); + + if (_selectedWeaponIndex == value) + return; + + var oldSelectedWeapon = SelectedWeapon; + _selectedWeaponIndex = value; + OnWeaponSelected?.Invoke(oldSelectedWeapon, SelectedWeapon); + } + } + + private readonly List _weapons = [WeaponData.Pistol]; + private int _selectedWeaponIndex = 0; +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/View/HealthView.cs b/DoomDeathmatch/src/Component/MVC/View/HealthView.cs new file mode 100644 index 0000000..1ae04c0 --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/View/HealthView.cs @@ -0,0 +1,23 @@ +using DoomDeathmatch.Component.MVC.Model; +using Engine.Scene.Component.BuiltIn.Renderer; + +namespace DoomDeathmatch.Component.MVC.View; + +public class HealthView : Engine.Scene.Component.Component +{ + private readonly TextRenderer _healthTextRenderer; + + public HealthView(TextRenderer parHealthTextRenderer) + { + _healthTextRenderer = parHealthTextRenderer; + } + + public void UpdateView(HealthModel parHealthModel) + { + var percentage = parHealthModel.Health / parHealthModel.MaxHealth * 100; + if (parHealthModel.Health != 0) + percentage = Math.Max(1, percentage); + + _healthTextRenderer.Text = $"Здоровье: {percentage:000}"; + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/View/ScoreView.cs b/DoomDeathmatch/src/Component/MVC/View/ScoreView.cs new file mode 100644 index 0000000..0640aae --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/View/ScoreView.cs @@ -0,0 +1,19 @@ +using DoomDeathmatch.Component.MVC.Model; +using Engine.Scene.Component.BuiltIn.Renderer; + +namespace DoomDeathmatch.Component.MVC.View; + +public class ScoreView : Engine.Scene.Component.Component +{ + private readonly TextRenderer _scoreTextRenderer; + + public ScoreView(TextRenderer parScoreTextRenderer) + { + _scoreTextRenderer = parScoreTextRenderer; + } + + public void UpdateView(ScoreModel parScoreModel) + { + _scoreTextRenderer.Text = $"Счет: {parScoreModel.Score:00000}"; + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/MVC/View/WeaponView.cs b/DoomDeathmatch/src/Component/MVC/View/WeaponView.cs new file mode 100644 index 0000000..7b8907d --- /dev/null +++ b/DoomDeathmatch/src/Component/MVC/View/WeaponView.cs @@ -0,0 +1,31 @@ +using DoomDeathmatch.Component.MVC.Model; +using Engine.Graphics.Texture; +using Engine.Scene.Component.BuiltIn.Renderer; + +namespace DoomDeathmatch.Component.MVC.View; + +public class WeaponView : Engine.Scene.Component.Component +{ + private readonly TextRenderer _weaponName; + private readonly TextRenderer _weaponAmmo; + private readonly Box2DRenderer _weaponSprite; + + public WeaponView(TextRenderer parWeaponName, TextRenderer parWeaponAmmo, Box2DRenderer parWeaponSprite) + { + _weaponName = parWeaponName; + _weaponAmmo = parWeaponAmmo; + _weaponSprite = parWeaponSprite; + } + + public void UpdateView(WeaponData parWeaponData) + { + UpdateAmmoView(parWeaponData); + _weaponName.Text = $"Оружие: {parWeaponData.Name}"; + _weaponSprite.Texture = Engine.Engine.Instance.AssetResourceManager.Load(parWeaponData.Texture); + } + + public void UpdateAmmoView(WeaponData parWeaponData) + { + _weaponAmmo.Text = $"Патроны: {parWeaponData.Ammo}/{parWeaponData.MaxAmmo}"; + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/UI/SelectorComponent.cs b/DoomDeathmatch/src/Component/UI/SelectorComponent.cs index 94d2fd5..e116a3a 100644 --- a/DoomDeathmatch/src/Component/UI/SelectorComponent.cs +++ b/DoomDeathmatch/src/Component/UI/SelectorComponent.cs @@ -67,7 +67,7 @@ public class SelectorComponent : Engine.Scene.Component.Component var scale = transformMatrix.ExtractScale(); GameObject.Transform.Translation = translation; - GameObject.Transform.Translation.X -= scale.X / 2 + 0.05f; + GameObject.Transform.Translation.X -= scale.X / 2; GameObject.Transform.Size.Y = scale.Y; } diff --git a/DoomDeathmatch/src/Component/UI/TestComponent.cs b/DoomDeathmatch/src/Component/UI/TestComponent.cs deleted file mode 100644 index 7be81b1..0000000 --- a/DoomDeathmatch/src/Component/UI/TestComponent.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Engine.Input; -using Engine.Scene.Component.BuiltIn; - -namespace DoomDeathmatch.Component.UI; - -public class TestComponent : Engine.Scene.Component.Component -{ - private readonly IInputHandler _inputHandler = Engine.Engine.Instance.InputHandler!; - public Camera? Camera { get; set; } - - public override void Update(double parDeltaTime) - { - if (Camera == null) - { - return; - } - - GameObject.Transform.Size.Xy = 2 * Camera.ScreenToWorld(_inputHandler.MousePosition).Xy; - } -} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/UI/TextAlignComponent.cs b/DoomDeathmatch/src/Component/UI/TextAlignComponent.cs index 261c764..5b79755 100644 --- a/DoomDeathmatch/src/Component/UI/TextAlignComponent.cs +++ b/DoomDeathmatch/src/Component/UI/TextAlignComponent.cs @@ -27,9 +27,7 @@ public class TextAlignComponent : Engine.Scene.Component.Component _cachedText = _textRenderer.Text; var font = _textRenderer.Font; var size = font.Measure(_textRenderer.Text); - var scale = GameObject.Transform.FullTransformMatrix.ExtractScale(); - var offset = GetOffset(size) + new Vector2(0, font.Metadata.Metrics.LineHeight - font.Metadata.Metrics.Ascender) / 2; - offset *= scale.Xy; + var offset = GetOffset(size) + new Vector2(0, _textRenderer.Font.Metadata.Metrics.Descender / 4); GameObject.Transform.Translation.Xy = offset; } diff --git a/DoomDeathmatch/src/Component/UI/UiComponent.cs b/DoomDeathmatch/src/Component/UI/UiComponent.cs index 61255f9..6271d46 100644 --- a/DoomDeathmatch/src/Component/UI/UiComponent.cs +++ b/DoomDeathmatch/src/Component/UI/UiComponent.cs @@ -8,7 +8,7 @@ public class UiComponent : Engine.Scene.Component.Component public UiContainerComponent? Container { get; set; } public Anchor Anchor { get; set; } = Anchor.Center; public Vector2 Offset { get; set; } = Vector2.Zero; - public Vector2 Center { get; set; } = Vector2.Zero; + public Anchor Center { get; set; } = Anchor.Center; public event Action? OnClick; public event Action? OnMouseOver; @@ -22,17 +22,17 @@ public class UiComponent : Engine.Scene.Component.Component return; } - GameObject.Transform.Translation.Xy = GetAnchorPosition(Container.GameObject.Transform.Size.Xy) + Offset; + var size = GameObject.Transform.Size * GameObject.Transform.Scale; + GameObject.Transform.Translation.Xy = GetAnchorPosition(Container.GameObject.Transform.Size.Xy, Anchor) + Offset - + GetAnchorPosition(size.Xy, Center); + var transformMatrix = GameObject.Transform.FullTransformMatrix; + var actualSize = transformMatrix.ExtractScale(); var translation = transformMatrix.ExtractTranslation(); - var scale = transformMatrix.ExtractScale(); - var relativeMousePosition = Container.MousePosition.Xy - - (translation.Xy); + var relativeMousePosition = Container.MousePosition.Xy - translation.Xy; - var objectSize = scale.Xy; - - if (Math.Abs(relativeMousePosition.X) <= objectSize.X / 2 && Math.Abs(relativeMousePosition.Y) <= objectSize.Y / 2) + if (Math.Abs(relativeMousePosition.X) <= actualSize.X / 2 && Math.Abs(relativeMousePosition.Y) <= actualSize.Y / 2) { OnMouseOver?.Invoke(this); @@ -48,14 +48,14 @@ public class UiComponent : Engine.Scene.Component.Component OnClick?.Invoke(this); } - private Vector2 GetAnchorPosition(Vector2 parSize) + private static Vector2 GetAnchorPosition(Vector2 parSize, Anchor parAnchor) { - return parSize * GetAnchorRatio(); + return parSize * GetAnchorRatio(parAnchor); } - private Vector2 GetAnchorRatio() + private static Vector2 GetAnchorRatio(Anchor parAnchor) { - return Anchor switch + return parAnchor switch { Anchor.TopLeft => new Vector2(-0.5f, 0.5f), Anchor.TopCenter => new Vector2(0, 0.5f), @@ -66,7 +66,7 @@ public class UiComponent : Engine.Scene.Component.Component Anchor.BottomLeft => new Vector2(-0.5f, -0.5f), Anchor.BottomCenter => new Vector2(0, -0.5f), Anchor.BottomRight => new Vector2(0.5f, -0.5f), - _ => throw new ArgumentOutOfRangeException(nameof(Anchor), Anchor, null) + _ => throw new ArgumentOutOfRangeException(nameof(parAnchor), parAnchor, null) }; } } \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/BillboardComponent.cs b/DoomDeathmatch/src/Component/Util/BillboardComponent.cs similarity index 96% rename from DoomDeathmatch/src/Component/BillboardComponent.cs rename to DoomDeathmatch/src/Component/Util/BillboardComponent.cs index d1e89a4..79d214c 100644 --- a/DoomDeathmatch/src/Component/BillboardComponent.cs +++ b/DoomDeathmatch/src/Component/Util/BillboardComponent.cs @@ -1,7 +1,7 @@ using Engine.Scene.Component.BuiltIn; using OpenTK.Mathematics; -namespace DoomDeathmatch.Component; +namespace DoomDeathmatch.Component.Util; public class BillboardComponent : Engine.Scene.Component.Component { diff --git a/DoomDeathmatch/src/Component/ControllerComponent.cs b/DoomDeathmatch/src/Component/Util/ControllerComponent.cs similarity index 97% rename from DoomDeathmatch/src/Component/ControllerComponent.cs rename to DoomDeathmatch/src/Component/Util/ControllerComponent.cs index 535c25b..2a58c48 100644 --- a/DoomDeathmatch/src/Component/ControllerComponent.cs +++ b/DoomDeathmatch/src/Component/Util/ControllerComponent.cs @@ -1,7 +1,7 @@ using Engine.Input; using OpenTK.Mathematics; -namespace DoomDeathmatch.Component; +namespace DoomDeathmatch.Component.Util; public class ControllerComponent : Engine.Scene.Component.Component { diff --git a/DoomDeathmatch/src/Component/Util/CopySizeComponent.cs b/DoomDeathmatch/src/Component/Util/CopySizeComponent.cs new file mode 100644 index 0000000..034098c --- /dev/null +++ b/DoomDeathmatch/src/Component/Util/CopySizeComponent.cs @@ -0,0 +1,25 @@ +using Engine.Scene.Component.BuiltIn; +using OpenTK.Mathematics; + +namespace DoomDeathmatch.Component.Util; + +public class CopySizeComponent : Engine.Scene.Component.Component +{ + public Vector3 Coefficient { get; set; } = Vector3.One; + public Transform? Target { get; set; } + + public override void Update(double parDeltaTime) + { + if (Target == null) + return; + + if (Coefficient.X != 0) + GameObject.Transform.Size.X = Target.Size.X * Coefficient.X; + + if (Coefficient.Y != 0) + GameObject.Transform.Size.Y = Target.Size.Y * Coefficient.Y; + + if (Coefficient.Z != 0) + GameObject.Transform.Size.Z = Target.Size.Z * Coefficient.Z; + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Component/DragComponent.cs b/DoomDeathmatch/src/Component/Util/DragComponent.cs similarity index 91% rename from DoomDeathmatch/src/Component/DragComponent.cs rename to DoomDeathmatch/src/Component/Util/DragComponent.cs index 99b93f0..0427a9f 100644 --- a/DoomDeathmatch/src/Component/DragComponent.cs +++ b/DoomDeathmatch/src/Component/Util/DragComponent.cs @@ -1,6 +1,6 @@ using OpenTK.Mathematics; -namespace DoomDeathmatch.Component; +namespace DoomDeathmatch.Component.Util; public class DragComponent : Engine.Scene.Component.Component { diff --git a/DoomDeathmatch/src/Component/GravityComponent.cs b/DoomDeathmatch/src/Component/Util/GravityComponent.cs similarity index 96% rename from DoomDeathmatch/src/Component/GravityComponent.cs rename to DoomDeathmatch/src/Component/Util/GravityComponent.cs index ac063cd..7231969 100644 --- a/DoomDeathmatch/src/Component/GravityComponent.cs +++ b/DoomDeathmatch/src/Component/Util/GravityComponent.cs @@ -1,6 +1,6 @@ using OpenTK.Mathematics; -namespace DoomDeathmatch.Component; +namespace DoomDeathmatch.Component.Util; public class GravityComponent : Engine.Scene.Component.Component { diff --git a/DoomDeathmatch/src/Component/RigidbodyComponent.cs b/DoomDeathmatch/src/Component/Util/RigidbodyComponent.cs similarity index 95% rename from DoomDeathmatch/src/Component/RigidbodyComponent.cs rename to DoomDeathmatch/src/Component/Util/RigidbodyComponent.cs index c18df42..219f5a3 100644 --- a/DoomDeathmatch/src/Component/RigidbodyComponent.cs +++ b/DoomDeathmatch/src/Component/Util/RigidbodyComponent.cs @@ -1,6 +1,6 @@ using OpenTK.Mathematics; -namespace DoomDeathmatch.Component; +namespace DoomDeathmatch.Component.Util; public class RigidbodyComponent : Engine.Scene.Component.Component { diff --git a/DoomDeathmatch/src/Component/RotateComponent.cs b/DoomDeathmatch/src/Component/Util/RotateComponent.cs similarity index 95% rename from DoomDeathmatch/src/Component/RotateComponent.cs rename to DoomDeathmatch/src/Component/Util/RotateComponent.cs index d961dd9..ab1bb29 100644 --- a/DoomDeathmatch/src/Component/RotateComponent.cs +++ b/DoomDeathmatch/src/Component/Util/RotateComponent.cs @@ -1,7 +1,7 @@ using Engine.Input; using OpenTK.Mathematics; -namespace DoomDeathmatch.Component; +namespace DoomDeathmatch.Component.Util; public class RotateComponent : Engine.Scene.Component.Component { diff --git a/DoomDeathmatch/src/DoomDeathmatch.cs b/DoomDeathmatch/src/DoomDeathmatch.cs index 36303bb..15f7f9b 100644 --- a/DoomDeathmatch/src/DoomDeathmatch.cs +++ b/DoomDeathmatch/src/DoomDeathmatch.cs @@ -21,70 +21,6 @@ public static class DoomDeathmatch { public static void Initialize(Engine.Engine parEngine) { - parEngine.SceneManager.TransitionTo(MainScene.Create(parEngine)); + parEngine.SceneManager.TransitionTo(() => MainScene.Create(parEngine)); } - - // private static Scene MainScene(Engine.Engine parEngine) - // { - // var playerObject = new GameObject(); - // playerObject.AddComponent(); - // playerObject.AddComponent(new ControllerComponent { Speed = 5f }); - // playerObject.AddComponent(new DragComponent { Drag = 5f, Coefficient = new Vector3(1, 1, 0) }); - // playerObject.AddComponent(new TestComponent()); - // - // var cameraObject = new GameObject(); - // cameraObject.Transform.Translation.Z = 2; - // cameraObject.AddComponent(); - // - // var testObject = new GameObject { Transform = { Translation = new Vector3(0, 6, 0), Rotation = Quaternion.FromAxisAngle(Vector3.UnitX, (float)Math.PI / 2) } }; - // testObject.AddComponent(new Box2DRenderer { Color = new Vector4(1, 0, 0, 1) }); - // - // var mesh = parEngine.AssetResourceManager.Load("model/untitled.obj"); - // var texture = parEngine.AssetResourceManager.Load("TestImage.png"); - // var font = parEngine.AssetResourceManager.Load("font/test"); - // - // var box2dRenderer = new GameObject - // { - // Transform = { Scale = new Vector3(1), Rotation = Quaternion.FromAxisAngle(Vector3.UnitX, (float)Math.PI / 2) } - // }; - // // box2dRenderer.AddComponent(new MeshRenderer { Mesh = mesh, Albedo = texture }); - // box2dRenderer.AddComponent(new TextRenderer { Font = font, Text = "A", RenderLayer = RenderLayer.HUD }); - // // box2dRenderer.AddComponent(new BillboardComponent { Target = cameraObject.Transform }); - // - // var xAxis = new GameObject(); - // xAxis.Transform.Translation.X = 5; - // xAxis.Transform.Scale.X = 10; - // xAxis.AddComponent(new Box2DRenderer { Color = new Vector4(1, 0, 0, 1) }); - // - // var yAxis = new GameObject(); - // yAxis.Transform.Translation.Y = 5; - // yAxis.Transform.Scale.X = 10; - // yAxis.Transform.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitZ, (float)Math.PI / 2); - // yAxis.AddComponent(new Box2DRenderer { Color = new Vector4(0, 1, 0, 1) }); - // - // var zAxis = new GameObject(); - // zAxis.Transform.Translation.Z = 5; - // zAxis.Transform.Scale.Y = 10; - // zAxis.Transform.Scale.X = 10; - // zAxis.Transform.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitX, (float)Math.PI / 2); - // zAxis.AddComponent(new Box2DRenderer - // { - // Color = new Vector4(0, 0, 1, 1), Texture = parEngine.AssetResourceManager.Load("test.jpeg") - // }); - // - // var scene = new Scene(); - // scene.Add(cameraObject); - // scene.AddChild(cameraObject, testObject); - // scene.Add(playerObject); - // scene.SetChild(playerObject, cameraObject); - // - // scene.Add(box2dRenderer); - // // scene.AddChild(box2dRenderer, testChild); - // - // scene.Add(xAxis); - // // scene.Add(yAxis); - // // scene.Add(zAxis); - // - // return scene; - // } } \ No newline at end of file diff --git a/DoomDeathmatch/src/GameObjectUtil.cs b/DoomDeathmatch/src/GameObjectUtil.cs new file mode 100644 index 0000000..46579b4 --- /dev/null +++ b/DoomDeathmatch/src/GameObjectUtil.cs @@ -0,0 +1,35 @@ +using Engine.Scene; +using Engine.Scene.Component.BuiltIn; + +namespace DoomDeathmatch; + +public static class GameObjectUtil +{ + public static GameObject CreateGameObject(Engine.Scene.Scene parScene, + List parComponents) + { + var gameObject = new GameObject(); + foreach (var component in parComponents) + { + gameObject.AddComponent(component); + } + + parScene.Add(gameObject); + + return gameObject; + } + + public static GameObject CreateGameObject(Engine.Scene.Scene parScene, Transform parTransform, + List parComponents) + { + var gameObject = new GameObject(parTransform); + foreach (var component in parComponents) + { + gameObject.AddComponent(component); + } + + parScene.Add(gameObject); + + return gameObject; + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Scene/Leaders/LeadersScene.cs b/DoomDeathmatch/src/Scene/Leaders/LeadersScene.cs index 73352c7..8069801 100644 --- a/DoomDeathmatch/src/Scene/Leaders/LeadersScene.cs +++ b/DoomDeathmatch/src/Scene/Leaders/LeadersScene.cs @@ -16,36 +16,25 @@ public static class LeadersScene var (cameraObject, camera) = UiUtil.CreateOrthographicCamera(scene); - var (uiContainerObject, uiContainer) = UiUtil.CreateBackgroundUi(scene, camera); + 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, + var (backUiObject, backUi, _) = UiUtil.CreateTextUi(scene, uiContainer, UiUtil.GetDoomFont(parEngine), "Назад"); - backUi.OnClick += _ => parEngine.SceneManager.TransitionTo(MainScene.Create(parEngine)); + backUi.OnClick += _ => parEngine.SceneManager.TransitionTo(() => MainScene.Create(parEngine)); - var (stackObject, stack) = UiUtil.CreateStackUi(scene, uiContainer, - [backUi]); - stack.Offset = new Vector2(0, -1f); - stackObject.Transform.Size = new Vector3(1f, 6f, 1f); + 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 = new GameObject - { - Transform = { Translation = new Vector3(0, 0, -1), Size = new Vector3(0.5f, 1f, 1f) } - }; - selectorObject.AddComponent(new SelectorComponent - { - Children = { backUi }, - SelectKey = KeyboardButtonCode.Space, - NextKey = KeyboardButtonCode.Down, - PrevKey = KeyboardButtonCode.Up, - }); - selectorObject.AddComponent(new Box2DRenderer { Color = new Vector4(1, 0, 0, 1) }); + var (selectorObject, selector) = UiUtil.CreateSelectorUi(scene, new SelectorComponent { Children = { backUi } }); scene.AddChild(uiContainerObject, selectorObject); - scene.SetChild(uiContainerObject, logoObject); - scene.SetChild(uiContainerObject, stackObject); - scene.SetChild(stackObject, backUiObject); + scene.AddChild(uiContainerObject, logoObject); + scene.AddChild(uiContainerObject, stackObject); + scene.AddChild(stackObject, backUiObject); return scene; } diff --git a/DoomDeathmatch/src/Scene/Main/MainScene.cs b/DoomDeathmatch/src/Scene/Main/MainScene.cs index ec875b4..b651f85 100644 --- a/DoomDeathmatch/src/Scene/Main/MainScene.cs +++ b/DoomDeathmatch/src/Scene/Main/MainScene.cs @@ -1,11 +1,8 @@ using DoomDeathmatch.Component.UI; using DoomDeathmatch.Scene.Leaders; +using DoomDeathmatch.Scene.Play; using DoomDeathmatch.Scene.Rules; -using Engine.Asset.Font; -using Engine.Input; -using Engine.Scene; using Engine.Scene.Component.BuiltIn; -using Engine.Scene.Component.BuiltIn.Renderer; using OpenTK.Mathematics; namespace DoomDeathmatch.Scene.Main; @@ -18,60 +15,49 @@ public static class MainScene var (cameraObject, camera) = UiUtil.CreateOrthographicCamera(scene); - AddMainUi(parEngine, scene, camera); + 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; } - - private static void AddMainUi(Engine.Engine parEngine, Engine.Scene.Scene parScene, Camera parCamera) - { - var (uiContainerObject, uiContainer) = UiUtil.CreateBackgroundUi(parScene, parCamera); - - var (playUiObject, playUi) = - UiUtil.CreateTextUi(parScene, uiContainer, UiUtil.GetDoomFont(parEngine), "Играть"); - - var (leadersUiObject, leadersUi) = - UiUtil.CreateTextUi(parScene, uiContainer, UiUtil.GetDoomFont(parEngine), "Лидеры"); - - var (rulesUiObject, rulesUi) = - UiUtil.CreateTextUi(parScene, uiContainer, UiUtil.GetDoomFont(parEngine), "Правила"); - - var (exitUiObject, exitUi) = - UiUtil.CreateTextUi(parScene, uiContainer, UiUtil.GetDoomFont(parEngine), "Выход"); - - var (stackObject, stack) = UiUtil.CreateStackUi(parScene, uiContainer, - [playUi, leadersUi, rulesUi, exitUi]); - stack.Offset = new Vector2(0, -1f); - stackObject.Transform.Size = new Vector3(2f, 5f, 1f); - - playUi.OnClick += _ => Console.WriteLine("Play"); - 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, parScene, uiContainer); - - var selectorObject = new GameObject - { - Transform = { Translation = new Vector3(0, 0, -1), Size = new Vector3(0.5f, 1f, 1f) } - }; - selectorObject.AddComponent(new SelectorComponent - { - Children = { playUi, leadersUi, rulesUi, exitUi }, - SelectKey = KeyboardButtonCode.Space, - NextKey = KeyboardButtonCode.Down, - PrevKey = KeyboardButtonCode.Up, - }); - selectorObject.AddComponent(new Box2DRenderer { Color = new Vector4(1, 0, 0, 1) }); - - parScene.AddChild(uiContainerObject, selectorObject); - - parScene.SetChild(uiContainerObject, stackObject); - parScene.SetChild(uiContainerObject, logoObject); - - parScene.SetChild(stackObject, playUiObject); - parScene.SetChild(stackObject, leadersUiObject); - parScene.SetChild(stackObject, rulesUiObject); - parScene.SetChild(stackObject, exitUiObject); - } } \ No newline at end of file diff --git a/DoomDeathmatch/src/Scene/Play/PlayScene.cs b/DoomDeathmatch/src/Scene/Play/PlayScene.cs new file mode 100644 index 0000000..aac150c --- /dev/null +++ b/DoomDeathmatch/src/Scene/Play/PlayScene.cs @@ -0,0 +1,136 @@ +using DoomDeathmatch.Component; +using DoomDeathmatch.Component.MVC.Controller; +using DoomDeathmatch.Component.MVC.View; +using DoomDeathmatch.Component.UI; +using DoomDeathmatch.Component.Util; +using Engine.Asset.Mesh; +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.Scene.Play; + +public static class PlayScene +{ + public static Engine.Scene.Scene Create(Engine.Engine parEngine) + { + var scene = new Engine.Scene.Scene(); + + var (hudCameraObject, hudCamera) = UiUtil.CreateOrthographicCamera(scene, RenderLayer.HUD); + var (uiContainerObject, uiContainer) = + UiUtil.CreateContainerUi(scene, new UiContainerComponent { Camera = hudCamera }); + + var (bottomContainerObject, bottomContainer) = + UiUtil.CreateContainerUi(scene, new UiContainerComponent { Container = uiContainer }); + bottomContainer.Anchor = Anchor.BottomCenter; + bottomContainer.Center = Anchor.BottomCenter; + bottomContainerObject.AddComponent(new Box2DRenderer + { + Color = new Vector4(1, 0, 0, 1), RenderLayer = RenderLayer.HUD + }); + bottomContainerObject.AddComponent(new CopySizeComponent + { + Target = uiContainerObject.Transform, Coefficient = new Vector3(1, 0, 1) + }); + bottomContainerObject.Transform.Size.Y = 1.5f; + scene.AddChild(uiContainerObject, bottomContainerObject); + + var (gunObject, (gunUi, gunSprite)) = UiUtil.CreateSpriteUi(scene, bottomContainer, + parEngine.AssetResourceManager.Load("texture/pistol.png"), RenderLayer.HUD); + gunObject.Transform.Scale = new Vector3(5); + gunUi.Anchor = Anchor.TopCenter; + gunUi.Center = Anchor.BottomCenter; + scene.AddChild(bottomContainerObject, gunObject); + + var (healthObject, healthUi, (_, healthTextRenderer)) = + UiUtil.CreateTextUi(scene, bottomContainer, UiUtil.GetDoomFont(parEngine), "Здоровье: 000", + TextAlignComponent.Align.Center, + RenderLayer.HUD); + healthObject.Transform.Scale = new Vector3(0.75f); + healthUi.Anchor = Anchor.CenterLeft; + healthUi.Center = Anchor.CenterLeft; + scene.AddChild(bottomContainerObject, healthObject); + + var (ammoObject, ammoUi, (_, ammoTextRenderer)) = + UiUtil.CreateTextUi(scene, bottomContainer, UiUtil.GetDoomFont(parEngine), "Патроны: 00/00", + TextAlignComponent.Align.Center, + RenderLayer.HUD); + ammoObject.Transform.Scale = new Vector3(0.75f); + ammoUi.Anchor = Anchor.TopRight; + ammoUi.Center = Anchor.TopRight; + scene.AddChild(bottomContainerObject, ammoObject); + + var (weaponObject, weaponUi, (_, weaponTextRenderer)) = + UiUtil.CreateTextUi(scene, bottomContainer, UiUtil.GetDoomFont(parEngine), "Оружие: ОРУЖИЕОР", + TextAlignComponent.Align.Center, + RenderLayer.HUD); + weaponObject.Transform.Scale = new Vector3(0.75f); + weaponUi.Anchor = Anchor.BottomRight; + weaponUi.Center = Anchor.BottomRight; + scene.AddChild(bottomContainerObject, weaponObject); + + var (topContainerObject, topContainer) = + UiUtil.CreateContainerUi(scene, new UiContainerComponent { Container = uiContainer }); + topContainer.Anchor = Anchor.TopCenter; + topContainer.Center = Anchor.TopCenter; + topContainerObject.AddComponent( + new Box2DRenderer { Color = new Vector4(1, 0, 0, 1), RenderLayer = RenderLayer.HUD }); + topContainerObject.AddComponent(new CopySizeComponent + { + Target = uiContainerObject.Transform, Coefficient = new Vector3(1, 0, 1) + }); + topContainerObject.Transform.Size.Y = 1f; + scene.AddChild(uiContainerObject, topContainerObject); + + var (timerObject, timerUi, _) = + UiUtil.CreateTextUi(scene, topContainer, UiUtil.GetDoomFont(parEngine), "Время: 00:00", + parRenderLayer: RenderLayer.HUD); + timerUi.Anchor = Anchor.CenterLeft; + timerUi.Center = Anchor.CenterLeft; + scene.AddChild(topContainerObject, timerObject); + + var (scoreObject, scoreUi, (_, scoreTextRenderer)) = + UiUtil.CreateTextUi(scene, topContainer, UiUtil.GetDoomFont(parEngine), "Счет: 00000", + parRenderLayer: RenderLayer.HUD); + scoreUi.Anchor = Anchor.CenterRight; + scoreUi.Center = Anchor.CenterRight; + scene.AddChild(topContainerObject, scoreObject); + + var playerObject = GameObjectUtil.CreateGameObject(scene, [ + new RigidbodyComponent(), + new ControllerComponent { Speed = 5f }, + new DragComponent { Drag = 5f, Coefficient = new Vector3(1, 1, 0) }, + + new PlayerController(), + + new WeaponController(), + new WeaponView(weaponTextRenderer, ammoTextRenderer, gunSprite), + + new HealthController(), + new HealthView(healthTextRenderer), + + new ScoreController(), + new ScoreView(scoreTextRenderer), + ]); + + var (perspectiveCameraObject, perspectiveCamera) = UiUtil.CreatePerspectiveCamera(scene); + perspectiveCameraObject.Transform.Translation.Z = 2; + + var mapObject = GameObjectUtil.CreateGameObject(scene, [ + new MeshRenderer { Mesh = parEngine.AssetResourceManager.Load("model/map.obj") }, + ]); + + var impObject = GameObjectUtil.CreateGameObject(scene, + new Transform { Translation = new Vector3(0, 0, 1), Scale = new Vector3(1, 2, 1), }, [ + new Box2DRenderer { Texture = parEngine.AssetResourceManager.Load("texture/imp.png") }, + new BillboardComponent { Target = perspectiveCameraObject.Transform } + ]); + + scene.AddChild(playerObject, perspectiveCameraObject); + + return scene; + } +} \ No newline at end of file diff --git a/DoomDeathmatch/src/Scene/Rules/RulesScene.cs b/DoomDeathmatch/src/Scene/Rules/RulesScene.cs index 1ec5d74..04c4512 100644 --- a/DoomDeathmatch/src/Scene/Rules/RulesScene.cs +++ b/DoomDeathmatch/src/Scene/Rules/RulesScene.cs @@ -1,9 +1,5 @@ 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.Rules; @@ -16,42 +12,31 @@ public static class RulesScene var (cameraObject, camera) = UiUtil.CreateOrthographicCamera(scene); - var (uiContainerObject, uiContainer) = UiUtil.CreateBackgroundUi(scene, camera); + 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, - parEngine.AssetResourceManager.Load("font/test"), "Назад"); - backUi.OnClick += _ => parEngine.SceneManager.TransitionTo(MainScene.Create(parEngine)); + 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, - parEngine.AssetResourceManager.Load("font/test"), "Правила"); + var (rulesObject, rulesUi, _) = UiUtil.CreateTextUi(scene, uiContainer, + UiUtil.GetDoomFont(parEngine), "Правила"); - var (stackObject, stack) = UiUtil.CreateStackUi(scene, uiContainer, - [rulesUi, backUi]); - stack.Offset = new Vector2(0, -1f); - stackObject.Transform.Size = new Vector3(1f, 6f, 1f); + 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 = new GameObject - { - Transform = { Translation = new Vector3(0, 0, -1), Size = new Vector3(0.5f, 1f, 1f) } - }; - selectorObject.AddComponent(new SelectorComponent - { - Children = { backUi }, - SelectKey = KeyboardButtonCode.Space, - NextKey = KeyboardButtonCode.Down, - PrevKey = KeyboardButtonCode.Up, - }); - selectorObject.AddComponent(new Box2DRenderer { Color = new Vector4(1, 0, 0, 1) }); + var (selectorObject, selector) = UiUtil.CreateSelectorUi(scene, new SelectorComponent { Children = { backUi } }); scene.AddChild(uiContainerObject, selectorObject); - scene.SetChild(uiContainerObject, logoObject); - scene.SetChild(uiContainerObject, stackObject); + scene.AddChild(uiContainerObject, logoObject); + scene.AddChild(uiContainerObject, stackObject); - scene.SetChild(stackObject, rulesObject); - scene.SetChild(stackObject, backUiObject); + scene.AddChild(stackObject, rulesObject); + scene.AddChild(stackObject, backUiObject); return scene; } diff --git a/DoomDeathmatch/src/UiUtil.cs b/DoomDeathmatch/src/UiUtil.cs index d4bab96..713e04b 100644 --- a/DoomDeathmatch/src/UiUtil.cs +++ b/DoomDeathmatch/src/UiUtil.cs @@ -1,6 +1,8 @@ using DoomDeathmatch.Component.UI; using Engine.Asset.Font; +using Engine.Graphics.Pipeline; using Engine.Graphics.Texture; +using Engine.Input; using Engine.Scene; using Engine.Scene.Component.BuiltIn; using Engine.Scene.Component.BuiltIn.Renderer; @@ -15,102 +17,154 @@ public static class UiUtil return parEngine.AssetResourceManager.Load("font/doom"); } - public static (GameObject, OrthographicCamera) CreateOrthographicCamera(Engine.Scene.Scene parScene) + public static (GameObject, OrthographicCamera) CreateOrthographicCamera(Engine.Scene.Scene parScene, + RenderLayer? parRenderLayer = null) { - var cameraObject = new GameObject(); - var camera = new OrthographicCamera(); - cameraObject.AddComponent(camera); - - parScene.Add(cameraObject); + OrthographicCamera camera; + var cameraObject = GameObjectUtil.CreateGameObject(parScene, [ + camera = new OrthographicCamera { RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT } + ]); return (cameraObject, camera); } - public static (GameObject, UiComponent) CreateTextUi(Engine.Scene.Scene parScene, UiContainerComponent parContainer, - Font parFont, string parText) + public static (GameObject, PerspectiveCamera) CreatePerspectiveCamera(Engine.Scene.Scene parScene, + RenderLayer? parRenderLayer = null) + { + PerspectiveCamera camera; + var cameraObject = GameObjectUtil.CreateGameObject(parScene, [ + camera = new PerspectiveCamera { RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT } + ]); + + return (cameraObject, camera); + } + + public static (GameObject, UiContainerComponent, (GameObject, TextRenderer)) CreateTextUi(Engine.Scene.Scene parScene, + UiContainerComponent parContainer, + Font parFont, string parText, TextAlignComponent.Align parAlign = TextAlignComponent.Align.Center, + RenderLayer? parRenderLayer = null) { var size = parFont.Measure(parText); var outerObject = new GameObject { Transform = { Size = new Vector3(size.X, size.Y, 1f), Translation = new Vector3(0, 0, -1) } }; - var uiComponent = new UiComponent { Container = parContainer, Anchor = Anchor.Center }; + var uiComponent = new UiContainerComponent { Container = parContainer }; outerObject.AddComponent(uiComponent); - outerObject.AddComponent(new Box2DRenderer { Color = new Vector4(0, 0, 1, 1) }); + outerObject.AddComponent(new Box2DRenderer + { + Color = new Vector4(0, 0, 1, 1), RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT + }); var innerObject = new GameObject { Transform = { Translation = new Vector3(0, 0, -1) } }; - innerObject.AddComponent(new TextRenderer { Font = parFont, Text = parText }); - innerObject.AddComponent(new TextAlignComponent { Alignment = TextAlignComponent.Align.Center }); + // var innerUiComponent = new UiComponent { Container = uiComponent }; + // innerObject.AddComponent(innerUiComponent); + var innerTextRenderer = new TextRenderer + { + Font = parFont, Text = parText, RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT + }; + innerObject.AddComponent(innerTextRenderer); + innerObject.AddComponent(new TextAlignComponent { Alignment = parAlign }); parScene.Add(outerObject); parScene.AddChild(outerObject, innerObject); - return (outerObject, uiComponent); + return (outerObject, uiComponent, (innerObject, innerTextRenderer)); } - public static (GameObject, UiContainerComponent) CreateBackgroundUi(Engine.Scene.Scene parScene, Camera parCamera) + public static (GameObject, UiContainerComponent) CreateContainerUi(Engine.Scene.Scene parScene, + UiContainerComponent parUiContainerComponent) { var uiContainerObject = new GameObject(); - var uiContainer = new UiContainerComponent { Camera = parCamera }; - uiContainerObject.AddComponent(uiContainer); - uiContainerObject.AddComponent(new Box2DRenderer { Color = new Vector4(0.1f, 0.1f, 0.1f, 1) }); + uiContainerObject.AddComponent(parUiContainerComponent); parScene.Add(uiContainerObject); + return (uiContainerObject, parUiContainerComponent); + } + + public static (GameObject, UiContainerComponent) CreateBackgroundUi(Engine.Scene.Scene parScene, + UiContainerComponent parUiContainerComponent, Vector4? parColor = null, + RenderLayer? parRenderLayer = null) + { + var (uiContainerObject, uiContainer) = CreateContainerUi(parScene, parUiContainerComponent); + uiContainerObject.AddComponent(new Box2DRenderer + { + Color = parColor ?? new Vector4(0.1f, 0.1f, 0.1f, 1), RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT + }); + return (uiContainerObject, uiContainer); } public static (GameObject, UiComponent) CreateLogoUi(Engine.Engine parEngine, Engine.Scene.Scene parScene, - UiContainerComponent parContainer) + UiContainerComponent parContainer, RenderLayer? parRenderLayer = null) { - var logoObject = new GameObject - { - Transform = + UiComponent uiComponent; + var logoObject = GameObjectUtil.CreateGameObject(parScene, + new Transform { Translation = new Vector3(0, 0, -10), Scale = new Vector3(3), Size = new Vector3(1.6385869565f, 1f, 1f) - } - }; - logoObject.AddComponent(new Box2DRenderer - { - Texture = parEngine.AssetResourceManager.Load("texture/doom_logo.png") - }); - - var uiComponent = new UiComponent { Container = null, Anchor = Anchor.Center }; - - logoObject.AddComponent(new UiComponent - { - Container = parContainer, Anchor = Anchor.Center, Offset = new Vector2(0, 3f) - }); - - parScene.Add(logoObject); + }, [ + new Box2DRenderer + { + Texture = parEngine.AssetResourceManager.Load("texture/doom_logo.png"), + RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT + }, + uiComponent = new UiComponent { Container = parContainer, Anchor = Anchor.Center } + ] + ); return (logoObject, uiComponent); } - public static (GameObject, StackComponent) CreateStackUi(Engine.Scene.Scene parScene, - UiContainerComponent parContainer, List parChildren, Orientation parOrientation = Orientation.Vertical) + public static (GameObject, (UiComponent, Box2DRenderer)) CreateSpriteUi(Engine.Scene.Scene parScene, + UiContainerComponent parContainer, + Texture? parTexture, RenderLayer? parRenderLayer = null) { - var stack = new StackComponent + var spriteObject = new GameObject(); + var spriteComponent = new Box2DRenderer { - Container = parContainer, - Anchor = Anchor.Center + Texture = parTexture, RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT }; + spriteObject.AddComponent(spriteComponent); + var uiComponent = new UiContainerComponent { Container = parContainer }; + spriteObject.AddComponent(uiComponent); - stack.Children.AddRange(parChildren); - foreach (var child in parChildren) - { - child.Container = stack; - } + return (spriteObject, (uiComponent, spriteComponent)); + } - var stackObject = new GameObject - { - Transform = { Translation = new Vector3(0, 0, -1) } - }; - stackObject.AddComponent(stack); - stackObject.AddComponent(new Box2DRenderer { Color = new Vector4(1, 0, 0, 1) }); + public static (GameObject, StackComponent) CreateStackUi(Engine.Scene.Scene parScene, + StackComponent parStackComponent, RenderLayer? parRenderLayer = null) + { + foreach (var child in parStackComponent.Children) + child.Container = parStackComponent; + + var stackObject = new GameObject { Transform = { Translation = new Vector3(0, 0, -1) } }; + stackObject.AddComponent(parStackComponent); + // stackObject.AddComponent(new Box2DRenderer { Color = new Vector4(1, 0, 0, 1), RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT }); parScene.Add(stackObject); - return (stackObject, stack); + return (stackObject, parStackComponent); + } + + public static (GameObject, SelectorComponent) CreateSelectorUi(Engine.Scene.Scene parScene, + SelectorComponent parSelectorComponent, RenderLayer? parRenderLayer = null) + { + var selectorObject = new GameObject { Transform = { Translation = new Vector3(0, 0, -1) } }; + selectorObject.AddComponent(parSelectorComponent); + var innerSelectorObject = new GameObject + { + Transform = { Translation = new Vector3(-0.5f, 0, 0), Size = new Vector3(0.25f, 0.5f, 1f) } + }; + innerSelectorObject.AddComponent(new Box2DRenderer + { + Color = new Vector4(1, 1, 1, 1), RenderLayer = parRenderLayer ?? RenderLayer.DEFAULT + }); + + parScene.Add(selectorObject); + parScene.AddChild(selectorObject, innerSelectorObject); + + return (selectorObject, parSelectorComponent); } } \ No newline at end of file diff --git a/Engine/src/Engine.cs b/Engine/src/Engine.cs index f864e24..95572b9 100644 --- a/Engine/src/Engine.cs +++ b/Engine/src/Engine.cs @@ -4,6 +4,7 @@ using Engine.Asset; using Engine.Asset.Font; using Engine.Asset.Mesh; using Engine.Graphics; +using Engine.Graphics.Pipeline; using Engine.Graphics.Pixel; using Engine.Graphics.Shader; using Engine.Graphics.Texture; @@ -155,28 +156,33 @@ public sealed class Engine Debug.RenderDocStartFrame(); #endif - Renderer.StartFrame(); + Renderer.RunScheduledActions(); - var projection = Matrix4.Identity; - var view = Matrix4.Identity; - lock (_sceneLock) + if (Monitor.TryEnter(_sceneLock)) { - var camera = SceneManager.CurrentScene?.MainCamera; - if (camera != null) + Renderer.StartFrame(); + var matrices = new Dictionary(); { - camera.ScreenSize = new Vector2i(Renderer.ViewportWidth, Renderer.ViewportHeight); - projection = camera.Projection; - view = camera.View; + var cameras = SceneManager.CurrentScene?.Cameras; + if (cameras != null) + { + foreach (var (renderLayer, camera) in cameras) + { + camera.ScreenSize = new Vector2i(Renderer.ViewportWidth, Renderer.ViewportHeight); + matrices[renderLayer] = (camera.Projection, camera.View); + } + } + + SceneManager.Render(); } + Monitor.Exit(_sceneLock); - SceneManager.Render(); + Renderer.EndFrame(matrices); + + Presenter!.Present(Renderer.RenderTexture); + Presenter!.Render(); } - Renderer.EndFrame(projection, view); - - Presenter!.Present(Renderer.RenderTexture); - Presenter!.Render(); - #if DEBUG Debug.RenderDocEndFrame(); #endif diff --git a/Engine/src/Graphics/GenericRenderer.cs b/Engine/src/Graphics/GenericRenderer.cs index f08c0bf..3e31621 100644 --- a/Engine/src/Graphics/GenericRenderer.cs +++ b/Engine/src/Graphics/GenericRenderer.cs @@ -10,11 +10,11 @@ namespace Engine.Graphics; public class GenericRenderer : IRenderer { public QuadRenderer QuadRenderer => _quadRenderer ??= new QuadRenderer(_engine, 1024 * 8); - public AnyMeshRenderer AnyMeshRenderer => _globalMeshRenderer ??= new AnyMeshRenderer(_engine, 1024); + public AnyMeshRenderer AnyMeshRenderer => _anyMeshRenderer ??= new AnyMeshRenderer(_engine, 1024); public TextRenderer TextRenderer => _textRenderer ??= new TextRenderer(_engine, 1024 * 8); private QuadRenderer? _quadRenderer; - private AnyMeshRenderer? _globalMeshRenderer; + private AnyMeshRenderer? _anyMeshRenderer; private TextRenderer? _textRenderer; private readonly Engine _engine; @@ -47,14 +47,23 @@ public class GenericRenderer : IRenderer GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - QuadRenderer.Render(parProjectionMatrix, parViewMatrix); - QuadRenderer.Reset(); + if (_anyMeshRenderer != null) + { + _anyMeshRenderer.Render(parProjectionMatrix, parViewMatrix); + _anyMeshRenderer.Reset(); + } - AnyMeshRenderer.Render(parProjectionMatrix, parViewMatrix); - AnyMeshRenderer.Reset(); + if (_quadRenderer != null) + { + _quadRenderer.Render(parProjectionMatrix, parViewMatrix); + _quadRenderer.Reset(); + } - TextRenderer.Render(parProjectionMatrix, parViewMatrix); - TextRenderer.Reset(); + if (_textRenderer != null) + { + _textRenderer.Render(parProjectionMatrix, parViewMatrix); + _textRenderer.Reset(); + } _framebuffer.Unbind(); diff --git a/Engine/src/Graphics/Renderer.cs b/Engine/src/Graphics/Renderer.cs index b94d77d..2aeb05b 100644 --- a/Engine/src/Graphics/Renderer.cs +++ b/Engine/src/Graphics/Renderer.cs @@ -74,8 +74,8 @@ public class Renderer // GL.Enable(EnableCap.FramebufferSrgb); - GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.Enable(EnableCap.Blend); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.Viewport(0, 0, parWidth, parHeight); } @@ -118,21 +118,22 @@ public class Renderer { EnsureRenderThread(); - RunScheduledActions(); - foreach (var renderer in _renderers.Values) { renderer.StartFrame(); } } - internal void EndFrame(in Matrix4 parViewMatrix, in Matrix4 parProjectionMatrix) + internal void EndFrame(Dictionary parMatrices) { EnsureRenderThread(); - foreach (var renderer in _renderers.Values) + foreach (var (renderLayer, renderer) in _renderers) { - renderer.EndFrame(in parViewMatrix, in parProjectionMatrix); + if (!parMatrices.TryGetValue(renderLayer, out var matrices)) + renderer.EndFrame(Matrix4.Identity, Matrix4.Identity); + else + renderer.EndFrame(in matrices.Item1, in matrices.Item2); } _framebuffer.Bind(); @@ -143,8 +144,11 @@ public class Renderer GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f); GL.Clear(ClearBufferMask.ColorBufferBit); - foreach (var renderer in _renderers.Values) + foreach (var (renderLayer, renderer) in _renderers) { + if (!parMatrices.ContainsKey(renderLayer)) + continue; + QuadRenderer.Commit(Matrix4.CreateScale(2f, -2f, 1f), Vector4.One, renderer._framebuffer.TextureInternal); QuadRenderer.Render(Matrix4.Identity, Matrix4.Identity); QuadRenderer.Reset(); @@ -167,7 +171,7 @@ public class Renderer } } - private void RunScheduledActions() + internal void RunScheduledActions() { while (_scheduleActions.TryDequeue(out var action)) { diff --git a/Engine/src/Input/KeyboardButtonCode.cs b/Engine/src/Input/KeyboardButtonCode.cs index baff356..bfdd0d5 100644 --- a/Engine/src/Input/KeyboardButtonCode.cs +++ b/Engine/src/Input/KeyboardButtonCode.cs @@ -29,6 +29,17 @@ public enum KeyboardButtonCode Y, Z, + D1, + D2, + D3, + D4, + D5, + D6, + D7, + D8, + D9, + D0, + Ctrl, Alt, Shift, diff --git a/Engine/src/Input/WindowInputHandler.cs b/Engine/src/Input/WindowInputHandler.cs index f4ad46b..5fc9442 100644 --- a/Engine/src/Input/WindowInputHandler.cs +++ b/Engine/src/Input/WindowInputHandler.cs @@ -103,6 +103,16 @@ public class WindowInputHandler(Window parWindow) : IInputHandler KeyboardButtonCode.End => Keys.End, KeyboardButtonCode.PageUp => Keys.PageUp, KeyboardButtonCode.PageDown => Keys.PageDown, + KeyboardButtonCode.D0 => Keys.D0, + KeyboardButtonCode.D1 => Keys.D1, + KeyboardButtonCode.D2 => Keys.D2, + KeyboardButtonCode.D3 => Keys.D3, + KeyboardButtonCode.D4 => Keys.D4, + KeyboardButtonCode.D5 => Keys.D5, + KeyboardButtonCode.D6 => Keys.D6, + KeyboardButtonCode.D7 => Keys.D7, + KeyboardButtonCode.D8 => Keys.D8, + KeyboardButtonCode.D9 => Keys.D9, _ => throw new ArgumentOutOfRangeException(nameof(parKeyboardButtonCode), parKeyboardButtonCode, null) }; } diff --git a/Engine/src/Resource/Loader/FontLoader.cs b/Engine/src/Resource/Loader/FontLoader.cs index 728f822..d13307f 100644 --- a/Engine/src/Resource/Loader/FontLoader.cs +++ b/Engine/src/Resource/Loader/FontLoader.cs @@ -19,7 +19,10 @@ public class FontLoader : IResourceLoader var atlasPath = Path.Combine(parPath, "atlas.png"); using var atlasStream = parStreamProvider.GetStream(atlasPath); - var atlasTexture = ImageLoader.Load(atlasStream).ToStaticTexture(); + var atlasImage = ImageLoader.Load(atlasStream); + + // TODO: We should not be using engine instance here + var atlasTexture = Engine.Instance.Renderer.Schedule(() => atlasImage.ToStaticTexture()).Result; return new Font(atlasTexture, metadata); } diff --git a/Engine/src/Resource/Loader/TextureLoader.cs b/Engine/src/Resource/Loader/TextureLoader.cs index d496779..7530a13 100644 --- a/Engine/src/Resource/Loader/TextureLoader.cs +++ b/Engine/src/Resource/Loader/TextureLoader.cs @@ -7,6 +7,7 @@ public class TextureLoader : IResourceLoader using var stream = parStreamProvider.GetStream(parPath); var image = ImageLoader.Load(stream); - return image.ToStaticTexture(); + // TODO: We should not be using engine instance here + return Engine.Instance.Renderer.Schedule(() => image.ToStaticTexture()).Result; } } \ No newline at end of file diff --git a/Engine/src/Scene/Component/BuiltIn/Camera.cs b/Engine/src/Scene/Component/BuiltIn/Camera.cs index 7d012be..2851e6e 100644 --- a/Engine/src/Scene/Component/BuiltIn/Camera.cs +++ b/Engine/src/Scene/Component/BuiltIn/Camera.cs @@ -1,4 +1,5 @@ using Engine.Graphics.Camera; +using Engine.Graphics.Pipeline; using OpenTK.Mathematics; using Serilog; @@ -13,6 +14,8 @@ public abstract class Camera( public float NearPlane { get; set; } = parNearPlane; public float FarPlane { get; set; } = parFarPlane; + public RenderLayer RenderLayer { get; set; } = RenderLayer.DEFAULT; + private Vector2i _screenSize = new(1, 1); public abstract Matrix4 View { get; } diff --git a/Engine/src/Scene/Component/Component.cs b/Engine/src/Scene/Component/Component.cs index f680bff..22cbeef 100644 --- a/Engine/src/Scene/Component/Component.cs +++ b/Engine/src/Scene/Component/Component.cs @@ -25,6 +25,14 @@ public abstract class Component : IUpdate, IRender public virtual void Destroy() { } + + public virtual void Enable() + { + } + + public virtual void Disable() + { + } } public static class ComponentTypeExtensions diff --git a/Engine/src/Scene/GameObject.cs b/Engine/src/Scene/GameObject.cs index b19e25b..45d7fd7 100644 --- a/Engine/src/Scene/GameObject.cs +++ b/Engine/src/Scene/GameObject.cs @@ -7,6 +7,17 @@ namespace Engine.Scene; public sealed class GameObject : IUpdate, IRender { public Guid Id { get; } = Guid.NewGuid(); + + public bool IsEnabled + { + get => IsSelfEnabled && IsParentEnabled; + set => IsSelfEnabled = value; + } + + private bool IsSelfEnabled { get; set; } = true; + private bool _prevIsSelfEnabled = true; + private bool IsParentEnabled => Scene?.Hierarchy.GetParent(this)?.IsEnabled ?? true; + public Transform Transform { get; } internal Scene? Scene { get; set; } @@ -50,6 +61,30 @@ public sealed class GameObject : IUpdate, IRender public void Update(double parDeltaTime) { + if (!IsEnabled) + { + if (!_prevIsSelfEnabled) + return; + + foreach (var component in _components) + { + component.Disable(); + } + + _prevIsSelfEnabled = false; + return; + } + + if (!_prevIsSelfEnabled) + { + foreach (var component in _components) + { + component.Enable(); + } + } + + _prevIsSelfEnabled = true; + foreach (var component in _components) { component.Update(parDeltaTime); @@ -58,6 +93,9 @@ public sealed class GameObject : IUpdate, IRender public void Render() { + if (!IsEnabled) + return; + foreach (var component in _components) { component.Render(); @@ -113,7 +151,7 @@ public sealed class GameObject : IUpdate, IRender parComponent.GameObject = this; _components.Add(parComponent); - _addedComponentTypes.Add(typeof(T).GetComponentBaseType()); + _addedComponentTypes.Add(parComponent.GetType().GetComponentBaseType()); }); } diff --git a/Engine/src/Scene/Hierarchy.cs b/Engine/src/Scene/Hierarchy.cs index 3e78833..accfd21 100644 --- a/Engine/src/Scene/Hierarchy.cs +++ b/Engine/src/Scene/Hierarchy.cs @@ -32,7 +32,7 @@ public class Hierarchy { if (_parentLookup.ContainsKey(parObj)) { - throw new ArgumentException("Object is already added to hierarchy"); + return; } _childrenLookup.Add(parObj, new List()); diff --git a/Engine/src/Scene/Scene.cs b/Engine/src/Scene/Scene.cs index 887242e..868b31f 100644 --- a/Engine/src/Scene/Scene.cs +++ b/Engine/src/Scene/Scene.cs @@ -1,4 +1,5 @@ using Engine.Graphics.Camera; +using Engine.Graphics.Pipeline; using Engine.Scene.Component.BuiltIn; namespace Engine.Scene; @@ -6,7 +7,8 @@ namespace Engine.Scene; public class Scene : IUpdate, IRender { public bool IsPlaying { get; private set; } - public ICamera? MainCamera { get; private set; } + public IReadOnlyDictionary Cameras => _cameras; + private readonly Dictionary _cameras = new(); internal Hierarchy Hierarchy { get; } = new(); @@ -21,14 +23,25 @@ public class Scene : IUpdate, IRender ProcessChanges(); - MainCamera = FindFirstComponent(); + var allCameras = FindAllComponents(); + foreach (var camera in allCameras) + { + _cameras.Add(camera.RenderLayer, camera); + } IsPlaying = true; } + public List FindAllComponents() where T : Component.Component + { + return Hierarchy.Objects.Select(parGameObject => parGameObject.GetComponent()) + .Where(parComponent => parComponent != null).ToList()!; + } + public T? FindFirstComponent() where T : Component.Component { - return Hierarchy.Objects.Select(parGameObject => parGameObject.GetComponent()).FirstOrDefault(parComponent => parComponent != null); + return Hierarchy.Objects.Select(parGameObject => parGameObject.GetComponent()) + .FirstOrDefault(parComponent => parComponent != null); } public void Update(double parDeltaTime) @@ -87,15 +100,10 @@ public class Scene : IUpdate, IRender }); } - public void SetChild(GameObject parParent, GameObject parChild) - { - Hierarchy.AddChild(parParent, parChild); - } - public void AddChild(GameObject parParent, GameObject parChild) { Add(parChild); - SetChild(parParent, parChild); + Hierarchy.AddChild(parParent, parChild); } public void Remove(GameObject parGameObject) diff --git a/Engine/src/Scene/SceneManager.cs b/Engine/src/Scene/SceneManager.cs index 2dcce9f..1456e50 100644 --- a/Engine/src/Scene/SceneManager.cs +++ b/Engine/src/Scene/SceneManager.cs @@ -5,9 +5,10 @@ public class SceneManager : IUpdate, IRender public Scene? CurrentScene => _currentScene; private Scene? _currentScene; - private Scene? _nextScene; + // private Scene? _nextScene; + private Func? _nextScene; - public void TransitionTo(Scene parScene) + public void TransitionTo(Func? parScene) { _nextScene = parScene; } @@ -17,7 +18,7 @@ public class SceneManager : IUpdate, IRender if (_nextScene != null) { _currentScene?.Exit(); - _currentScene = _nextScene; + _currentScene = _nextScene(); _nextScene = null; _currentScene.Enter(); } diff --git a/Engine/src/Util/Timer.cs b/Engine/src/Util/Timer.cs new file mode 100644 index 0000000..239c722 --- /dev/null +++ b/Engine/src/Util/Timer.cs @@ -0,0 +1,62 @@ +namespace Engine.Util; + +public class Timer +{ + public event Action? OnFinished; + public event Action? OnUpdate; + + public double TotalTime + { + get => _totalTime; + set + { + if (value <= 0) + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value); + + _totalTime = value; + CurrentTime = value; + } + } + + public double CurrentTime + { + get => _currentTime; + set + { + if (value < 0) + value = 0; + if (value > TotalTime) + value = TotalTime; + + _currentTime = value; + OnUpdate?.Invoke(value); + + if (IsFinished) + OnFinished?.Invoke(); + } + } + + public bool IsFinished => _currentTime <= 0; + + private double _totalTime; + private double _currentTime; + + public Timer(double parTotalTime) + { + if (parTotalTime <= 0) + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parTotalTime); + + _totalTime = parTotalTime; + _currentTime = parTotalTime; + } + + public void Update(double parDeltaTime) + { + CurrentTime -= parDeltaTime; + } + + public void Reset() + { + CurrentTime = TotalTime; + } +} \ No newline at end of file diff --git a/EngineTests/src/Scene/HierarchyTests.cs b/EngineTests/src/Scene/HierarchyTests.cs index 35fc9dc..a3e535d 100644 --- a/EngineTests/src/Scene/HierarchyTests.cs +++ b/EngineTests/src/Scene/HierarchyTests.cs @@ -169,16 +169,16 @@ public class HierarchyTests Assert.That(_hierarchy.GetChildren(obj).Count(), Is.EqualTo(0)); } - [Test] - public void AddDuplicateObjectThrows() - { - var obj = new object(); - - _hierarchy.Add(obj); - _hierarchy.Add(obj); - - Assert.Throws(() => _hierarchy.ProcessChanges()); - } + // [Test] + // public void AddDuplicateObjectThrows() + // { + // var obj = new object(); + // + // _hierarchy.Add(obj); + // _hierarchy.Add(obj); + // + // Assert.Throws(() => _hierarchy.ProcessChanges()); + // } [Test] public void AddChild_ParentNotInHierarchyThrows() diff --git a/PresenterConsole/src/ConsoleInputHandler.cs b/PresenterConsole/src/ConsoleInputHandler.cs index 25919fa..ed595fa 100644 --- a/PresenterConsole/src/ConsoleInputHandler.cs +++ b/PresenterConsole/src/ConsoleInputHandler.cs @@ -99,6 +99,16 @@ public class ConsoleInputHandler : IInputHandler KeyboardButtonCode.End => 0x23, KeyboardButtonCode.PageUp => 0x21, KeyboardButtonCode.PageDown => 0x22, + KeyboardButtonCode.D0 => 0x30, + KeyboardButtonCode.D1 => 0x31, + KeyboardButtonCode.D2 => 0x32, + KeyboardButtonCode.D3 => 0x33, + KeyboardButtonCode.D4 => 0x34, + KeyboardButtonCode.D5 => 0x35, + KeyboardButtonCode.D6 => 0x36, + KeyboardButtonCode.D7 => 0x37, + KeyboardButtonCode.D8 => 0x38, + KeyboardButtonCode.D9 => 0x39, _ => throw new ArgumentOutOfRangeException(nameof(parKeyboardButtonCode), parKeyboardButtonCode, null) }; } \ No newline at end of file diff --git a/PresenterWpf/src/WPFInputHandler.cs b/PresenterWpf/src/WPFInputHandler.cs index 6d182b5..3aebb08 100644 --- a/PresenterWpf/src/WPFInputHandler.cs +++ b/PresenterWpf/src/WPFInputHandler.cs @@ -163,6 +163,16 @@ public class WpfInputHandler : IInputHandler Key.Insert => (int)KeyboardButtonCode.Insert, Key.Home => (int)KeyboardButtonCode.Home, Key.End => (int)KeyboardButtonCode.End, + Key.D0 => (int)KeyboardButtonCode.D0, + Key.D1 => (int)KeyboardButtonCode.D1, + Key.D2 => (int)KeyboardButtonCode.D2, + Key.D3 => (int)KeyboardButtonCode.D3, + Key.D4 => (int)KeyboardButtonCode.D4, + Key.D5 => (int)KeyboardButtonCode.D5, + Key.D6 => (int)KeyboardButtonCode.D6, + Key.D7 => (int)KeyboardButtonCode.D7, + Key.D8 => (int)KeyboardButtonCode.D8, + Key.D9 => (int)KeyboardButtonCode.D9, _ => -1 };