Files
prosperon/examples/paladin.ce
2026-02-26 15:54:11 -06:00

304 lines
7.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

log.console("paladin game starting")
var time = use('time')
var random = use('random').random
var core = use('core')
var sprite = use('sprite')
var text2d = use('text2d')
var particles2d = use('particles2d')
var compositor = use('compositor')
var film2d = use('film2d')
var tilemap2d = use('tilemap2d')
var clay = use('clay')
var sprites = [] // Keep references for cleanup
var emitters = [] // Particle emitters
var bunnies = [] // Bouncing bunnies for Y-sort test
// Cameras
var world_camera = {
pos: {x: 2.5, y: 2.5},
width: 5,
height: 5,
anchor: {x: 0.5, y: 0.5}
}
var hud_camera = {
pos: {x: 0, y: 0},
width: 640,
height: 360,
anchor: {x: 0, y: 0}
}
// Group effects definition - THIS IS THE KEY PART
var group_effects = {
'bloom': {
effects: [{type: 'bloom', threshold: 0.1, intensity: 5, blur_passes: 1}]
},
'masked_fire': {
effects: [
{type: 'bloom', threshold: 0.1, intensity: 5, blur_passes: 0},
{type: 'mask', channel: 'alpha', mask_group: 'mask_text'}
]
},
'corner_fire': {
effects: [{type: 'mask', channel: 'alpha', mask_group: 'corner_mask'}]
}
}
// Compositor config - pure data
var compositor_config = {
clear: {r: 0, g: 0, b: 0, a: 1},
planes: [
{
name: 'world',
plane: 'world',
camera: world_camera,
resolution: {width: 500, height: 500},
presentation: 'letterbox',
clear: {r: 0.1, g: 0.1, b: 0.9, a: 1}
},
{
name: 'hud',
plane: 'hud',
camera: hud_camera,
resolution: {width: 640, height: 360},
presentation: 'integer_scale',
clear: {r: 0, g: 0, b: 0, a: 0},
layer_sort: {
'100': 'y' // Bunny layer uses Y-sort
}
},
{
name: 'ui',
plane: 'ui',
camera: hud_camera,
resolution: {width: 640, height: 360},
presentation: 'integer_scale',
clear: null
}
],
group_effects
}
function init_game() {
// Cleanup old sprites
var i = 0
for (i = 0; i < length(sprites); i++)
sprites[i].destroy()
sprites = []
emitters = []
bunnies = []
// World sprites
// Background Tilemap
var tiles = []
var x = 0
var y = 0
for (x = 0; x < 5; x++) {
tiles[x] = []
for (y = 0; y < 5; y++) {
tiles[x][y] = 'examples/tiles/terrain_dirt_cloud'
}
}
sprites[] = tilemap2d({
plane: 'world',
layer: 0,
tiles: tiles,
tile_width: 1,
tile_height: 1,
offset_x: 0,
offset_y: 0
})
sprites[] = sprite({
plane: 'world',
layer: 10,
image: 'examples/enemies/saw_a',
pos: {x: 1, y: 1},
anchor_x: 0.5,
})
// HUD sprites
sprites[] = text2d({
plane: 'hud',
groups: ['mask_text'], // Effect routing only
layer: 50,
text: 'PALADIN',
pos: {x: 640/2 - 270, y: 360/2},
font: 'examples/fonts/dos',
size: 150
})
var masked_fire = particles2d.create({
plane: 'hud',
groups: ['masked_fire'], // Effect routing only
layer: 40,
image: 'examples/tiles/fireball',
width: 40,
height: 40
})
sprites[] = masked_fire
emitters[] = particles2d.emitters.create({
pos: {x: 320, y: 180},
spawn_area: {width: 500, height: 200},
velocity: {x: 0, y: 50},
velocity_var: {x: 30, y: 30},
life: 2,
rate: 60,
scale: 3,
scale_var: 0.3,
color: {r: 1, g: 0.6, b: 0.2},
handle: masked_fire
})
sprites[] = sprite({
plane: 'hud',
groups: ['corner_mask'], // Effect routing only
layer: 60,
image: 'examples/tiles/fireball',
pos: {x: 600, y: 40},
width: 50,
height: 50,
anchor_x: 0.5,
anchor_y: 0.5
})
var corner_fire = particles2d.create({
plane: 'hud',
groups: ['corner_fire'], // Effect routing only
layer: 70,
image: 'examples/tiles/fireball',
width: 25,
height: 25
})
sprites[] = corner_fire
emitters[] = particles2d.emitters.create({
pos: {x: 600, y: 40},
spawn_area: {width: 30, height: 30},
velocity: {x: 0, y: 30},
velocity_var: {x: 20, y: 20},
life: 1.5,
rate: 10,
scale: 1,
scale_var: 0.2,
color: {r: 1, g: 0.5, b: 0.1},
handle: corner_fire
})
var bloom_fire = particles2d.create({
plane: 'hud',
groups: ['bloom'], // Effect routing only
layer: 80,
image: 'examples/tiles/fireball',
width: 48,
height: 48
})
sprites[] = bloom_fire
emitters[] = particles2d.emitters.create({
pos: {x: 100, y: 100},
spawn_area: {width: 50, height: 50},
velocity: {x: 100, y: 0},
velocity_var: {x: 40, y: 40},
life: 2.5,
rate: 12,
scale: 1.2,
scale_var: 0.4,
color: {r: 1, g: 0.8, b: 0.3},
handle: bloom_fire
})
// Bouncing bunnies - exactly two, big, bottom of screen, Y-sort layer 100
var bunny = null
for (i = 0; i < 2; i++) {
bunny = sprite({
plane: 'hud',
layer: 100, // This layer has Y-sort enabled
image: 'examples/bunny',
pos: {x: 320 + (i == 0 ? -20 : 20), y: 340},
width: 96,
height: 96,
anchor_x: 0.5,
})
bunny._base_y = 340
bunny._t = i * 0.7 // phase offset so they dont match
bunny._amp = 240 // bounce height in pixels
bunny._speed = 1 * random() // bounce speed
sprites[] = bunny
bunnies[] = bunny
}
log.console("World initialized - " + text(length(film2d.query({}))) + " drawables")
}
var json = use('json')
var last_time = 0
function update(dt) {
// Update all particle emitters
var i = 0
for (i = 0; i < length(emitters); i++)
particles2d.emitters.update(emitters[i], dt)
// Update bouncing bunnies
// Update bouncing bunnies (vertical bob only)
var b = null
var cycle = null
var u = null
for (i = 0; i < length(bunnies); i++) {
b = bunnies[i]
b._t += dt
// Bob between base_y and base_y - amp using triangle wave
cycle = (b._t * b._speed) % 2
u = cycle < 1 ? cycle : 2 - cycle
b.pos.y = b._base_y - u * b._amp
// Optional: if your Y-sort uses an explicit key, keep it in sync
// b.y_sort_key = b.pos.y
}
}
function render() {
// 1. Build Clay UI
var clay_tree = clay.layout(function() {
clay.vstack({gap: 10, padding: 20, align: 'center'}, function() {
clay.text("Clay UI Sample", {font_size: 24, color: {r:1,g:1,b:0}})
clay.image('examples/tiles/key_blue', {size:{width:32,height:32}, color: {r:1,g:0,b:0}})
clay.container({size: [200, 100], background_color: {r:0.2, g:0.2, b:0.2, a:0.8}, padding: 10}, function() {
clay.vstack(function() {
clay.text("List Item 1")
clay.text("List Item 2")
clay.text("List Item 3")
})
})
})
}, {width: 640, height: 360})
// Assign clay drawables to UI plane
compositor_config.planes[2].drawables = clay_tree.drawables
compositor_config.planes[2].clear = {r: 0, g: 0, b: 0, a: 0}
var plan = compositor.compile(compositor_config)
return compositor.execute(plan)
}
init_game()
core.start({
width: 1280,
height: 720,
title: "Paladin - Data Oriented",
framerate: 60,
update: update,
render: render,
editor: function(ui) {
}
})