fix missing shader
This commit is contained in:
3
core.cm
3
core.cm
@@ -13,6 +13,9 @@
|
||||
// Headless mode (no window, no input, no render, no audio):
|
||||
// core.start({ headless: true, update: function(dt) { ... } })
|
||||
|
||||
var io = use('cellfs')
|
||||
io.mount('/Users/john/work/prosperon')
|
||||
|
||||
var time_mod = use('time')
|
||||
|
||||
var core = {}
|
||||
|
||||
143
examples/chess/board_view.cm
Normal file
143
examples/chess/board_view.cm
Normal file
@@ -0,0 +1,143 @@
|
||||
var shape = use('shape2d')
|
||||
var text2d = use('text2d')
|
||||
|
||||
var S = 60
|
||||
var GW = S * 8
|
||||
var GH = S * 8
|
||||
|
||||
var light_color = {r: 0.93, g: 0.93, b: 0.85, a: 1}
|
||||
var dark_color = {r: 0.45, g: 0.55, b: 0.35, a: 1}
|
||||
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 hover_color = {r: 0.8, g: 0.85, b: 0.6, a: 1}
|
||||
|
||||
var piece_letter = {
|
||||
king: "K", queen: "Q", rook: "R",
|
||||
bishop: "B", knight: "N", pawn: "P"
|
||||
}
|
||||
var white_text = {r: 1, g: 1, b: 1, a: 1}
|
||||
var black_text = {r: 0.1, g: 0.1, b: 0.1, a: 1}
|
||||
|
||||
var board_shapes = []
|
||||
var piece_labels = {}
|
||||
var status_label = null
|
||||
var next_id = 0
|
||||
|
||||
function init(grid) {
|
||||
var bx = 0, by = 0, row = null, col = null
|
||||
for (by = 0; by < 8; by++) {
|
||||
row = []
|
||||
for (bx = 0; bx < 8; bx++) {
|
||||
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,
|
||||
fill: {r: col.r, g: col.g, b: col.b, a: col.a},
|
||||
plane: 'game', layer: 0
|
||||
}))
|
||||
}
|
||||
push(board_shapes, row)
|
||||
}
|
||||
|
||||
next_id = 0
|
||||
grid.each(function(p) {
|
||||
next_id++
|
||||
p._id = next_id
|
||||
piece_labels[text(next_id)] = text2d({
|
||||
text: piece_letter[p.kind],
|
||||
pos: {x: p.coord[0] * S + S / 2, y: p.coord[1] * S + S / 2},
|
||||
size: 36,
|
||||
color: (p.colour == 'white') ? white_text : black_text,
|
||||
plane: 'game', layer: 1
|
||||
})
|
||||
})
|
||||
|
||||
status_label = text2d({
|
||||
text: "White's turn", pos: {x: 10, y: GH - 20},
|
||||
plane: 'hud', size: 14, color: {r: 1, g: 1, b: 1, a: 1}
|
||||
})
|
||||
}
|
||||
|
||||
function sync_pieces(grid) {
|
||||
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 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
|
||||
})
|
||||
}
|
||||
|
||||
function rebuild_pieces(grid) {
|
||||
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 key = text(p._id)
|
||||
var lbl = piece_labels[key]
|
||||
if (!lbl) {
|
||||
lbl = text2d({
|
||||
text: piece_letter[p.kind],
|
||||
pos: {x: p.coord[0] * S + S / 2, y: p.coord[1] * S + S / 2},
|
||||
size: 36,
|
||||
color: (p.colour == 'white') ? white_text : black_text,
|
||||
plane: 'game', layer: 1
|
||||
})
|
||||
piece_labels[key] = lbl
|
||||
}
|
||||
lbl.pos.x = p.coord[0] * S + S / 2
|
||||
lbl.pos.y = p.coord[1] * S + S / 2
|
||||
lbl.text = piece_letter[p.kind]
|
||||
lbl.visible = true
|
||||
})
|
||||
}
|
||||
|
||||
function highlight(selectPos, validMoves, hover_gx, hover_gy) {
|
||||
var x = 0, y = 0, col = null
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
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}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
board_shapes[selectPos[1]][selectPos[0]].fill = {
|
||||
r: select_color.r, g: select_color.g, b: select_color.b, a: select_color.a
|
||||
}
|
||||
|
||||
var i = 0, m = null
|
||||
for (i = 0; i < length(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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function set_status(msg) {
|
||||
status_label.text = msg
|
||||
}
|
||||
|
||||
return {
|
||||
S: S, GW: GW, GH: GH,
|
||||
init: init,
|
||||
sync_pieces: sync_pieces,
|
||||
rebuild_pieces: rebuild_pieces,
|
||||
highlight: highlight,
|
||||
set_status: set_status
|
||||
}
|
||||
@@ -2,16 +2,21 @@ var core = use('core')
|
||||
var camera = use('camera')
|
||||
var compositor = use('compositor')
|
||||
var input = use('input')
|
||||
var shape = use('shape2d')
|
||||
var text2d = use('text2d')
|
||||
|
||||
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 board_view = use('examples/chess/board_view')
|
||||
|
||||
var S = 60
|
||||
var GW = S * 8, GH = S * 8
|
||||
var grid = Grid(8, 8)
|
||||
grid.width = 8
|
||||
grid.height = 8
|
||||
var mover = MovementSystem(grid, rules)
|
||||
startingPos(grid)
|
||||
board_view.init(grid)
|
||||
|
||||
var S = board_view.S, GW = board_view.GW, GH = board_view.GH
|
||||
var move_history = []
|
||||
|
||||
var game_cam = camera.make({width: GW, height: GH, pos: {x: GW / 2, y: GH / 2}})
|
||||
@@ -24,119 +29,19 @@ input.configure({
|
||||
}
|
||||
})
|
||||
|
||||
// Build board
|
||||
var grid = Grid(8, 8)
|
||||
grid.width = 8
|
||||
grid.height = 8
|
||||
var mover = MovementSystem(grid, rules)
|
||||
startingPos(grid)
|
||||
|
||||
// Board squares (shape2d)
|
||||
var light_color = {r: 0.93, g: 0.93, b: 0.85, a: 1}
|
||||
var dark_color = {r: 0.45, g: 0.55, b: 0.35, a: 1}
|
||||
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, row = null, col = null
|
||||
for (by = 0; by < 8; by++) {
|
||||
row = []
|
||||
for (bx = 0; bx < 8; bx++) {
|
||||
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,
|
||||
fill: {r: col.r, g: col.g, b: col.b, a: col.a},
|
||||
plane: 'game', layer: 0
|
||||
}))
|
||||
}
|
||||
push(board_shapes, row)
|
||||
}
|
||||
|
||||
// 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_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},
|
||||
size: 36,
|
||||
color: (p.colour == 'white') ? white_color : black_color,
|
||||
plane: 'game', layer: 1
|
||||
})
|
||||
})
|
||||
|
||||
// Selection state
|
||||
var selectPos = null
|
||||
var validMoves = []
|
||||
|
||||
// Mouse position in grid coords
|
||||
var hover_gx = -1, hover_gy = -1
|
||||
|
||||
// Status text
|
||||
var status_label = text2d({
|
||||
text: "White's turn", pos: {x: 10, y: GH - 20},
|
||||
plane: 'hud', size: 14, color: {r: 1, g: 1, b: 1, a: 1}
|
||||
})
|
||||
|
||||
function update_status() {
|
||||
status_label.text = mover.turn + "'s turn"
|
||||
}
|
||||
|
||||
function reset_board_colors() {
|
||||
var x = 0, y = 0, col = null
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
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
|
||||
board_shapes[selectPos[1]][selectPos[0]].fill = {
|
||||
r: select_color.r, g: select_color.g, b: select_color.b, a: select_color.a
|
||||
}
|
||||
|
||||
// Highlight valid moves
|
||||
var i = 0, m = null
|
||||
for (i = 0; i < length(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
|
||||
}
|
||||
}
|
||||
var file_letters = "abcdefgh"
|
||||
function sq_name(x, y) {
|
||||
return text(file_letters, x, x + 1) + text(y + 1)
|
||||
}
|
||||
|
||||
function compute_valid_moves(from) {
|
||||
validMoves = []
|
||||
var piece = grid.at(from)[0]
|
||||
if (!piece) return
|
||||
|
||||
var x = 0, y = 0, to = null, dest = null
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
@@ -149,22 +54,6 @@ 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 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
|
||||
@@ -173,7 +62,7 @@ var game_input = {
|
||||
if (action == 'cancel') {
|
||||
selectPos = null
|
||||
validMoves = []
|
||||
highlight_selection()
|
||||
board_view.highlight(selectPos, validMoves, hover_gx, hover_gy)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -182,9 +71,7 @@ var game_input = {
|
||||
cell = grid.at(clicked)
|
||||
|
||||
if (selectPos) {
|
||||
// Try to move
|
||||
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
|
||||
@@ -197,13 +84,12 @@ var game_input = {
|
||||
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()
|
||||
board_view.sync_pieces(grid)
|
||||
board_view.set_status(mover.turn + "'s turn")
|
||||
}
|
||||
selectPos = null
|
||||
validMoves = []
|
||||
} else if (length(cell) && cell[0].colour == mover.turn) {
|
||||
// Select different piece
|
||||
selectPos = clicked
|
||||
compute_valid_moves(selectPos)
|
||||
} else {
|
||||
@@ -211,13 +97,12 @@ var game_input = {
|
||||
validMoves = []
|
||||
}
|
||||
} else {
|
||||
// Select piece
|
||||
if (length(cell) && cell[0].colour == mover.turn) {
|
||||
selectPos = clicked
|
||||
compute_valid_moves(selectPos)
|
||||
}
|
||||
}
|
||||
highlight_selection()
|
||||
board_view.highlight(selectPos, validMoves, hover_gx, hover_gy)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,11 +111,6 @@ 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]
|
||||
@@ -275,8 +155,8 @@ probe.register("chess", {
|
||||
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()
|
||||
board_view.sync_pieces(grid)
|
||||
board_view.set_status(mover.turn + "'s turn")
|
||||
return {ok: true, move: sq_name(fx, fy) + "-" + sq_name(tx, ty)}
|
||||
}
|
||||
return {ok: false, error: "move rejected"}
|
||||
@@ -297,7 +177,6 @@ core.start({
|
||||
input: function(ev) {
|
||||
var wp = null
|
||||
if (ev.type == 'mouse_motion') {
|
||||
// Convert pixel coords to grid coords via camera
|
||||
wp = game_cam.window_to_world(ev.pos[0], ev.pos[1])
|
||||
if (wp) {
|
||||
hover_gx = floor(wp.x / S)
|
||||
@@ -307,7 +186,7 @@ core.start({
|
||||
},
|
||||
|
||||
update: function(dt) {
|
||||
highlight_selection()
|
||||
board_view.highlight(selectPos, validMoves, hover_gx, hover_gy)
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
166
examples/chess/client.ce
Normal file
166
examples/chess/client.ce
Normal file
@@ -0,0 +1,166 @@
|
||||
var core = use('core')
|
||||
var camera = use('camera')
|
||||
var compositor = use('compositor')
|
||||
var input = use('input')
|
||||
|
||||
var Grid = use('examples/chess/grid')
|
||||
var rules = use('examples/chess/rules')
|
||||
var board_view = use('examples/chess/board_view')
|
||||
var game_state = use('examples/chess/game_state')
|
||||
|
||||
var grid = Grid(8, 8)
|
||||
grid.width = 8
|
||||
grid.height = 8
|
||||
board_view.init(grid)
|
||||
|
||||
var S = board_view.S, GW = board_view.GW, GH = board_view.GH
|
||||
|
||||
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}})
|
||||
|
||||
input.configure({
|
||||
action_map: {
|
||||
select: ['mouse_button_left'],
|
||||
cancel: ['escape', 'mouse_button_right']
|
||||
}
|
||||
})
|
||||
|
||||
// Network state
|
||||
var my_color = null
|
||||
var server_actor = null
|
||||
var current_turn = "white"
|
||||
|
||||
// Selection state (declared early for $receiver access)
|
||||
var selectPos = null
|
||||
var validMoves = []
|
||||
var hover_gx = -1, hover_gy = -1
|
||||
|
||||
board_view.set_status("Connecting to host...")
|
||||
|
||||
$contact(function(server) {
|
||||
if (server) {
|
||||
server_actor = server
|
||||
log.console("Connected to host!")
|
||||
board_view.set_status("Connected, waiting for game...")
|
||||
} else {
|
||||
log.error("Failed to connect to host")
|
||||
board_view.set_status("Connection failed!")
|
||||
}
|
||||
}, {address: "127.0.0.1", port: 7777})
|
||||
|
||||
$receiver(function(msg) {
|
||||
if (msg.type == "assign") {
|
||||
my_color = msg.color
|
||||
log.console("Assigned color: " + my_color)
|
||||
board_view.set_status("Playing as " + my_color)
|
||||
} else if (msg.type == "state") {
|
||||
current_turn = game_state.deserialize(msg, grid, board_view)
|
||||
board_view.set_status(current_turn + "'s turn")
|
||||
selectPos = null
|
||||
validMoves = []
|
||||
} else if (msg.type == "result") {
|
||||
if (!msg.ok) {
|
||||
board_view.set_status("Move rejected: " + msg.error)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Local input — client plays black
|
||||
function compute_valid_moves(from) {
|
||||
validMoves = []
|
||||
var piece = grid.at(from)[0]
|
||||
if (!piece) return
|
||||
var x = 0, y = 0, to = null, dest = null
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
to = [x, y]
|
||||
dest = grid.at(to)
|
||||
if (length(dest) && dest[0].colour == piece.colour) continue
|
||||
if (rules.canMove(piece, from, to, grid))
|
||||
push(validMoves, to)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var game_input = {
|
||||
on_input: function(action, data) {
|
||||
var clicked = null, cell = null, is_valid = false, i = 0
|
||||
if (!data.pressed) return
|
||||
if (!my_color || current_turn != my_color) return
|
||||
|
||||
if (action == 'cancel') {
|
||||
selectPos = null
|
||||
validMoves = []
|
||||
board_view.highlight(selectPos, validMoves, hover_gx, hover_gy)
|
||||
return
|
||||
}
|
||||
|
||||
if (action == 'select' && hover_gx >= 0 && hover_gx < 8 && hover_gy >= 0 && hover_gy < 8) {
|
||||
clicked = [hover_gx, hover_gy]
|
||||
cell = grid.at(clicked)
|
||||
|
||||
if (selectPos) {
|
||||
is_valid = false
|
||||
for (i = 0; i < length(validMoves); i++) {
|
||||
if (validMoves[i][0] == clicked[0] && validMoves[i][1] == clicked[1]) {
|
||||
is_valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid) {
|
||||
// Send move to server — don't apply locally
|
||||
if (server_actor) {
|
||||
send(server_actor, {type: "move", fx: selectPos[0], fy: selectPos[1], tx: clicked[0], ty: clicked[1]})
|
||||
}
|
||||
selectPos = null
|
||||
validMoves = []
|
||||
} else if (length(cell) && cell[0].colour == my_color) {
|
||||
selectPos = clicked
|
||||
compute_valid_moves(selectPos)
|
||||
} else {
|
||||
selectPos = null
|
||||
validMoves = []
|
||||
}
|
||||
} else {
|
||||
if (length(cell) && cell[0].colour == my_color) {
|
||||
selectPos = clicked
|
||||
compute_valid_moves(selectPos)
|
||||
}
|
||||
}
|
||||
board_view.highlight(selectPos, validMoves, hover_gx, hover_gy)
|
||||
}
|
||||
}
|
||||
}
|
||||
input.player1().possess(game_input)
|
||||
|
||||
var comp_config = {
|
||||
clear: {r: 0.15, g: 0.15, b: 0.2, a: 1},
|
||||
planes: [
|
||||
{name: 'game', camera: game_cam, resolution: {width: GW, height: GH}, presentation: 'letterbox'},
|
||||
{name: 'hud', camera: hud_cam, resolution: {width: GW, height: GH}, presentation: 'stretch'}
|
||||
]
|
||||
}
|
||||
|
||||
core.start({
|
||||
width: 640, height: 640, title: "Chess - Client (Black)",
|
||||
|
||||
input: function(ev) {
|
||||
var wp = null
|
||||
if (ev.type == 'mouse_motion') {
|
||||
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)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
update: function(dt) {
|
||||
board_view.highlight(selectPos, validMoves, hover_gx, hover_gy)
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return compositor.execute(compositor.compile(comp_config))
|
||||
}
|
||||
})
|
||||
31
examples/chess/game_state.cm
Normal file
31
examples/chess/game_state.cm
Normal file
@@ -0,0 +1,31 @@
|
||||
var Piece = use('examples/chess/pieces').Piece
|
||||
|
||||
function serialize(grid, turn) {
|
||||
var pieces = []
|
||||
grid.each(function(p) {
|
||||
pieces[] = {kind: p.kind, colour: p.colour, x: p.coord[0], y: p.coord[1], id: p._id}
|
||||
})
|
||||
return {type: "state", turn: turn, pieces: pieces}
|
||||
}
|
||||
|
||||
function deserialize(state, grid, board_view) {
|
||||
var x = 0, y = 0
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
grid.cells[y][x] = []
|
||||
}
|
||||
}
|
||||
|
||||
var i = 0, pd = null, p = null
|
||||
for (i = 0; i < length(state.pieces); i++) {
|
||||
pd = state.pieces[i]
|
||||
p = Piece(pd.kind, pd.colour)
|
||||
p._id = pd.id
|
||||
grid.add(p, [pd.x, pd.y])
|
||||
}
|
||||
|
||||
board_view.rebuild_pieces(grid)
|
||||
return state.turn
|
||||
}
|
||||
|
||||
return {serialize: serialize, deserialize: deserialize}
|
||||
184
examples/chess/host.ce
Normal file
184
examples/chess/host.ce
Normal file
@@ -0,0 +1,184 @@
|
||||
var core = use('core')
|
||||
var camera = use('camera')
|
||||
var compositor = use('compositor')
|
||||
var input = use('input')
|
||||
|
||||
var Grid = use('examples/chess/grid')
|
||||
var MovementSystem = use('examples/chess/movement')
|
||||
var pieces = use('examples/chess/pieces')
|
||||
var rules = use('examples/chess/rules')
|
||||
var board_view = use('examples/chess/board_view')
|
||||
var game_state = use('examples/chess/game_state')
|
||||
|
||||
var grid = Grid(8, 8)
|
||||
grid.width = 8
|
||||
grid.height = 8
|
||||
var mover = MovementSystem(grid, rules)
|
||||
pieces.startingPosition(grid)
|
||||
board_view.init(grid)
|
||||
|
||||
var S = board_view.S, GW = board_view.GW, GH = board_view.GH
|
||||
|
||||
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}})
|
||||
|
||||
input.configure({
|
||||
action_map: {
|
||||
select: ['mouse_button_left'],
|
||||
cancel: ['escape', 'mouse_button_right']
|
||||
}
|
||||
})
|
||||
|
||||
// Network state
|
||||
var client_actor = null
|
||||
|
||||
board_view.set_status("Waiting for client on port 7777...")
|
||||
|
||||
$portal(function(connection) {
|
||||
log.console("Client connected!")
|
||||
client_actor = connection
|
||||
send(client_actor, {type: "assign", color: "black"})
|
||||
send(client_actor, game_state.serialize(grid, mover.turn))
|
||||
board_view.set_status("White's turn - Game started!")
|
||||
}, 7777)
|
||||
|
||||
$receiver(function(msg) {
|
||||
var from = null, to = null, cell = null, piece = null
|
||||
if (msg.type == "move") {
|
||||
from = [msg.fx, msg.fy]
|
||||
to = [msg.tx, msg.ty]
|
||||
cell = grid.at(from)
|
||||
if (!length(cell)) {
|
||||
send(client_actor, {type: "result", ok: false, error: "no piece"})
|
||||
return
|
||||
}
|
||||
piece = cell[0]
|
||||
if (piece.colour != "black") {
|
||||
send(client_actor, {type: "result", ok: false, error: "not your piece"})
|
||||
return
|
||||
}
|
||||
if (mover.turn != "black") {
|
||||
send(client_actor, {type: "result", ok: false, error: "not your turn"})
|
||||
return
|
||||
}
|
||||
if (!rules.canMove(piece, from, to, grid)) {
|
||||
send(client_actor, {type: "result", ok: false, error: "illegal move"})
|
||||
return
|
||||
}
|
||||
if (mover.tryMove(piece, to)) {
|
||||
board_view.sync_pieces(grid)
|
||||
board_view.set_status(mover.turn + "'s turn")
|
||||
send(client_actor, game_state.serialize(grid, mover.turn))
|
||||
} else {
|
||||
send(client_actor, {type: "result", ok: false, error: "move rejected"})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Local input — host plays white
|
||||
var selectPos = null
|
||||
var validMoves = []
|
||||
var hover_gx = -1, hover_gy = -1
|
||||
|
||||
function compute_valid_moves(from) {
|
||||
validMoves = []
|
||||
var piece = grid.at(from)[0]
|
||||
if (!piece) return
|
||||
var x = 0, y = 0, to = null, dest = null
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
to = [x, y]
|
||||
dest = grid.at(to)
|
||||
if (length(dest) && dest[0].colour == piece.colour) continue
|
||||
if (rules.canMove(piece, from, to, grid))
|
||||
push(validMoves, to)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (mover.turn != 'white') return
|
||||
|
||||
if (action == 'cancel') {
|
||||
selectPos = null
|
||||
validMoves = []
|
||||
board_view.highlight(selectPos, validMoves, hover_gx, hover_gy)
|
||||
return
|
||||
}
|
||||
|
||||
if (action == 'select' && hover_gx >= 0 && hover_gx < 8 && hover_gy >= 0 && hover_gy < 8) {
|
||||
clicked = [hover_gx, hover_gy]
|
||||
cell = grid.at(clicked)
|
||||
|
||||
if (selectPos) {
|
||||
is_valid = false
|
||||
for (i = 0; i < length(validMoves); i++) {
|
||||
if (validMoves[i][0] == clicked[0] && validMoves[i][1] == clicked[1]) {
|
||||
is_valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid) {
|
||||
src_piece = grid.at(selectPos)[0]
|
||||
if (src_piece && mover.tryMove(src_piece, clicked)) {
|
||||
board_view.sync_pieces(grid)
|
||||
board_view.set_status(mover.turn + "'s turn")
|
||||
if (client_actor) {
|
||||
send(client_actor, game_state.serialize(grid, mover.turn))
|
||||
}
|
||||
}
|
||||
selectPos = null
|
||||
validMoves = []
|
||||
} else if (length(cell) && cell[0].colour == 'white') {
|
||||
selectPos = clicked
|
||||
compute_valid_moves(selectPos)
|
||||
} else {
|
||||
selectPos = null
|
||||
validMoves = []
|
||||
}
|
||||
} else {
|
||||
if (length(cell) && cell[0].colour == 'white') {
|
||||
selectPos = clicked
|
||||
compute_valid_moves(selectPos)
|
||||
}
|
||||
}
|
||||
board_view.highlight(selectPos, validMoves, hover_gx, hover_gy)
|
||||
}
|
||||
}
|
||||
}
|
||||
input.player1().possess(game_input)
|
||||
|
||||
var comp_config = {
|
||||
clear: {r: 0.15, g: 0.15, b: 0.2, a: 1},
|
||||
planes: [
|
||||
{name: 'game', camera: game_cam, resolution: {width: GW, height: GH}, presentation: 'letterbox'},
|
||||
{name: 'hud', camera: hud_cam, resolution: {width: GW, height: GH}, presentation: 'stretch'}
|
||||
]
|
||||
}
|
||||
|
||||
core.start({
|
||||
width: 640, height: 640, title: "Chess - Host (White)",
|
||||
|
||||
input: function(ev) {
|
||||
var wp = null
|
||||
if (ev.type == 'mouse_motion') {
|
||||
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)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
update: function(dt) {
|
||||
board_view.highlight(selectPos, validMoves, hover_gx, hover_gy)
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return compositor.execute(compositor.compile(comp_config))
|
||||
}
|
||||
})
|
||||
@@ -6,7 +6,7 @@
|
||||
var video = use('sdl3/video')
|
||||
var gpu_mod = use('sdl3/gpu')
|
||||
var blob_mod = use('blob')
|
||||
var io = use('fd')
|
||||
var io = use('cellfs')
|
||||
var png = use('image/png')
|
||||
var qoi = use('image/qoi')
|
||||
var gif = use('image/gif')
|
||||
|
||||
18
staef.c
18
staef.c
@@ -9,8 +9,7 @@
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string.h>
|
||||
#define MSDF_IMPLEMENTATION
|
||||
#include "msdf.h"
|
||||
|
||||
@@ -681,25 +680,28 @@ QJSCLASS(font,)
|
||||
static void attach_font_texture(JSContext *js, JSValue *pret, font *f) {
|
||||
JS_FRAME(js);
|
||||
JS_ROOT(obj, *pret);
|
||||
JS_ROOT(texData, JS_NULL);
|
||||
JSValue tmp;
|
||||
if (f->pixels) {
|
||||
JS_ROOT(texData, JS_NewObject(js));
|
||||
texData.val = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, texData.val, "width", JS_NewInt32(js, f->atlas_size));
|
||||
JS_SetPropertyStr(js, texData.val, "height", JS_NewInt32(js, f->atlas_size));
|
||||
JS_SetPropertyStr(js, texData.val, "format", JS_NewString(js, "rgba8"));
|
||||
tmp = JS_NewString(js, "rgba8");
|
||||
JS_SetPropertyStr(js, texData.val, "format", tmp);
|
||||
|
||||
size_t byte_size = f->atlas_size * f->atlas_size * 4;
|
||||
JS_SetPropertyStr(js, texData.val, "pixels", js_new_blob_stoned_copy(js, f->pixels, byte_size));
|
||||
tmp = js_new_blob_stoned_copy(js, f->pixels, byte_size);
|
||||
JS_SetPropertyStr(js, texData.val, "pixels", tmp);
|
||||
|
||||
JS_SetPropertyStr(js, obj.val, "texture", texData.val);
|
||||
}
|
||||
|
||||
// Add mode string
|
||||
const char *mode_str = "bitmap";
|
||||
if (f->mode == FONT_MODE_SDF) mode_str = "sdf";
|
||||
else if (f->mode == FONT_MODE_MSDF) mode_str = "msdf";
|
||||
JS_SetPropertyStr(js, obj.val, "mode", JS_NewString(js, mode_str));
|
||||
tmp = JS_NewString(js, mode_str);
|
||||
JS_SetPropertyStr(js, obj.val, "mode", tmp);
|
||||
|
||||
// Add range_px and sharpness for SDF/MSDF fonts
|
||||
JS_SetPropertyStr(js, obj.val, "range_px", JS_NewFloat64(js, f->range_px));
|
||||
JS_SetPropertyStr(js, obj.val, "sharpness", JS_NewFloat64(js, f->sharpness));
|
||||
*pret = obj.val;
|
||||
|
||||
Reference in New Issue
Block a user