223 lines
5.3 KiB
JavaScript
223 lines
5.3 KiB
JavaScript
/**
|
|
* Moth Game Framework
|
|
* Higher-level game development framework built on top of Prosperon
|
|
*/
|
|
|
|
var os = use('os');
|
|
var io = use('io');
|
|
var transform = use('transform');
|
|
var rasterize = use('rasterize');
|
|
var video_actor = use('sdl_video')
|
|
|
|
var window
|
|
var render
|
|
|
|
var gameactor
|
|
|
|
$_.start(e => {
|
|
if (gameactor) return
|
|
gameactor = e.actor
|
|
loop()
|
|
}, 'tests/prosperon.js')
|
|
|
|
send(video_actor, {
|
|
kind: "window",
|
|
op:"create"
|
|
}, e => {
|
|
if (e.error) {
|
|
console.error(e.error)
|
|
os.exit(1)
|
|
}
|
|
|
|
window = e.id
|
|
|
|
send(video_actor,{
|
|
kind:"window",
|
|
op:"makeRenderer",
|
|
id:window
|
|
}, e => {
|
|
if (e.error) {
|
|
console.error(e.error)
|
|
os.exit(1)
|
|
}
|
|
|
|
render = e.id
|
|
console.log(`Created window and renderer id ${render}`)
|
|
})
|
|
})
|
|
|
|
var last = os.now()
|
|
|
|
// Engine state
|
|
var camera = {
|
|
x: 0,
|
|
y: 0,
|
|
scale: 1,
|
|
rotation: 0
|
|
}
|
|
|
|
// Convert high-level draw commands to low-level renderer commands
|
|
function translate_draw_commands(commands) {
|
|
var renderer_commands = []
|
|
|
|
commands.forEach(function(cmd) {
|
|
if (cmd.material && cmd.material.color) {
|
|
renderer_commands.push({
|
|
op: "set",
|
|
prop: "drawColor",
|
|
value: cmd.material.color
|
|
})
|
|
}
|
|
|
|
switch(cmd.cmd) {
|
|
case "draw_rect":
|
|
// Handle rectangles with optional rounding and thickness
|
|
if (cmd.opt && cmd.opt.radius && cmd.opt.radius > 0) {
|
|
// Rounded rectangle
|
|
var thickness = (cmd.opt.thickness === 0) ? 0 : (cmd.opt.thickness || 1)
|
|
var raster_result = rasterize.round_rect(cmd.rect, cmd.opt.radius, thickness)
|
|
|
|
if (raster_result.type === 'rect') {
|
|
renderer_commands.push({
|
|
op: "fillRect",
|
|
data: {rect: raster_result.data}
|
|
})
|
|
} else if (raster_result.type === 'rects') {
|
|
// SDL video expects 'rects' operation, not 'fillRects'
|
|
raster_result.data.forEach(function(rect) {
|
|
renderer_commands.push({
|
|
op: "fillRect",
|
|
data: {rect: rect}
|
|
})
|
|
})
|
|
}
|
|
} else if (cmd.opt && cmd.opt.thickness && cmd.opt.thickness > 0) {
|
|
// Outlined rectangle
|
|
var raster_result = rasterize.outline_rect(cmd.rect, cmd.opt.thickness)
|
|
|
|
if (raster_result.type === 'rect') {
|
|
renderer_commands.push({
|
|
op: "fillRect",
|
|
data: {rect: raster_result.data}
|
|
})
|
|
} else if (raster_result.type === 'rects') {
|
|
// SDL video expects 'rects' operation with array
|
|
renderer_commands.push({
|
|
op: "rects",
|
|
data: {rects: raster_result.data}
|
|
})
|
|
}
|
|
} else {
|
|
// Filled rectangle
|
|
renderer_commands.push({
|
|
op: "fillRect",
|
|
data: {rect: cmd.rect}
|
|
})
|
|
}
|
|
break
|
|
|
|
case "draw_circle":
|
|
case "draw_ellipse":
|
|
break
|
|
// Rasterize ellipse to points or rects
|
|
var radii = cmd.radii || [cmd.radius, cmd.radius]
|
|
var raster_result = rasterize.ellipse(cmd.pos, radii, cmd.opt || {})
|
|
|
|
if (raster_result.type === 'points') {
|
|
renderer_commands.push({
|
|
op: "point",
|
|
data: {points: raster_result.data}
|
|
})
|
|
} else if (raster_result.type === 'rects') {
|
|
// Use 'rects' operation for multiple rectangles
|
|
renderer_commands.push({
|
|
op: "rects",
|
|
data: {rects: raster_result.data}
|
|
})
|
|
}
|
|
break
|
|
|
|
case "draw_line":
|
|
renderer_commands.push({
|
|
op: "line",
|
|
data: {points: cmd.points}
|
|
})
|
|
break
|
|
|
|
case "draw_point":
|
|
renderer_commands.push({
|
|
op: "point",
|
|
data: {points: [cmd.pos]}
|
|
})
|
|
break
|
|
|
|
case "draw_image":
|
|
// TODO: Handle image loading and texture management
|
|
renderer_commands.push({
|
|
op: "texture",
|
|
data: cmd
|
|
})
|
|
break
|
|
|
|
case "draw_text":
|
|
// Use debugText for now
|
|
renderer_commands.push({
|
|
op: "debugText",
|
|
data: {
|
|
pos: cmd.pos || {x: 0, y: 0},
|
|
text: cmd.text || ""
|
|
}
|
|
})
|
|
break
|
|
}
|
|
})
|
|
|
|
return renderer_commands
|
|
}
|
|
|
|
function loop()
|
|
{
|
|
os.frame()
|
|
var now = os.now()
|
|
var dt = now - last
|
|
last = now
|
|
|
|
// Update the game
|
|
send(gameactor, {kind:'update', dt:dt}, e => {
|
|
// Get draw commands from game
|
|
send(gameactor, {kind:'draw'}, draw_commands => {
|
|
var batch_commands = []
|
|
|
|
batch_commands.push({
|
|
op: "set",
|
|
prop: "drawColor",
|
|
value: [0.1,0.1,0.15,1]
|
|
})
|
|
|
|
// Clear the screen
|
|
batch_commands.push({
|
|
op: "clear"
|
|
})
|
|
|
|
if (draw_commands && draw_commands.length > 0) {
|
|
var renderer_commands = translate_draw_commands(draw_commands)
|
|
batch_commands = batch_commands.concat(renderer_commands)
|
|
}
|
|
|
|
batch_commands.push({
|
|
op: "present"
|
|
})
|
|
|
|
send(video_actor, {
|
|
kind: "renderer",
|
|
id: render,
|
|
op: "batch",
|
|
data: batch_commands
|
|
}, _ => {
|
|
var diff = os.now() - now
|
|
$_.delay(loop,1/240)
|
|
})
|
|
})
|
|
})
|
|
}
|