
agents.spencerSchumann.Scene Maven / Gradle / Ivy
package agents.spencerSchumann;
import java.util.ArrayList;
import engine.core.MarioForwardModel;
/**
* @author Spencer Schumann
*/
public class Scene {
public ArrayList floors = new ArrayList();
public ArrayList walls = new ArrayList();
public ArrayList ceilings = new ArrayList();
public ArrayList bumpables = new ArrayList();
public ArrayList enemyEmitters = new ArrayList();
public long constructTime;
// The extreme top left corner of the scene, in world coordinates
public float originX;
public float originY;
@Override
public Scene clone() {
// TODO: I should really be calling s.clone() here; see Object.clone().
Scene s = new Scene();
s.update(this);
return s;
}
public void update(Scene scene) {
// TODO: no deep copy of edges; will this cause problems?
clearEdges();
add(scene);
originX = scene.originX;
originY = scene.originY;
}
public void clearEdges() {
floors.clear();
walls.clear();
ceilings.clear();
bumpables.clear();
enemyEmitters.clear();
}
private Scene() {
}
public Scene(float originX, float originY) {
this.originX = originX;
this.originY = originY;
}
public Scene(MarioForwardModel model, int[][] scene) {
long startTime = System.nanoTime();
float[] marioPos = model.getMarioFloatPos();
originX = (float) Math.floor(marioPos[0] / 16.0f) * 16.0f - (model.obsGridWidth / 2) * 16.0f;
originY = (float) Math.floor(marioPos[1] / 16.0f) * 16.0f - (model.obsGridHeight / 2) * 16.0f;
boolean[][] visited = new boolean[scene.length][scene[0].length];
int x, y;
for (x = 0; x < scene.length; x++) {
for (y = 0; y < scene[x].length; y++) {
int tile = scene[x][y];
if (tile == Tiles.COIN) {
// TODO
} else if (!visited[y][x]) {
if (Tiles.isWall(tile)) {
Scene block = new Scene(originX, originY);
block.expandWall(scene, visited, x, y);
add(block);
} else if (tile == Tiles.JUMPTHROUGH) {
Scene ledge = new Scene(originX, originY);
ledge.expandLedge(scene, visited, x, y);
add(ledge);
}
}
}
}
// TODO: update bumpables and EnemyEmitters, if not already done
constructTime = System.nanoTime() - startTime;
}
// Expand vectorized block from an initial starting point, and mark
// all tiles that are part of this block as visited
private void expandWall(int[][] scene, boolean[][] visited, int x, int y) {
if (visited[y][x]) {
return;
}
visited[y][x] = true;
// left side
if (x > 0) {
if (Tiles.isWall(scene[x - 1][y])) {
expandWall(scene, visited, x - 1, y);
} else {
walls.add(new Edge(originX + x * 16.0f, originY + y * 16.0f,
originX + x * 16.0f, originY + (y + 1) * 16.0f));
}
}
// right side
if (x < scene.length - 1) {
if (Tiles.isWall(scene[x + 1][y])) {
expandWall(scene, visited, x + 1, y);
} else {
walls.add(new Edge(originX + (x + 1) * 16.0f, originY + y * 16.0f,
originX + (x + 1) * 16.0f, originY + (y + 1) * 16.0f));
}
}
// top side
if (y > 0) {
if (Tiles.isWall(scene[x][y - 1])) {
expandWall(scene, visited, x, y - 1);
} else {
floors.add(new Edge(originX + x * 16.0f, originY + y * 16.0f,
originX + (x + 1) * 16.0f, originY + y * 16.0f));
}
}
// bottom side
if (y < scene[x].length - 1) {
if (Tiles.isWall(scene[x][y + 1])) {
expandWall(scene, visited, x, y + 1);
} else {
ceilings.add(new Edge(originX + x * 16.0f, originY + (y + 1) * 16.0f,
originX + (x + 1) * 16.0f, originY + (y + 1) * 16.0f));
}
}
coalesce();
}
// Expand ledge
private void expandLedge(int[][] scene, boolean[][] visited, int x, int y) {
if (visited[y][x]) {
return;
}
visited[y][x] = true;
int startx = x;
int endx = x;
// Find left side of ledge
while (startx > 0 && scene[startx - 1][y] == Tiles.JUMPTHROUGH) {
startx--;
visited[y][startx] = true;
}
// Find right side of ledge
while (endx < scene.length - 1 && scene[endx + 1][y] == Tiles.JUMPTHROUGH) {
endx++;
visited[y][endx] = true;
}
floors.add(new Edge(originX + startx * 16.0f, originY + y * 16.0f,
originX + (endx + 1) * 16.0f, originY + y * 16.0f));
}
// Coalesce adjacent edges of the same type into one
private void coalesce() {
// TODO
// Note: should I have a contiguous ceiling, or break it up for
// each special?
coalesce(walls);
coalesce(ceilings);
coalesce(floors);
coalesce(enemyEmitters);
// NOTE: bumpables shouldn't be coalesced.
}
private void coalesce(ArrayList edges) {
// Super stupid way for now.
// TODO: optimize. Without coalesce, everything runs in about
// 60 microseconds max. With coalesce, times get up to around 6
// milliseconds. That's a large chunk of the allotted 40 ms to
// be wasting on this.
boolean foundOne = true;
while (foundOne) {
foundOne = false;
for (Edge a : edges) {
for (Edge b : edges) {
if (a == b) {
continue;
}
foundOne = true;
if (a.x1 == b.x1 && a.y1 == b.y1) {
// Overlapping? Something is wrong...
throw new RuntimeException("Overlapping edges!");
} else if (a.x1 == b.x2 && a.y1 == b.y2) {
a.x1 = b.x1;
a.y1 = b.y1;
} else if (a.x2 == b.x1 && a.y2 == b.y1) {
a.x2 = b.x2;
a.y2 = b.y2;
} else {
foundOne = false;
}
if (foundOne) {
edges.remove(b);
break;
}
}
if (foundOne) {
break;
}
}
}
}
// Add the edges in the subscene to this scene
private void add(Scene subscene) {
floors.addAll(subscene.floors);
walls.addAll(subscene.walls);
ceilings.addAll(subscene.ceilings);
bumpables.addAll(subscene.bumpables);
enemyEmitters.addAll(subscene.enemyEmitters);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy