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 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();
}
}

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.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<WorldObject> 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 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
// --- 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) {

View File

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