tilebox and workorders started

stable
Ivory 2023-02-13 20:23:13 -05:00
parent 51d6c3db8b
commit c4bfd44cc9
26 changed files with 365 additions and 65 deletions

View File

@ -173,6 +173,30 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre
}
}
private final Vector2i getNextBoxDimensions() {
if(context.fixedSize) {
return context.box.dim.asInt();
} else {
return Vector2i.zero;
}
}
private LayoutStyle getDefaultLayoutStyle() {
if(context.fixedSize) {
if(context.horizontal) {
return LayoutStyle.shrink; // IDK if thats a good default...
} else {
return LayoutStyle.expandWidth;
}
} else {
if(context.horizontal) {
return LayoutStyle.normal;
} else {
return LayoutStyle.normal;
}
}
}
// === ELEMENTS ===
//
@ -247,39 +271,26 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre
}
protected boolean button(String text) {
return button(genButtonId(), text, false);
return button(genButtonId(), text, getDefaultLayoutStyle());
}
protected boolean button(String text, boolean expand) {
return button(genButtonId(), text, expand);
protected boolean button(String text, LayoutStyle style) {
return button(genButtonId(), text, style);
}
protected boolean button(String id, String text) {
return button(id, text, false);
return button(id, text, getDefaultLayoutStyle());
}
protected boolean button(String id, String text, boolean expand) {
int h = 32;
if(expand && context.fixedSize) {
h = (int) context.box.h;
}
int w = (int) context.box.w;
if(context.horizontal && !context.fixedSize) {
w = 100;
}
int x = (int) context.box.x;
int y = (int) context.box.y;
protected boolean button(String id, String text, LayoutStyle style) {
Vector2i position = getNextBoxLocation();
Vector2i availableSpace = getNextBoxDimensions();
if(!context.fixedSize) {
if(context.vertical()) {
y += (int) context.box.h;
} else {
x += (int) context.box.w;
}
}
Box buttonBox = new Box(x, y, w, h);
Box buttonBox = new Box(
position,
availableSpace.x == 0 ? style.width : (float) Math.min(style.width, availableSpace.x),
availableSpace.y == 0 ? style.height : (float) Math.min(style.height, availableSpace.y)
);
Button btn = getButton(id);
if(!context.hasRegisteredGuiArea) {
@ -287,8 +298,8 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre
}
btn.setText(text);
btn.setPosition(x, y);
btn.setSize(w, h);
btn.setPosition((int) buttonBox.x, (int) buttonBox.y);
btn.setSize((int) buttonBox.w, (int) buttonBox.h);
btn.setLayer(getCurrentLayer());
adjustBox(buttonBox.w, buttonBox.h);

View File

@ -0,0 +1,17 @@
package xyz.valnet.engine.graphics;
public class LayoutStyle {
public int width = 100, height = 32;
public static LayoutStyle normal = LayoutStyle.sized(100, 32);
public static LayoutStyle expand = LayoutStyle.sized(Integer.MAX_VALUE, Integer.MAX_VALUE);
public static LayoutStyle shrink = LayoutStyle.sized(0, 0);
public static LayoutStyle expandWidth = LayoutStyle.sized(Integer.MAX_VALUE, 32);
public static LayoutStyle sized(int w, int h) {
LayoutStyle btn = new LayoutStyle();
btn.width = w;
btn.height = h;
return btn;
}
}

View File

@ -143,4 +143,13 @@ public class Box implements Serializable {
public Box outset(float f) {
return new Box(x - f, y - f, w + 2 * f, h + 2 * f);
}
public Box quantize() {
return Box.fromPoints(
(float) Math.floor(x),
(float) Math.floor(y),
(float) Math.ceil(x2),
(float) Math.ceil(y2)
);
}
}

View File

@ -0,0 +1,76 @@
package xyz.valnet.engine.math;
import java.io.Serializable;
public class TileBox implements Serializable {
public final int x, y;
public final int w, h;
public final Vector2i topLeft;
@FunctionalInterface
public interface TileCallback {
public void apply(int x, int y);
}
public TileBox(int x, int y, int w, int h) {
if(w < 0) {
x += w + 1;
w *= -1;
}
if(h < 0) {
y += h + 1;
h *= -1;
}
this.x = x;
this.y = y;
this.w = w;
this.h = h;
topLeft = new Vector2i(x, y);
}
public TileBox(Vector2i pos, Vector2i dim) {
this(pos.x, pos.y, dim.x, dim.y);
}
public TileBox(int x, int y, Vector2i dim) {
this(x, y, dim.x, dim.y);
}
public TileBox(Vector2i pos, int w, int h) {
this(pos.x, pos.y, w, h);
}
public void forEach(TileCallback cb) {
for(int i = 0; i < w; i ++) {
for(int j = 0; j < h; j ++) {
cb.apply(x + i, y + j);
}
}
}
public static TileBox fromPoints(int x, int y, int x2, int y2) {
return new TileBox(
x <= x2 ? x : x2,
y <= y2 ? y : y2,
x <= x2 ? (x2 - x + 1) : (x - x2 + 1),
y <= y2 ? (y2 - y + 1) : (y - y2 + 1)
);
}
public static TileBox fromPoints(Vector2i a, int x2, int y2) {
return fromPoints(a.x, a.y, x2, y2);
}
public static TileBox fromPoints(int x, int y, Vector2i b) {
return fromPoints(x, y, b.x, b.y);
}
public static TileBox fromPoints(Vector2i a, Vector2i b) {
return fromPoints(a.x, a.y, b.x, b.y);
}
public Box asBox() {
return new Box(x, y, w, h);
}
}

View File

@ -6,6 +6,9 @@ public class Vector2i implements Serializable {
public int x, y;
public static Vector2i one = new Vector2i(1, 1);
public static Vector2i zero = new Vector2i(0, 0);
public Vector2i() {
x = 0;
y = 0;
@ -55,12 +58,16 @@ public class Vector2i implements Serializable {
return new Vector2i(x - 1, y);
}
public Box getTileBox() {
return new Box(x, y, 1, 1);
public TileBox getTileBox() {
return new TileBox(x, y, 1, 1);
}
public String toString() {
return "<" + x + ", " + y + ">";
}
public Vector2i sub(Vector2i b) {
return new Vector2i(this.x - b.x, this.y - b.y);
}
}

View File

@ -249,6 +249,12 @@ public abstract class SceneGraph implements IScene {
.collect(Collectors.toList()));
}
private ArrayList<GameObject> getTransientObjects() {
return new ArrayList<GameObject>(objects.stream()
.filter(go -> (go instanceof ITransient))
.collect(Collectors.toList()));
}
private void save() {
try {
FileOutputStream file = new FileOutputStream("SAVE_DATA.TXT");
@ -276,6 +282,7 @@ public abstract class SceneGraph implements IScene {
input.close();
file.close();
DebugTab.log("imported " + newObjects.size() + " objects");
dump(newObjects);
ArrayList<GameObject> toRemove = getNonTransientObjects();
for(GameObject obj : toRemove) {
@ -287,6 +294,12 @@ public abstract class SceneGraph implements IScene {
for(GameObject obj : newObjects) obj.link(this);
for(GameObject obj : newObjects) obj.addedToScene();
// transients that survive a scene load, should be
// re-connected to the new scene
for(GameObject obj : getTransientObjects()) {
obj.connect();
}
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -3,6 +3,7 @@ package xyz.valnet.hadean.designation;
import java.util.List;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.interfaces.BuildType;
import xyz.valnet.hadean.interfaces.IBuildable;
@ -12,7 +13,8 @@ public abstract class Designation<T extends ISelectable> extends GameObject impl
@Override
@SuppressWarnings("unchecked")
public void buildAt(Box box) {
public void buildAt(TileBox tileBox) {
Box box = tileBox.asBox();
Class<T> type = getType();
List<T> things = getAll(type);
for(ISelectable thing : things) {

View File

@ -8,6 +8,7 @@ import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.graphics.Sprite;
import xyz.valnet.engine.graphics.Tile9;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
@ -96,6 +97,10 @@ public class Camera extends GameObject implements ITransient, IMouseCaptureArea
return world2screen(pos.x, pos.y);
}
public final Vector2i world2screen(Vector2i pos) {
return world2screen(pos.x, pos.y);
}
public final Vector2f screen2world(float x, float y) {
return new Vector2f((x - screenWidth / 2 + focus.x * tileWidth) / tileWidth, (y - screenHeight / 2 + focus.y * tileWidth) / tileWidth);
}
@ -144,10 +149,15 @@ public class Camera extends GameObject implements ITransient, IMouseCaptureArea
Drawing.drawSprite(sprite, (int)(screenPos.x), (int)(screenPos.y), (int)(tileWidth * w), (int)(tileWidth * h));
}
@Deprecated
public final void draw(float layer, Tile9 sprite, Box box) {
draw(layer, sprite, box.x, box.y, box.w, box.h);
}
public final void draw(float layer, Tile9 sprite, TileBox box) {
draw(layer, sprite, box.x, box.y, box.w, box.h);
}
public final void draw(float layer, Tile9 sprite, float x, float y, float w, float h) {
Vector2i screenPos = world2screen(x, y);
Drawing.setLayer(layer + (((y + h) - minY) / (maxY - minY)));

View File

@ -4,6 +4,7 @@ import java.util.List;
import xyz.valnet.engine.App;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.engine.scenegraph.IMouseCaptureArea;
@ -60,13 +61,13 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea, ITransi
private void broadcastWorldCoords() {
Vector2i worldcoords = camera.getWorldMouse().asInt();
if(mouseDown) {
listener.update(Box.fromPoints(startingPoint, camera.getWorldMouse()));
listener.update(TileBox.fromPoints(startingPoint, camera.getWorldMouse().asInt()));
return;
}
if(type == BuildType.SINGLE && dimensions != null) {
listener.update(new Box(worldcoords, dimensions));
listener.update(new TileBox(worldcoords, dimensions));
} else {
listener.update(new Box(worldcoords, 1, 1));
listener.update(new TileBox(worldcoords, Vector2i.one));
}
}
@ -104,7 +105,7 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea, ITransi
startingPoint = camera.getWorldMouse().asInt();
mouseDown = true;
if(type == BuildType.SINGLE) {
listener.build(new Box(startingPoint, dimensions));
listener.build(new TileBox(startingPoint, dimensions));
}
}
}
@ -114,7 +115,7 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea, ITransi
if(button == 0 && active && mouseDown) {
mouseDown = false;
if(type == BuildType.AREA) {
listener.build(Box.fromPoints(camera.getWorldMouse(), startingPoint));
listener.build(TileBox.fromPoints(camera.getWorldMouse().asInt(), startingPoint));
}
}
}

View File

@ -9,8 +9,6 @@ import xyz.valnet.engine.App;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.engine.scenegraph.IMouseCaptureArea;
import xyz.valnet.engine.scenegraph.ITransient;

View File

@ -0,0 +1,45 @@
package xyz.valnet.hadean.gameobjects.jobs;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.interfaces.IWorkshop;
public class WorkOrder extends GameObject {
private boolean recurring = false;
private int count = 10;
private String name = "Cut Stone Blocks";
private IWorkshop shop = null;
public boolean getRecurring() {
return recurring;
}
public int getCount() {
return count;
}
public String getName() {
return name;
}
public void increaseCount() {
count ++;
}
public void decreaseCount() {
count --;
}
public WorkOrder setShop(IWorkshop shop) {
this.shop = shop;
return this;
}
public boolean validForShop(IWorkshop shop) {
return this.shop == null || this.shop == shop;
}
public boolean isSpecificToShop(IWorkshop shop) {
return this.shop != null && shop == this.shop;
}
}

View File

@ -0,0 +1,41 @@
package xyz.valnet.hadean.gameobjects.jobs;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.interfaces.IWorkshop;
public class WorkOrderManager extends GameObject {
private Set<WorkOrder> orders;
@Override
protected void start() {
super.start();
this.onAddGameObject((obj) -> {
if(obj instanceof WorkOrder) {
orders.add((WorkOrder) obj);
}
});
this.onRemoveGameObject((obj) -> {
if(obj instanceof WorkOrder) {
orders.remove((WorkOrder) obj);
}
});
}
@Override
protected void create() {
super.create();
orders = new HashSet<>();
}
public Set<WorkOrder> getOrders(IWorkshop shop) {
return orders.stream()
.filter((order) -> order.validForShop(shop))
.collect(Collectors.toSet());
}
}

View File

@ -14,7 +14,6 @@ import xyz.valnet.hadean.gameobjects.worldobjects.Tree;
import xyz.valnet.hadean.gameobjects.worldobjects.WorldObject;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Boulder;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Item;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Log;
import xyz.valnet.hadean.gameobjects.worldobjects.zones.FarmPlot;
import xyz.valnet.hadean.interfaces.IItemPredicate;
import xyz.valnet.hadean.interfaces.IPingable;

View File

@ -7,7 +7,6 @@ import xyz.valnet.engine.App;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.engine.scenegraph.ITransient;
import xyz.valnet.hadean.HadeanGame;

View File

@ -1,14 +1,18 @@
package xyz.valnet.hadean.gameobjects.ui;
import xyz.valnet.engine.graphics.LayoutStyle;
import xyz.valnet.engine.graphics.ImmediateUI;
import xyz.valnet.engine.scenegraph.ITransient;
import xyz.valnet.hadean.gameobjects.inputlayer.SelectionLayer;
import xyz.valnet.hadean.gameobjects.jobs.WorkOrder;
import xyz.valnet.hadean.gameobjects.jobs.WorkOrderManager;
import xyz.valnet.hadean.interfaces.IWorkshop;
public class WorkshopOrdersUI extends ImmediateUI implements ITransient {
private IWorkshop shop;
private SelectionLayer selectionLayer;
private WorkOrderManager manager;
public void open(IWorkshop shop) {
this.shop = shop;
@ -23,22 +27,67 @@ public class WorkshopOrdersUI extends ImmediateUI implements ITransient {
if(shop == null) return;
window(0, 0, 200, 300, () -> {
text("stuff");
var all = manager.getOrders(shop);
var specifics = all.stream()
.filter(workorder -> workorder.isSpecificToShop(shop))
.toList();
for(WorkOrder order : specifics) {
group(() -> {
text(order.getName());
space(4);
horizontal(() -> {
if(button("--", LayoutStyle.sized(32, 16))) {
order.decreaseCount();
}
space(4);
if(button("-", LayoutStyle.sized(16, 16))) {
order.decreaseCount();
}
space(4);
vertical(() -> {
// space(8);
text("" + order.getCount());
});
space(4);
if(button("+", LayoutStyle.sized(16, 16))) {
order.increaseCount();
}
space(4);
if(button("++", LayoutStyle.sized(32, 16))) {
order.increaseCount();
}
});
});
space(8);
}
text("" + (all.size() - specifics.size()) + " implicit general orders");
space(8);
if(button("New Order")) {
add(new WorkOrder().setShop(shop));
}
});
}
@Override
protected void connect() {
super.connect();
this.selectionLayer = get(SelectionLayer.class);
selectionLayer = get(SelectionLayer.class);
manager = get(WorkOrderManager.class);
}
@Override
protected void start() {
super.start();
this.selectionLayer.subscribe((selection) -> {
if(!selection.contains(shop)) {
if(shop == null) {
return;
} else if(selection.size() != 1) {
close();
} else if(selection.get(0) instanceof IWorkshop) {
shop = (IWorkshop) selection.get(0);
}
});
}

View File

@ -8,7 +8,7 @@ import java.util.Map;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.designation.CutTreesDesignation;
@ -37,7 +37,7 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IBuildLay
private BuildLayer buildLayer;
private Camera camera;
private Box renderBox = Box.none;
private TileBox renderBox = null;
private String selectedCategory = null;
@ -104,15 +104,19 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IBuildLay
if(!opened || selectedBuildable == null) return;
// draw the currently selected build item
Assets.flat.pushColor(Color.white);
Vector2i topLeft = camera.world2screen(renderBox.a);
Vector2i topLeft = camera.world2screen(renderBox.topLeft);
Assets.font.drawString(selectedBuildable.name, topLeft.x, topLeft.y - 20);
Assets.flat.swapColor(Color.white.withAlpha(0.6f));
camera.draw(Layers.BUILD_INTERACTABLE, Assets.selectionFrame, renderBox);
Assets.flat.swapColor(Color.white.withAlpha(0.35f));
for(int i = 0; i < renderBox.w; i ++) for(int j = 0; j < renderBox.h; j ++) {{
camera.draw(Layers.BUILD_INTERACTABLE, Assets.checkerBoard, renderBox.x + i, renderBox.y + j);
}}
Assets.flat.popColor();
}
@ -232,12 +236,12 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IBuildLay
}
@Override
public void update(Box box) {
public void update(TileBox box) {
renderBox = box;
}
@Override
public void build(Box box) {
public void build(TileBox box) {
if(selectedBuildable == null) return;
try {
IBuildable building = selectedBuildable.constructor.newInstance();

View File

@ -19,6 +19,8 @@ public class MenuTab extends Tab implements IPauser {
@Override
protected void gui() {
if(!shouldRender()) return;
window(1024 / 2 - width / 2, animate(-height - 50, 576 / 2 - height / 2), width, height, () -> {
text(" === Paused ===");
space(8);

View File

@ -1,7 +1,6 @@
package xyz.valnet.hadean.gameobjects.worldobjects;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.interfaces.IBuildable;
import xyz.valnet.hadean.interfaces.ISelectable;
@ -12,8 +11,8 @@ import xyz.valnet.hadean.util.detail.Detail;
public abstract class Buildable extends WorldObject implements IBuildable, ITileThing, ISelectable {
@Override
public void buildAt(Box box) {
setPosition(box);
public void buildAt(TileBox box) {
setPosition(box.asBox());
}
@Override

View File

@ -2,7 +2,6 @@ package xyz.valnet.hadean.gameobjects.worldobjects;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.hadean.gameobjects.jobs.Job;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.terrain.Tile;

View File

@ -5,7 +5,6 @@ import java.util.Set;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.math.Vector4i;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.gameobjects.Camera;

View File

@ -46,7 +46,9 @@ public class MasonWorkshop extends Construction implements IWorkshop {
@Override
public Action[] getActions() {
return new Action[] { OPEN_ORDERS };
if(isBuilt()) {
return new Action[] { OPEN_ORDERS };
} else return new Action[0];
}
@Override
@ -61,5 +63,15 @@ public class MasonWorkshop extends Construction implements IWorkshop {
super.connect();
ordersWindow = get(WorkshopOrdersUI.class);
}
@Override
public String getBuildTabName() {
return "Mason";
}
@Override
public String getBuildTabCategory() {
return "Workshops";
}
}

View File

@ -3,6 +3,7 @@ package xyz.valnet.hadean.gameobjects.worldobjects.zones;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.math.Vector4i;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
@ -15,7 +16,7 @@ public class FarmPlot extends Zone {
if(!visible) return;
Vector4i pos = getWorldPosition();
Assets.flat.pushColor(new Color(0.4f, 1f, 0.3f, 0.2f));
camera.draw(Layers.GROUND, Assets.whiteBox, pos.x, pos.y, pos.z, pos.w);
camera.draw(Layers.TILES, Assets.whiteBox, pos.x, pos.y, pos.z, pos.w);
Assets.flat.popColor();
}
@ -63,4 +64,8 @@ public class FarmPlot extends Zone {
@Override
public void onPlaced(Tile tile) {}
@Override
public ISelectable.Priority getSelectPriority() {
return ISelectable.Priority.LOW;
}
}

View File

@ -1,11 +1,11 @@
package xyz.valnet.hadean.interfaces;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.TileBox;
public interface IBuildLayerListener {
public void update(Box box);
public void build(Box box);
public void update(TileBox box);
public void build(TileBox box);
public void cancel();
}

View File

@ -1,11 +1,11 @@
package xyz.valnet.hadean.interfaces;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.engine.math.Vector2i;
public interface IBuildable {
public void buildAt(Box box);
public void buildAt(TileBox box);
public String getBuildTabCategory();
public BuildType getBuildType();

View File

@ -1,5 +1,5 @@
package xyz.valnet.hadean.interfaces;
public interface IWorkshop {
public interface IWorkshop extends ISelectable {
}

View File

@ -6,6 +6,7 @@ import xyz.valnet.hadean.gameobjects.ui.BottomBar;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.Clock;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.jobs.WorkOrderManager;
import xyz.valnet.hadean.gameobjects.ui.SelectionUI;
import xyz.valnet.hadean.gameobjects.ui.WorkshopOrdersUI;
import xyz.valnet.hadean.gameobjects.terrain.Terrain;
@ -44,16 +45,18 @@ public class GameScene extends SceneGraph {
objects.add(new Pawn());
}
objects.add(new WorkshopOrdersUI());
objects.add(new SelectionLayer());
objects.add(new SelectionUI());
objects.add(new WorkOrderManager());
objects.add(new ExclusivityManager());
objects.add(new SelectionLayer());
objects.add(new BuildLayer());
objects.add(new WorkshopOrdersUI());
objects.add(new SelectionUI());
objects.add(new HoverQuery());
objects.add(new BottomBar());
objects.add(new ExclusivityManager());
objects.add(new BuildTab());
objects.add(new JobBoardTab());
objects.add(new DebugTab());