diff --git a/assets/graphics/objects.atlas b/assets/graphics/objects.atlas index cdd59d4..f16a607 100644 --- a/assets/graphics/objects.atlas +++ b/assets/graphics/objects.atlas @@ -25,342 +25,496 @@ oak_tree/oak_tree orig: 41, 63 offset: 0, 0 index: -1 -player/idle_down +player/attack_down rotate: false xy: 86, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 0 -player/idle_down +player/attack_down rotate: false xy: 2, 38 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 1 -player/idle_down +player/attack_down rotate: false xy: 47, 105 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 2 -player/idle_down +player/attack_down rotate: false xy: 86, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 3 -player/idle_down +player/attack_left rotate: false xy: 122, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 4 -player/idle_down + index: 0 +player/attack_left rotate: false xy: 2, 2 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 5 -player/idle_left + index: 1 +player/attack_left rotate: false xy: 86, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 0 -player/idle_left + index: 2 +player/attack_left rotate: false xy: 122, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 1 -player/idle_left + index: 3 +player/attack_right rotate: false xy: 158, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 2 -player/idle_left + index: 0 +player/attack_right rotate: false xy: 122, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 3 -player/idle_left + index: 1 +player/attack_right rotate: false xy: 158, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 4 -player/idle_left + index: 2 +player/attack_right rotate: false xy: 194, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 5 -player/idle_right + index: 3 +player/attack_up rotate: false xy: 158, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 0 -player/idle_right +player/attack_up rotate: false xy: 194, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 1 -player/idle_right +player/attack_up rotate: false xy: 230, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 2 -player/idle_right +player/attack_up rotate: false xy: 194, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 3 -player/idle_right - rotate: false - xy: 230, 185 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: 4 -player/idle_right - rotate: false - xy: 266, 221 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: 5 -player/idle_up - rotate: false - xy: 230, 149 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: 0 -player/idle_up - rotate: false - xy: 266, 185 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: 1 -player/idle_up - rotate: false - xy: 302, 221 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: 2 -player/idle_up +player/idle_down rotate: false xy: 266, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 3 -player/idle_up - rotate: false - xy: 302, 185 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: 4 -player/idle_up + index: 0 +player/idle_down rotate: false xy: 338, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 5 -player/walk_down + index: 1 +player/idle_down rotate: false xy: 302, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 0 -player/walk_down + index: 2 +player/idle_down rotate: false xy: 338, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 1 -player/walk_down + index: 3 +player/idle_down rotate: false xy: 374, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 2 -player/walk_down + index: 4 +player/idle_down rotate: false xy: 338, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 3 -player/walk_down + index: 5 +player/idle_left rotate: false xy: 374, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 4 -player/walk_down + index: 0 +player/idle_left rotate: false xy: 410, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 5 -player/walk_left + index: 1 +player/idle_left rotate: false xy: 374, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 0 -player/walk_left + index: 2 +player/idle_left rotate: false xy: 410, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 1 -player/walk_left + index: 3 +player/idle_left rotate: false xy: 446, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 2 -player/walk_left + index: 4 +player/idle_left rotate: false xy: 410, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 3 -player/walk_left + index: 5 +player/idle_right rotate: false xy: 446, 185 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 4 -player/walk_left + index: 0 +player/idle_right rotate: false xy: 446, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 5 -player/walk_right + index: 1 +player/idle_right rotate: false xy: 47, 69 size: 32, 32 orig: 32, 32 offset: 0, 0 - index: 0 -player/walk_right + index: 2 +player/idle_right rotate: false xy: 38, 33 size: 32, 32 orig: 32, 32 offset: 0, 0 + index: 3 +player/idle_right + rotate: false + xy: 74, 33 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 4 +player/idle_right + rotate: false + xy: 86, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 5 +player/idle_up + rotate: false + xy: 122, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 0 +player/idle_up + rotate: false + xy: 158, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 1 +player/idle_up + rotate: false + xy: 194, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 2 +player/idle_up + rotate: false + xy: 230, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 3 +player/idle_up + rotate: false + xy: 266, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 4 +player/idle_up + rotate: false + xy: 302, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 5 +player/walk_down + rotate: false + xy: 338, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 0 +player/walk_down + rotate: false + xy: 374, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 1 +player/walk_down + rotate: false + xy: 410, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 2 +player/walk_down + rotate: false + xy: 446, 113 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 3 +player/walk_down + rotate: false + xy: 83, 77 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 4 +player/walk_down + rotate: false + xy: 119, 77 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 5 +player/walk_left + rotate: false + xy: 155, 77 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 0 +player/walk_left + rotate: false + xy: 191, 77 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 1 +player/walk_left + rotate: false + xy: 227, 77 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 2 +player/walk_left + rotate: false + xy: 263, 77 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 3 +player/walk_left + rotate: false + xy: 299, 77 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 4 +player/walk_left + rotate: false + xy: 335, 77 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 5 +player/walk_right + rotate: false + xy: 371, 77 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 0 +player/walk_right + rotate: false + xy: 407, 77 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 index: 1 player/walk_right rotate: false - xy: 74, 33 + xy: 443, 77 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 2 player/walk_right rotate: false - xy: 86, 113 + xy: 110, 41 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 3 player/walk_right rotate: false - xy: 122, 113 + xy: 110, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 4 player/walk_right rotate: false - xy: 158, 113 + xy: 146, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 5 player/walk_up rotate: false - xy: 194, 113 + xy: 182, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 0 player/walk_up rotate: false - xy: 230, 113 + xy: 218, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 1 player/walk_up rotate: false - xy: 266, 113 + xy: 254, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 2 player/walk_up rotate: false - xy: 302, 113 + xy: 290, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 3 player/walk_up rotate: false - xy: 338, 113 + xy: 326, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 4 player/walk_up rotate: false - xy: 374, 113 + xy: 362, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: 5 +training_dummy/damaged_down + rotate: false + xy: 230, 185 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 0 +training_dummy/damaged_down + rotate: false + xy: 266, 221 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 1 +training_dummy/damaged_down + rotate: false + xy: 230, 149 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 2 +training_dummy/damaged_down + rotate: false + xy: 266, 185 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 3 +training_dummy/damaged_down + rotate: false + xy: 302, 221 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 4 +training_dummy/idle_down + rotate: false + xy: 302, 185 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: 0 trap/idle_down rotate: false xy: 38, 13 @@ -370,7 +524,7 @@ trap/idle_down index: 0 trap/idle_down rotate: false - xy: 410, 129 + xy: 482, 217 size: 16, 16 orig: 16, 16 offset: 0, 0 diff --git a/assets/graphics/objects.png b/assets/graphics/objects.png index a1d600d..a893acc 100644 Binary files a/assets/graphics/objects.png and b/assets/graphics/objects.png differ diff --git a/assets/maps/mainmap.tmx b/assets/maps/mainmap.tmx index 0d417d6..d44726f 100644 --- a/assets/maps/mainmap.tmx +++ b/assets/maps/mainmap.tmx @@ -1,18 +1,18 @@ - + - + - eJylkjsOwjAQRF3z6SI+HVBDzwGIa6BGqYEa+tAHLpCz+G5MJK80Wm2MgeJJibUz6511cM6twdJgA8IXTIyzEhTxew8OiqOh2YKBcV5EjwdoiSeoYs3O0PB/N+sKnKL2Bi7E1ejbeS5iHp48AvlUhi4Xnol9fKZWshSPBtQ92Qp6DzpTpjbqBenH9ZLpPeHJu2vVDngXnjK2emhSWYnPi3x+2ds5zsZ3sN5Nrhdryw/1+n3/yxCMFOOe2tTdpmCmmGf0fwPl7aDo + eJylkjsOwjAQRN3z6SI+HVBDzwGIa6BGqYEa+tAHLpCz+GxMJK80Wm2MgeJJibUz6511cM6twdJgA8IXTIyzEhTxew8OiqOh2YKBcV5EjwdoiSeoYs3O0PB/N+sKnKL2Bi7E1ejbeS5iHp48AvlUhi4Xnol9fKZWshSPBtQ92Qp6DzpTpjbqBenH9ZLpPeHJu2vVDngXnjK2emhSWYnPi3x+2ds5zsZ3sN5Nrhdryw/1+n3/yxCMFOOe2tTdpmCmmGf0fwNwWqII - eJxjYBgFo2AUjALKgQcQC0DZ7kTqAQAhOACg + eJxjYBgFo2AUjALKgScQC0LZHkTqAQAhxACj @@ -36,5 +36,6 @@ + diff --git a/assets/maps/mystic.tiled-project b/assets/maps/mystic.tiled-project index a107de7..0005154 100644 --- a/assets/maps/mystic.tiled-project +++ b/assets/maps/mystic.tiled-project @@ -20,6 +20,17 @@ ], "valuesAsFlags": false }, + { + "id": 4, + "name": "BodyType", + "storageType": "string", + "type": "enum", + "values": [ + "StaticBody", + "DynamicBody" + ], + "valuesAsFlags": false + }, { "color": "#ffa0a0a4", "drawFill": true, @@ -41,6 +52,22 @@ "type": "string", "value": "OBJECTS" }, + { + "name": "bodyType", + "propertyType": "BodyType", + "type": "string", + "value": "DynamicBody" + }, + { + "name": "damage", + "type": "float", + "value": 0 + }, + { + "name": "damageDelay", + "type": "float", + "value": 0 + }, { "name": "life", "type": "int", diff --git a/assets/maps/objects.tsx b/assets/maps/objects.tsx index ef674dd..37acace 100644 --- a/assets/maps/objects.tsx +++ b/assets/maps/objects.tsx @@ -1,10 +1,12 @@ - + + + @@ -14,6 +16,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -43,4 +65,17 @@ + + + + + + + + + + + + + diff --git a/assets/maps/objects/training_dummy.png b/assets/maps/objects/training_dummy.png new file mode 100644 index 0000000..e77e1ed Binary files /dev/null and b/assets/maps/objects/training_dummy.png differ diff --git a/assets_raw/objects/player/attack_down_00.png b/assets_raw/objects/player/attack_down_00.png new file mode 100644 index 0000000..d935a14 Binary files /dev/null and b/assets_raw/objects/player/attack_down_00.png differ diff --git a/assets_raw/objects/player/attack_down_01.png b/assets_raw/objects/player/attack_down_01.png new file mode 100644 index 0000000..e5c8aae Binary files /dev/null and b/assets_raw/objects/player/attack_down_01.png differ diff --git a/assets_raw/objects/player/attack_down_02.png b/assets_raw/objects/player/attack_down_02.png new file mode 100644 index 0000000..1236927 Binary files /dev/null and b/assets_raw/objects/player/attack_down_02.png differ diff --git a/assets_raw/objects/player/attack_down_03.png b/assets_raw/objects/player/attack_down_03.png new file mode 100644 index 0000000..4e8340e Binary files /dev/null and b/assets_raw/objects/player/attack_down_03.png differ diff --git a/assets_raw/objects/player/attack_left_00.png b/assets_raw/objects/player/attack_left_00.png new file mode 100644 index 0000000..acf5838 Binary files /dev/null and b/assets_raw/objects/player/attack_left_00.png differ diff --git a/assets_raw/objects/player/attack_left_01.png b/assets_raw/objects/player/attack_left_01.png new file mode 100644 index 0000000..7700bf3 Binary files /dev/null and b/assets_raw/objects/player/attack_left_01.png differ diff --git a/assets_raw/objects/player/attack_left_02.png b/assets_raw/objects/player/attack_left_02.png new file mode 100644 index 0000000..01ae758 Binary files /dev/null and b/assets_raw/objects/player/attack_left_02.png differ diff --git a/assets_raw/objects/player/attack_left_03.png b/assets_raw/objects/player/attack_left_03.png new file mode 100644 index 0000000..0234eb0 Binary files /dev/null and b/assets_raw/objects/player/attack_left_03.png differ diff --git a/assets_raw/objects/player/attack_right_00.png b/assets_raw/objects/player/attack_right_00.png new file mode 100644 index 0000000..8628488 Binary files /dev/null and b/assets_raw/objects/player/attack_right_00.png differ diff --git a/assets_raw/objects/player/attack_right_01.png b/assets_raw/objects/player/attack_right_01.png new file mode 100644 index 0000000..fc9056f Binary files /dev/null and b/assets_raw/objects/player/attack_right_01.png differ diff --git a/assets_raw/objects/player/attack_right_02.png b/assets_raw/objects/player/attack_right_02.png new file mode 100644 index 0000000..ce56a51 Binary files /dev/null and b/assets_raw/objects/player/attack_right_02.png differ diff --git a/assets_raw/objects/player/attack_right_03.png b/assets_raw/objects/player/attack_right_03.png new file mode 100644 index 0000000..fe20af2 Binary files /dev/null and b/assets_raw/objects/player/attack_right_03.png differ diff --git a/assets_raw/objects/player/attack_up_00.png b/assets_raw/objects/player/attack_up_00.png new file mode 100644 index 0000000..4699d0c Binary files /dev/null and b/assets_raw/objects/player/attack_up_00.png differ diff --git a/assets_raw/objects/player/attack_up_01.png b/assets_raw/objects/player/attack_up_01.png new file mode 100644 index 0000000..01062c9 Binary files /dev/null and b/assets_raw/objects/player/attack_up_01.png differ diff --git a/assets_raw/objects/player/attack_up_02.png b/assets_raw/objects/player/attack_up_02.png new file mode 100644 index 0000000..e66c6f3 Binary files /dev/null and b/assets_raw/objects/player/attack_up_02.png differ diff --git a/assets_raw/objects/player/attack_up_03.png b/assets_raw/objects/player/attack_up_03.png new file mode 100644 index 0000000..0d79669 Binary files /dev/null and b/assets_raw/objects/player/attack_up_03.png differ diff --git a/assets_raw/objects/training_dummy/damaged_down_00.png b/assets_raw/objects/training_dummy/damaged_down_00.png new file mode 100644 index 0000000..e77e1ed Binary files /dev/null and b/assets_raw/objects/training_dummy/damaged_down_00.png differ diff --git a/assets_raw/objects/training_dummy/damaged_down_01.png b/assets_raw/objects/training_dummy/damaged_down_01.png new file mode 100644 index 0000000..ea2af33 Binary files /dev/null and b/assets_raw/objects/training_dummy/damaged_down_01.png differ diff --git a/assets_raw/objects/training_dummy/damaged_down_02.png b/assets_raw/objects/training_dummy/damaged_down_02.png new file mode 100644 index 0000000..bbc1ca0 Binary files /dev/null and b/assets_raw/objects/training_dummy/damaged_down_02.png differ diff --git a/assets_raw/objects/training_dummy/damaged_down_03.png b/assets_raw/objects/training_dummy/damaged_down_03.png new file mode 100644 index 0000000..7485543 Binary files /dev/null and b/assets_raw/objects/training_dummy/damaged_down_03.png differ diff --git a/assets_raw/objects/training_dummy/damaged_down_04.png b/assets_raw/objects/training_dummy/damaged_down_04.png new file mode 100644 index 0000000..6927185 Binary files /dev/null and b/assets_raw/objects/training_dummy/damaged_down_04.png differ diff --git a/assets_raw/objects/training_dummy/idle_down_00.png b/assets_raw/objects/training_dummy/idle_down_00.png new file mode 100644 index 0000000..e77e1ed Binary files /dev/null and b/assets_raw/objects/training_dummy/idle_down_00.png differ diff --git a/core/src/main/java/io/github/com/quillraven/GdxGame.java b/core/src/main/java/io/github/com/quillraven/GdxGame.java index 13d8b78..e657676 100644 --- a/core/src/main/java/io/github/com/quillraven/GdxGame.java +++ b/core/src/main/java/io/github/com/quillraven/GdxGame.java @@ -7,6 +7,7 @@ import com.badlogic.gdx.InputMultiplexer; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.Screen; import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver; +import com.badlogic.gdx.graphics.FPSLogger; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.g2d.Batch; @@ -33,6 +34,7 @@ public class GdxGame extends Game { private OrthographicCamera camera; private Viewport viewport; private GLProfiler glProfiler; + private FPSLogger fpsLogger; private InputMultiplexer inputMultiplexer; private final Map, Screen> screenCache = new HashMap<>(); @@ -51,6 +53,7 @@ public class GdxGame extends Game { glProfiler = new GLProfiler(Gdx.graphics); glProfiler.enable(); + fpsLogger = new FPSLogger(); addScreen(new LoadingScreen(this)); setScreen(LoadingScreen.class); @@ -81,9 +84,8 @@ public class GdxGame extends Game { super.render(); - Gdx.graphics.setTitle("Mystic Tutorial " + - "- Draw Calls: " + glProfiler.getDrawCalls() + " " + - "- FPS: " + Gdx.graphics.getFramesPerSecond()); + Gdx.graphics.setTitle("Mystic Tutorial - Draw Calls: " + glProfiler.getDrawCalls()); + fpsLogger.log(); } @Override diff --git a/core/src/main/java/io/github/com/quillraven/ai/AnimationState.java b/core/src/main/java/io/github/com/quillraven/ai/AnimationState.java index 2400931..3b09b1d 100644 --- a/core/src/main/java/io/github/com/quillraven/ai/AnimationState.java +++ b/core/src/main/java/io/github/com/quillraven/ai/AnimationState.java @@ -5,6 +5,8 @@ import com.badlogic.gdx.ai.fsm.State; import com.badlogic.gdx.ai.msg.Telegram; import io.github.com.quillraven.component.Animation2D; import io.github.com.quillraven.component.Animation2D.AnimationType; +import io.github.com.quillraven.component.Attack; +import io.github.com.quillraven.component.Damaged; import io.github.com.quillraven.component.Fsm; import io.github.com.quillraven.component.Move; @@ -20,6 +22,18 @@ public enum AnimationState implements State { Move move = Move.MAPPER.get(entity); if (move != null && !move.getDirection().isZero()) { Fsm.MAPPER.get(entity).getAnimationFsm().changeState(WALK); + return; + } + + Attack attack = Attack.MAPPER.get(entity); + if (attack != null && attack.isAttacking()) { + Fsm.MAPPER.get(entity).getAnimationFsm().changeState(ATTACK); + return; + } + + Damaged damaged = Damaged.MAPPER.get(entity); + if (damaged != null) { + Fsm.MAPPER.get(entity).getAnimationFsm().changeState(DAMAGED); } } @@ -51,6 +65,54 @@ public enum AnimationState implements State { public void exit(Entity entity) { } + @Override + public boolean onMessage(Entity entity, Telegram telegram) { + return false; + } + }, + + ATTACK { + @Override + public void enter(Entity entity) { + Animation2D.MAPPER.get(entity).setType(AnimationType.ATTACK); + } + + @Override + public void update(Entity entity) { + Attack attack = Attack.MAPPER.get(entity); + if (attack.canAttack()) { + Fsm.MAPPER.get(entity).getAnimationFsm().changeState(IDLE); + } + } + + @Override + public void exit(Entity entity) { + } + + @Override + public boolean onMessage(Entity entity, Telegram telegram) { + return false; + } + }, + + DAMAGED { + @Override + public void enter(Entity entity) { + Animation2D.MAPPER.get(entity).setType(AnimationType.DAMAGED); + } + + @Override + public void update(Entity entity) { + Animation2D animation2D = Animation2D.MAPPER.get(entity); + if (animation2D.isFinished()) { + Fsm.MAPPER.get(entity).getAnimationFsm().changeState(IDLE); + } + } + + @Override + public void exit(Entity entity) { + } + @Override public boolean onMessage(Entity entity, Telegram telegram) { return false; diff --git a/core/src/main/java/io/github/com/quillraven/component/Animation2D.java b/core/src/main/java/io/github/com/quillraven/component/Animation2D.java index 151d3d3..7a4923d 100644 --- a/core/src/main/java/io/github/com/quillraven/component/Animation2D.java +++ b/core/src/main/java/io/github/com/quillraven/component/Animation2D.java @@ -85,9 +85,16 @@ public class Animation2D implements Component { return this.stateTime; } + public boolean isFinished() { + return animation.isAnimationFinished(stateTime); + } + public enum AnimationType { IDLE, - WALK; + WALK, + ATTACK, + DAMAGED, + ; private final String atlasKey; diff --git a/core/src/main/java/io/github/com/quillraven/component/Attack.java b/core/src/main/java/io/github/com/quillraven/component/Attack.java new file mode 100644 index 0000000..5a1b53d --- /dev/null +++ b/core/src/main/java/io/github/com/quillraven/component/Attack.java @@ -0,0 +1,39 @@ +package io.github.com.quillraven.component; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.ComponentMapper; + +public class Attack implements Component { + public static final ComponentMapper MAPPER = ComponentMapper.getFor(Attack.class); + + private float damage; + private float damageDelay; + private float attackTimer; + + public Attack(float damage, float damageDelay) { + this.damage = damage; + this.damageDelay = damageDelay; + this.attackTimer = 0f; + } + + public boolean canAttack() { + return this.attackTimer == 0f; + } + + public boolean isAttacking() { + return this.attackTimer > 0f; + } + + public void startAttack() { + this.attackTimer = this.damageDelay; + } + + public void decAttackTimer(float deltaTime) { + attackTimer = Math.max(0f, attackTimer - deltaTime); + } + + public float getDamage() { + return damage; + } + +} diff --git a/core/src/main/java/io/github/com/quillraven/component/Damaged.java b/core/src/main/java/io/github/com/quillraven/component/Damaged.java new file mode 100644 index 0000000..d415613 --- /dev/null +++ b/core/src/main/java/io/github/com/quillraven/component/Damaged.java @@ -0,0 +1,22 @@ +package io.github.com.quillraven.component; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.ComponentMapper; + +public class Damaged implements Component { + public static final ComponentMapper MAPPER = ComponentMapper.getFor(Damaged.class); + + private float damage; + + public Damaged(float damage) { + this.damage = damage; + } + + public void addDamage(float amount) { + this.damage += amount; + } + + public float getDamage() { + return damage; + } +} diff --git a/core/src/main/java/io/github/com/quillraven/screen/GameScreen.java b/core/src/main/java/io/github/com/quillraven/screen/GameScreen.java index 904118f..5331989 100644 --- a/core/src/main/java/io/github/com/quillraven/screen/GameScreen.java +++ b/core/src/main/java/io/github/com/quillraven/screen/GameScreen.java @@ -19,8 +19,10 @@ import io.github.com.quillraven.audio.AudioService; import io.github.com.quillraven.input.GameControllerState; import io.github.com.quillraven.input.KeyboardController; import io.github.com.quillraven.system.AnimationSystem; +import io.github.com.quillraven.system.AttackSystem; import io.github.com.quillraven.system.CameraSystem; import io.github.com.quillraven.system.ControllerSystem; +import io.github.com.quillraven.system.DamagedSystem; import io.github.com.quillraven.system.FacingSystem; import io.github.com.quillraven.system.FsmSystem; import io.github.com.quillraven.system.LifeSystem; @@ -67,7 +69,13 @@ public class GameScreen extends ScreenAdapter { this.engine.addSystem(new PhysicMoveSystem()); this.engine.addSystem(new PhysicSystem(physicWorld, 1 / 60f)); this.engine.addSystem(new FacingSystem()); + this.engine.addSystem(new AttackSystem(physicWorld)); this.engine.addSystem(new FsmSystem()); + // DamagedSystem must run after FsmSystem to correctly + // detect when a damaged animation should be played. + // This is done by checking if an entity has a Damaged component, + // and this component is removed in the DamagedSystem. + this.engine.addSystem(new DamagedSystem()); this.engine.addSystem(new TriggerSystem(audioService)); this.engine.addSystem(new LifeSystem(this.viewModel)); this.engine.addSystem(new AnimationSystem(game.getAssetService())); diff --git a/core/src/main/java/io/github/com/quillraven/system/AttackSystem.java b/core/src/main/java/io/github/com/quillraven/system/AttackSystem.java new file mode 100644 index 0000000..307eb38 --- /dev/null +++ b/core/src/main/java/io/github/com/quillraven/system/AttackSystem.java @@ -0,0 +1,95 @@ +package io.github.com.quillraven.system; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Body; +import com.badlogic.gdx.physics.box2d.Fixture; +import com.badlogic.gdx.physics.box2d.PolygonShape; +import com.badlogic.gdx.physics.box2d.Shape.Type; +import com.badlogic.gdx.physics.box2d.World; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.GdxRuntimeException; +import io.github.com.quillraven.component.Attack; +import io.github.com.quillraven.component.Damaged; +import io.github.com.quillraven.component.Facing; +import io.github.com.quillraven.component.Facing.FacingDirection; +import io.github.com.quillraven.component.Life; +import io.github.com.quillraven.component.Physic; + +public class AttackSystem extends IteratingSystem { + public static final Rectangle attackAABB = new Rectangle(); + + private final World world; + private final Vector2 tmpVertex; + private Body attackerBody; + private float attackDamage; + + public AttackSystem(World world) { + super(Family.all(Attack.class, Facing.class, Physic.class).get()); + this.world = world; + this.tmpVertex = new Vector2(); + this.attackerBody = null; + this.attackDamage = 0f; + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + Attack attack = Attack.MAPPER.get(entity); + if (attack.canAttack()) return; + + attack.decAttackTimer(deltaTime); + if (attack.canAttack()) { + FacingDirection facingDirection = Facing.MAPPER.get(entity).getDirection(); + attackerBody = Physic.MAPPER.get(entity).getBody(); + PolygonShape attackPolygonShape = getAttackFixture(attackerBody, facingDirection); + updateAttackAABB(attackerBody.getPosition(), attackPolygonShape); + + this.attackDamage = attack.getDamage(); + world.QueryAABB(this::attackCallback, attackAABB.x, attackAABB.y, attackAABB.width, attackAABB.height); + } + } + + private boolean attackCallback(Fixture fixture) { + Body body = fixture.getBody(); + if (body.equals(attackerBody)) return true; + if (!(body.getUserData() instanceof Entity entity)) return true; + + Life life = Life.MAPPER.get(entity); + if (life == null) { + return true; + } + + Damaged damaged = Damaged.MAPPER.get(entity); + if (damaged == null) { + entity.add(new Damaged(this.attackDamage)); + } else { + damaged.addDamage(this.attackDamage); + } + return true; + } + + private void updateAttackAABB(Vector2 bodyPosition, PolygonShape attackPolygonShape) { + attackPolygonShape.getVertex(0, tmpVertex); + tmpVertex.add(bodyPosition); + attackAABB.setPosition(tmpVertex.x, tmpVertex.y); + + attackPolygonShape.getVertex(2, tmpVertex); + tmpVertex.add(bodyPosition); + attackAABB.setSize(tmpVertex.x, tmpVertex.y); + } + + private PolygonShape getAttackFixture(Body body, FacingDirection direction) { + Array fixtureList = body.getFixtureList(); + String fixtureName = "attack_sensor_" + direction.getAtlasKey(); + for (Fixture fixture : fixtureList) { + if (fixtureName.equals(fixture.getUserData()) && Type.Polygon.equals(fixture.getShape().getType())) { + return (PolygonShape) fixture.getShape(); + } + } + + throw new GdxRuntimeException("Entity has no polygon attack sensor with userData '" + fixtureName + "'"); + } +} diff --git a/core/src/main/java/io/github/com/quillraven/system/ControllerSystem.java b/core/src/main/java/io/github/com/quillraven/system/ControllerSystem.java index 6895707..7e54b40 100644 --- a/core/src/main/java/io/github/com/quillraven/system/ControllerSystem.java +++ b/core/src/main/java/io/github/com/quillraven/system/ControllerSystem.java @@ -4,6 +4,7 @@ import com.badlogic.ashley.core.Entity; import com.badlogic.ashley.core.Family; import com.badlogic.ashley.systems.IteratingSystem; import io.github.com.quillraven.GdxGame; +import io.github.com.quillraven.component.Attack; import io.github.com.quillraven.component.Controller; import io.github.com.quillraven.component.Move; import io.github.com.quillraven.input.Command; @@ -30,6 +31,7 @@ public class ControllerSystem extends IteratingSystem { case DOWN -> moveEntity(entity, 0f, -1f); case LEFT -> moveEntity(entity, -1f, 0f); case RIGHT -> moveEntity(entity, 1f, 0f); + case SELECT -> startEntityAttack(entity); case CANCEL -> game.setScreen(MenuScreen.class); } } @@ -46,6 +48,13 @@ public class ControllerSystem extends IteratingSystem { controller.getReleasedCommands().clear(); } + private void startEntityAttack(Entity entity) { + Attack attack = Attack.MAPPER.get(entity); + if (attack != null && attack.canAttack()) { + attack.startAttack(); + } + } + private void moveEntity(Entity entity, float dx, float dy) { Move move = Move.MAPPER.get(entity); if (move != null) { diff --git a/core/src/main/java/io/github/com/quillraven/system/DamagedSystem.java b/core/src/main/java/io/github/com/quillraven/system/DamagedSystem.java new file mode 100644 index 0000000..06b68ef --- /dev/null +++ b/core/src/main/java/io/github/com/quillraven/system/DamagedSystem.java @@ -0,0 +1,25 @@ +package io.github.com.quillraven.system; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import io.github.com.quillraven.component.Damaged; +import io.github.com.quillraven.component.Life; + +public class DamagedSystem extends IteratingSystem { + + public DamagedSystem() { + super(Family.all(Damaged.class).get()); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + Damaged damaged = Damaged.MAPPER.get(entity); + entity.remove(Damaged.class); + + Life life = Life.MAPPER.get(entity); + if (life != null) { + life.addLife(-damaged.getDamage()); + } + } +} diff --git a/core/src/main/java/io/github/com/quillraven/system/PhysicDebugRenderSystem.java b/core/src/main/java/io/github/com/quillraven/system/PhysicDebugRenderSystem.java index 242f965..f273d99 100644 --- a/core/src/main/java/io/github/com/quillraven/system/PhysicDebugRenderSystem.java +++ b/core/src/main/java/io/github/com/quillraven/system/PhysicDebugRenderSystem.java @@ -2,6 +2,9 @@ package io.github.com.quillraven.system; import com.badlogic.ashley.core.EntitySystem; import com.badlogic.gdx.graphics.Camera; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer; import com.badlogic.gdx.physics.box2d.World; import com.badlogic.gdx.utils.Disposable; @@ -9,10 +12,12 @@ import com.badlogic.gdx.utils.Disposable; public class PhysicDebugRenderSystem extends EntitySystem implements Disposable { private final World physicWorld; private final Box2DDebugRenderer box2DDebugRenderer; + private final ShapeRenderer shapeRenderer; private final Camera camera; public PhysicDebugRenderSystem(World physicWorld, Camera camera) { this.box2DDebugRenderer = new Box2DDebugRenderer(); + this.shapeRenderer = new ShapeRenderer(); this.physicWorld = physicWorld; this.camera = camera; setProcessing(false); @@ -21,10 +26,22 @@ public class PhysicDebugRenderSystem extends EntitySystem implements Disposable @Override public void update(float deltaTime) { this.box2DDebugRenderer.render(physicWorld, camera.combined); + + this.shapeRenderer.setProjectionMatrix(camera.combined); + this.shapeRenderer.begin(ShapeRenderer.ShapeType.Line); + this.shapeRenderer.setColor(Color.RED); + Rectangle attackAABB = AttackSystem.attackAABB; + this.shapeRenderer.rect( + attackAABB.x, + attackAABB.y, + attackAABB.width - attackAABB.x, + attackAABB.height - attackAABB.y); + this.shapeRenderer.end(); } @Override public void dispose() { this.box2DDebugRenderer.dispose(); + this.shapeRenderer.dispose(); } } diff --git a/core/src/main/java/io/github/com/quillraven/system/PhysicSystem.java b/core/src/main/java/io/github/com/quillraven/system/PhysicSystem.java index 6408911..e0465e9 100644 --- a/core/src/main/java/io/github/com/quillraven/system/PhysicSystem.java +++ b/core/src/main/java/io/github/com/quillraven/system/PhysicSystem.java @@ -10,6 +10,7 @@ import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.Contact; import com.badlogic.gdx.physics.box2d.ContactImpulse; import com.badlogic.gdx.physics.box2d.ContactListener; +import com.badlogic.gdx.physics.box2d.Fixture; import com.badlogic.gdx.physics.box2d.Manifold; import com.badlogic.gdx.physics.box2d.World; import io.github.com.quillraven.component.Physic; @@ -95,26 +96,28 @@ public class PhysicSystem extends IteratingSystem implements EntityListener, Con @Override public void beginContact(Contact contact) { - Object userDataA = contact.getFixtureA().getBody().getUserData(); - Object userDataB = contact.getFixtureB().getBody().getUserData(); + Fixture fixtureA = contact.getFixtureA(); + Object userDataA = fixtureA.getBody().getUserData(); + Fixture fixtureB = contact.getFixtureB(); + Object userDataB = fixtureB.getBody().getUserData(); if (!(userDataA instanceof Entity entityA) || !(userDataB instanceof Entity entityB)) { return; } - playerTriggerContact(entityA, entityB); + playerTriggerContact(entityA, fixtureA, entityB, fixtureB); } - private static void playerTriggerContact(Entity entityA, Entity entityB) { + private static void playerTriggerContact(Entity entityA, Fixture fixtureA, Entity entityB, Fixture fixtureB) { Trigger trigger = Trigger.MAPPER.get(entityA); - boolean isPlayer = Player.MAPPER.get(entityB) != null; + boolean isPlayer = Player.MAPPER.get(entityB) != null && !fixtureB.isSensor(); if (trigger != null && isPlayer) { trigger.setTriggeringEntity(entityB); return; } trigger = Trigger.MAPPER.get(entityB); - isPlayer = Player.MAPPER.get(entityA) != null; + isPlayer = Player.MAPPER.get(entityA) != null && !fixtureA.isSensor(); if (trigger != null && isPlayer) { trigger.setTriggeringEntity(entityA); } diff --git a/core/src/main/java/io/github/com/quillraven/tiled/TiledAshleyConfigurator.java b/core/src/main/java/io/github/com/quillraven/tiled/TiledAshleyConfigurator.java index 4dc15b1..9c925cc 100644 --- a/core/src/main/java/io/github/com/quillraven/tiled/TiledAshleyConfigurator.java +++ b/core/src/main/java/io/github/com/quillraven/tiled/TiledAshleyConfigurator.java @@ -17,6 +17,7 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.BodyDef; import com.badlogic.gdx.physics.box2d.BodyDef.BodyType; +import com.badlogic.gdx.physics.box2d.Fixture; import com.badlogic.gdx.physics.box2d.FixtureDef; import com.badlogic.gdx.physics.box2d.World; import com.badlogic.gdx.utils.GdxRuntimeException; @@ -25,6 +26,7 @@ import io.github.com.quillraven.asset.AssetService; import io.github.com.quillraven.asset.AtlasAsset; import io.github.com.quillraven.component.Animation2D; import io.github.com.quillraven.component.Animation2D.AnimationType; +import io.github.com.quillraven.component.Attack; import io.github.com.quillraven.component.CameraFollow; import io.github.com.quillraven.component.Controller; import io.github.com.quillraven.component.Facing; @@ -92,7 +94,6 @@ public class TiledAshleyConfigurator { Entity entity = this.engine.createEntity(); TiledMapTile tile = tileMapObject.getTile(); TextureRegion textureRegion = getTextureRegion(tile); - String classType = tile.getProperties().get("type", "", String.class); float sortOffsetY = tile.getProperties().get("sortOffsetY", 0, Integer.class); sortOffsetY *= GdxGame.UNIT_SCALE; int z = tile.getProperties().get("z", 1, Integer.class); @@ -103,9 +104,10 @@ public class TiledAshleyConfigurator { tileMapObject.getScaleX(), tileMapObject.getScaleY(), sortOffsetY, entity); + BodyType bodyType = getObjectBodyType(tile); addEntityPhysic( tile.getObjects(), - "Prop".equals(classType) ? BodyType.StaticBody : BodyType.DynamicBody, + bodyType, Vector2.Zero, entity); addEntityAnimation(tile, entity); @@ -114,6 +116,7 @@ public class TiledAshleyConfigurator { addEntityCameraFollow(tileMapObject, entity); addEntityLife(tile, entity); addEntityPlayer(tileMapObject, entity); + addEntityAttack(tile, entity); entity.add(new Facing(FacingDirection.DOWN)); entity.add(new Fsm(entity)); entity.add(new Graphic(textureRegion, Color.WHITE.cpy())); @@ -122,6 +125,24 @@ public class TiledAshleyConfigurator { this.engine.addEntity(entity); } + private BodyType getObjectBodyType(TiledMapTile tile) { + String classType = tile.getProperties().get("type", "", String.class); + if ("Prop".equals(classType)) { + return BodyType.StaticBody; + } + + String bodyTypeStr = tile.getProperties().get("bodyType", "DynamicBody", String.class); + return BodyType.valueOf(bodyTypeStr); + } + + private void addEntityAttack(TiledMapTile tile, Entity entity) { + float damage = tile.getProperties().get("damage", 0f, Float.class); + if (damage == 0f) return; + + float damageDelay = tile.getProperties().get("damageDelay", 0f, Float.class); + entity.add(new Attack(damage, damageDelay)); + } + private void addEntityPlayer(TiledMapTileMapObject tileMapObject, Entity entity) { if ("Player".equals(tileMapObject.getName())) { entity.add(new Player()); @@ -227,7 +248,8 @@ public class TiledAshleyConfigurator { body.setUserData(userData); for (MapObject object : mapObjects) { FixtureDef fixtureDef = TiledPhysics.fixtureDefOf(object, scaling, relativeTo); - body.createFixture(fixtureDef); + Fixture fixture = body.createFixture(fixtureDef); + fixture.setUserData(object.getName()); fixtureDef.shape.dispose(); } return body;