Added most of the documentation.
This commit is contained in:
@@ -37,10 +37,27 @@ import com.gamejolt.mikykr5.ceidecpong.states.LogoScreenState;
|
||||
import com.gamejolt.mikykr5.ceidecpong.states.MainMenuState;
|
||||
import com.gamejolt.mikykr5.ceidecpong.utils.AsyncAssetLoader;
|
||||
|
||||
/**
|
||||
* This is the central class of the Game. It is in charge of maintaining the game's
|
||||
* life cycle and switching between the different application states. It also renders
|
||||
* the fade effects when switching states.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class GameCore extends Game {
|
||||
/**
|
||||
* Tag used for logging.
|
||||
*/
|
||||
private static final String TAG = "GAME_CORE";
|
||||
|
||||
/**
|
||||
* Class name used for logging.
|
||||
*/
|
||||
private static final String CLASS_NAME = GameCore.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* An enumerated type used for state switching.
|
||||
*/
|
||||
public enum game_states_t {
|
||||
LOGO_SCREEN(0), MAIN_MENU(1), IN_GAME(2), QUIT(3), LOADING(4);
|
||||
|
||||
@@ -59,18 +76,55 @@ public class GameCore extends Game {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A pointer to the currently active state.
|
||||
*/
|
||||
private game_states_t currState;
|
||||
|
||||
/**
|
||||
* A pointer to the state to switch to. Usually null.
|
||||
*/
|
||||
public game_states_t nextState;
|
||||
|
||||
/**
|
||||
* An array to hold all application states.
|
||||
*/
|
||||
private BaseState[] states;
|
||||
|
||||
/**
|
||||
* The {@link SpriteBatch} used to render all 2D graphics in the game.
|
||||
*/
|
||||
public SpriteBatch batch;
|
||||
|
||||
/**
|
||||
* A pixel perfect camera used to render the fade effects.
|
||||
*/
|
||||
private OrthographicCamera pixelPerfectCamera;
|
||||
|
||||
// Fade in/out effect fields.
|
||||
/**
|
||||
* The fade graphic.
|
||||
*/
|
||||
private Texture fadeTexture;
|
||||
|
||||
/**
|
||||
* A {@link MutableFloat} used to interpolate the transparency of {@link GameCore#fadeTexture}.
|
||||
*/
|
||||
private MutableFloat alpha;
|
||||
|
||||
/**
|
||||
* A {@link Tween} instance used to interpolate between full transparency to no transparency.
|
||||
*/
|
||||
private Tween fadeOut;
|
||||
|
||||
/**
|
||||
* A {@link Tween} instance used to interpolate between no transparency to full transparency.
|
||||
*/
|
||||
private Tween fadeIn;
|
||||
|
||||
/**
|
||||
* A flag to indicate that a fade effect is in progress.
|
||||
*/
|
||||
private boolean fading;
|
||||
|
||||
@Override
|
||||
@@ -78,7 +132,7 @@ public class GameCore extends Game {
|
||||
AsyncAssetLoader loader = AsyncAssetLoader.getInstance();
|
||||
|
||||
// Set up rendering fields and settings.
|
||||
ShaderProgram.pedantic = false;
|
||||
ShaderProgram.pedantic = false; // Not passing all variables to a shader will not close the game.
|
||||
batch = new SpriteBatch();
|
||||
batch.enableBlending();
|
||||
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
|
||||
@@ -91,6 +145,7 @@ public class GameCore extends Game {
|
||||
fadeTexture = new Texture(pixmap);
|
||||
pixmap.dispose();
|
||||
|
||||
// Create the initial interpolators and start with a fade in effect.
|
||||
alpha = new MutableFloat(1.0f);
|
||||
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);
|
||||
@@ -112,6 +167,7 @@ public class GameCore extends Game {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register every state as an AssetsLoadedListener if the state implements the interface.
|
||||
for(BaseState state : states){
|
||||
if(state != null && state instanceof AssetsLoadedListener)
|
||||
loader.addListener((AssetsLoadedListener)state);
|
||||
@@ -138,6 +194,7 @@ public class GameCore extends Game {
|
||||
|
||||
// If the current state set a value for nextState then switch to that state.
|
||||
if(nextState != null){
|
||||
// First disable the current state so that it will no longer catch user inputs.
|
||||
states[currState.getValue()].onStateDisabled();
|
||||
|
||||
if(!fadeOut.isStarted()){
|
||||
@@ -198,12 +255,13 @@ public class GameCore extends Game {
|
||||
public void dispose(){
|
||||
super.dispose();
|
||||
|
||||
// Dispose screens.
|
||||
// Dispose all states.
|
||||
for(BaseState state : states){
|
||||
if(state != null)
|
||||
state.dispose();
|
||||
}
|
||||
|
||||
// Dispose other graphics.
|
||||
fadeTexture.dispose();
|
||||
batch.dispose();
|
||||
}
|
||||
|
@@ -15,10 +15,34 @@
|
||||
*/
|
||||
package com.gamejolt.mikykr5.ceidecpong;
|
||||
|
||||
/**
|
||||
* This class holds some project-wise constants.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public abstract class ProjectConstants{
|
||||
/**
|
||||
* What to return when the application terminates successfully.
|
||||
*/
|
||||
public static final int EXIT_SUCCESS = 0;
|
||||
|
||||
/**
|
||||
* What to return when the application terminates closes due to an error.
|
||||
*/
|
||||
public static final int EXIT_FAILURE = 1;
|
||||
public static final boolean DEBUG = true;
|
||||
|
||||
/**
|
||||
* Enable/disable logging.
|
||||
*/
|
||||
public static final boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Logical screen width.
|
||||
*/
|
||||
public static final int FB_WIDTH = 1920;
|
||||
|
||||
/**
|
||||
* Logical screen height.
|
||||
*/
|
||||
public static final int FB_HEIGHT = 1080;
|
||||
}
|
@@ -19,7 +19,15 @@ import com.badlogic.ashley.core.Component;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
/**
|
||||
* A 2D bounding rectangle component.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class BoundingBoxComponent extends Component implements Poolable {
|
||||
/**
|
||||
* The bounding rectangle.
|
||||
*/
|
||||
public Rectangle bbox;
|
||||
|
||||
public BoundingBoxComponent() {
|
||||
|
@@ -17,10 +17,14 @@ package com.gamejolt.mikykr5.ceidecpong.ecs.components;
|
||||
|
||||
import com.badlogic.ashley.core.ComponentMapper;
|
||||
|
||||
/**
|
||||
* A holder class for all {@link ComponentMapper} instances used by the game.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public abstract class Mappers {
|
||||
public static final ComponentMapper<PositionComponent> positionMapper = ComponentMapper.getFor(PositionComponent.class);
|
||||
public static final ComponentMapper<VelocityComponent> velocityMapper = ComponentMapper.getFor(VelocityComponent.class);
|
||||
public static final ComponentMapper<TextureComponent> textureMapper = ComponentMapper.getFor(TextureComponent.class);
|
||||
public static final ComponentMapper<SpriteComponent> spriteMapper = ComponentMapper.getFor(SpriteComponent.class);
|
||||
public static final ComponentMapper<BoundingBoxComponent> bboxMapper = ComponentMapper.getFor(BoundingBoxComponent.class);
|
||||
public static final ComponentMapper<ScoreComponent> scoreMapper = ComponentMapper.getFor(ScoreComponent.class);
|
||||
|
@@ -18,10 +18,18 @@ package com.gamejolt.mikykr5.ceidecpong.ecs.components;
|
||||
import com.badlogic.ashley.core.Component;
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
/**
|
||||
* A Player identity {@link Component}
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class PlayerComponent extends Component implements Poolable {
|
||||
public static int HUMAN_PLAYER = 0;
|
||||
public static int COMPUTER_PLAYER = 1;
|
||||
public static final int HUMAN_PLAYER = 0;
|
||||
public static final int COMPUTER_PLAYER = 1;
|
||||
|
||||
/**
|
||||
* An identifier used to determine the type of player.
|
||||
*/
|
||||
public int id = -1;
|
||||
|
||||
@Override
|
||||
|
@@ -18,10 +18,28 @@ package com.gamejolt.mikykr5.ceidecpong.ecs.components;
|
||||
import com.badlogic.ashley.core.Component;
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
/**
|
||||
* A 2D position {@link Component}.
|
||||
*
|
||||
* @author Miguel Astor.
|
||||
*/
|
||||
public class PositionComponent extends Component implements Poolable {
|
||||
/**
|
||||
* The X coordinate.
|
||||
*/
|
||||
public float x = 0;
|
||||
|
||||
/**
|
||||
* The Y coordinate.
|
||||
*/
|
||||
public float y = 0;
|
||||
|
||||
/**
|
||||
* Sets both coordinates simultaneously.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
public void setXY(float x, float y){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
@@ -18,7 +18,15 @@ package com.gamejolt.mikykr5.ceidecpong.ecs.components;
|
||||
import com.badlogic.ashley.core.Component;
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
/**
|
||||
* A {@link Component} to hold a player's score.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class ScoreComponent extends Component implements Poolable{
|
||||
/**
|
||||
* The score.
|
||||
*/
|
||||
public int score = 0;
|
||||
|
||||
@Override
|
||||
|
@@ -1,9 +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.ceidecpong.ecs.components;
|
||||
|
||||
import com.badlogic.ashley.core.Component;
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
import com.gamejolt.mikykr5.ceidecpong.utils.managers.CachedSoundManager;
|
||||
|
||||
/**
|
||||
* A sound effect {@link Component}
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class SoundComponent extends Component implements Poolable {
|
||||
/**
|
||||
* The path of the sound effect. Used as a key by {@link CachedSoundManager}.
|
||||
*/
|
||||
public String path = "";
|
||||
|
||||
@Override
|
||||
|
@@ -19,7 +19,15 @@ import com.badlogic.ashley.core.Component;
|
||||
import com.badlogic.gdx.graphics.g2d.Sprite;
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
/**}
|
||||
* A 2D renderable {@link Component}.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class SpriteComponent extends Component implements Poolable {
|
||||
/**
|
||||
* The renderable sprite.
|
||||
*/
|
||||
public Sprite sprite;
|
||||
|
||||
public SpriteComponent(){
|
||||
|
@@ -1,39 +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.ceidecpong.ecs.components;
|
||||
|
||||
import com.badlogic.ashley.core.Component;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
public class TextureComponent extends Component implements Poolable{
|
||||
public Texture texture;
|
||||
|
||||
public TextureComponent(){
|
||||
texture = null;
|
||||
}
|
||||
|
||||
public TextureComponent(Texture texture){
|
||||
this.texture = texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
if(texture != null)
|
||||
texture.dispose();
|
||||
texture = null;
|
||||
}
|
||||
}
|
@@ -18,10 +18,27 @@ package com.gamejolt.mikykr5.ceidecpong.ecs.components;
|
||||
import com.badlogic.ashley.core.Component;
|
||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||
|
||||
/**
|
||||
* A 2D velocity {@link Component}
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class VelocityComponent extends Component implements Poolable {
|
||||
/**
|
||||
* The velocity in the X axis.
|
||||
*/
|
||||
public float vx = 0;
|
||||
|
||||
/**
|
||||
* The velocity in the Y axis.
|
||||
*/
|
||||
public float vy = 0;
|
||||
|
||||
/**
|
||||
* Sets both fields simultaneously.
|
||||
* @param vx
|
||||
* @param vy
|
||||
*/
|
||||
public void setXY(float vx, float vy){
|
||||
this.vx = vx;
|
||||
this.vy = vy;
|
||||
|
@@ -15,10 +15,29 @@
|
||||
*/
|
||||
package com.gamejolt.mikykr5.ceidecpong.ecs.entities;
|
||||
|
||||
import com.badlogic.ashley.core.Entity;
|
||||
import com.badlogic.ashley.core.PooledEngine;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
import com.gamejolt.mikykr5.ceidecpong.states.InGameState;
|
||||
|
||||
/**
|
||||
* Base class for entity initializers. Implementations must create all initial {@link Entity} objects
|
||||
* needed by their respective games.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public abstract class EntityInitializerBase implements Disposable{
|
||||
/**
|
||||
* Creates all {@link Entity} objects and loads the needed assets.
|
||||
* @param engine A {@link PooledEngine} instance as used by {@link InGameState}
|
||||
*/
|
||||
public abstract void createAllEntities(PooledEngine engine);
|
||||
|
||||
/**
|
||||
* Associates all assets loaded to their respective entities.
|
||||
*
|
||||
* @param engine A {@link PooledEngine} instance as used by {@link InGameState}
|
||||
* @throws IllegalStateException If the entities have not been created before calling this method.
|
||||
*/
|
||||
public abstract void setLoadableAssets(PooledEngine engine) throws IllegalStateException;
|
||||
}
|
||||
|
@@ -34,17 +34,61 @@ import com.gamejolt.mikykr5.ceidecpong.ecs.components.VelocityComponent;
|
||||
import com.gamejolt.mikykr5.ceidecpong.utils.AsyncAssetLoader;
|
||||
import com.gamejolt.mikykr5.ceidecpong.utils.managers.CachedSoundManager;
|
||||
|
||||
public class PongEntityInitializer extends EntityInitializerBase {
|
||||
/**
|
||||
* A concrete implementation of a {@link EntityInitializerBase} that creates all the entities
|
||||
* needed by the Pong game.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class PongEntityInitializer extends EntityInitializerBase{
|
||||
/**
|
||||
* An assets loader instance.
|
||||
*/
|
||||
private AsyncAssetLoader loader;
|
||||
|
||||
/**
|
||||
* An entity that plays a sound when the user scores.
|
||||
*/
|
||||
private Entity victorySound;
|
||||
|
||||
/**
|
||||
* An entity that plays a sound when the computer scores.
|
||||
*/
|
||||
private Entity defeatSound;
|
||||
|
||||
/**
|
||||
* An entity that represents the ball in the game.
|
||||
*/
|
||||
private Entity ball;
|
||||
|
||||
/**
|
||||
* An entity that represents the human player.
|
||||
*/
|
||||
private Entity paddleUser;
|
||||
|
||||
/**
|
||||
* An entity that represents the computer player.
|
||||
*/
|
||||
private Entity paddleComp;
|
||||
|
||||
/**
|
||||
* An entity that is used to render the background.
|
||||
*/
|
||||
private Entity background;
|
||||
|
||||
/**
|
||||
* Flag that indicates that all entities have been created.
|
||||
*/
|
||||
private boolean entitiesCreated;
|
||||
|
||||
/**
|
||||
* Flag that indicates that all assets associated to entities have been loaded.
|
||||
*/
|
||||
private boolean assetsLoaded;
|
||||
|
||||
/**
|
||||
* Create the initializer and set the flags to false.
|
||||
*/
|
||||
public PongEntityInitializer() {
|
||||
entitiesCreated = false;
|
||||
assetsLoaded = false;
|
||||
@@ -52,25 +96,29 @@ public class PongEntityInitializer extends EntityInitializerBase {
|
||||
|
||||
@Override
|
||||
public void createAllEntities(PooledEngine engine){
|
||||
// Get instances of the needed asset loaders.
|
||||
loader = AsyncAssetLoader.getInstance();
|
||||
CachedSoundManager soundManager = CachedSoundManager.getInstance();
|
||||
|
||||
// Load all textures and sound effects.
|
||||
loader.addAssetToLoad("data/gfx/textures/pong_atlas.atlas", TextureAtlas.class);
|
||||
loader.addAssetToLoad("data/gfx/textures/bckg.png", Texture.class);
|
||||
soundManager.loadSound("data/sfx/BounceYoFrankie.ogg");
|
||||
soundManager.loadSound("data/sfx/oh_yeah_wav_cut.ogg");
|
||||
soundManager.loadSound("data/sfx/atari_boom.ogg");
|
||||
|
||||
// Create the entities related to the sound effects.
|
||||
victorySound = engine.createEntity();
|
||||
victorySound.add(engine.createComponent(SoundComponent.class));
|
||||
|
||||
defeatSound = engine.createEntity();
|
||||
defeatSound.add(engine.createComponent(SoundComponent.class));
|
||||
|
||||
// Create the background.
|
||||
background = engine.createEntity();
|
||||
background.add(engine.createComponent(PositionComponent.class));
|
||||
background.add(engine.createComponent(SpriteComponent.class));
|
||||
|
||||
// Create the ball.
|
||||
ball = engine.createEntity();
|
||||
ball.add(engine.createComponent(PositionComponent.class));
|
||||
ball.add(engine.createComponent(VelocityComponent.class));
|
||||
@@ -78,6 +126,7 @@ public class PongEntityInitializer extends EntityInitializerBase {
|
||||
ball.add(engine.createComponent(BoundingBoxComponent.class));
|
||||
ball.add(engine.createComponent(SoundComponent.class));
|
||||
|
||||
// Create the human player.
|
||||
paddleUser = engine.createEntity();
|
||||
paddleUser.add(engine.createComponent(PositionComponent.class));
|
||||
paddleUser.add(engine.createComponent(VelocityComponent.class));
|
||||
@@ -86,6 +135,7 @@ public class PongEntityInitializer extends EntityInitializerBase {
|
||||
paddleUser.add(engine.createComponent(ScoreComponent.class));
|
||||
paddleUser.add(engine.createComponent(PlayerComponent.class));
|
||||
|
||||
// Create the computer player.
|
||||
paddleComp = engine.createEntity();
|
||||
paddleComp.add(engine.createComponent(PositionComponent.class));
|
||||
paddleComp.add(engine.createComponent(VelocityComponent.class));
|
||||
@@ -94,6 +144,7 @@ public class PongEntityInitializer extends EntityInitializerBase {
|
||||
paddleComp.add(engine.createComponent(ScoreComponent.class));
|
||||
paddleComp.add(engine.createComponent(PlayerComponent.class));
|
||||
|
||||
// Register all entities.
|
||||
engine.addEntity(victorySound);
|
||||
engine.addEntity(defeatSound);
|
||||
engine.addEntity(background);
|
||||
@@ -101,6 +152,7 @@ public class PongEntityInitializer extends EntityInitializerBase {
|
||||
engine.addEntity(paddleUser);
|
||||
engine.addEntity(paddleComp);
|
||||
|
||||
// Mark the flag.
|
||||
entitiesCreated = true;
|
||||
}
|
||||
|
||||
@@ -109,33 +161,42 @@ public class PongEntityInitializer extends EntityInitializerBase {
|
||||
if(!entitiesCreated)
|
||||
throw new IllegalStateException("Entities have not been created before setting assets.");
|
||||
|
||||
// Some variables used to initialize the ball.
|
||||
Vector2 randomVector = new Vector2().set(Vector2.X).setAngle(MathUtils.random(-60, 60));
|
||||
int randomSign = MathUtils.random(-1, 1) >= 0 ? 1 : -1;
|
||||
|
||||
// Fetch the assets.
|
||||
TextureAtlas atlas = loader.getAsset("data/gfx/textures/pong_atlas.atlas", TextureAtlas.class);
|
||||
Texture bckg = loader.getAsset("data/gfx/textures/bckg.png", Texture.class);
|
||||
|
||||
// Add the sound effects to the entities.
|
||||
Mappers.soundMapper.get(victorySound).path = "data/sfx/oh_yeah_wav_cut.ogg";
|
||||
Mappers.soundMapper.get(defeatSound).path = "data/sfx/atari_boom.ogg";
|
||||
|
||||
// Set up the background.
|
||||
Mappers.spriteMapper.get(background).sprite = new Sprite(bckg);
|
||||
Mappers.positionMapper.get(background).setXY(-(ProjectConstants.FB_WIDTH / 2.0f), -(ProjectConstants.FB_HEIGHT / 2.0f));
|
||||
|
||||
// Set up the ball.
|
||||
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(randomVector.x * 475.0f * randomSign, randomVector.y * 475.0f * randomSign);
|
||||
Mappers.bboxMapper.get(ball).bbox.set(Mappers.spriteMapper.get(ball).sprite.getBoundingRectangle());
|
||||
Mappers.soundMapper.get(ball).path = "data/sfx/BounceYoFrankie.ogg";
|
||||
|
||||
// Set up the human player.
|
||||
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 = PlayerComponent.HUMAN_PLAYER;
|
||||
|
||||
// Set up the computer player.
|
||||
Mappers.spriteMapper.get(paddleComp).sprite = atlas.createSprite("paddle");
|
||||
Mappers.positionMapper.get(paddleComp).setXY(((ProjectConstants.FB_WIDTH / 2) - 1) - 100 - Mappers.spriteMapper.get(paddleComp).sprite.getWidth(), -(Mappers.spriteMapper.get(paddleComp).sprite.getHeight() / 2));
|
||||
Mappers.bboxMapper.get(paddleComp).bbox.set(Mappers.spriteMapper.get(paddleComp).sprite.getBoundingRectangle());
|
||||
Mappers.playerMapper.get(paddleComp).id = PlayerComponent.COMPUTER_PLAYER;
|
||||
|
||||
// Release the assets loader instance and mark the flag.
|
||||
AsyncAssetLoader.freeInstance();
|
||||
assetsLoaded = true;
|
||||
}
|
||||
@@ -148,6 +209,7 @@ public class PongEntityInitializer extends EntityInitializerBase {
|
||||
if(!assetsLoaded)
|
||||
throw new IllegalStateException("Assets have not been loaded before disposing.");
|
||||
|
||||
// Release the sound manager instance.
|
||||
CachedSoundManager.freeInstance();
|
||||
}
|
||||
}
|
||||
|
@@ -3,10 +3,30 @@ package com.gamejolt.mikykr5.ceidecpong.ecs.systems.messaging;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.badlogic.ashley.core.EntitySystem;
|
||||
|
||||
/**
|
||||
* A message from a {@link EntitySystem }to another.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class InterSystemMessage{
|
||||
/**
|
||||
* A string to identify the receiver of the message. Can contain anything so long as the intended receiver
|
||||
* knows.
|
||||
*/
|
||||
public final String target;
|
||||
|
||||
/**
|
||||
* A holder for arbitrary data.
|
||||
*/
|
||||
public final Map<String, Object> data;
|
||||
|
||||
/**
|
||||
* Creates a new message object.
|
||||
*
|
||||
* @param target The receiver of the message.
|
||||
*/
|
||||
public InterSystemMessage(String target){
|
||||
this.target = target;
|
||||
this.data = new HashMap<String, Object>();
|
||||
|
@@ -3,11 +3,26 @@ package com.gamejolt.mikykr5.ceidecpong.ecs.systems.messaging;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import com.badlogic.ashley.core.EntitySystem;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
|
||||
/**
|
||||
* A messaging queue to communicate two {@link EntitySystem} instances.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public abstract class InterSystemMessagingQueue{
|
||||
/**
|
||||
* The message queue.
|
||||
*/
|
||||
private static Queue<InterSystemMessage> queue = new LinkedList<InterSystemMessage>();
|
||||
|
||||
/**
|
||||
* Adds a message to the queue.
|
||||
*
|
||||
* @param message The message to add.
|
||||
* @throws IllegalArgumentException If message is null.
|
||||
*/
|
||||
public static synchronized void pushMessage(InterSystemMessage message) throws IllegalArgumentException{
|
||||
if(message == null)
|
||||
throw new IllegalArgumentException("Message is null");
|
||||
@@ -15,6 +30,14 @@ public abstract class InterSystemMessagingQueue{
|
||||
queue.add(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a message from the queue if it's intended receiver is the caller of this method. A message is removed from the
|
||||
* queue only if it was successfully retrieved.
|
||||
*
|
||||
* @param receiver The intended receiver.
|
||||
* @return The message.
|
||||
* @throws IllegalArgumentException If receiver is null.
|
||||
*/
|
||||
public static synchronized InterSystemMessage popMessage(String receiver) throws IllegalArgumentException{
|
||||
InterSystemMessage message = null;
|
||||
|
||||
|
@@ -26,92 +26,198 @@ import com.badlogic.gdx.utils.Disposable;
|
||||
import com.gamejolt.mikykr5.ceidecpong.interfaces.AssetsLoadedListener;
|
||||
import com.gamejolt.mikykr5.ceidecpong.utils.AsyncAssetLoader;
|
||||
|
||||
/**
|
||||
* A reusable scrolling infinite background similar to those used commonly in PSX games.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class ScrollingBackground implements Disposable, AssetsLoadedListener{
|
||||
/**
|
||||
* Tag used for logging.
|
||||
*/
|
||||
private static final String TAG = "SCROLLING_BACKGROUND";
|
||||
|
||||
/**
|
||||
* Class name used for logging.
|
||||
*/
|
||||
private static final String CLASS_NAME = ScrollingBackground.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* The path of the shader used by the effect.
|
||||
*/
|
||||
private static final String SHADER_PATH = "shaders/movingBckg/movingBckg";
|
||||
|
||||
/**
|
||||
* The assets loader instance.
|
||||
*/
|
||||
private AsyncAssetLoader loader;
|
||||
|
||||
/**
|
||||
* The texture to render.
|
||||
*/
|
||||
private Texture backgroundTexture;
|
||||
|
||||
/**
|
||||
* An sprite to hold the texture.
|
||||
*/
|
||||
private Sprite background;
|
||||
|
||||
/**
|
||||
* A compiled shader object used during rendering.
|
||||
*/
|
||||
private ShaderProgram shader;
|
||||
|
||||
/**
|
||||
* Holds the location of the u_scaling variable of the shader.
|
||||
*/
|
||||
private int u_scaling;
|
||||
|
||||
/**
|
||||
* Holds the location of the u_displacement variable of the shader.
|
||||
*/
|
||||
private int u_displacement;
|
||||
|
||||
/**
|
||||
* The scaling to apply to the texture.
|
||||
*/
|
||||
private float scaling;
|
||||
|
||||
/**
|
||||
* The displacement to apply to the texture.
|
||||
*/
|
||||
private float displacement;
|
||||
private String texturePath;
|
||||
|
||||
/**
|
||||
* Creates a new effect using a default scaling and displacement. The
|
||||
* texture is loaded with {@link AsyncAssetLoader}.
|
||||
*
|
||||
* @param texturePath The internal path of the texture to use.
|
||||
*/
|
||||
public ScrollingBackground(String texturePath){
|
||||
this(texturePath, 2.0f, 0.0f, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new effect using a default scaling and displacement.
|
||||
*
|
||||
* @param texturePath The internal path of the texture to use.
|
||||
* @param loadAsync Whether to use {@link AsyncAssetLoader} or not.
|
||||
*/
|
||||
public ScrollingBackground(String texturePath, boolean loadAsync){
|
||||
this(texturePath, 2.0f, 0.0f, loadAsync);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new effect using a default displacement. The
|
||||
* texture is loaded with {@link AsyncAssetLoader}.
|
||||
*
|
||||
* @param texturePath The internal path of the texture to use.
|
||||
* @param scaling The scaling to apply to the texture.
|
||||
*/
|
||||
public ScrollingBackground(String texturePath, float scaling){
|
||||
this(texturePath, scaling, 0.0f, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new effect using a default displacement.
|
||||
*
|
||||
* @param texturePath The internal path of the texture to use.
|
||||
* @param scaling The scaling to apply to the texture.
|
||||
* @param loadAsync Whether to use {@link AsyncAssetLoader} or not.
|
||||
*/
|
||||
public ScrollingBackground(String texturePath, float scaling, boolean loadAsync){
|
||||
this(texturePath, scaling, 0.0f, loadAsync);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new effect.
|
||||
*
|
||||
* @param texturePath The internal path of the texture to use.
|
||||
* @param scaling The scaling to apply to the texture.
|
||||
* @param displacement The displacement to apply to the texture.
|
||||
* @param loadAsync Whether to use {@link AsyncAssetLoader} or not.
|
||||
*/
|
||||
public ScrollingBackground(String texturePath, float scaling, float displacement, boolean loadAsync){
|
||||
if(loadAsync){
|
||||
// If an asynchronous load was requested then use the assets loader.
|
||||
loader = AsyncAssetLoader.getInstance();
|
||||
loader.addAssetToLoad(texturePath, Texture.class);
|
||||
loader.addListener(this);
|
||||
}else{
|
||||
// Else load the texture manually.
|
||||
backgroundTexture = new Texture(Gdx.files.internal(texturePath));
|
||||
initGraphics();
|
||||
}
|
||||
|
||||
// Load and compile the shader. If the shader failed to load or compile the disable the effect.
|
||||
shader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + "_vert.glsl"), Gdx.files.internal(SHADER_PATH + "_frag.glsl"));
|
||||
if(!shader.isCompiled()){
|
||||
Gdx.app.error(TAG, CLASS_NAME + ".ScrollingBackground() :: Failed to compile the shader.");
|
||||
Gdx.app.error(TAG, CLASS_NAME + shader.getLog());
|
||||
shader = null;
|
||||
u_scaling = 0;
|
||||
u_displacement = 0;
|
||||
}else{
|
||||
// If the shader compiled fine then cache it's uniforms.
|
||||
u_scaling = shader.getUniformLocation("u_scaling");
|
||||
u_displacement = shader.getUniformLocation("u_displacement");
|
||||
}
|
||||
|
||||
u_scaling = shader.getUniformLocation("u_scaling");
|
||||
u_displacement = shader.getUniformLocation("u_displacement");
|
||||
|
||||
// Set all other fields.
|
||||
this.texturePath = texturePath;
|
||||
this.scaling = scaling;
|
||||
this.displacement = displacement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this effect.
|
||||
*
|
||||
* @param batch The {@link SpriteBatch} to use for the rendering.
|
||||
* @throws IllegalStateException If the {@link SpriteBatch} did not call {@link SpriteBatch#begin()} befor this method was called.
|
||||
*/
|
||||
public void render(SpriteBatch batch) throws IllegalStateException{
|
||||
if(!batch.isDrawing())
|
||||
throw new IllegalStateException("Must be called between SpriteBatch.begin() and SpriteBatch.end()");
|
||||
|
||||
// If the shader was loaded then set it as the current shader.
|
||||
if(shader != null){
|
||||
batch.setShader(shader);
|
||||
shader.setUniformf(u_scaling, scaling);
|
||||
shader.setUniformf(u_displacement, displacement);
|
||||
}
|
||||
|
||||
// Render.
|
||||
background.draw(batch);
|
||||
|
||||
if(shader != null) batch.setShader(null);
|
||||
// If the shader was loaded then disable it.
|
||||
if(shader != null)
|
||||
batch.setShader(null);
|
||||
|
||||
// Update the displacement a little bit.
|
||||
// GOTCHA: This will look slower or faster depending on the speed of the computer.
|
||||
displacement = displacement < 0.0f ? 1.0f : displacement - 0.0005f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
// Dispose all graphic assets.
|
||||
backgroundTexture.dispose();
|
||||
if(shader != null) shader.dispose();
|
||||
if(shader != null)
|
||||
shader.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssetsLoaded(){
|
||||
// Get the graphics and initialize them. Then release the assets loader.
|
||||
backgroundTexture = loader.getAsset(texturePath, Texture.class);
|
||||
initGraphics();
|
||||
|
||||
AsyncAssetLoader.freeInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the graphic asset's parameters and creates the sprite.
|
||||
*/
|
||||
private void initGraphics(){
|
||||
// Set up the texture.
|
||||
backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
|
||||
|
@@ -15,6 +15,16 @@
|
||||
*/
|
||||
package com.gamejolt.mikykr5.ceidecpong.interfaces;
|
||||
|
||||
public interface AssetsLoadedListener {
|
||||
import com.gamejolt.mikykr5.ceidecpong.utils.AsyncAssetLoader;
|
||||
|
||||
/**
|
||||
* An interface for objects that want to be notified when {@link AsyncAssetLoader} has finished loading all requested assets.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public interface AssetsLoadedListener{
|
||||
/**
|
||||
* Called when {@link AsyncAssetLoader} has finished loading so that observers can fetch their assets.
|
||||
*/
|
||||
public void onAssetsLoaded();
|
||||
}
|
||||
|
@@ -19,19 +19,53 @@ import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.InputProcessor;
|
||||
import com.badlogic.gdx.Screen;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.gamejolt.mikykr5.ceidecpong.GameCore;
|
||||
|
||||
/**
|
||||
* Base class for all the game states.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public abstract class BaseState implements Screen, InputProcessor{
|
||||
/**
|
||||
* Class used for logging.
|
||||
*/
|
||||
private static final String CLASS_NAME = BaseState.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* A {@link GameCore} instance to use it's {@link SpriteBatch}
|
||||
*/
|
||||
protected GameCore core;
|
||||
|
||||
/**
|
||||
* A flag to indicate that the state is the currently active state.
|
||||
*/
|
||||
protected boolean stateEnabled;
|
||||
|
||||
/**
|
||||
* A pixel perfect camera used to render all 2D assets for a concrete state instance.
|
||||
*/
|
||||
protected OrthographicCamera pixelPerfectCamera;
|
||||
protected Vector3 win2world;
|
||||
protected Vector2 touchPointWorldCoords;
|
||||
|
||||
/**
|
||||
* An auxiliary vector used to convert screen coordinates to world coordinates.
|
||||
*/
|
||||
protected final Vector3 win2world;
|
||||
|
||||
/**
|
||||
* An auxiliary vector used to hold the unprojected world coordinates of a touch or click.
|
||||
*/
|
||||
protected final Vector2 touchPointWorldCoords;
|
||||
|
||||
/**
|
||||
* Sets up all the general state fields.
|
||||
*
|
||||
* @param core The game core.
|
||||
* @throws IllegalArgumentException If core is null.
|
||||
*/
|
||||
public BaseState(final GameCore core) throws IllegalArgumentException{
|
||||
if(core == null)
|
||||
throw new IllegalArgumentException(CLASS_NAME + ": Core is null.");
|
||||
|
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.gamejolt.mikykr5.ceidecpong.states;
|
||||
|
||||
import com.badlogic.ashley.core.Engine;
|
||||
import com.badlogic.ashley.core.PooledEngine;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input;
|
||||
@@ -40,31 +41,85 @@ import com.gamejolt.mikykr5.ceidecpong.ecs.systems.messaging.InterSystemMessage;
|
||||
import com.gamejolt.mikykr5.ceidecpong.ecs.systems.messaging.InterSystemMessagingQueue;
|
||||
import com.gamejolt.mikykr5.ceidecpong.interfaces.AssetsLoadedListener;
|
||||
|
||||
/**
|
||||
* The state in charge of executing and handling the game itself.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class InGameState extends BaseState implements AssetsLoadedListener{
|
||||
/**
|
||||
* The {@link Engine} responsible for handling the ECS design pattern.
|
||||
*/
|
||||
private PooledEngine engine;
|
||||
|
||||
/**
|
||||
* The entity creator.
|
||||
*/
|
||||
private EntityInitializerBase entityInitializer;
|
||||
|
||||
/**
|
||||
* A {@link FrameBuffer} used to render to a logical screen. This way the game can be
|
||||
* designed for a single screen resolution and scaled to the running device's screen resolution.
|
||||
*/
|
||||
private FrameBuffer frameBuffer;
|
||||
|
||||
/**
|
||||
* The screen width.
|
||||
*/
|
||||
private int w;
|
||||
|
||||
/**
|
||||
* The screen height.
|
||||
*/
|
||||
private int h;
|
||||
private final float oldRatio;
|
||||
|
||||
/**
|
||||
* The aspect ratio of the logical screen.
|
||||
*/
|
||||
private final float fbAspectRatio;
|
||||
|
||||
/**
|
||||
* Flag to indicate that all assets have been successfully loaded.
|
||||
*/
|
||||
private boolean assetsLoaded;
|
||||
|
||||
/**
|
||||
* A pixel perfect camera used for rendering to the frame buffer.
|
||||
*/
|
||||
private OrthographicCamera fbCamera;
|
||||
|
||||
/**
|
||||
* The bounding rectangle of the frame buffer.
|
||||
*/
|
||||
private Rectangle fbBounds;
|
||||
|
||||
/**
|
||||
* An auxiliary vector for input calculations.
|
||||
*/
|
||||
private final Vector3 temp;
|
||||
|
||||
/**
|
||||
* Creates the state and the entity processing systems.
|
||||
*
|
||||
* @param core A GameCore instance. See {@link BaseState#BaseState(GameCore)}.
|
||||
* @throws IllegalArgumentException If core is null;
|
||||
*/
|
||||
public InGameState(final GameCore core) throws IllegalArgumentException{
|
||||
super(core);
|
||||
|
||||
// Initialize all fields.
|
||||
engine = new PooledEngine();
|
||||
frameBuffer = new FrameBuffer(Format.RGB565, ProjectConstants.FB_WIDTH, ProjectConstants.FB_HEIGHT, false);
|
||||
fbBounds = new Rectangle();
|
||||
w = Gdx.graphics.getWidth();
|
||||
w = Gdx.graphics.getHeight();
|
||||
oldRatio = aspectRatio(ProjectConstants.FB_WIDTH, ProjectConstants.FB_HEIGHT);
|
||||
assetsLoaded = false;
|
||||
fbCamera = new OrthographicCamera(ProjectConstants.FB_WIDTH, ProjectConstants.FB_HEIGHT);
|
||||
temp = new Vector3();
|
||||
|
||||
// Create the framebuffer.
|
||||
frameBuffer = new FrameBuffer(Format.RGB565, ProjectConstants.FB_WIDTH, ProjectConstants.FB_HEIGHT, false);
|
||||
fbAspectRatio = aspectRatio(ProjectConstants.FB_WIDTH, ProjectConstants.FB_HEIGHT);
|
||||
fbCamera = new OrthographicCamera(ProjectConstants.FB_WIDTH, ProjectConstants.FB_HEIGHT);
|
||||
fbBounds = new Rectangle();
|
||||
|
||||
// Create all entities.
|
||||
entityInitializer = new PongEntityInitializer();
|
||||
entityInitializer.createAllEntities(engine);
|
||||
@@ -103,7 +158,7 @@ public class InGameState extends BaseState implements AssetsLoadedListener{
|
||||
|
||||
// Scale the frame buffer to the current screen size.
|
||||
renderW = w;
|
||||
renderH = renderW / oldRatio;
|
||||
renderH = renderW / fbAspectRatio;
|
||||
|
||||
// Set the rendering position of the frame buffer.
|
||||
x = -(renderW / 2.0f);
|
||||
@@ -135,10 +190,13 @@ public class InGameState extends BaseState implements AssetsLoadedListener{
|
||||
|
||||
@Override
|
||||
public boolean keyDown(int keycode){
|
||||
// If the user pressed the escape key (the back button in Android) then go back
|
||||
// to the main menu. Else ignore the key.
|
||||
if(keycode == Input.Keys.BACK || keycode == Input.Keys.ESCAPE){
|
||||
core.nextState = game_states_t.MAIN_MENU;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -146,6 +204,7 @@ public class InGameState extends BaseState implements AssetsLoadedListener{
|
||||
public boolean touchDown(int screenX, int screenY, int pointer, int button){
|
||||
InterSystemMessage message;
|
||||
|
||||
// If the user touched the screen inside the frame buffer then notify the player positioning system.
|
||||
if(touchInsideFrameBuffer(screenX, screenY)){
|
||||
message = new InterSystemMessage(HumanPlayerPositioningSystem.class.getCanonicalName());
|
||||
message.data.put("INPUT_Y", convertWorldYToFrameBufferY(screenY));
|
||||
@@ -159,6 +218,7 @@ public class InGameState extends BaseState implements AssetsLoadedListener{
|
||||
public boolean touchDragged(int screenX, int screenY, int pointer){
|
||||
InterSystemMessage message;
|
||||
|
||||
// If the user touched the screen inside the frame buffer then notify the player positioning system.
|
||||
if(touchInsideFrameBuffer(screenX, screenY)){
|
||||
message = new InterSystemMessage(HumanPlayerPositioningSystem.class.getCanonicalName());
|
||||
message.data.put("INPUT_Y", convertWorldYToFrameBufferY(screenY));
|
||||
@@ -174,12 +234,19 @@ public class InGameState extends BaseState implements AssetsLoadedListener{
|
||||
assetsLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user clicked or touched a point inside the frame buffer.
|
||||
*
|
||||
* @param screenX The X coordinate of the touch point.
|
||||
* @param screenY The Y coordinate of the touch point.
|
||||
* @return True if the touch point is inside the frame buffer.
|
||||
*/
|
||||
private boolean touchInsideFrameBuffer(int screenX, int screenY){
|
||||
float fbW, fbH;
|
||||
|
||||
unprojectTouch(screenX, screenY);
|
||||
fbW = w;
|
||||
fbH = fbW / oldRatio;
|
||||
fbH = fbW / fbAspectRatio;
|
||||
fbBounds.set(-(fbW / 2.0f), -(fbH / 2.0f), fbW, fbH);
|
||||
|
||||
if(fbBounds.contains(touchPointWorldCoords)){
|
||||
@@ -189,8 +256,14 @@ public class InGameState extends BaseState implements AssetsLoadedListener{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the Y coordinate of a touch point in screen coordinates to the world coordinates of the framebuffer.
|
||||
*
|
||||
* @param y The Y coordinate of a touch point.
|
||||
* @return The Y coordinate converted to world coordinates.
|
||||
*/
|
||||
private float convertWorldYToFrameBufferY(float y){
|
||||
float fbH = h / oldRatio;
|
||||
float fbH = h / fbAspectRatio;
|
||||
temp.set(0, y + (fbH / 2.0f), 0);
|
||||
fbCamera.unproject(temp, 0, 0, w, fbH);
|
||||
|
||||
|
@@ -77,7 +77,6 @@ public class LoadingState extends BaseState{
|
||||
|
||||
if(!loadingDone && loader != null){
|
||||
if(loader.loadAssets()){
|
||||
loader.notifyListeners();
|
||||
loadingDone = true;
|
||||
}
|
||||
}
|
||||
|
@@ -22,35 +22,80 @@ import com.badlogic.gdx.assets.AssetManager;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
import com.gamejolt.mikykr5.ceidecpong.interfaces.AssetsLoadedListener;
|
||||
|
||||
/**
|
||||
* An singleton wrapper around an {@link AssetManager} object.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*
|
||||
*/
|
||||
public final class AsyncAssetLoader implements Disposable{
|
||||
/**
|
||||
* A list of all listeners registered with this loader.
|
||||
*/
|
||||
private LinkedList<AssetsLoadedListener> listeners;
|
||||
|
||||
/**
|
||||
* The {@link AssetManager} used to load the assets.
|
||||
*/
|
||||
private AssetManager manager;
|
||||
|
||||
/**
|
||||
* Creates the listeners list and the assets manager. Made private so that this class cannot be
|
||||
* instantiated outside of itself.
|
||||
*/
|
||||
private AsyncAssetLoader(){
|
||||
listeners = new LinkedList<AssetsLoadedListener>();
|
||||
manager = new AssetManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* A holder for the singleton instance of {@link AsyncAssetLoader}.
|
||||
*/
|
||||
private static final class SingletonHolder{
|
||||
/**
|
||||
* How many references to the singleton instance there are.
|
||||
*/
|
||||
public static int REF_COUNT = 0;
|
||||
|
||||
/**
|
||||
* The singleton instance.
|
||||
*/
|
||||
public static AsyncAssetLoader INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the singleton instance of this class.
|
||||
*
|
||||
* @return The singleton instance.
|
||||
*/
|
||||
public static AsyncAssetLoader getInstance(){
|
||||
// If the instance does not exists then create it and update it's reference counter.
|
||||
if(SingletonHolder.REF_COUNT == 0)
|
||||
SingletonHolder.INSTANCE = new AsyncAssetLoader();
|
||||
SingletonHolder.REF_COUNT++;
|
||||
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a reference to the singleton instance of this class.
|
||||
*/
|
||||
public static void freeInstance(){
|
||||
SingletonHolder.REF_COUNT--;
|
||||
|
||||
// If there are no more references to the instance then delete it.
|
||||
if(SingletonHolder.REF_COUNT <= 0){
|
||||
SingletonHolder.INSTANCE.dispose();
|
||||
SingletonHolder.INSTANCE = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new listener to the listeners queue.
|
||||
*
|
||||
* @param listener An {@link AssetsLoadedListener} instance.
|
||||
* @throws IllegalArgumentException if listener is null.
|
||||
*/
|
||||
public void addListener(AssetsLoadedListener listener) throws IllegalArgumentException{
|
||||
try{
|
||||
checkParametes(listener, "listener");
|
||||
@@ -61,6 +106,13 @@ public final class AsyncAssetLoader implements Disposable{
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests a new asset to be loaded.
|
||||
*
|
||||
* @param path The internal path of the asset.
|
||||
* @param assetClass The class of the asset to load. Must be a class recognized by {@link AssetManager}.
|
||||
* @throws IllegalArgumentException If either argument is null.
|
||||
*/
|
||||
public <T> void addAssetToLoad(String path, Class<T> assetClass) throws IllegalArgumentException{
|
||||
try{
|
||||
checkParametes(path, "path");
|
||||
@@ -72,6 +124,14 @@ public final class AsyncAssetLoader implements Disposable{
|
||||
manager.load(path, assetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an asset from the manager after it has been loaded.
|
||||
*
|
||||
* @param path The internal path of the asset.
|
||||
* @param assetClass The class of the asset to load. Must be a class recognized by {@link AssetManager}.
|
||||
* @return The asset.
|
||||
* @throws IllegalArgumentException If either argument is null.
|
||||
*/
|
||||
public <T> T getAsset(String path, Class<T> assetClass) throws IllegalArgumentException{
|
||||
try{
|
||||
checkParametes(path, "path");
|
||||
@@ -83,17 +143,37 @@ public final class AsyncAssetLoader implements Disposable{
|
||||
return manager.get(path, assetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the {@link AssetManager}. Notifies all the registered listeners if the loading finished.
|
||||
*
|
||||
* @return True if all assets are loaded.
|
||||
*/
|
||||
public boolean loadAssets(){
|
||||
return manager.update();
|
||||
boolean done = manager.update();
|
||||
|
||||
if(done)
|
||||
notifyListeners();
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
public void notifyListeners(){
|
||||
/**
|
||||
* Notifies all listener objects that this loader has finished it's work.
|
||||
*/
|
||||
private void notifyListeners(){
|
||||
for(AssetsLoadedListener listener : listeners)
|
||||
listener.onAssetsLoaded();
|
||||
|
||||
listeners.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given parameter is null.
|
||||
*
|
||||
* @param parameter The parameter to check.
|
||||
* @param paramName The name of the parameter to append to the exception if it is null.
|
||||
* @throws IllegalArgumentException If parameter is null.
|
||||
*/
|
||||
private void checkParametes(Object parameter, String paramName) throws IllegalArgumentException{
|
||||
if(parameter == null) throw new IllegalArgumentException("Parameter: " + paramName + " is null.");
|
||||
}
|
||||
|
@@ -23,62 +23,125 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
|
||||
|
||||
/**
|
||||
* A {@link BitmapFont} loader and manager with a cache.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class CachedFontManager{
|
||||
/**
|
||||
* The characters used by all the {@link BitmapFont} objects loaded.
|
||||
*/
|
||||
public static final String FONT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890:,";
|
||||
|
||||
/**
|
||||
* The standar font size for all loaded {@link BitmapFont} objects.
|
||||
*/
|
||||
public static final int BASE_FONT_SIZE = 40;
|
||||
|
||||
/**
|
||||
* The cache of {@link BitmapFont} objects.
|
||||
*/
|
||||
private Map<String, BitmapFont> fonts;
|
||||
|
||||
/**
|
||||
* Creates the cache. Made private so that this class cannot be instantiated outside of itself.
|
||||
*/
|
||||
private CachedFontManager(){
|
||||
fonts = new HashMap<String, BitmapFont>();
|
||||
}
|
||||
|
||||
/**
|
||||
* A holder for the singleton instance of {@link CachedFontManager}.
|
||||
*/
|
||||
private static final class SingletonHolder{
|
||||
/**
|
||||
* How many references to the singleton instance there are.
|
||||
*/
|
||||
public static int REF_COUNT = 0;
|
||||
|
||||
/**
|
||||
* The singleton instance.
|
||||
*/
|
||||
public static CachedFontManager INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the singleton instance of this class.
|
||||
*
|
||||
* @return The singleton instance.
|
||||
*/
|
||||
public static CachedFontManager getInstance(){
|
||||
// If the instance does not exists then create it and update it's reference counter.
|
||||
if(SingletonHolder.REF_COUNT == 0)
|
||||
SingletonHolder.INSTANCE = new CachedFontManager();
|
||||
SingletonHolder.REF_COUNT++;
|
||||
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a reference to the singleton instance of this class.
|
||||
*/
|
||||
public static void freeInstance(){
|
||||
SingletonHolder.REF_COUNT--;
|
||||
|
||||
// If there are no more references to the instance then delete it.
|
||||
if(SingletonHolder.REF_COUNT <= 0){
|
||||
SingletonHolder.INSTANCE.dispose();
|
||||
SingletonHolder.INSTANCE = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a {@link BitmapFont} with the given path and {@link CachedFontManager#BASE_FONT_SIZE} as default size.
|
||||
*
|
||||
* @param path The internal path of the font to load.
|
||||
* @return The font.
|
||||
*/
|
||||
public BitmapFont loadFont(String path){
|
||||
return loadFont(path, BASE_FONT_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a {@link BitmapFont} with the given path and size.
|
||||
*
|
||||
* @param path The internal path of the font to load.
|
||||
* @param size The size of the font to load.
|
||||
* @return
|
||||
*/
|
||||
public BitmapFont loadFont(String path, int size){
|
||||
// If the font is already in the cache the return it.
|
||||
// GOTCHA: The same font cannot be loaded with two different sizes.
|
||||
if(fonts.containsKey(path))
|
||||
return fonts.get(path);
|
||||
|
||||
// Declare all variables used to create a font.
|
||||
FreeTypeFontGenerator fontGenerator;
|
||||
FreeTypeFontParameter fontParameters;
|
||||
BitmapFont font;
|
||||
|
||||
// Set the parameters of the font to load.
|
||||
fontParameters = new FreeTypeFontParameter();
|
||||
fontParameters.characters = FONT_CHARS;
|
||||
fontParameters.size = size;
|
||||
fontParameters.flip = false;
|
||||
|
||||
// Create a new bitmap font from the given TrueType font.
|
||||
fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal(path));
|
||||
font = fontGenerator.generateFont(fontParameters);
|
||||
fonts.put(path, font);
|
||||
|
||||
// Clean the font generator.
|
||||
fontGenerator.dispose();
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a specific {@link BitmapFont} from the cache and disposes it.
|
||||
* @param path
|
||||
*/
|
||||
public void unloadFont(String path){
|
||||
if(fonts.containsKey(path)){
|
||||
fonts.get(path).dispose();
|
||||
@@ -86,9 +149,13 @@ public class CachedFontManager{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and disposes all the loaded fonts.
|
||||
*/
|
||||
private void dispose(){
|
||||
Gdx.app.log("FONT_MANAGER", "Disposing fonts.");
|
||||
|
||||
//
|
||||
for(BitmapFont font : fonts.values())
|
||||
font.dispose();
|
||||
fonts.clear();
|
||||
|
@@ -21,33 +21,72 @@ import java.util.Map;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.audio.Sound;
|
||||
|
||||
/**
|
||||
* A {@link Sound} effect loader and manager with a cache.
|
||||
*
|
||||
* @author Miguel Astor
|
||||
*/
|
||||
public class CachedSoundManager {
|
||||
/**
|
||||
* The cache of {@link Sound} objects.
|
||||
*/
|
||||
private Map<String, Sound> sounds;
|
||||
|
||||
/**
|
||||
* Creates the cache. Made private so that this class cannot be instantiated outside of itself.
|
||||
*/
|
||||
private CachedSoundManager(){
|
||||
sounds = new HashMap<String, Sound>();
|
||||
}
|
||||
|
||||
/**
|
||||
* A holder for the singleton instance of {@link CachedSoundManager}.
|
||||
*/
|
||||
private static final class SingletonHolder{
|
||||
/**
|
||||
* How many references to the singleton instance there are.
|
||||
*/
|
||||
public static int REF_COUNT = 0;
|
||||
|
||||
/**
|
||||
* The singleton instance.
|
||||
*/
|
||||
public static CachedSoundManager INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the singleton instance of this class.
|
||||
*
|
||||
* @return The singleton instance.
|
||||
*/
|
||||
public static CachedSoundManager getInstance(){
|
||||
// If the instance does not exists then create it and update it's reference counter.
|
||||
if(SingletonHolder.REF_COUNT == 0)
|
||||
SingletonHolder.INSTANCE = new CachedSoundManager();
|
||||
SingletonHolder.REF_COUNT++;
|
||||
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a reference to the singleton instance of this class.
|
||||
*/
|
||||
public static void freeInstance(){
|
||||
SingletonHolder.REF_COUNT--;
|
||||
|
||||
// If there are no more references to the instance then delete it.
|
||||
if(SingletonHolder.REF_COUNT <= 0){
|
||||
SingletonHolder.INSTANCE.dispose();
|
||||
SingletonHolder.INSTANCE = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a {@link Sound} effect with the given path.
|
||||
*
|
||||
* @param path The internal path of the sound effect to load.
|
||||
* @return The sound effect.
|
||||
*/
|
||||
public Sound loadSound(String path){
|
||||
if(sounds.containsKey(path))
|
||||
return sounds.get(path);
|
||||
@@ -58,6 +97,10 @@ public class CachedSoundManager {
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a specific {@link Sound} from the cache and disposes it.
|
||||
* @param path
|
||||
*/
|
||||
public void unloadSound(String path){
|
||||
if(sounds.containsKey(path)){
|
||||
sounds.get(path).dispose();
|
||||
@@ -65,6 +108,9 @@ public class CachedSoundManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and disposes all the loaded sounds.
|
||||
*/
|
||||
private void dispose(){
|
||||
Gdx.app.log("SOUND_MANAGER", "Disposing sounds.");
|
||||
|
||||
|
Reference in New Issue
Block a user