304 lines
7.0 KiB
Plaintext
304 lines
7.0 KiB
Plaintext
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 don’t 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) {
|
||
}
|
||
})
|