Files
retro3d/examples/forest.ce
2025-12-21 10:39:05 -06:00

193 lines
4.3 KiB
Plaintext

// Forest example (Diablo-style camera) for lance3d
// Fixed 3/4 camera, WASD movement
// Press ESC to exit.
var time_mod = use('time')
var lance3d = use('core')
var math = use('math/radians')
// Meshes
var ground_mesh = null
var trunk_mesh = null
var canopy_mesh = null
var player_mesh = null
// Materials
var ground_mat = null
var trunk_mat = null
var canopy_mat_a = null
var canopy_mat_b = null
var player_mat = null
// Player state
var player = {
x: 0,
y: 0.5,
z: 0,
yaw: 0,
speed: 6.0
}
// Trees: array of {x, z, trunk_h, trunk_r, canopy_s, canopy_mat}
var trees = []
var num_trees = 80
var cam_offset = { x: 10, y: 12, z: 10 }
var last_time = 0
function _init() {
log.console("lance3d Forest (Diablo camera) Example")
log.console("WASD move, ESC exit")
lance3d.set_style("ps1")
lance3d.seed(1337)
lance3d.set_lighting({
sun_dir: [0.4, 1.0, 0.2],
sun_color: [1.0, 0.95, 0.9],
ambient: [0.35, 0.35, 0.40]
})
lance3d.set_fog({
enabled: true,
color: [0.55, 0.70, 0.90],
near: 40,
far: 160
})
// Create meshes
ground_mesh = lance3d.make_plane(220, 220)
trunk_mesh = lance3d.make_cube(1, 1, 1)
canopy_mesh = lance3d.make_cube(1, 1, 1)
player_mesh = lance3d.make_cube(1, 1, 1)
// Create materials
ground_mat = { paint: [0.12, 0.22, 0.10, 1.0], coverage: "opaque", face: "single", lamp: "lit" }
trunk_mat = { paint: [0.35, 0.23, 0.14, 1.0], coverage: "opaque", face: "single", lamp: "lit" }
canopy_mat_a = { paint: [0.11, 0.40, 0.18, 1.0], coverage: "opaque", face: "single", lamp: "lit" }
canopy_mat_b = { paint: [0.09, 0.33, 0.14, 1.0], coverage: "opaque", face: "single", lamp: "lit" }
player_mat = { paint: [0.85, 0.25, 0.20, 1.0], coverage: "opaque", face: "single", lamp: "lit" }
// Generate trees
for (var i = 0; i < num_trees; i++) {
var x = (lance3d.rand() - 0.5) * 90
var z = (lance3d.rand() - 0.5) * 90
trees.push({
x: x,
z: z,
trunk_h: lance3d.rand() * 3 + 2,
trunk_r: lance3d.rand() * 0.25 + 0.25,
canopy_s: lance3d.rand() * 1.0 + 1.5,
canopy_mat: lance3d.rand() < 0.5 ? canopy_mat_a : canopy_mat_b
})
}
last_time = time_mod.number()
frame()
}
function _update(dt) {
if (lance3d.key('escape')) {
$stop()
return
}
// Movement input
var forward = 0
var right = 0
if (lance3d.key('w')) forward += 1
if (lance3d.key('s')) forward -= 1
if (lance3d.key('d')) right -= 1
if (lance3d.key('a')) right += 1
if (forward != 0 || right != 0) {
// Update yaw based on movement direction
player.yaw = math.arc_tangent(forward, -right)
var fx = math.sine(player.yaw)
var fz = math.cosine(player.yaw)
var len = math.sqrt(fx * fx + fz * fz)
if (len > 0) {
fx /= len
fz /= len
}
player.x += fx * player.speed * dt
player.z += fz * player.speed * dt
}
}
function _draw() {
lance3d.clear(0.55, 0.70, 0.90, 1.0)
// Set up camera following player
lance3d.camera_perspective(55, 0.1, 300)
lance3d.camera_look_at(
player.x + cam_offset.x,
cam_offset.y,
player.z + cam_offset.z,
player.x, 0, player.z
)
// Draw ground
lance3d.draw_mesh(ground_mesh, null, ground_mat)
// Draw tree trunks
for (var i = 0; i < trees.length; i++) {
var tree = trees[i]
var trunk_transform = lance3d.trs_matrix(
tree.x, tree.trunk_h / 2, tree.z,
0, 0, 0, 1,
tree.trunk_r, tree.trunk_h, tree.trunk_r
)
lance3d.draw_mesh(trunk_mesh, trunk_transform, trunk_mat)
}
// Draw tree canopies
for (var i = 0; i < trees.length; i++) {
var tree = trees[i]
var canopy_transform = lance3d.trs_matrix(
tree.x, tree.trunk_h + tree.canopy_s / 2, tree.z,
0, 0, 0, 1,
tree.canopy_s, tree.canopy_s, tree.canopy_s
)
lance3d.draw_mesh(canopy_mesh, canopy_transform, tree.canopy_mat)
}
// Draw player
var q = lance3d.euler_to_quat(0, player.yaw, 0)
var player_transform = lance3d.trs_matrix(
player.x, player.y, player.z,
q.x, q.y, q.z, q.w,
0.7, 1.0, 0.7
)
lance3d.draw_mesh(player_mesh, player_transform, player_mat)
}
function frame() {
lance3d._begin_frame()
if (!lance3d._process_events()) {
log.console("Exiting...")
$stop()
return
}
var now = time_mod.number()
var dt = now - last_time
last_time = now
_update(dt)
_draw()
lance3d._end_frame()
$delay(frame, 1/60)
}
_init()