From 0c726ed416c4604cae2dc72db2f2b8074cc2507b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beatrice=20Dellac=C3=A0?= Date: Fri, 14 Nov 2025 23:18:16 +0100 Subject: [PATCH] implement world factory --- .../retrorender/engine/ModelLibrary.java | 40 ++++++++- .../retrorender/engine/TownFactory.java | 46 ++++++++++ .../beatrice/retrorender/engine/World3D.java | 85 +++++++++++++------ .../retrorender/engine/WorldObject.java | 1 - 4 files changed, 143 insertions(+), 29 deletions(-) create mode 100644 core/src/main/java/wtf/beatrice/retrorender/engine/TownFactory.java diff --git a/core/src/main/java/wtf/beatrice/retrorender/engine/ModelLibrary.java b/core/src/main/java/wtf/beatrice/retrorender/engine/ModelLibrary.java index 4bd5ff4..e0579af 100644 --- a/core/src/main/java/wtf/beatrice/retrorender/engine/ModelLibrary.java +++ b/core/src/main/java/wtf/beatrice/retrorender/engine/ModelLibrary.java @@ -18,13 +18,16 @@ public class ModelLibrary { public final Model groundModel; public final Model unitCubeModel; + // new: town-related primitives + public final Model houseBlockModel; + public final Model pathTileModel; + public ModelLibrary() { - // ground texture + // --- ground texture + model (unchanged) --- groundTexture = new Texture(Gdx.files.internal("textures/paving.png")); groundTexture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest); groundTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat); - // ground model (32x32 plane) float halfSize = 32f; float tileScale = 16f; @@ -52,17 +55,48 @@ public class ModelLibrary { ); groundModel = builder.end(); - // a generic 2x2x2 cube model (can be reused for buildings, crates, etc.) + // generic 2x2x2 cube unitCubeModel = builder.createBox( 2f, 2f, 2f, new Material(ColorAttribute.createDiffuse(1f, 1f, 1f, 1f)), VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal ); + + // simple “blocky house” primitive: 4x3x4 + houseBlockModel = builder.createBox( + 4f, 3f, 4f, + new Material(ColorAttribute.createDiffuse(0.9f, 0.8f, 0.7f, 1f)), + VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal + ); + + // flat path tile (2D quad slightly above ground) + builder.begin(); + Material pathMat = new Material( + ColorAttribute.createDiffuse(0.6f, 0.6f, 0.6f, 1f) + ); + MeshPartBuilder pathMpb = builder.part( + "pathTile", + GL20.GL_TRIANGLES, + VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal, + pathMat + ); + float tHalf = 1f; // tile size 4x4 + float y = 0.01f; // just above ground to avoid z-fighting + pathMpb.rect( + -tHalf, y, tHalf, + tHalf, y, tHalf, + tHalf, y, -tHalf, + -tHalf, y, -tHalf, + 0f, 1f, 0f + ); + pathTileModel = builder.end(); } public void dispose() { groundModel.dispose(); unitCubeModel.dispose(); + houseBlockModel.dispose(); + pathTileModel.dispose(); groundTexture.dispose(); } } diff --git a/core/src/main/java/wtf/beatrice/retrorender/engine/TownFactory.java b/core/src/main/java/wtf/beatrice/retrorender/engine/TownFactory.java new file mode 100644 index 0000000..482c090 --- /dev/null +++ b/core/src/main/java/wtf/beatrice/retrorender/engine/TownFactory.java @@ -0,0 +1,46 @@ +package wtf.beatrice.retrorender.engine; + +import com.badlogic.gdx.graphics.g3d.ModelInstance; + +public class TownFactory { + + private final ModelLibrary models; + + public TownFactory(ModelLibrary models) { + this.models = models; + } + + public WorldObject createHouse(String id, float x, float z) { + ModelInstance inst = new ModelInstance(models.houseBlockModel); + // houseBlockModel is 4x3x4 → center at y=1.5 + inst.transform.setToTranslation(x, 1.5f, z); + + // collider roughly matches the visual: halfExtents = (2,1.5,2) + Collider col = Collider.box(2f, 1.5f, 2f); + + WorldObject obj = new WorldObject(id, inst, col); + obj.staticObject = true; + obj.castsShadow = true; + return obj; + } + + public WorldObject createCrate(String id, float x, float z) { + ModelInstance inst = new ModelInstance(models.unitCubeModel); + // unit cube is 2x2x2 → center at y=1 + inst.transform.setToTranslation(x, 1f, z); + + Collider col = Collider.box(1f, 1f, 1f); + WorldObject obj = new WorldObject(id, inst, col); + obj.staticObject = true; + return obj; + } + + public WorldObject createPathTile(String id, float x, float z) { + ModelInstance inst = new ModelInstance(models.pathTileModel); + inst.transform.setToTranslation(x, 0f, z); + // purely visual, no collider + WorldObject obj = new WorldObject(id, inst, Collider.none()); + obj.staticObject = true; + return obj; + } +} diff --git a/core/src/main/java/wtf/beatrice/retrorender/engine/World3D.java b/core/src/main/java/wtf/beatrice/retrorender/engine/World3D.java index 6709ca2..7ddec9a 100644 --- a/core/src/main/java/wtf/beatrice/retrorender/engine/World3D.java +++ b/core/src/main/java/wtf/beatrice/retrorender/engine/World3D.java @@ -2,6 +2,7 @@ package wtf.beatrice.retrorender.engine; import com.badlogic.gdx.graphics.g3d.Environment; import com.badlogic.gdx.graphics.g3d.ModelBatch; +import com.badlogic.gdx.graphics.g3d.ModelInstance; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Vector3; @@ -15,6 +16,7 @@ public class World3D { private final WorldObject ground; private final List objects = new ArrayList<>(); + private final TownFactory townFactory; private final Vector3 tmpWorld = new Vector3(); private final Vector3 tmpFeet = new Vector3(); @@ -29,43 +31,76 @@ public class World3D { public World3D(ModelLibrary models) { this.models = models; + this.townFactory = new TownFactory(models); // --- ground --- ground = new WorldObject( "ground", - new com.badlogic.gdx.graphics.g3d.ModelInstance(models.groundModel), - Collider.none() // treat plane as baseHeight = 0, not as a collider + new ModelInstance(models.groundModel), + Collider.none() ); ground.staticObject = true; - // --- some cubes (temporary test geometry) --- - addCube("center", 0f, 1f, 0f); - addCube("cube-ne", 8f, 1f, 8f); - addCube("cube-nw", -8f, 1f, 8f); - addCube("cube-se", 8f, 1f, -8f); - addCube("cube-sw", -8f, 1f, -8f); - - WorldObject pillar = addCube("pillar", 0f, 3f, -10f); - // scale pillar’s transform (purely visual) - pillar.instance.transform - .setToScaling(1f, 3f, 1f) - .translate(0f, 3f, -10f); - // collider is still 1x1x1, you can adjust collider.halfExtents here if needed + // --- build a tiny town layout instead of random cubes --- + buildTestTown(); } - private WorldObject addCube(String id, float x, float y, float z) { - var instance = new com.badlogic.gdx.graphics.g3d.ModelInstance(models.unitCubeModel); - instance.transform.setToTranslation(x, y, z); - - // cube is 2x2x2, so half extents = 1 - Collider collider = Collider.box(1f, 1f, 1f); - - WorldObject obj = new WorldObject(id, instance, collider); - obj.staticObject = true; + private void addObject(WorldObject obj) { objects.add(obj); - return obj; } + private void buildTestTown() { + float tileSize = 2f; // world units per “map tile” + + // Simple 7x7 layout: + // H = house, P = path, . = empty + String[] layout = { + ".............", + "..H.C.....H..", + "..P.......P..", + "..P.......P..", + "..P.......P..", + "..P.......P..", + "..P.......P..", + "..P.......P..", + "..H.......H..", + "............." + }; + + int rows = layout.length; + int cols = layout[0].length(); + + float offsetX = -(cols - 1) * tileSize * 0.5f; + float offsetZ = -(rows - 1) * tileSize * 0.5f; + + for (int row = 0; row < rows; row++) { + String line = layout[row]; + for (int col = 0; col < cols; col++) { + char c = line.charAt(col); + + float x = offsetX + col * tileSize; + float z = offsetZ + row * tileSize; + + switch (c) { + case 'H': + addObject(townFactory.createHouse("house_" + row + "_" + col, x, z)); + break; + case 'P': + addObject(townFactory.createPathTile("path_" + row + "_" + col, x, z)); + break; + case 'C': + addObject(townFactory.createCrate("crate_" + row + "_" + col, x, z)); + default: + break; + } + } + } + + // maybe put a crate in the middle + + } + + public void update(float delta) { // here you can update objects that animate / move for (WorldObject obj : objects) { diff --git a/core/src/main/java/wtf/beatrice/retrorender/engine/WorldObject.java b/core/src/main/java/wtf/beatrice/retrorender/engine/WorldObject.java index 8cdc66b..59bcad1 100644 --- a/core/src/main/java/wtf/beatrice/retrorender/engine/WorldObject.java +++ b/core/src/main/java/wtf/beatrice/retrorender/engine/WorldObject.java @@ -21,7 +21,6 @@ public class WorldObject { } public void update(float delta) { - instance.transform.rotate(Vector3.Y, delta * 20f); // default: do nothing // you can subclass or add strategies later for rotating, animating, AI, etc. }