diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 71c98c5..b9a29bc 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -8,7 +8,7 @@ position = ComponentMapper.getFor(PositionComponent.class); + public static final ComponentMapper sprite = ComponentMapper.getFor(SpriteComponent.class); + public static final ComponentMapper soundEffect = ComponentMapper.getFor(SoundEffectComponent.class); +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/PositionComponent.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/PositionComponent.java new file mode 100644 index 0000000..e2f7dc5 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/PositionComponent.java @@ -0,0 +1,30 @@ +/* + * 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 PositionComponent extends Component implements Poolable { + public int x = 0; + public int y = 0; + + @Override + public void reset() { + x = 0; + y = 0; + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/SoundEffectComponent.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/SoundEffectComponent.java new file mode 100644 index 0000000..683db43 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/SoundEffectComponent.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 SoundEffectComponent extends Component implements Poolable { + int soundEffectID = -1; + + @Override + public void reset() { + soundEffectID = -1; + } +} 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..4dbb032 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/SpriteComponent.java @@ -0,0 +1,38 @@ +/* + * 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 = null; + + public SpriteComponent() { + reset(); + } + + public SpriteComponent(Sprite sprite){ + this.sprite = sprite; + } + + @Override + public void reset() { + if(sprite != null) + sprite = null; + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/TextureComponent.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/TextureComponent.java new file mode 100644 index 0000000..80dce08 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/components/TextureComponent.java @@ -0,0 +1,27 @@ +/* + * 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.Texture; + +public class TextureComponent extends Component{ + public Texture texture; + + public TextureComponent(Texture texture){ + this.texture = texture; + } +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/EntityInitializerBase.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/EntityInitializerBase.java new file mode 100644 index 0000000..cd4c83a --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/EntityInitializerBase.java @@ -0,0 +1,24 @@ +/* + * 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.PooledEngine; + +public abstract class EntityInitializerBase{ + public abstract void createAllEntities(PooledEngine engine); + public abstract void setLoadableAssets(PooledEngine engine) throws IllegalStateException; + public abstract void disposeAssets(PooledEngine engine) throws IllegalStateException; +} diff --git a/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PoukemonEntityInitializer.java b/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PoukemonEntityInitializer.java new file mode 100644 index 0000000..62410c4 --- /dev/null +++ b/core/src/com/gamejolt/mikykr5/poukemon/ecs/entities/PoukemonEntityInitializer.java @@ -0,0 +1,85 @@ +/* + * 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.PositionComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.SpriteComponent; +import com.gamejolt.mikykr5.poukemon.ecs.components.TextureComponent; +import com.gamejolt.mikykr5.poukemon.utils.AsyncAssetLoader; + +public class PoukemonEntityInitializer extends EntityInitializerBase { + private AsyncAssetLoader loader; + private Entity ball; + 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("gfx/textures/ball.png", Texture.class); + + ball = engine.createEntity(); + ball.add(engine.createComponent(PositionComponent.class)); + ball.add(engine.createComponent(SpriteComponent.class)); + + 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(new TextureComponent(loader.getAsset("gfx/textures/ball.png", Texture.class))); + + AsyncAssetLoader.freeInstance(); + assetsLoaded = true; + } + + @Override + public void disposeAssets(PooledEngine engine) throws IllegalStateException { + if(!entitiesCreated) + throw new IllegalStateException("Entities have not been created before disposing assets."); + + if(!entitiesCreated) + 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/states/BaseState.java b/core/src/com/gamejolt/mikykr5/poukemon/states/BaseState.java index 1eda7b3..0efcefe 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/states/BaseState.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/states/BaseState.java @@ -46,6 +46,9 @@ public abstract class BaseState implements Screen, InputProcessor{ ; STATE METHODS ; ;;;;;;;;;;;;;;;;;*/ + /** + * Executes a set of standard actions when the state is set by the {@link GameCore}. + */ public void onStateEnabled(){ stateEnabled = true; Gdx.input.setInputProcessor(this); @@ -53,6 +56,9 @@ public abstract class BaseState implements Screen, InputProcessor{ Gdx.input.setCatchMenuKey(true); } + /** + * Executes a set of standard actions when the state is removed by the {@link GameCore}. + */ public void onStateDisabled(){ stateEnabled = false; Gdx.input.setInputProcessor(null); @@ -71,7 +77,9 @@ public abstract class BaseState implements Screen, InputProcessor{ public abstract void dispose(); @Override - public void resize(int width, int height){ } + public void resize(int width, int height){ + this.pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + } @Override public void show(){ } @@ -89,6 +97,13 @@ public abstract class BaseState implements Screen, InputProcessor{ ; HELPER METHODS ; ;;;;;;;;;;;;;;;;;;*/ + /** + * Converts a point in screen coordinates to world coordinates inside the view of this state's {@link BaseState#pixelPerfectCamera}. + * The result is stored in the {@link BaseState#touchPointWorldCoords} vector. + * + * @param screenX The x coordinate in window space. + * @param screenY The y coordinate in window space. + */ protected final void unprojectTouch(int screenX, int screenY){ win2world.set(screenX, screenY, 0.0f); pixelPerfectCamera.unproject(win2world); diff --git a/core/src/com/gamejolt/mikykr5/poukemon/states/InGameState.java b/core/src/com/gamejolt/mikykr5/poukemon/states/InGameState.java index f6ef53e..988f085 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/states/InGameState.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/states/InGameState.java @@ -15,22 +15,126 @@ */ package com.gamejolt.mikykr5.poukemon.states; +import com.badlogic.ashley.core.PooledEngine; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Pixmap.Format; +import com.badlogic.gdx.graphics.glutils.FrameBuffer; import com.gamejolt.mikykr5.poukemon.GameCore; +import com.gamejolt.mikykr5.poukemon.GameCore.game_states_t; +import com.gamejolt.mikykr5.poukemon.ecs.entities.EntityInitializerBase; +import com.gamejolt.mikykr5.poukemon.ecs.entities.PoukemonEntityInitializer; +import com.gamejolt.mikykr5.poukemon.interfaces.AssetsLoadedListener; -public class InGameState extends BaseState { - public InGameState(final GameCore core) throws IllegalArgumentException { +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 final float oldRatio; + private boolean assetsLoaded; + + public InGameState(final GameCore core) throws IllegalArgumentException{ super(core); + + engine = new PooledEngine(); + frameBuffer = new FrameBuffer(Format.RGB565, FB_WIDTH, FB_HEIGHT, false); + w = Gdx.graphics.getWidth(); + oldRatio = aspectRatio(FB_WIDTH, FB_HEIGHT); + assetsLoaded = false; + + entityInitializer = new PoukemonEntityInitializer(); + entityInitializer.createAllEntities(engine); } @Override - public void render(float delta) { - Gdx.gl.glClearColor(0, 0, 0, 1); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + public void render(float delta){ + float x, y, renderW, renderH; + + if(assetsLoaded){ + // Update the game using the ECS pattern. + engine.update(delta); + + // Clear the screen. + Gdx.gl.glClearColor(0, 0, 0, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + // Render the scene to a frame buffer so that we can apply screen effects later. + frameBuffer.begin();{ + Gdx.gl.glClearColor(0.2f, 0.2f, 0.5f, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + }frameBuffer.end(); + + // Scale the frame buffer to the current screen size. + renderW = w; + renderH = renderW / oldRatio; + + // Set the rendering position of the frame buffer. + x = -(renderW / 2.0f); + y = -(renderH / 2.0f); + + // Render the frame buffer applying screen effects if needed. + core.batch.begin();{ + core.batch.draw(frameBuffer.getColorBufferTexture(), x, y, renderW, renderH); + }core.batch.end(); + } } @Override - public void dispose() { + public void dispose(){ + frameBuffer.dispose(); + engine.removeAllEntities(); + } + + @Override + 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); + w = width; + } + + @Override + public boolean keyDown(int keycode){ + if(keycode == Input.Keys.BACK || keycode == Input.Keys.ESCAPE){ + core.nextState = game_states_t.MAIN_MENU; + return true; + } + return false; + } + + @Override + public boolean touchDown(int screenX, int screenY, int pointer, int button){ + unprojectTouch(screenX, screenY); + + return false; + } + + @Override + public boolean touchDragged(int screenX, int screenY, int pointer){ + unprojectTouch(screenX, screenY); + + return false; + } + + /** + * Calculates the aspect ratio of a given width and height. + * + * @param w The width. + * @param h The height. + * @return The aspect ratio. + */ + private float aspectRatio(float w, float h){ + return w / h; + } + + @Override + public void onAssetsLoaded() { + entityInitializer.setLoadableAssets(engine); + assetsLoaded = true; } } diff --git a/core/src/com/gamejolt/mikykr5/poukemon/states/MainMenuState.java b/core/src/com/gamejolt/mikykr5/poukemon/states/MainMenuState.java index 3142767..24cc8b7 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/states/MainMenuState.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/states/MainMenuState.java @@ -36,9 +36,9 @@ import com.gamejolt.mikykr5.poukemon.utils.CachedFontManager; public class MainMenuState extends BaseState implements AssetsLoadedListener{ // Helper fields. - private AsyncAssetLoader loader; - private CachedFontManager fontManager; - private boolean assetsLoaded; + private AsyncAssetLoader loader; + private CachedFontManager fontManager; + private boolean assetsLoaded; // Buttons and other GUI components. private TextButton startButton; diff --git a/core/src/com/gamejolt/mikykr5/poukemon/utils/AsyncAssetLoader.java b/core/src/com/gamejolt/mikykr5/poukemon/utils/AsyncAssetLoader.java index abbf9f3..bc04acc 100644 --- a/core/src/com/gamejolt/mikykr5/poukemon/utils/AsyncAssetLoader.java +++ b/core/src/com/gamejolt/mikykr5/poukemon/utils/AsyncAssetLoader.java @@ -17,10 +17,12 @@ package com.gamejolt.mikykr5.poukemon.utils; import java.util.LinkedList; +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.assets.AssetManager; +import com.badlogic.gdx.utils.Disposable; import com.gamejolt.mikykr5.poukemon.interfaces.AssetsLoadedListener; -public final class AsyncAssetLoader { +public final class AsyncAssetLoader implements Disposable{ private LinkedList listeners; private AssetManager manager; @@ -43,7 +45,10 @@ public final class AsyncAssetLoader { public static void freeInstance(){ SingletonHolder.REF_COUNT--; - if(SingletonHolder.REF_COUNT <= 0) SingletonHolder.INSTANCE = null; + if(SingletonHolder.REF_COUNT <= 0){ + SingletonHolder.INSTANCE.dispose(); + SingletonHolder.INSTANCE = null; + } } public void addListener(AssetsLoadedListener listener) throws IllegalArgumentException{ @@ -92,4 +97,10 @@ public final class AsyncAssetLoader { private void checkParametes(Object parameter, String paramName) throws IllegalArgumentException{ if(parameter == null) throw new IllegalArgumentException("Parameter: " + paramName + " is null."); } + + @Override + public void dispose(){ + Gdx.app.log("ASYNC_LOADER", "Disposing asset manager."); + manager.dispose(); + } }