implement world factory

This commit is contained in:
2025-11-14 23:18:16 +01:00
parent 7a599ab1e5
commit 0c726ed416
4 changed files with 143 additions and 29 deletions

View File

@@ -18,13 +18,16 @@ public class ModelLibrary {
public final Model groundModel; public final Model groundModel;
public final Model unitCubeModel; public final Model unitCubeModel;
// new: town-related primitives
public final Model houseBlockModel;
public final Model pathTileModel;
public ModelLibrary() { public ModelLibrary() {
// ground texture // --- ground texture + model (unchanged) ---
groundTexture = new Texture(Gdx.files.internal("textures/paving.png")); groundTexture = new Texture(Gdx.files.internal("textures/paving.png"));
groundTexture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest); groundTexture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
groundTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat); groundTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
// ground model (32x32 plane)
float halfSize = 32f; float halfSize = 32f;
float tileScale = 16f; float tileScale = 16f;
@@ -52,17 +55,48 @@ public class ModelLibrary {
); );
groundModel = builder.end(); groundModel = builder.end();
// a generic 2x2x2 cube model (can be reused for buildings, crates, etc.) // generic 2x2x2 cube
unitCubeModel = builder.createBox( unitCubeModel = builder.createBox(
2f, 2f, 2f, 2f, 2f, 2f,
new Material(ColorAttribute.createDiffuse(1f, 1f, 1f, 1f)), new Material(ColorAttribute.createDiffuse(1f, 1f, 1f, 1f)),
VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal 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() { public void dispose() {
groundModel.dispose(); groundModel.dispose();
unitCubeModel.dispose(); unitCubeModel.dispose();
houseBlockModel.dispose();
pathTileModel.dispose();
groundTexture.dispose(); groundTexture.dispose();
} }
} }

View File

@@ -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;
}
}

View File

@@ -2,6 +2,7 @@ package wtf.beatrice.retrorender.engine;
import com.badlogic.gdx.graphics.g3d.Environment; import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.ModelBatch; 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.Matrix4;
import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.math.Vector3;
@@ -15,6 +16,7 @@ public class World3D {
private final WorldObject ground; private final WorldObject ground;
private final List<WorldObject> objects = new ArrayList<>(); private final List<WorldObject> objects = new ArrayList<>();
private final TownFactory townFactory;
private final Vector3 tmpWorld = new Vector3(); private final Vector3 tmpWorld = new Vector3();
private final Vector3 tmpFeet = new Vector3(); private final Vector3 tmpFeet = new Vector3();
@@ -29,43 +31,76 @@ public class World3D {
public World3D(ModelLibrary models) { public World3D(ModelLibrary models) {
this.models = models; this.models = models;
this.townFactory = new TownFactory(models);
// --- ground --- // --- ground ---
ground = new WorldObject( ground = new WorldObject(
"ground", "ground",
new com.badlogic.gdx.graphics.g3d.ModelInstance(models.groundModel), new ModelInstance(models.groundModel),
Collider.none() // treat plane as baseHeight = 0, not as a collider Collider.none()
); );
ground.staticObject = true; ground.staticObject = true;
// --- some cubes (temporary test geometry) --- // --- build a tiny town layout instead of random cubes ---
addCube("center", 0f, 1f, 0f); buildTestTown();
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 pillars 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
} }
private WorldObject addCube(String id, float x, float y, float z) { private void addObject(WorldObject obj) {
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;
objects.add(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) { public void update(float delta) {
// here you can update objects that animate / move // here you can update objects that animate / move
for (WorldObject obj : objects) { for (WorldObject obj : objects) {

View File

@@ -21,7 +21,6 @@ public class WorldObject {
} }
public void update(float delta) { public void update(float delta) {
instance.transform.rotate(Vector3.Y, delta * 20f);
// default: do nothing // default: do nothing
// you can subclass or add strategies later for rotating, animating, AI, etc. // you can subclass or add strategies later for rotating, animating, AI, etc.
} }