fix examples

This commit is contained in:
2026-02-25 16:58:06 -06:00
parent 250f535abe
commit 29818b1b0b
16 changed files with 354 additions and 119 deletions

View File

@@ -59,7 +59,7 @@ for (i = 0; i < 100; i++) {
random.random() * GH
)
}
count_label.text = "Bunnies: " + length(bunnies)
count_label.text = "Bunnies: " + text(length(bunnies))
// Mouse position tracking
var mouse_x = GW / 2, mouse_y = GH / 2
@@ -85,12 +85,12 @@ core.start({
update: function(dt) {
// Spawn bunnies while clicking
var down = input.player1().down()
var si = 0
if (down.spawn) {
var si = 0
for (si = 0; si < 50; si++) {
add_bunny(mouse_x, mouse_y)
}
count_label.text = "Bunnies: " + length(bunnies)
count_label.text = "Bunnies: " + text(length(bunnies))
}
// Update all bunnies
@@ -112,7 +112,7 @@ core.start({
frame_count++
fps_timer += dt
if (fps_timer >= 1) {
fps_label.text = "FPS: " + frame_count
fps_label.text = "FPS: " + text(frame_count)
frame_count = 0
fps_timer -= 1
}

View File

@@ -3,16 +3,16 @@ var camera = use('camera')
var compositor = use('compositor')
var input = use('input')
var shape = use('shape2d')
var sprite_factory = use('sprite')
var text2d = use('text2d')
var Grid = use('grid')
var MovementSystem = use('movement').MovementSystem
var startingPos = use('pieces').startingPosition
var rules = use('rules')
var Grid = use('examples/chess/grid')
var MovementSystem = use('examples/chess/movement')
var startingPos = use('examples/chess/pieces').startingPosition
var rules = use('examples/chess/rules')
var S = 60
var GW = S * 8, GH = S * 8
var move_history = []
var game_cam = camera.make({width: GW, height: GH, pos: {x: GW / 2, y: GH / 2}})
var hud_cam = camera.make({width: GW, height: GH, pos: {x: GW / 2, y: GH / 2}})
@@ -38,11 +38,11 @@ var select_color = {r: 1, g: 0.84, b: 0, a: 1}
var valid_color = {r: 0.6, g: 0.8, b: 0.4, a: 1}
var board_shapes = []
var bx = 0, by = 0
var bx = 0, by = 0, row = null, col = null
for (by = 0; by < 8; by++) {
var row = []
row = []
for (bx = 0; bx < 8; bx++) {
var col = ((bx + by) & 1) ? dark_color : light_color
col = ((bx + by) & 1) ? dark_color : light_color
push(row, shape.rect({
pos: {x: bx * S + S / 2, y: by * S + S / 2},
width: S, height: S,
@@ -53,17 +53,25 @@ for (by = 0; by < 8; by++) {
push(board_shapes, row)
}
// Piece sprites — one per piece, keyed by piece object
var piece_sprites = {}
// Piece letter abbreviations
var piece_letter = {
king: "K", queen: "Q", rook: "R",
bishop: "B", knight: "N", pawn: "P"
}
var white_color = {r: 1, g: 1, b: 1, a: 1}
var black_color = {r: 0.1, g: 0.1, b: 0.1, a: 1}
// Piece labels — one per piece, keyed by piece id
var piece_labels = {}
var piece_id = 0
grid.each(function(p) {
piece_id++
p._id = piece_id
piece_sprites[piece_id] = sprite_factory({
image: p.sprite,
piece_labels[text(piece_id)] = text2d({
text: piece_letter[p.kind],
pos: {x: p.coord[0] * S + S / 2, y: p.coord[1] * S + S / 2},
width: S, height: S,
anchor_x: 0.5, anchor_y: 0.5,
size: 36,
color: (p.colour == 'white') ? white_color : black_color,
plane: 'game', layer: 1
})
})
@@ -86,17 +94,27 @@ function update_status() {
}
function reset_board_colors() {
var x = 0, y = 0
var x = 0, y = 0, col = null
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++) {
var col = ((x + y) & 1) ? dark_color : light_color
col = ((x + y) & 1) ? dark_color : light_color
board_shapes[y][x].fill = {r: col.r, g: col.g, b: col.b, a: col.a}
}
}
}
var hover_color = {r: 0.8, g: 0.85, b: 0.6, a: 1}
function highlight_selection() {
reset_board_colors()
// Hover highlight
if (hover_gx >= 0 && hover_gx < 8 && hover_gy >= 0 && hover_gy < 8) {
board_shapes[hover_gy][hover_gx].fill = {
r: hover_color.r, g: hover_color.g, b: hover_color.b, a: hover_color.a
}
}
if (!selectPos) return
// Highlight selected square
@@ -105,9 +123,9 @@ function highlight_selection() {
}
// Highlight valid moves
var i = 0
var i = 0, m = null
for (i = 0; i < length(validMoves); i++) {
var m = validMoves[i]
m = validMoves[i]
board_shapes[m[1]][m[0]].fill = {
r: valid_color.r, g: valid_color.g, b: valid_color.b, a: valid_color.a
}
@@ -132,22 +150,24 @@ function compute_valid_moves(from) {
}
function sync_piece_sprites() {
var keys = array(piece_labels)
var i = 0
for (i = 0; i < length(keys); i++) {
piece_labels[keys[i]].visible = false
}
grid.each(function(p) {
var spr = piece_sprites[p._id]
if (!spr) return
if (p.captured) {
spr.visible = false
} else {
spr.pos.x = p.coord[0] * S + S / 2
spr.pos.y = p.coord[1] * S + S / 2
spr.visible = true
}
var lbl = piece_labels[text(p._id)]
if (!lbl) return
lbl.pos.x = p.coord[0] * S + S / 2
lbl.pos.y = p.coord[1] * S + S / 2
lbl.visible = true
})
}
// Input handler
var game_input = {
on_input: function(action, data) {
var clicked = null, cell = null, is_valid = false, i = 0, src_piece = null
if (!data.pressed) return
if (action == 'cancel') {
@@ -158,13 +178,13 @@ var game_input = {
}
if (action == 'select' && hover_gx >= 0 && hover_gx < 8 && hover_gy >= 0 && hover_gy < 8) {
var clicked = [hover_gx, hover_gy]
var cell = grid.at(clicked)
clicked = [hover_gx, hover_gy]
cell = grid.at(clicked)
if (selectPos) {
// Try to move
var is_valid = false
var i = 0
is_valid = false
i = 0
for (i = 0; i < length(validMoves); i++) {
if (validMoves[i][0] == clicked[0] && validMoves[i][1] == clicked[1]) {
is_valid = true
@@ -173,8 +193,10 @@ var game_input = {
}
if (is_valid) {
var src_piece = grid.at(selectPos)[0]
src_piece = grid.at(selectPos)[0]
if (src_piece && mover.tryMove(src_piece, clicked)) {
move_history[] = sq_name(selectPos[0], selectPos[1]) + "-" + sq_name(clicked[0], clicked[1])
log.chess("move " + sq_name(selectPos[0], selectPos[1]) + "-" + sq_name(clicked[0], clicked[1]) + " turn=" + mover.turn)
sync_piece_sprites()
update_status()
}
@@ -201,6 +223,66 @@ var game_input = {
}
input.player1().possess(game_input)
// --- Probe endpoints for AI play ---
var probe = use('probe')
var file_letters = "abcdefgh"
function sq_name(x, y) {
return text(file_letters, x, x + 1) + text(y + 1)
}
function piece_char(p) {
var chars = {king: "K", queen: "Q", rook: "R", bishop: "B", knight: "N", pawn: "P"}
var c = chars[p.kind]
if (p.colour == 'black') c = lower(c)
return c
}
probe.register("chess", {
board: function(a) {
var rows = []
var y = 0, x = 0, cell = null, row = null
for (y = 7; y >= 0; y--) {
row = ""
for (x = 0; x < 8; x++) {
cell = grid.at([x, y])
if (length(cell)) {
row = row + piece_char(cell[0])
} else {
row = row + "."
}
if (x < 7) row = row + " "
}
rows[] = row
}
return {turn: mover.turn, moves: move_history, board: rows}
},
move: function(a) {
var fx = a.fx, fy = a.fy, tx = a.tx, ty = a.ty
if (is_null(fx) || is_null(fy) || is_null(tx) || is_null(ty))
return {ok: false, error: "need fx fy tx ty"}
var from = [fx, fy]
var to = [tx, ty]
var cell = grid.at(from)
if (!length(cell))
return {ok: false, error: "no piece at " + sq_name(fx, fy)}
var piece = cell[0]
if (piece.colour != mover.turn)
return {ok: false, error: "not " + piece.colour + "'s turn"}
if (!rules.canMove(piece, from, to, grid))
return {ok: false, error: "illegal move"}
if (mover.tryMove(piece, to)) {
move_history[] = sq_name(fx, fy) + "-" + sq_name(tx, ty)
log.chess("move " + sq_name(fx, fy) + "-" + sq_name(tx, ty) + " turn=" + mover.turn)
sync_piece_sprites()
update_status()
return {ok: true, move: sq_name(fx, fy) + "-" + sq_name(tx, ty)}
}
return {ok: false, error: "move rejected"}
}
})
var comp_config = {
clear: {r: 0.15, g: 0.15, b: 0.2, a: 1},
planes: [
@@ -210,12 +292,13 @@ var comp_config = {
}
core.start({
width: 640, height: 640, title: "Chess",
width: 640, height: 640, title: "Chess", probe: true,
input: function(ev) {
var wp = null
if (ev.type == 'mouse_motion') {
// Convert pixel coords to grid coords via camera
var wp = game_cam.window_to_world(ev.pos.x, ev.pos.y)
wp = game_cam.window_to_world(ev.pos[0], ev.pos[1])
if (wp) {
hover_gx = floor(wp.x / S)
hover_gy = floor(wp.y / S)
@@ -224,6 +307,7 @@ core.start({
},
update: function(dt) {
highlight_selection()
},
render: function() {

View File

@@ -1,3 +1,6 @@
function px(p) { return !is_null(p.x) ? p.x : p[0] }
function py(p) { return !is_null(p.y) ? p.y : p[1] }
function grid(w, h) {
var newgrid = meme(grid_prototype)
newgrid.width = w;
@@ -23,25 +26,28 @@ var grid_prototype = {
// alias for cell
at(pos) {
return this.cell(pos.x, pos.y);
return this.cell(px(pos), py(pos));
},
// add an entity into a cell
add(entity, pos) {
push(this.cell(pos.x, pos.y), entity);
entity.coord = array(pos);
var cx = px(pos), cy = py(pos);
push(this.cell(cx, cy), entity);
entity.coord = [cx, cy];
},
// remove an entity from a cell
remove(entity, pos) {
this.cells[pos.y][pos.x] = filter(this.cells[pos.y][pos.x], x => x != entity)
var cx = px(pos), cy = py(pos);
this.cells[cy][cx] = filter(this.cells[cy][cx], x => x != entity)
},
// bounds check
inBounds(pos) {
var cx = px(pos), cy = py(pos);
return (
pos.x >= 0 && pos.x < this.width &&
pos.y >= 0 && pos.y < this.height
cx >= 0 && cx < this.width &&
cy >= 0 && cy < this.height
);
},
@@ -54,7 +60,7 @@ var grid_prototype = {
for (x = 0; x < this.width; x++) {
list = this.cells[y][x]
arrfor(list, function(entity) {
fn(entity, entity.coord);
fn(entity);
})
}
}
@@ -67,7 +73,7 @@ var grid_prototype = {
var x = 0;
for (y = 0; y < this.height; y++) {
for (x = 0; x < this.width; x++) {
out += length(this.cells[y][x]);
out += text(length(this.cells[y][x]));
}
if (y != this.height - 1) out += "\n";
}

View File

@@ -19,15 +19,14 @@ var MovementSystem_prototype = {
var victims = this.grid.at(dest);
if (length(victims) && victims[0].colour == piece.colour) return false;
if (length(victims)) victims[0].captured = true;
if (length(victims)) {
victims[0].captured = true;
this.grid.remove(victims[0], dest);
}
this.grid.remove(piece, piece.coord);
this.grid.add (piece, dest);
// grid.add() re-creates coord; re-add .x/.y fields:
piece.coord.x = dest.x;
piece.coord.y = dest.y;
this.turn = (this.turn == 'white') ? 'black' : 'white';
return true;
}

View File

@@ -14,14 +14,14 @@ function startingPosition(grid) {
// pawns
for (x = 0; x < 8; x++) {
grid.add(Piece('pawn', W), [x, 6]);
grid.add(Piece('pawn', B), [x, 1]);
grid.add(Piece('pawn', W), [x, 1]);
grid.add(Piece('pawn', B), [x, 6]);
}
// major pieces
var back = ['rook','knight','bishop','queen','king','bishop','knight','rook'];
for (x = 0; x < 8; x++) {
grid.add(Piece(back[x], W), [x, 7]);
grid.add(Piece(back[x], B), [x, 0]);
grid.add(Piece(back[x], W), [x, 0]);
grid.add(Piece(back[x], B), [x, 7]);
}
}

View File

@@ -5,8 +5,8 @@ function cy(c) { return !is_null(c.y) ? c.y : c[1] }
/* simple move-shape checks */
var deltas = {
pawn: function (pc, dx, dy, ctx) {
var dir = (pc.colour == 'white') ? -1 : 1;
var base = (pc.colour == 'white') ? 6 : 1;
var dir = (pc.colour == 'white') ? 1 : -1;
var base = (pc.colour == 'white') ? 1 : 6;
var one = (dy == dir && dx == 0 && length(ctx.grid.at(ctx.to)) == 0);
var two = (dy == 2 * dir && dx == 0 && cy(pc.coord) == base &&
length(ctx.grid.at({ x: cx(pc.coord), y: cy(pc.coord)+dir })) == 0 &&
@@ -42,4 +42,4 @@ function canMove(piece, from, to, grid) {
return clearLine(from, to, grid);
}
return { canMove };
return { canMove: canMove };

View File

@@ -111,12 +111,12 @@ core.start({
// Scoring
if (bx < 0) {
score2++
score_label.text = score1 + " " + score2
score_label.text = text(score1) + " " + text(score2)
reset_ball()
}
if (bx > GW) {
score1++
score_label.text = score1 + " " + score2
score_label.text = text(score1) + " " + text(score2)
reset_ball()
}
},

View File

@@ -140,6 +140,7 @@ core.start({
// New head position
var hx = snake_pos[0].x + dir.x
var hy = snake_pos[0].y + dir.y
var tail = null
// Wrap
if (hx < 0) hx = gridW - 1
@@ -164,23 +165,27 @@ core.start({
// Add head with tween from old head position
var old_wp = grid_to_world(snake_pos[0].x, snake_pos[0].y)
var new_wp = grid_to_world(hx, hy)
snake_pos.unshift({x: hx, y: hy})
var new_pos = [{x: hx, y: hy}]
for (i = 0; i < length(snake_pos); i++) push(new_pos, snake_pos[i])
snake_pos = new_pos
var head = shape.rect({
pos: {x: old_wp.x, y: old_wp.y}, width: cellSize - 2, height: cellSize - 2,
fill: {r: 0, g: 1, b: 0.3, a: 1}, plane: 'game'
})
// Smooth tween from old position to new position
tw.tween(head.pos).to({x: new_wp.x, y: new_wp.y}, move_interval).ease(ease.linear)
snake_shapes.unshift(head)
var new_shapes = [head]
for (i = 0; i < length(snake_shapes); i++) push(new_shapes, snake_shapes[i])
snake_shapes = new_shapes
// Eat apple?
if (hx == apple_gx && hy == apple_gy) {
score++
score_label.text = "Score: " + score
score_label.text = "Score: " + text(score)
spawn_apple()
} else {
// Remove tail
var tail = pop(snake_shapes)
tail = pop(snake_shapes)
tail.destroy()
pop(snake_pos)
}

View File

@@ -45,10 +45,10 @@ var board_shapes = []
function init_board() {
board = []
board_shapes = []
var r = 0, c = 0
var r = 0, c = 0, row = null, srow = null
for (r = 0; r < ROWS; r++) {
var row = []
var srow = []
row = []
srow = []
for (c = 0; c < COLS; c++) {
push(row, null)
push(srow, shape.rect({
@@ -155,7 +155,7 @@ function rotate_blocks(blocks) {
function clear_lines() {
var lines = 0
var r = ROWS - 1, c = 0, full = false, newRow = null
var r = ROWS - 1, c = 0, full = false, newRow = null, sr = 0
while (r >= 0) {
full = true
for (c = 0; c < COLS; c++) {
@@ -164,7 +164,7 @@ function clear_lines() {
if (full) {
lines++
// Shift rows down
var sr = r
sr = r
while (sr > 0) {
for (c = 0; c < COLS; c++) {
board[sr][c] = board[sr - 1][c]
@@ -191,15 +191,15 @@ function clear_lines() {
else if (lines == 4) score += 800
linesCleared += lines
level = floor(linesCleared / 10)
score_label.text = "Score: " + score
level_label.text = "Level: " + level
score_label.text = "Score: " + text(score)
level_label.text = "Level: " + text(level)
}
function update_piece_shapes() {
var i = 0
var i = 0, bx = 0, by = 0
for (i = 0; i < 4; i++) {
var bx = pieceX + piece.blocks[i][0]
var by = pieceY + piece.blocks[i][1]
bx = pieceX + piece.blocks[i][0]
by = pieceY + piece.blocks[i][1]
piece_shapes[i].pos.x = bx * TILE + TILE / 2
piece_shapes[i].pos.y = by * TILE + TILE / 2
piece_shapes[i].fill = piece.color
@@ -208,10 +208,10 @@ function update_piece_shapes() {
}
function update_next_display() {
var i = 0
var i = 0, bx = 0, by = 0
for (i = 0; i < 4; i++) {
var bx = nextPiece.blocks[i][0]
var by = nextPiece.blocks[i][1]
bx = nextPiece.blocks[i][0]
by = nextPiece.blocks[i][1]
next_shapes[i].pos.x = (COLS + 1) * TILE + bx * TILE + TILE / 2
next_shapes[i].pos.y = 20 + by * TILE + TILE / 2
next_shapes[i].fill = nextPiece.color
@@ -220,13 +220,14 @@ function update_next_display() {
}
function spawn_piece() {
var i = 0
piece = nextPiece || random_shape()
nextPiece = random_shape()
pieceX = 3
pieceY = 0
if (collides(pieceX, pieceY, piece.blocks)) {
gameOver = true
var i = 0
i = 0
for (i = 0; i < 4; i++) piece_shapes[i].visible = false
return
}