Build 3D scenes in FXGL — enable experimental 3D mode, set up Camera3D with free-look or follow-entity modes, load OBJ models via AssetLoader, spawn 3D entities with Model3D views, create built-in 3D primitives (Cuboid, Prism, Torus, Cylinder, Cone), add a six- face Skybox, animate 3D entities with AnimationBuilder, implement 3D collision with PhysicsComponent3D, build a third-person camera, and create Minecraft-style voxel worlds. Use this skill when building a 3D game, a 3D level, a first-person or third- person view, a 3D model viewer, or any JavaFX 3D scene within FXGL.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Build 3D scenes in FXGL — enable experimental 3D mode, set up Camera3D with free-look or follow-entity modes, load OBJ models via AssetLoader, spawn 3D entities with Model3D views, create built-in 3D primitives (Cuboid, Prism, Torus, Cylinder, Cone), add a six- face Skybox, animate 3D entities with AnimationBuilder, implement 3D collision with PhysicsComponent3D, build a third-person camera, and create Minecraft-style voxel worlds. Use this skill when building a 3D game, a 3D level, a first-person or third- person view, a 3D model viewer, or any JavaFX 3D scene within FXGL.
@OverrideprotectedvoidinitSettings(GameSettings settings) {
settings.setWidth(1280);
settings.setHeight(720);
settings.setTitle("My 3D Game");
settings.setExperimental3D(true); // required for 3D scene
}
Camera3D Setup
@OverrideprotectedvoidinitGame() {
// Get the 3D cameraCamera3Dcamera= getGameScene().getCamera3D();
// Position (X right, Y up, Z toward viewer)
camera.getTransform().setTranslate(0, -5, -20);
// Field of view
camera.setFieldOfView(60);
// Clip planes — objects outside this range are not rendered
camera.setNearClip(0.1);
camera.setFarClip(5000.0);
}
// Six face images: front, back, top, bottom, left, right// All must be the same size (power-of-two resolution recommended)import com.almasb.fxgl.scene3d.Skybox;
// Place face images in assets/textures/skybox/Skyboxskybox=newSkybox(
getAssetLoader().loadImage("skybox/front.png"),
getAssetLoader().loadImage("skybox/back.png"),
getAssetLoader().loadImage("skybox/top.png"),
getAssetLoader().loadImage("skybox/bottom.png"),
getAssetLoader().loadImage("skybox/left.png"),
getAssetLoader().loadImage("skybox/right.png"),
500.0// skybox size — must exceed far clip to avoid visible edges
);
getGameScene().addGameView(skybox);
// Skybox automatically follows the camera — no manual update needed
Lighting
@OverrideprotectedvoidinitGame() {
// Ambient light — illuminates everything equallyAmbientLightambient=newAmbientLight(Color.color(0.3, 0.3, 0.3));
// Point light — illuminates from a positionPointLightpointLight=newPointLight(Color.WHITE);
pointLight.setTranslateX(0);
pointLight.setTranslateY(-10);
pointLight.setTranslateZ(-5);
// Add lights to the scene's 3D root
getGameScene().getRoot3D().getChildren().addAll(ambient, pointLight);
}
Animating 3D Entities
// Rotate a 3D entity around the Y axis
animationBuilder()
.duration(Duration.seconds(3))
.repeatInfinitely()
.rotate(planetEntity)
.from(0)
.to(360)
.axis(newPoint3D(0, 1, 0)) // Y axis
.buildAndPlay();
// Translate along Z axis (move toward viewer)
animationBuilder()
.duration(Duration.seconds(2))
.interpolator(Interpolators.SMOOTH.EASE_BOTH())
.translate(entity)
.from(newPoint3D(0, 0, -50))
.to(newPoint3D(0, 0, 0))
.buildAndPlay();
// 3D uses FXGL's own axis-aligned bounding box intersection (not Box2D)// Entities need BoundingBoxComponent populated with a 3D boxEntityprojectile= entityBuilder()
.at(x, y, z)
.bbox(BoundingShape.box3D(0.5, 0.5, 0.5))
.collidable()
.with(newProjectileComponent(direction, 20))
.buildAndAttach();
Entitytarget= entityBuilder()
.at(tx, ty, tz)
.bbox(BoundingShape.box3D(2, 2, 2))
.collidable()
.build();
onCollisionBegin(EntityType.BULLET, EntityType.ENEMY, (bullet, enemy) -> {
bullet.removeFromWorld();
enemy.getComponent(HPComponent.class).damage(25);
});
Minecraft-Style Voxel World
privatestaticfinalintTILE=1; // 1 unit per voxelprivatevoidbuildChunk(int[][][] grid) {
for (intx=0; x < grid.length; x++) {
for (inty=0; y < grid[x].length; y++) {
for (intz=0; z < grid[x][y].length; z++) {
if (grid[x][y][z] == 0) continue;
Cuboidcube=newCuboid(TILE, TILE, TILE);
cube.setMaterial(getMaterialForType(grid[x][y][z]));
entityBuilder()
.at(x * TILE, y * TILE, z * TILE)
.view(cube)
.bbox(BoundingShape.box3D(TILE, TILE, TILE))
.collidable()
.buildAndAttach();
}
}
}
}
// Place / remove voxel on click via raycastingprivatevoidplaceVoxel(MouseEvent e) {
// Cast ray from camera through screen point — manual intersection test// FXGL 3D: use PickResult from JavaFX scene picking
getGameScene().getRoot3D().addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
PickResultpick= event.getPickResult();
if (pick.getIntersectedNode() != null) {
Point3Dpoint= pick.getIntersectedPoint();
// Snap to grid and spawn new blockintgx= (int) Math.round(point.getX());
intgy= (int) Math.round(point.getY());
intgz= (int) Math.round(point.getZ());
spawnBlock(gx, gy, gz);
}
});
}
Gotchas
setExperimental3D(true) is required — without it the getGameScene().getCamera3D()
call returns null and 3D entities are not rendered in 3D space.
JavaFX 3D requires hardware acceleration — on headless servers or older GPUs,
3D rendering falls back to software rendering, which is extremely slow. Test early.
Y axis is inverted vs. 2D — in JavaFX 3D, Y increases downward in 2D but the 3D
coordinate system has Y pointing up. Camera moves use the 3D convention.
Box2D physics is 2D only — PhysicsComponent with Box2D does not work in 3D space.
Use manual bounding box collision or JavaFX 3D pick events for 3D collision.
OBJ loading requires MTL adjacent to OBJ — FXGL's OBJ loader resolves material files
relative to the OBJ path. Both files must be in assets/models/.
Skybox size must exceed camera.setFarClip() — if the skybox cube is smaller than the
far clip, you'll see black corners where the skybox ends.
animationBuilder().rotate() on 3D entities needs axis(new Point3D(x,y,z)) — the 2D
single-angle form only rotates around Z. Pass the axis explicitly for 3D rotation.
PointLight scope in JavaFX 3D — by default a PointLight illuminates everything in the
scene. Use light.setScope() to restrict illumination to specific nodes if you have many lights.
Voxel worlds with thousands of cubes — each Cuboid is a separate JavaFX Node. Above
~10,000 nodes, JavaFX's scene graph slows significantly. Use instanced rendering or chunk
culling (only spawn visible chunks).