From 5c829f5ea725f56a4ee105ffa99629990d582b86 Mon Sep 17 00:00:00 2001 From: Miguel Angel Astor Romero Date: Tue, 21 Oct 2014 15:56:11 -0430 Subject: [PATCH] Converted the game into pong. --- android/AndroidManifest.xml | 2 +- android/assets/data/fonts/CRYSTAL-Regular.ttf | Bin 0 -> 13252 bytes .../assets/data/gfx/textures/pong_atlas.atlas | 27 ++++ .../assets/data/gfx/textures/pong_atlas.png | Bin 0 -> 10526 bytes android/ic_pong-web.png | Bin 0 -> 12923 bytes android/res/drawable-hdpi/ic_pong.png | Bin 0 -> 2096 bytes android/res/drawable-mdpi/ic_pong.png | Bin 0 -> 1096 bytes android/res/drawable-xhdpi/ic_pong.png | Bin 0 -> 3249 bytes android/res/drawable-xxhdpi/ic_pong.png | Bin 0 -> 6438 bytes android/res/values/strings.xml | 2 +- .../gamejolt/mikykr5/poukemon/GameCore.java | 10 +- .../mikykr5/poukemon/ProjectConstants.java | 5 +- .../ecs/components/BoundingBoxComponent.java | 33 +++++ .../poukemon/ecs/components/Mappers.java | 4 + .../ecs/components/PlayerComponent.java | 28 ++++ .../ecs/components/ScoreComponent.java | 28 ++++ .../ecs/components/SpriteComponent.java | 33 +++++ .../ecs/entities/PongEntityInitializer.java | 112 ++++++++++++++++ .../entities/PoukemonEntityInitializer.java | 97 -------------- .../ecs/systems/CollisionDetectionSystem.java | 121 ++++++++++++++++++ .../ComputerPlayerPositioningSystem.java | 55 ++++++++ .../systems/HumanPlayerPositioningSystem.java | 48 +++++++ .../ecs/systems/InterSystemMessage.java | 14 ++ .../systems/InterSystemMessagingQueue.java | 36 ++++++ .../ecs/systems/PositioningSystem.java | 11 +- .../poukemon/ecs/systems/RenderingSystem.java | 10 +- .../poukemon/ecs/systems/ScoringSystem.java | 80 ++++++++++++ .../mikykr5/poukemon/states/BaseState.java | 2 +- .../mikykr5/poukemon/states/InGameState.java | 86 +++++++++++-- .../utils/managers/CachedFontManager.java | 2 + .../poukemon/desktop/DesktopLauncher.java | 2 +- 31 files changed, 710 insertions(+), 138 deletions(-) create mode 100644 android/assets/data/fonts/CRYSTAL-Regular.ttf create mode 100644 android/assets/data/gfx/textures/pong_atlas.atlas create mode 100644 android/assets/data/gfx/textures/pong_atlas.png create mode 100644 android/ic_pong-web.png create mode 100644 android/res/drawable-hdpi/ic_pong.png create mode 100644 android/res/drawable-mdpi/ic_pong.png create mode 100644 android/res/drawable-xhdpi/ic_pong.png create mode 100644 android/res/drawable-xxhdpi/ic_pong.png create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/components/BoundingBoxComponent.java create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/components/PlayerComponent.java create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/components/ScoreComponent.java create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/components/SpriteComponent.java create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PongEntityInitializer.java delete mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PoukemonEntityInitializer.java create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/CollisionDetectionSystem.java create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/ComputerPlayerPositioningSystem.java create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/HumanPlayerPositioningSystem.java create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/InterSystemMessage.java create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/InterSystemMessagingQueue.java create mode 100644 core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/ScoringSystem.java diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index b9a29bc..f24c569 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -8,7 +8,7 @@ CgC2qlDgkvoV;iVMmratMDW)#qa5Hhk7 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 literal 0 HcmV?d00001 diff --git a/android/assets/data/gfx/textures/pong_atlas.atlas b/android/assets/data/gfx/textures/pong_atlas.atlas new file mode 100644 index 0000000..7c38966 --- /dev/null +++ b/android/assets/data/gfx/textures/pong_atlas.atlas @@ -0,0 +1,27 @@ + +pong_atlas.png +size: 256,512 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +ball + rotate: false + xy: 2, 2 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: 1 +glasspaddle2 + rotate: false + xy: 2, 68 + size: 64, 256 + orig: 64, 256 + offset: 0, 0 + index: -1 +paddle + rotate: false + xy: 68, 68 + size: 64, 256 + orig: 64, 256 + offset: 0, 0 + index: -1 diff --git a/android/assets/data/gfx/textures/pong_atlas.png b/android/assets/data/gfx/textures/pong_atlas.png new file mode 100644 index 0000000000000000000000000000000000000000..5ad2d1f6c699c5790445778134feb29ad579585c GIT binary patch literal 10526 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 YBZ#V#9HU#l{P~_cV|KdWhwH!m7p?dg+yDRo literal 0 HcmV?d00001 diff --git a/android/res/drawable-hdpi/ic_pong.png b/android/res/drawable-hdpi/ic_pong.png new file mode 100644 index 0000000000000000000000000000000000000000..4bf11a13bac3fef65fa91b4028ac133332e6bdd6 GIT binary patch literal 2096 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 - PouKemon + CEIDEC-Pong diff --git a/core/src/com/gamejolt/mikykr5/poukemon/GameCore.java b/core/src/com/gamejolt/mikykr5/poukemon/GameCore.java index 9223edb..db8d274 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/GameCore.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/GameCore.java @@ -92,7 +92,7 @@ public class GameCore extends Game { pixmap.dispose(); alpha = new MutableFloat(1.0f); - fadeOut = Tween.to(alpha, 0, 2.5f).target(1.0f).ease(TweenEquations.easeInQuint); + fadeOut = Tween.to(alpha, 0, 0.5f).target(1.0f).ease(TweenEquations.easeInQuint); fadeIn = Tween.to(alpha, 0, 2.5f).target(0.0f).ease(TweenEquations.easeInQuint); fadeIn.start(); fading = true; @@ -123,10 +123,6 @@ public class GameCore extends Game { currState = game_states_t.LOGO_SCREEN; nextState = null; this.setScreen(states[currState.getValue()]); - states[currState.getValue()].onStateEnabled(); - - // Set initial input handler. - Gdx.input.setInputProcessor(states[currState.getValue()]); // Set log level if(ProjectConstants.DEBUG){ @@ -134,7 +130,6 @@ public class GameCore extends Game { }else{ Gdx.app.setLogLevel(Application.LOG_NONE); } - } @Override @@ -159,7 +154,7 @@ public class GameCore extends Game { if(nextState != game_states_t.QUIT){ currState = nextState; nextState = null; - states[currState.getValue()].onStateEnabled(); + //states[currState.getValue()].onStateEnabled(); setScreen(states[currState.getValue()]); }else{ nextState = null; @@ -184,6 +179,7 @@ public class GameCore extends Game { fading = false; fadeIn.free(); fadeIn = Tween.to(alpha, 0, 0.5f).target(0.0f).ease(TweenEquations.easeInQuint); + states[currState.getValue()].onStateEnabled(); } } diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ProjectConstants.java b/core/src/com/gamejolt/mikykr5/poukemon/ProjectConstants.java index 2c36916..f58529a 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/ProjectConstants.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/ProjectConstants.java @@ -18,8 +18,7 @@ package com.gamejolt.mikykr5.poukemon; public abstract class ProjectConstants{ public static final int EXIT_SUCCESS = 0; public static final int EXIT_FAILURE = 1; - public static final boolean DEBUG = true; - - public static final int[] POWERS_OF_2 = {64, 128, 256, 512, 1024, 2048}; + public static final int FB_WIDTH = 1920; + public static final int FB_HEIGHT = 1080; } \ No newline at end of file diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/BoundingBoxComponent.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/BoundingBoxComponent.java new file mode 100644 index 0000000..137f0fb --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/BoundingBoxComponent.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, Miguel Angel Astor Romero + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Read the LICENSE file for more details. + */ +package com.gamejolt.mikykr5.poukemon.ecs.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.utils.Pool.Poolable; + +public class BoundingBoxComponent extends Component implements Poolable { + public Rectangle bbox; + + public BoundingBoxComponent() { + reset(); + } + + @Override + public void reset() { + bbox = new Rectangle(); + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/Mappers.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/Mappers.java index 537f7c4..c0c1a42 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/Mappers.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/Mappers.java @@ -22,4 +22,8 @@ public abstract class Mappers { public static final ComponentMapper velocityMapper = ComponentMapper.getFor(VelocityComponent.class); public static final ComponentMapper soundEffectMapper = ComponentMapper.getFor(SoundEffectComponent.class); public static final ComponentMapper textureMapper = ComponentMapper.getFor(TextureComponent.class); + public static final ComponentMapper spriteMapper = ComponentMapper.getFor(SpriteComponent.class); + public static final ComponentMapper bboxMapper = ComponentMapper.getFor(BoundingBoxComponent.class); + public static final ComponentMapper scoreMapper = ComponentMapper.getFor(ScoreComponent.class); + public static final ComponentMapper playerMapper = ComponentMapper.getFor(PlayerComponent.class); } diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/PlayerComponent.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/PlayerComponent.java new file mode 100644 index 0000000..e5c2dd6 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/PlayerComponent.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014, Miguel Angel Astor Romero + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Read the LICENSE file for more details. + */ +package com.gamejolt.mikykr5.poukemon.ecs.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.utils.Pool.Poolable; + +public class PlayerComponent extends Component implements Poolable { + public int id = -1; + + @Override + public void reset() { + id = -1; + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/ScoreComponent.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/ScoreComponent.java new file mode 100644 index 0000000..69ddcb7 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/ScoreComponent.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014, Miguel Angel Astor Romero + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Read the LICENSE file for more details. + */ +package com.gamejolt.mikykr5.poukemon.ecs.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.utils.Pool.Poolable; + +public class ScoreComponent extends Component implements Poolable{ + public int score = 0; + + @Override + public void reset() { + score = 0; + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/SpriteComponent.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/SpriteComponent.java new file mode 100644 index 0000000..e25a759 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/SpriteComponent.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, Miguel Angel Astor Romero + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Read the LICENSE file for more details. + */ +package com.gamejolt.mikykr5.poukemon.ecs.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.g2d.Sprite; +import com.badlogic.gdx.utils.Pool.Poolable; + +public class SpriteComponent extends Component implements Poolable { + public Sprite sprite; + + public SpriteComponent(){ + reset(); + } + + @Override + public void reset() { + sprite = null; + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PongEntityInitializer.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PongEntityInitializer.java new file mode 100644 index 0000000..a5cc09e --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PongEntityInitializer.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014, Miguel Angel Astor Romero + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Read the LICENSE file for more details. + */ +package com.gamejolt.mikykr5.poukemon.ecs.entities; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.PooledEngine; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.gamejolt.mikykr5.poukemon.ProjectConstants; +import com.gamejolt.mikykr5.poukemon.ecs.components.BoundingBoxComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.Mappers; +import com.gamejolt.mikykr5.poukemon.ecs.components.PlayerComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.PositionComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.ScoreComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.SpriteComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.VelocityComponent; +import com.gamejolt.mikykr5.poukemon.utils.AsyncAssetLoader; + +public class PongEntityInitializer extends EntityInitializerBase { + private AsyncAssetLoader loader; + private Entity ball; + private Entity paddleUser; + private Entity paddleComp; + private boolean entitiesCreated; + private boolean assetsLoaded; + + public PongEntityInitializer() { + entitiesCreated = false; + assetsLoaded = false; + } + + @Override + public void createAllEntities(PooledEngine engine){ + loader = AsyncAssetLoader.getInstance(); + + loader.addAssetToLoad("data/gfx/textures/pong_atlas.atlas", TextureAtlas.class); + + ball = engine.createEntity(); + ball.add(engine.createComponent(PositionComponent.class)); + ball.add(engine.createComponent(VelocityComponent.class)); + ball.add(engine.createComponent(SpriteComponent.class)); + ball.add(engine.createComponent(BoundingBoxComponent.class)); + + paddleUser = engine.createEntity(); + paddleUser.add(engine.createComponent(PositionComponent.class)); + paddleUser.add(engine.createComponent(SpriteComponent.class)); + paddleUser.add(engine.createComponent(BoundingBoxComponent.class)); + paddleUser.add(engine.createComponent(ScoreComponent.class)); + paddleUser.add(engine.createComponent(PlayerComponent.class)); + + paddleComp = engine.createEntity(); + paddleComp.add(engine.createComponent(PositionComponent.class)); + paddleComp.add(engine.createComponent(VelocityComponent.class)); + paddleComp.add(engine.createComponent(SpriteComponent.class)); + paddleComp.add(engine.createComponent(BoundingBoxComponent.class)); + paddleComp.add(engine.createComponent(ScoreComponent.class)); + paddleComp.add(engine.createComponent(PlayerComponent.class)); + + engine.addEntity(ball); + engine.addEntity(paddleUser); + engine.addEntity(paddleComp); + + entitiesCreated = true; + } + + @Override + public void setLoadableAssets(PooledEngine engine) throws IllegalStateException{ + if(!entitiesCreated) + throw new IllegalStateException("Entities have not been created before setting assets."); + + TextureAtlas atlas = loader.getAsset("data/gfx/textures/pong_atlas.atlas", TextureAtlas.class); + + Mappers.spriteMapper.get(ball).sprite = atlas.createSprite("ball"); + Mappers.positionMapper.get(ball).setXY(-(Mappers.spriteMapper.get(ball).sprite.getWidth() / 2), -(Mappers.spriteMapper.get(ball).sprite.getHeight() / 2)); + Mappers.velocityMapper.get(ball).setXY(173, -475); + Mappers.bboxMapper.get(ball).bbox.set(Mappers.spriteMapper.get(ball).sprite.getBoundingRectangle()); + + Mappers.spriteMapper.get(paddleUser).sprite = atlas.createSprite("glasspaddle2"); + Mappers.positionMapper.get(paddleUser).setXY(-(ProjectConstants.FB_WIDTH / 2) + 100, -(Mappers.spriteMapper.get(paddleUser).sprite.getHeight() / 2)); + Mappers.bboxMapper.get(paddleUser).bbox.set(Mappers.spriteMapper.get(paddleUser).sprite.getBoundingRectangle()); + Mappers.playerMapper.get(paddleUser).id = 0; + + Mappers.spriteMapper.get(paddleComp).sprite = atlas.createSprite("paddle"); + Mappers.positionMapper.get(paddleComp).setXY(((ProjectConstants.FB_WIDTH / 2) - 1) - 100, -(Mappers.spriteMapper.get(paddleComp).sprite.getHeight() / 2)); + Mappers.bboxMapper.get(paddleComp).bbox.set(Mappers.spriteMapper.get(paddleComp).sprite.getBoundingRectangle()); + Mappers.playerMapper.get(paddleComp).id = 1; + + AsyncAssetLoader.freeInstance(); + assetsLoaded = true; + } + + @Override + public void dispose() throws IllegalStateException { + if(!entitiesCreated) + throw new IllegalStateException("Entities have not been created before disposing assets."); + + if(!assetsLoaded) + throw new IllegalStateException("Assets have not been loaded before disposing."); + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PoukemonEntityInitializer.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PoukemonEntityInitializer.java deleted file mode 100644 index f2dd25c..0000000 --- a/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PoukemonEntityInitializer.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2014, Miguel Angel Astor Romero - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Read the LICENSE file for more details. - */ -package com.gamejolt.mikykr5.poukemon.ecs.entities; - -import com.badlogic.ashley.core.Component; -import com.badlogic.ashley.core.Entity; -import com.badlogic.ashley.core.PooledEngine; -import com.badlogic.ashley.utils.ImmutableArray; -import com.badlogic.gdx.graphics.Texture; -import com.gamejolt.mikykr5.poukemon.ecs.components.Mappers; -import com.gamejolt.mikykr5.poukemon.ecs.components.PositionComponent; -import com.gamejolt.mikykr5.poukemon.ecs.components.TextureComponent; -import com.gamejolt.mikykr5.poukemon.ecs.components.VelocityComponent; -import com.gamejolt.mikykr5.poukemon.utils.AsyncAssetLoader; - -public class PoukemonEntityInitializer extends EntityInitializerBase { - private AsyncAssetLoader loader; - private Entity ball; - private Entity roseliaBody; - private Entity roseliaHead; - private Entity roseliaArms; - private Entity roseliaEyeLeft; - private Entity roseliaEyeRight; - private boolean entitiesCreated; - private boolean assetsLoaded; - - public PoukemonEntityInitializer() { - entitiesCreated = false; - assetsLoaded = false; - } - - @Override - public void createAllEntities(PooledEngine engine){ - loader = AsyncAssetLoader.getInstance(); - - // TODO: Load Roselia's sprites. - // TODO: Load ball sprites. - // TODO: Create entities. - - loader.addAssetToLoad("data/gfx/textures/ball.png", Texture.class); - - ball = engine.createEntity(); - ball.add(engine.createComponent(PositionComponent.class)); - ball.add(engine.createComponent(VelocityComponent.class)); - - engine.addEntity(ball); - - entitiesCreated = true; - } - - @Override - public void setLoadableAssets(PooledEngine engine) throws IllegalStateException{ - if(!entitiesCreated) - throw new IllegalStateException("Entities have not been created before setting assets."); - - ball.add(engine.createComponent(TextureComponent.class)); - Mappers.textureMapper.get(ball).texture = loader.getAsset("data/gfx/textures/ball.png", Texture.class); - Mappers.positionMapper.get(ball).setXY(-(Mappers.textureMapper.get(ball).texture.getWidth() / 2), -(1080 / 2) + 128); - - //TODO: Set Roselia's textures. - - AsyncAssetLoader.freeInstance(); - assetsLoaded = true; - } - - @Override - public void dispose() throws IllegalStateException { - if(!entitiesCreated) - throw new IllegalStateException("Entities have not been created before disposing assets."); - - if(!assetsLoaded) - throw new IllegalStateException("Assets have not been loaded before disposing."); - - ImmutableArray components = ball.getComponents(); - for(int i = 0; i < components.size(); i++){ - Component c = components.get(i); - if(c instanceof TextureComponent){ - ((TextureComponent)c).texture.dispose(); - } - } - - // TODO: Dispose of Roselia's textures. - } -} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/CollisionDetectionSystem.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/CollisionDetectionSystem.java new file mode 100644 index 0000000..11f710f --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/CollisionDetectionSystem.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2014, Miguel Angel Astor Romero + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Read the LICENSE file for more details. + */ +package com.gamejolt.mikykr5.poukemon.ecs.systems; + +import com.badlogic.ashley.core.Engine; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.ashley.utils.ImmutableArray; +import com.gamejolt.mikykr5.poukemon.ProjectConstants; +import com.gamejolt.mikykr5.poukemon.ecs.components.BoundingBoxComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.Mappers; +import com.gamejolt.mikykr5.poukemon.ecs.components.PositionComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.SpriteComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.VelocityComponent; + +public class CollisionDetectionSystem extends IteratingSystem { + private ImmutableArray collidables; + private final float screenLeftBorder; + private final float screenRightBorder; + private final float screenTopBorder; + private final float screenBottomBorder; + + @SuppressWarnings("unchecked") + public CollisionDetectionSystem(Engine engine){ + super(Family.getFor(PositionComponent.class, BoundingBoxComponent.class, VelocityComponent.class)); + + collidables = engine.getEntitiesFor(Family.getFor(BoundingBoxComponent.class)); + screenLeftBorder = -((float)ProjectConstants.FB_WIDTH / 2.0f); + screenRightBorder = ((float)ProjectConstants.FB_WIDTH / 2.0f) - 1.0f; + screenTopBorder = ((float)ProjectConstants.FB_HEIGHT / 2.0f) - 1.0f; + screenBottomBorder = -((float)ProjectConstants.FB_HEIGHT / 2.0f); + } + + @Override + public void processEntity(Entity entity, float deltaTime){ + InterSystemMessage message; + PositionComponent position = Mappers.positionMapper.get(entity); + BoundingBoxComponent bounds = Mappers.bboxMapper.get(entity); + VelocityComponent velocity = Mappers.velocityMapper.get(entity); + + // Check if this entity is within the screen. + // If the entity collides with any of the borders then bounce or score as needed. + if(position.x < screenLeftBorder){ + position.x = screenLeftBorder; + velocity.vx = velocity.vx < 0.0f ? -velocity.vx : velocity.vx; + resetEntity(entity); + + message = new InterSystemMessage(ScoringSystem.class.getCanonicalName()); + message.data.put("SCORE", 1); + InterSystemMessagingQueue.pushMessage(message); + } + + if(position.x + bounds.bbox.getWidth() >= screenRightBorder){ + position.x = screenRightBorder - bounds.bbox.getWidth(); + velocity.vx = velocity.vx > 0.0f ? -velocity.vx : velocity.vx; + resetEntity(entity); + + message = new InterSystemMessage(ScoringSystem.class.getCanonicalName()); + message.data.put("SCORE", 0); + InterSystemMessagingQueue.pushMessage(message); + } + + if(position.y < screenBottomBorder){ + position.y = screenBottomBorder; + velocity.vy = velocity.vy < 0.0f ? -velocity.vy : velocity.vy; + accelerate(velocity); + } + + if(position.y + bounds.bbox.getHeight() >= screenTopBorder){ + position.y = screenTopBorder - bounds.bbox.getHeight(); + velocity.vy = velocity.vy > 0.0f ? -velocity.vy : velocity.vy; + accelerate(velocity); + } + + for(int i = 0; i < collidables.size(); i++){ + if(collidables.get(i).getIndex() == entity.getIndex()){ + continue; + }else{ + } + } + + message = new InterSystemMessage(ComputerPlayerPositioningSystem.class.getCanonicalName()); + message.data.put("BALL_Y", position.y); + InterSystemMessagingQueue.pushMessage(message); + } + + private void accelerate(VelocityComponent velocity){ + velocity.vx *= 1.03f; + velocity.vy *= 1.03f; + } + + private void resetEntity(Entity entity){ + PositionComponent position = Mappers.positionMapper.get(entity); + SpriteComponent sprite = Mappers.spriteMapper.get(entity); + VelocityComponent velocity = Mappers.velocityMapper.get(entity); + + velocity.setXY(173, -475); + + if(position != null){ + if(sprite != null){ + position.setXY(-(sprite.sprite.getWidth() / 2), -(sprite.sprite.getHeight() / 2)); + }else{ + position.setXY(0, 0); + } + } + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/ComputerPlayerPositioningSystem.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/ComputerPlayerPositioningSystem.java new file mode 100644 index 0000000..67b5b59 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/ComputerPlayerPositioningSystem.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, Miguel Angel Astor Romero + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Read the LICENSE file for more details. + */ +package com.gamejolt.mikykr5.poukemon.ecs.systems; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.gamejolt.mikykr5.poukemon.ecs.components.Mappers; +import com.gamejolt.mikykr5.poukemon.ecs.components.PlayerComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.PositionComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.VelocityComponent; + +public class ComputerPlayerPositioningSystem extends IteratingSystem { + @SuppressWarnings("unchecked") + public ComputerPlayerPositioningSystem() { + super(Family.getFor(PlayerComponent.class, VelocityComponent.class, PositionComponent.class)); + } + + @Override + public void processEntity(Entity entity, float deltaTime) { + InterSystemMessage message; + VelocityComponent velocity = Mappers.velocityMapper.get(entity); + PositionComponent position = Mappers.positionMapper.get(entity); + PlayerComponent player = Mappers.playerMapper.get(entity); + + if(player.id == 1){ + while((message = InterSystemMessagingQueue.popMessage(ComputerPlayerPositioningSystem.class.getCanonicalName())) != null){ + float ballY; + + if(message.data.containsKey("BALL_Y")){ + ballY = (Float) message.data.get("BALL_Y"); + + if(ballY > position.y){ + velocity.vy = 550.0f; + }else if (ballY < position.y){ + velocity.vy = -550.0f; + } + } + } + } + } +} \ No newline at end of file diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/HumanPlayerPositioningSystem.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/HumanPlayerPositioningSystem.java new file mode 100644 index 0000000..e960b08 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/HumanPlayerPositioningSystem.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014, Miguel Angel Astor Romero + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Read the LICENSE file for more details. + */ +package com.gamejolt.mikykr5.poukemon.ecs.systems; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.gamejolt.mikykr5.poukemon.ecs.components.Mappers; +import com.gamejolt.mikykr5.poukemon.ecs.components.PlayerComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.PositionComponent; + +public class HumanPlayerPositioningSystem extends IteratingSystem { + @SuppressWarnings("unchecked") + public HumanPlayerPositioningSystem() { + super(Family.getFor(PlayerComponent.class, PositionComponent.class)); + } + + @Override + public void processEntity(Entity entity, float deltaTime) { + InterSystemMessage message; + PositionComponent position = Mappers.positionMapper.get(entity); + PlayerComponent player = Mappers.playerMapper.get(entity); + + if(player.id == 0){ + while((message = InterSystemMessagingQueue.popMessage(HumanPlayerPositioningSystem.class.getCanonicalName())) != null){ + float playerY; + + if(message.data.containsKey("INPUT_Y")){ + playerY = (Float) message.data.get("INPUT_Y"); + position.y = playerY; + } + } + } + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/InterSystemMessage.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/InterSystemMessage.java new file mode 100644 index 0000000..6b1cae2 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/InterSystemMessage.java @@ -0,0 +1,14 @@ +package com.gamejolt.mikykr5.poukemon.ecs.systems; + +import java.util.HashMap; +import java.util.Map; + +public class InterSystemMessage{ + public final String target; + public final Map data; + + public InterSystemMessage(String target){ + this.target = target; + this.data = new HashMap(); + } +} \ No newline at end of file diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/InterSystemMessagingQueue.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/InterSystemMessagingQueue.java new file mode 100644 index 0000000..ca3d635 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/InterSystemMessagingQueue.java @@ -0,0 +1,36 @@ +package com.gamejolt.mikykr5.poukemon.ecs.systems; + +import java.util.LinkedList; +import java.util.Queue; + +import com.badlogic.gdx.Gdx; + +public abstract class InterSystemMessagingQueue{ + private static Queue queue = new LinkedList(); + + public static synchronized void pushMessage(InterSystemMessage message) throws IllegalArgumentException{ + if(message == null) + throw new IllegalArgumentException("Message is null"); + + queue.add(message); + } + + public static synchronized InterSystemMessage popMessage(String receiver) throws IllegalArgumentException{ + InterSystemMessage message = null; + + if(receiver == null) + throw new IllegalArgumentException("Target is null."); + + for(InterSystemMessage msg : queue){ + if(msg.target.compareTo(receiver) == 0){ + message = msg; + break; + } + } + if(message != null && !queue.remove(message)){ + Gdx.app.error("MESSAGING_QUEUE", "Queue did not contain message?"); + } + + return message; + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/PositioningSystem.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/PositioningSystem.java index a617c18..82efc85 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/PositioningSystem.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/PositioningSystem.java @@ -22,23 +22,18 @@ import com.gamejolt.mikykr5.poukemon.ecs.components.Mappers; import com.gamejolt.mikykr5.poukemon.ecs.components.PositionComponent; import com.gamejolt.mikykr5.poukemon.ecs.components.VelocityComponent; -public class PositioningSystem extends IteratingSystem { - private static final float[] FRICTION = {0.95f, 0.95f}; - +public class PositioningSystem extends IteratingSystem{ @SuppressWarnings("unchecked") - public PositioningSystem() { + public PositioningSystem(){ super(Family.getFor(PositionComponent.class, VelocityComponent.class)); } @Override - public void processEntity(Entity entity, float deltaTime) { + public void processEntity(Entity entity, float deltaTime){ PositionComponent position = Mappers.positionMapper.get(entity); VelocityComponent velocity = Mappers.velocityMapper.get(entity); position.x += velocity.vx * deltaTime; position.y += velocity.vy * deltaTime; - - velocity.vx *= FRICTION[0]; - velocity.vy *= FRICTION[1]; } } diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/RenderingSystem.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/RenderingSystem.java index 825d914..7e1a165 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/RenderingSystem.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/RenderingSystem.java @@ -21,14 +21,14 @@ import com.badlogic.ashley.systems.IteratingSystem; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.gamejolt.mikykr5.poukemon.ecs.components.Mappers; import com.gamejolt.mikykr5.poukemon.ecs.components.PositionComponent; -import com.gamejolt.mikykr5.poukemon.ecs.components.TextureComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.SpriteComponent; public class RenderingSystem extends IteratingSystem{ private final SpriteBatch batch; @SuppressWarnings("unchecked") public RenderingSystem(SpriteBatch batch){ - super(Family.getFor(PositionComponent.class, TextureComponent.class)); + super(Family.getFor(PositionComponent.class, SpriteComponent.class)); this.batch = batch; } @@ -36,13 +36,13 @@ public class RenderingSystem extends IteratingSystem{ @Override public void processEntity(Entity entity, float deltaTime) throws IllegalStateException{ PositionComponent position = Mappers.positionMapper.get(entity); - TextureComponent texture = Mappers.textureMapper.get(entity); + SpriteComponent sprite = Mappers.spriteMapper.get(entity); if(!batch.isDrawing()) throw new IllegalStateException("Sprite batch did not call begin before processing entites."); - if(texture.texture != null){ - batch.draw(texture.texture, position.x, position.y); + if(sprite.sprite != null){ + batch.draw(sprite.sprite, position.x, position.y); } } } diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/ScoringSystem.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/ScoringSystem.java new file mode 100644 index 0000000..98a70eb --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/systems/ScoringSystem.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014, Miguel Angel Astor Romero + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Read the LICENSE file for more details. + */ +package com.gamejolt.mikykr5.poukemon.ecs.systems; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.gamejolt.mikykr5.poukemon.ProjectConstants; +import com.gamejolt.mikykr5.poukemon.ecs.components.Mappers; +import com.gamejolt.mikykr5.poukemon.ecs.components.PlayerComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.ScoreComponent; +import com.gamejolt.mikykr5.poukemon.utils.managers.CachedFontManager; + +public class ScoringSystem extends IteratingSystem { + private final SpriteBatch batch; + private BitmapFont font; + + @SuppressWarnings("unchecked") + public ScoringSystem(final SpriteBatch batch){ + super(Family.getFor(ScoreComponent.class, PlayerComponent.class)); + this.batch = batch; + this.font = CachedFontManager.getInstance().loadFont("data/fonts/CRYSTAL-Regular.ttf", 180); + CachedFontManager.freeInstance(); + } + + @Override + public void processEntity(Entity entity, float deltaTime) { + TextBounds bounds; + float x, y; + + InterSystemMessage message; + ScoreComponent score = Mappers.scoreMapper.get(entity); + PlayerComponent player = Mappers.playerMapper.get(entity); + + while((message = InterSystemMessagingQueue.popMessage(ScoringSystem.class.getCanonicalName())) != null){ + int playerId; + + if(message.data.containsKey("SCORE")){ + playerId = (Integer) message.data.get("SCORE"); + + if(playerId == player.id){ + score.score++; + }else{ + InterSystemMessagingQueue.pushMessage(message); + break; + } + } + } + + bounds = font.getBounds(String.format("%02d", score.score)); + + y = (ProjectConstants.FB_HEIGHT / 2.0f) - (bounds.height / 2.0f) - 20; + if(player.id == 0){ + x = -(ProjectConstants.FB_WIDTH / 4.0f) - (bounds.width / 2.0f); + }else if(player.id == 1){ + x = (ProjectConstants.FB_WIDTH / 4.0f) - (bounds.width / 2.0f);; + }else + return; + + font.setColor(Color.WHITE); + font.draw(batch, String.format("%02d", score.score), x, y); + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/states/BaseState.java b/core/src/com/gamejolt/mikykr5/poukemon/states/BaseState.java index 0efcefe..ff7ef3f 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/states/BaseState.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/states/BaseState.java @@ -104,7 +104,7 @@ public abstract class BaseState implements Screen, InputProcessor{ * @param screenX The x coordinate in window space. * @param screenY The y coordinate in window space. */ - protected final void unprojectTouch(int screenX, int screenY){ + protected void unprojectTouch(int screenX, int screenY){ win2world.set(screenX, screenY, 0.0f); pixelPerfectCamera.unproject(win2world); touchPointWorldCoords.set(win2world.x, win2world.y); diff --git a/core/src/com/gamejolt/mikykr5/poukemon/states/InGameState.java b/core/src/com/gamejolt/mikykr5/poukemon/states/InGameState.java index 706e545..acd426b 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/states/InGameState.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/states/InGameState.java @@ -22,40 +22,59 @@ import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.glutils.FrameBuffer; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; import com.gamejolt.mikykr5.poukemon.GameCore; import com.gamejolt.mikykr5.poukemon.GameCore.game_states_t; +import com.gamejolt.mikykr5.poukemon.ProjectConstants; import com.gamejolt.mikykr5.poukemon.ecs.entities.EntityInitializerBase; -import com.gamejolt.mikykr5.poukemon.ecs.entities.PoukemonEntityInitializer; +import com.gamejolt.mikykr5.poukemon.ecs.entities.PongEntityInitializer; +import com.gamejolt.mikykr5.poukemon.ecs.systems.CollisionDetectionSystem; +import com.gamejolt.mikykr5.poukemon.ecs.systems.ComputerPlayerPositioningSystem; +import com.gamejolt.mikykr5.poukemon.ecs.systems.HumanPlayerPositioningSystem; +import com.gamejolt.mikykr5.poukemon.ecs.systems.InterSystemMessage; +import com.gamejolt.mikykr5.poukemon.ecs.systems.InterSystemMessagingQueue; import com.gamejolt.mikykr5.poukemon.ecs.systems.PositioningSystem; import com.gamejolt.mikykr5.poukemon.ecs.systems.RenderingSystem; +import com.gamejolt.mikykr5.poukemon.ecs.systems.ScoringSystem; import com.gamejolt.mikykr5.poukemon.interfaces.AssetsLoadedListener; public class InGameState extends BaseState implements AssetsLoadedListener{ - private static final int FB_WIDTH = 1920; - private static final int FB_HEIGHT = 1080; - private PooledEngine engine; private EntityInitializerBase entityInitializer; private FrameBuffer frameBuffer; private int w; + private int h; private final float oldRatio; private boolean assetsLoaded; private OrthographicCamera fbCamera; + private Rectangle fbBounds; + private Vector2 fbWoorldCoords; public InGameState(final GameCore core) throws IllegalArgumentException{ super(core); engine = new PooledEngine(); - frameBuffer = new FrameBuffer(Format.RGB565, FB_WIDTH, FB_HEIGHT, false); + frameBuffer = new FrameBuffer(Format.RGB565, ProjectConstants.FB_WIDTH, ProjectConstants.FB_HEIGHT, false); + fbBounds = new Rectangle(); w = Gdx.graphics.getWidth(); - oldRatio = aspectRatio(FB_WIDTH, FB_HEIGHT); + w = Gdx.graphics.getHeight(); + oldRatio = aspectRatio(ProjectConstants.FB_WIDTH, ProjectConstants.FB_HEIGHT); assetsLoaded = false; - fbCamera = new OrthographicCamera(FB_WIDTH, FB_HEIGHT); + fbCamera = new OrthographicCamera(ProjectConstants.FB_WIDTH, ProjectConstants.FB_HEIGHT); + fbWoorldCoords = new Vector2(); - entityInitializer = new PoukemonEntityInitializer(); + // Create all entities. + entityInitializer = new PongEntityInitializer(); entityInitializer.createAllEntities(engine); + // Add systems in the order they will be processed. engine.addSystem(new PositioningSystem()); + engine.addSystem(new CollisionDetectionSystem(engine)); + engine.addSystem(new HumanPlayerPositioningSystem()); + engine.addSystem(new ComputerPlayerPositioningSystem()); + engine.addSystem(new ScoringSystem(core.batch)); engine.addSystem(new RenderingSystem(core.batch)); } @@ -92,7 +111,7 @@ public class InGameState extends BaseState implements AssetsLoadedListener{ // Render the frame buffer applying screen effects if needed. core.batch.setProjectionMatrix(pixelPerfectCamera.combined); core.batch.begin();{ - core.batch.draw(frameBuffer.getColorBufferTexture(), x, y, renderW, renderH, 0, 0, FB_WIDTH, FB_HEIGHT, false, true); + core.batch.draw(frameBuffer.getColorBufferTexture(), x, y, renderW, renderH, 0, 0, ProjectConstants.FB_WIDTH, ProjectConstants.FB_HEIGHT, false, true); }core.batch.end(); } } @@ -108,8 +127,9 @@ public class InGameState extends BaseState implements AssetsLoadedListener{ public void resize(int width, int height){ // It's important to call the resize method of the superclass to ensure // the pixel perfect camera is properly recreated. - super.resize(FB_WIDTH, FB_HEIGHT); + super.resize(width, height); w = width; + h = height; } @Override @@ -123,16 +143,28 @@ public class InGameState extends BaseState implements AssetsLoadedListener{ @Override public boolean touchDown(int screenX, int screenY, int pointer, int button){ - unprojectTouch(screenX, screenY); + InterSystemMessage message; - return false; + if(touchInsideFrameBuffer(screenX, screenY)){ + message = new InterSystemMessage(HumanPlayerPositioningSystem.class.getCanonicalName()); + message.data.put("INPUT_Y", convertWorldHeightToFrameBufferHeight(touchPointWorldCoords.y)); + InterSystemMessagingQueue.pushMessage(message); + } + + return true; } @Override public boolean touchDragged(int screenX, int screenY, int pointer){ - unprojectTouch(screenX, screenY); + InterSystemMessage message; - return false; + if(touchInsideFrameBuffer(screenX, screenY)){ + message = new InterSystemMessage(HumanPlayerPositioningSystem.class.getCanonicalName()); + message.data.put("INPUT_Y", convertWorldHeightToFrameBufferHeight(touchPointWorldCoords.y)); + InterSystemMessagingQueue.pushMessage(message); + } + + return true; } @Override @@ -141,6 +173,32 @@ public class InGameState extends BaseState implements AssetsLoadedListener{ assetsLoaded = true; } + private boolean touchInsideFrameBuffer(int screenX, int screenY){ + float fbW, fbH; + + unprojectTouch(screenX, screenY); + fbW = w; + fbH = fbW / oldRatio; + fbBounds.set(-(fbW / 2.0f), -(fbH / 2.0f), fbW, fbH); + + if(fbBounds.contains(touchPointWorldCoords)){ + return true; + }else{ + return false; + } + } + + private float convertWorldHeightToFrameBufferHeight(float height){ + float newHeight, oldHeight, b = (float)ProjectConstants.FB_HEIGHT / (float)h; + + oldHeight = height + ((ProjectConstants.FB_HEIGHT / 2.0f) - 1.0f); + oldHeight /= (float)h; + newHeight = (oldHeight * b) * ProjectConstants.FB_HEIGHT; + newHeight -= ProjectConstants.FB_HEIGHT; + + return newHeight; + } + /** * Calculates the aspect ratio of a given width and height. * diff --git a/core/src/com/gamejolt/mikykr5/poukemon/utils/managers/CachedFontManager.java b/core/src/com/gamejolt/mikykr5/poukemon/utils/managers/CachedFontManager.java index 0ffd852..2833578 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/utils/managers/CachedFontManager.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/utils/managers/CachedFontManager.java @@ -88,6 +88,8 @@ public class CachedFontManager{ } private void dispose(){ + Gdx.app.log("FONT_MANAGER", "Disposing fonts."); + for(BitmapFont font : fonts.values()) font.dispose(); diff --git a/desktop/src/com/gamejolt/mikykr5/poukemon/desktop/DesktopLauncher.java b/desktop/src/com/gamejolt/mikykr5/poukemon/desktop/DesktopLauncher.java index 5eecc73..0bb3b2b 100644 --- a/desktop/src/com/gamejolt/mikykr5/poukemon/desktop/DesktopLauncher.java +++ b/desktop/src/com/gamejolt/mikykr5/poukemon/desktop/DesktopLauncher.java @@ -26,7 +26,7 @@ public class DesktopLauncher { config.width = 1024; config.height = 768; config.resizable = true; - config.title = "PouKémon"; + config.title = "CEIDEC-Pong"; new LwjglApplication(new GameCore(), config); }