Add beginnings of game code.
This commit is contained in:
		
							
								
								
									
										121
									
								
								core/src/com/me/asteroids/AsteroidFactory.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								core/src/com/me/asteroids/AsteroidFactory.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
			
		||||
package com.me.asteroids;
 | 
			
		||||
 | 
			
		||||
import com.badlogic.gdx.math.MathUtils;
 | 
			
		||||
import com.badlogic.gdx.math.Polygon;
 | 
			
		||||
import com.badlogic.gdx.math.Vector2;
 | 
			
		||||
import com.me.common.Random;
 | 
			
		||||
 | 
			
		||||
public final class AsteroidFactory {
 | 
			
		||||
 | 
			
		||||
    public static final Random rand = new Random();
 | 
			
		||||
 | 
			
		||||
    int vertexCount;
 | 
			
		||||
    float size;
 | 
			
		||||
 | 
			
		||||
    float sizeVariation;
 | 
			
		||||
    float angleVariation;
 | 
			
		||||
 | 
			
		||||
    boolean sizeRelativeToLast;
 | 
			
		||||
 | 
			
		||||
    public AsteroidFactory setVertexCount(int vertexCount) {
 | 
			
		||||
        this.vertexCount = vertexCount;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public AsteroidFactory setSize(float size) {
 | 
			
		||||
        this.size = size;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public AsteroidFactory setSizeVariation(float sizeVariation) {
 | 
			
		||||
        this.sizeVariation = sizeVariation;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public AsteroidFactory sizeRelativeToLast() {
 | 
			
		||||
        this.sizeRelativeToLast = true;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public AsteroidFactory sizeRelativeToInitial() {
 | 
			
		||||
        this.sizeRelativeToLast = false;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public AsteroidFactory setAngleVariation(float angleVariation) {
 | 
			
		||||
        this.angleVariation = angleVariation;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validate() {
 | 
			
		||||
        if (vertexCount <= 2) {
 | 
			
		||||
            throw new IllegalStateException(String.format("Illegal vertexCount: %d. Must be >= 3.", vertexCount));
 | 
			
		||||
        }
 | 
			
		||||
        if (size <= 0) {
 | 
			
		||||
            throw new IllegalStateException(String.format("Illegal vertexCount: %f. Must be > 0.", size));
 | 
			
		||||
        }
 | 
			
		||||
        if (sizeVariation < 0) {
 | 
			
		||||
            throw new IllegalStateException(String.format("Illegal sizeVariation: %f. Must be >= 0.", sizeVariation));
 | 
			
		||||
        }
 | 
			
		||||
        if (sizeVariation > size) {
 | 
			
		||||
            throw new IllegalStateException(String.format("Illegal sizeVariation: %f. Must be <= size.", sizeVariation));
 | 
			
		||||
        }
 | 
			
		||||
        if (angleVariation < 0) {
 | 
			
		||||
            throw new IllegalStateException(String.format("Illegal angleVariation: %f. Must be >= 0.", angleVariation));
 | 
			
		||||
        }
 | 
			
		||||
        if (angleVariation >  MathUtils.PI2 / vertexCount / 2) {
 | 
			
		||||
            throw new IllegalStateException(String.format("Illegal angleVariation: %f. May cause vertexes positions to swap.", angleVariation));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Vector2 applyAngleVariation(Vector2 vertex) {
 | 
			
		||||
        if (angleVariation > 0) {
 | 
			
		||||
            float half = angleVariation * 0.5f;
 | 
			
		||||
            vertex.rotateRad(rand.nextFloat(-half, half));
 | 
			
		||||
        }
 | 
			
		||||
        return vertex;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private float applySizeVariation(float size) {
 | 
			
		||||
        if (sizeVariation > 0) {
 | 
			
		||||
            float half = sizeVariation * 0.5f;
 | 
			
		||||
            float variation = rand.nextFloat(-half, half);
 | 
			
		||||
            if (sizeRelativeToLast) {
 | 
			
		||||
                size += variation;
 | 
			
		||||
                size = MathUtils.clamp(size, this.size - half, this.size + half);
 | 
			
		||||
            } else {
 | 
			
		||||
                size = this.size + variation;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Polygon generate() {
 | 
			
		||||
        validate();
 | 
			
		||||
 | 
			
		||||
        float angleStep = MathUtils.PI2 / vertexCount;
 | 
			
		||||
 | 
			
		||||
        // Pick a random starting angle
 | 
			
		||||
        float startAngle = rand.nextFloat() * MathUtils.PI2;
 | 
			
		||||
        Vector2 dir = new Vector2(MathUtils.cos(startAngle), MathUtils.sin(startAngle));
 | 
			
		||||
 | 
			
		||||
        float lastSize = size;
 | 
			
		||||
        float[] vertices = new float[vertexCount * 2];
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < vertexCount; i++) {
 | 
			
		||||
            Vector2 vertex = dir.cpy();
 | 
			
		||||
 | 
			
		||||
            vertex = applyAngleVariation(vertex);
 | 
			
		||||
            lastSize = applySizeVariation(lastSize);
 | 
			
		||||
 | 
			
		||||
            vertex.scl(lastSize);
 | 
			
		||||
            vertices[i * 2] = vertex.x;
 | 
			
		||||
            vertices[(i * 2) + 1] = vertex.y;
 | 
			
		||||
 | 
			
		||||
            dir.rotateRad(angleStep);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new Polygon(vertices);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								core/src/com/me/asteroids/Asteroids.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								core/src/com/me/asteroids/Asteroids.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
package com.me.asteroids;
 | 
			
		||||
 | 
			
		||||
import com.badlogic.gdx.ApplicationAdapter;
 | 
			
		||||
import com.badlogic.gdx.Gdx;
 | 
			
		||||
import com.me.asteroids.screens.GameScreen;
 | 
			
		||||
import com.me.common.Game;
 | 
			
		||||
 | 
			
		||||
public class Asteroids extends ApplicationAdapter {
 | 
			
		||||
 | 
			
		||||
	public Graphics graphics;
 | 
			
		||||
	private Game game;
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void create () {
 | 
			
		||||
		graphics = new Graphics(Constants.WIDTH, Constants.HEIGHT);
 | 
			
		||||
		graphics.initialize();
 | 
			
		||||
 | 
			
		||||
		game = new Game();
 | 
			
		||||
		game.setNextScreen(new GameScreen(graphics));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void render () {
 | 
			
		||||
		game.update(Gdx.graphics.getDeltaTime());
 | 
			
		||||
		game.render();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void dispose () {
 | 
			
		||||
		graphics.dispose();
 | 
			
		||||
		game.dispose();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void resize(int width, int height) {
 | 
			
		||||
		graphics.setScreenSize(width, height);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								core/src/com/me/asteroids/Constants.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								core/src/com/me/asteroids/Constants.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
package com.me.asteroids;
 | 
			
		||||
 | 
			
		||||
public class Constants {
 | 
			
		||||
 | 
			
		||||
    public static final int WIDTH = 800;
 | 
			
		||||
    public static final int HEIGHT = 600;
 | 
			
		||||
 | 
			
		||||
    public static final int HALF_WIDTH = WIDTH / 2;
 | 
			
		||||
    public static final int HALF_HEIGHT = HEIGHT / 2;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								core/src/com/me/asteroids/Graphics.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								core/src/com/me/asteroids/Graphics.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
			
		||||
package com.me.asteroids;
 | 
			
		||||
 | 
			
		||||
import com.badlogic.gdx.Gdx;
 | 
			
		||||
import com.badlogic.gdx.graphics.Camera;
 | 
			
		||||
import com.badlogic.gdx.graphics.GL20;
 | 
			
		||||
import com.badlogic.gdx.graphics.OrthographicCamera;
 | 
			
		||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
 | 
			
		||||
import com.badlogic.gdx.utils.viewport.FitViewport;
 | 
			
		||||
import com.badlogic.gdx.utils.viewport.Viewport;
 | 
			
		||||
 | 
			
		||||
public class Graphics {
 | 
			
		||||
 | 
			
		||||
    private int worldWidth, worldHeight;
 | 
			
		||||
    private int screenWidth, screenHeight;
 | 
			
		||||
 | 
			
		||||
    private Camera camera;
 | 
			
		||||
    private Viewport viewport;
 | 
			
		||||
 | 
			
		||||
    private ShapeRenderer shapeRenderer;
 | 
			
		||||
 | 
			
		||||
    public Graphics(int worldWidth, int worldHeight) {
 | 
			
		||||
        this.worldWidth = worldWidth;
 | 
			
		||||
        this.worldHeight = worldHeight;
 | 
			
		||||
        this.screenWidth = Gdx.graphics.getWidth();
 | 
			
		||||
        this.screenHeight = Gdx.graphics.getHeight();
 | 
			
		||||
 | 
			
		||||
        this.camera = new OrthographicCamera();
 | 
			
		||||
        this.viewport = new FitViewport(worldHeight, worldWidth, camera);
 | 
			
		||||
 | 
			
		||||
        this.shapeRenderer = new ShapeRenderer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void initialize() {
 | 
			
		||||
        Gdx.gl.glClearColor(0, 0, 0, 1);
 | 
			
		||||
        updateDimensions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void reset() {
 | 
			
		||||
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setScreenSize(int width, int height) {
 | 
			
		||||
        screenWidth = width;
 | 
			
		||||
        screenHeight = height;
 | 
			
		||||
        updateDimensions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void dispose() {
 | 
			
		||||
        shapeRenderer.dispose();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ShapeRenderer getShapeRenderer() {
 | 
			
		||||
        return shapeRenderer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateDimensions() {
 | 
			
		||||
        viewport.setWorldSize(worldWidth, worldHeight);
 | 
			
		||||
        viewport.update(screenWidth, screenHeight, true);
 | 
			
		||||
 | 
			
		||||
        shapeRenderer.setProjectionMatrix(camera.combined);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								core/src/com/me/asteroids/Utils.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								core/src/com/me/asteroids/Utils.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
package com.me.asteroids;
 | 
			
		||||
 | 
			
		||||
import com.badlogic.gdx.math.MathUtils;
 | 
			
		||||
import com.badlogic.gdx.math.Vector2;
 | 
			
		||||
 | 
			
		||||
import java.lang.Math;
 | 
			
		||||
 | 
			
		||||
public final class Utils {
 | 
			
		||||
 | 
			
		||||
    public static float rotate(float rotation, float degrees) {
 | 
			
		||||
        rotation += degrees;
 | 
			
		||||
        if (rotation < 0) {
 | 
			
		||||
            rotation = 360 - rotation;
 | 
			
		||||
        } else if (rotation > 360) {
 | 
			
		||||
            rotation -= 360;
 | 
			
		||||
        }
 | 
			
		||||
        return rotation;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Vector2 setUnitVectorAngle(Vector2 vector, float degrees) {
 | 
			
		||||
        return vector.set((float) Math.cos(degrees * MathUtils.degreesToRadians), (float) Math.sin(degrees * MathUtils.degreesToRadians));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Vector2 setUnitVectorAngleRad(Vector2 vector, float radians) {
 | 
			
		||||
        return vector.set((float) Math.cos(radians), (float) Math.sin(radians));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								core/src/com/me/asteroids/screens/GameScreen.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								core/src/com/me/asteroids/screens/GameScreen.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
package com.me.asteroids.screens;
 | 
			
		||||
 | 
			
		||||
import com.me.asteroids.Graphics;
 | 
			
		||||
import com.me.common.Screen;
 | 
			
		||||
 | 
			
		||||
public class GameScreen extends Screen {
 | 
			
		||||
 | 
			
		||||
    Graphics graphics;
 | 
			
		||||
 | 
			
		||||
    public GameScreen(Graphics graphics) {
 | 
			
		||||
        this.graphics = graphics;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setup() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(float dt) {
 | 
			
		||||
        graphics.reset();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void dispose() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								core/src/com/me/common/Game.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								core/src/com/me/common/Game.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
package com.me.common;
 | 
			
		||||
 | 
			
		||||
public class Game {
 | 
			
		||||
 | 
			
		||||
    private Screen screen;
 | 
			
		||||
    private Screen nextScreen;
 | 
			
		||||
 | 
			
		||||
    public void update(float dt) {
 | 
			
		||||
        if (nextScreen != null) {
 | 
			
		||||
            handleScreeUpdate();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (screen != null) {
 | 
			
		||||
            screen.update(dt);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void render() {
 | 
			
		||||
        if (screen != null) {
 | 
			
		||||
            screen.render();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void handleScreeUpdate() {
 | 
			
		||||
        if (screen != null) screen.dispose();
 | 
			
		||||
 | 
			
		||||
        nextScreen.setup();
 | 
			
		||||
        screen = nextScreen;
 | 
			
		||||
        nextScreen = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNextScreen(Screen screen) {
 | 
			
		||||
        nextScreen = screen;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void dispose() {
 | 
			
		||||
        screen.dispose();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								core/src/com/me/common/MockRenderer.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								core/src/com/me/common/MockRenderer.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
package com.me.common;
 | 
			
		||||
 | 
			
		||||
public class MockRenderer implements Renderer {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void render() {}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								core/src/com/me/common/MockScreen.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								core/src/com/me/common/MockScreen.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
package com.me.common;
 | 
			
		||||
 | 
			
		||||
public class MockScreen extends Screen {
 | 
			
		||||
 | 
			
		||||
    public void setup() {
 | 
			
		||||
        setRenderer(new MockRenderer());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void update(float dt) {}
 | 
			
		||||
 | 
			
		||||
    public void dispose() {}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								core/src/com/me/common/Random.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								core/src/com/me/common/Random.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
package com.me.common;
 | 
			
		||||
 | 
			
		||||
public class Random extends java.util.Random {
 | 
			
		||||
 | 
			
		||||
    public Random() {
 | 
			
		||||
        super();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Random(long seed) {
 | 
			
		||||
        super(seed);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float nextFloat(float min, float max) {
 | 
			
		||||
        return min + (nextFloat() * Math.abs(min - max));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int nextInt(int min, int max) {
 | 
			
		||||
        return min + nextInt(Math.abs(min - max));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								core/src/com/me/common/Renderer.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								core/src/com/me/common/Renderer.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
package com.me.common;
 | 
			
		||||
 | 
			
		||||
public interface Renderer {
 | 
			
		||||
 | 
			
		||||
    void render();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								core/src/com/me/common/Screen.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								core/src/com/me/common/Screen.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
package com.me.common;
 | 
			
		||||
 | 
			
		||||
public abstract class Screen {
 | 
			
		||||
 | 
			
		||||
    private Renderer renderer;
 | 
			
		||||
 | 
			
		||||
    public abstract void setup();
 | 
			
		||||
 | 
			
		||||
    public abstract void update(float dt);
 | 
			
		||||
 | 
			
		||||
    public abstract void dispose();
 | 
			
		||||
 | 
			
		||||
    public void setRenderer(Renderer renderer) {
 | 
			
		||||
        this.renderer = renderer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void render() {
 | 
			
		||||
        if (renderer != null) {
 | 
			
		||||
            renderer.render();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								core/src/com/me/common/ecs/Component.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								core/src/com/me/common/ecs/Component.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
package com.me.common.ecs;
 | 
			
		||||
 | 
			
		||||
public abstract class Component {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								core/src/com/me/common/ecs/ComponentBag.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								core/src/com/me/common/ecs/ComponentBag.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
package com.me.common.ecs;
 | 
			
		||||
 | 
			
		||||
public class ComponentBag {
 | 
			
		||||
 | 
			
		||||
    private Component[] items;
 | 
			
		||||
    private int size;
 | 
			
		||||
 | 
			
		||||
    public ComponentBag() {
 | 
			
		||||
        this.items = new Component[16];
 | 
			
		||||
        this.size = items.length;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Component get(int index) {
 | 
			
		||||
        if (index > size) {
 | 
			
		||||
            throw new IndexOutOfBoundsException("index > size");
 | 
			
		||||
        }
 | 
			
		||||
        return items[index];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void insert(int index, Component item) {
 | 
			
		||||
        if (index >= size) {
 | 
			
		||||
            grow((int) (index * 1.5f));
 | 
			
		||||
        }
 | 
			
		||||
        items[index] = item;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void remove(int index) {
 | 
			
		||||
        if (index >= size) {
 | 
			
		||||
            throw new IndexOutOfBoundsException("index must be < size");
 | 
			
		||||
        }
 | 
			
		||||
        items[index] = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void grow(int newSize) {
 | 
			
		||||
        Component[] newItems = new Component[newSize];
 | 
			
		||||
        System.arraycopy(this.items, 0, newItems, 0, size);
 | 
			
		||||
        size = newSize;
 | 
			
		||||
        this.items = newItems;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								core/src/com/me/common/ecs/ComponentType.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								core/src/com/me/common/ecs/ComponentType.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,78 @@
 | 
			
		||||
package com.me.common.ecs;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
public class ComponentType {
 | 
			
		||||
 | 
			
		||||
    private static final Map<Class<? extends Component>, ComponentType> types = new HashMap<>();
 | 
			
		||||
    private static final ComponentType[] typeById = new ComponentType[Long.SIZE];
 | 
			
		||||
 | 
			
		||||
    private static long nextBit = 1l;
 | 
			
		||||
    private static int nextId = 0;
 | 
			
		||||
 | 
			
		||||
    private long bits;
 | 
			
		||||
    private int id;
 | 
			
		||||
 | 
			
		||||
    private ComponentType() {
 | 
			
		||||
        this.bits = nextBit;
 | 
			
		||||
        this.id = nextId++;
 | 
			
		||||
 | 
			
		||||
        this.nextBit <<= 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected long getBits() {
 | 
			
		||||
        return bits;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected int getId() {
 | 
			
		||||
        return this.id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static long getMaskBits(Class<? extends Component>... components) {
 | 
			
		||||
        long mask = 0l;
 | 
			
		||||
        for (Class<? extends Component> clazz : components) {
 | 
			
		||||
            mask |= getTypeBits(clazz);
 | 
			
		||||
        }
 | 
			
		||||
        return mask;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static long getTypeBits(Class<? extends Component> component) {
 | 
			
		||||
        return getComponentType(component).getBits();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static int getTypeId(Class<? extends Component> component) {
 | 
			
		||||
        return getComponentType(component).getId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static ComponentType getById(int id) {
 | 
			
		||||
        return typeById[id];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected boolean isTypeInMask(long mask) {
 | 
			
		||||
        return (bits & mask) == mask;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static void registerComponentType(Class<? extends Component> component) {
 | 
			
		||||
        ComponentType type = types.get(component);
 | 
			
		||||
        if (type != null) {
 | 
			
		||||
            throw new IllegalArgumentException(component.getName() + " has already been registered.");
 | 
			
		||||
        }
 | 
			
		||||
        type = new ComponentType();
 | 
			
		||||
        types.put(component, type);
 | 
			
		||||
        typeById[type.getId()] = type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static ComponentType getComponentType(Class<? extends Component> component) {
 | 
			
		||||
        ComponentType type = types.get(component);
 | 
			
		||||
        if (type == null) {
 | 
			
		||||
            throw new IllegalArgumentException(component.getName() + " has not been registered.");
 | 
			
		||||
        }
 | 
			
		||||
        return type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static int getRegisteredComponentTypeCount() {
 | 
			
		||||
        return types.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								core/src/com/me/common/ecs/Engine.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								core/src/com/me/common/ecs/Engine.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
			
		||||
package com.me.common.ecs;
 | 
			
		||||
 | 
			
		||||
import com.badlogic.gdx.utils.Array;
 | 
			
		||||
 | 
			
		||||
public class Engine {
 | 
			
		||||
 | 
			
		||||
    private Array<Entity> entities;
 | 
			
		||||
    private ComponentBag[] components;
 | 
			
		||||
    private Array<EntitySystem> systems;
 | 
			
		||||
 | 
			
		||||
    public Engine() {
 | 
			
		||||
        this.entities = new Array<>();
 | 
			
		||||
        this.systems = new Array<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void registerComponentClass(Class<? extends Component> clazz) {
 | 
			
		||||
        ComponentType.registerComponentType(clazz);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void registerSystem(EntitySystem system) {
 | 
			
		||||
        this.systems.add(system);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void ready() {
 | 
			
		||||
        this.components = new ComponentBag[ComponentType.getRegisteredComponentTypeCount()];
 | 
			
		||||
        for (int i = 0; i < components.length; i++) {
 | 
			
		||||
            components[i] = new ComponentBag();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void update(float dt) {
 | 
			
		||||
        for (EntitySystem system : systems) {
 | 
			
		||||
            system.preProcessing();
 | 
			
		||||
            updateSystem(system, dt);
 | 
			
		||||
            system.postProcessing();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Entity createEntity() {
 | 
			
		||||
        Entity entity = new Entity(this);
 | 
			
		||||
        entities.add(entity);
 | 
			
		||||
        return entity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void removeEntity(Entity entity) {
 | 
			
		||||
        removeAllEntityComponents(entity.getId());
 | 
			
		||||
        entities.removeValue(entity, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void removeAllEntityComponents(int entityId) {
 | 
			
		||||
        for (int i = 0; i < components.length; i++) {
 | 
			
		||||
            components[i].insert(entityId, null);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void addEntityComponent(Entity entity, Component component) {
 | 
			
		||||
        ComponentType type = ComponentType.getComponentType(component.getClass());
 | 
			
		||||
        components[type.getId()].insert(entity.getId(), component);
 | 
			
		||||
        entity.addComponentType(type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void removeEntityComponent(Entity entity, Component component) {
 | 
			
		||||
        ComponentType type = ComponentType.getComponentType(component.getClass());
 | 
			
		||||
        components[type.getId()].remove(entity.getId());
 | 
			
		||||
        entity.removeComponentType(type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected <T extends Component> T getEntityComponent(Entity entity, Class<T> clazz) {
 | 
			
		||||
        ComponentType type = ComponentType.getComponentType(clazz);
 | 
			
		||||
        return clazz.cast(components[type.getId()].get(entity.getId()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void updateSystem(EntitySystem system, float dt) {
 | 
			
		||||
        for (Entity entity : entities) {
 | 
			
		||||
            if (!entity.isActive()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Check if this system is interested in this entity
 | 
			
		||||
            if ((entity.getComponentBits() & system.getTypeMask()) != system.getTypeMask()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If so, process the entity
 | 
			
		||||
            system.processEntity(entity, dt);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								core/src/com/me/common/ecs/Entity.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								core/src/com/me/common/ecs/Entity.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
			
		||||
package com.me.common.ecs;
 | 
			
		||||
 | 
			
		||||
public final class Entity {
 | 
			
		||||
 | 
			
		||||
    private static int nextId = 0;
 | 
			
		||||
 | 
			
		||||
    private Engine engine;
 | 
			
		||||
 | 
			
		||||
    private int id;
 | 
			
		||||
    private boolean active;
 | 
			
		||||
 | 
			
		||||
    private long componentBits;
 | 
			
		||||
 | 
			
		||||
    protected Entity(Engine engine) {
 | 
			
		||||
        this.engine = engine;
 | 
			
		||||
        this.active = false;
 | 
			
		||||
        this.id = nextId++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isActive() {
 | 
			
		||||
        return active;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void activate() {
 | 
			
		||||
        this.active = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void deactivate() {
 | 
			
		||||
        this.active = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public <T extends Component> T getComponent(Class<T> clazz) {
 | 
			
		||||
        return engine.getEntityComponent(this, clazz);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addComponent(Component component) {
 | 
			
		||||
        engine.addEntityComponent(this, component);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void removeComponent(Component component) {
 | 
			
		||||
        engine.removeEntityComponent(this, component);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void addComponentType(ComponentType type) {
 | 
			
		||||
        componentBits |= type.getBits();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void removeComponentType(ComponentType type) {
 | 
			
		||||
        componentBits &= ~type.getBits();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected long getComponentBits() {
 | 
			
		||||
        return componentBits;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								core/src/com/me/common/ecs/EntitySystem.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								core/src/com/me/common/ecs/EntitySystem.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
package com.me.common.ecs;
 | 
			
		||||
 | 
			
		||||
public abstract class EntitySystem {
 | 
			
		||||
 | 
			
		||||
    private long typeBits;
 | 
			
		||||
 | 
			
		||||
    public EntitySystem(Class<? extends Component>... components) {
 | 
			
		||||
        typeBits = ComponentType.getMaskBits(components);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return the type mask for this system. Only entities containing all component types specified
 | 
			
		||||
     * by the mask will be processed by it.
 | 
			
		||||
     */
 | 
			
		||||
    public long getTypeMask() {
 | 
			
		||||
        return typeBits;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void preProcessing() {}
 | 
			
		||||
 | 
			
		||||
    public abstract void processEntity(Entity entity, float dt);
 | 
			
		||||
 | 
			
		||||
    public void postProcessing() {}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user