forked from cory/tildefriends
Cory McWilliams
d293637741
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3530 ed5197a5-7fde-0310-b194-c3ffbd925b24
208 lines
5.4 KiB
JavaScript
208 lines
5.4 KiB
JavaScript
"use strict";
|
|
|
|
//! {"require": ["libiframe"]}
|
|
|
|
let isClient = imports.terminal != null;
|
|
if (isClient) {
|
|
require("libiframe").iframe({
|
|
source: `
|
|
document.documentElement.setAttribute("style", "width: 100%; height: 100%; margin: 0; padding: 0");
|
|
document.body.setAttribute("style", "display: flex; flex-direction: column; height: 100%; width: 100%; margin: 0; padding: 0");
|
|
document.body.style.color = '#fff';
|
|
document.body.style.backgroundColor = '#000';
|
|
|
|
var canvas = document.createElement("canvas");
|
|
canvas.setAttribute("style", "flex: 1 1; image-rendering: pixelated");
|
|
canvas.width = 128;
|
|
canvas.height = 128;
|
|
document.body.append(canvas);
|
|
|
|
var buttonBar = document.createElement("div");
|
|
buttonBar.setAttribute("style", "flex: 0 1 1in; display: flex; flex-direction: row");
|
|
var buttons = ["<", "^", "v", ">", "Fire!"];
|
|
for (var i = 0; i < buttons.length; i++) {
|
|
var button = document.createElement("input");
|
|
button.setAttribute("type", "button");
|
|
button.setAttribute("style", "flex: 1 1");
|
|
button.value = buttons[i];
|
|
button.onclick = buttonClicked.bind(null, buttons[i]);
|
|
buttonBar.append(button);
|
|
}
|
|
document.body.append(buttonBar);
|
|
|
|
var buttonCallback;
|
|
function buttonClicked(button) {
|
|
if (buttonCallback) {
|
|
buttonCallback(button);
|
|
}
|
|
}
|
|
|
|
var kExportNames = [
|
|
"beginPath",
|
|
"fill",
|
|
"save",
|
|
"restore",
|
|
"scale",
|
|
"rotate",
|
|
"translate",
|
|
"transform",
|
|
"arc",
|
|
"moveTo",
|
|
"lineTo",
|
|
"fillRect",
|
|
"fillText",
|
|
"stroke",
|
|
];
|
|
var context = canvas.getContext("2d");
|
|
var exports = {};
|
|
for (var i = 0; i < kExportNames.length; i++) {
|
|
exports[kExportNames[i]] = context[kExportNames[i]].bind(context);
|
|
}
|
|
exports.setButtonCallback = function(callback) { buttonCallback = callback; };
|
|
exports.setFillStyle = function(style) { context.fillStyle = style; };
|
|
exports.setStrokeStyle = function(style) { context.strokeStyle = style; };
|
|
exports.setLineWidth = function(width) { context.lineWidth = width; };
|
|
rpc.export(exports);
|
|
`,
|
|
style: `
|
|
border: 0;
|
|
`}).then(initialize).catch(terminal.print);
|
|
|
|
function initialize(iframe) {
|
|
iframe.setButtonCallback(click);
|
|
draw(iframe);
|
|
core.register("onMessage", onMessage.bind(null, iframe));
|
|
core.getService("server").then(function(server) {
|
|
server.postMessage({ready: true});
|
|
});
|
|
}
|
|
|
|
async function click(button) {
|
|
(await core.getService("server")).postMessage({button: button});
|
|
}
|
|
|
|
function draw(iframe) {
|
|
iframe.setFillStyle('#222');
|
|
iframe.fillRect(0, 0, 640, 480);
|
|
}
|
|
|
|
function drawTank(iframe, x, y, color, angle) {
|
|
iframe.save();
|
|
iframe.setLineWidth(1);
|
|
iframe.setFillStyle(color);
|
|
iframe.setStrokeStyle(color);
|
|
iframe.translate(x, y);
|
|
iframe.beginPath();
|
|
iframe.arc(0, 0, 4, Math.PI, 2 * Math.PI);
|
|
iframe.fill();
|
|
iframe.beginPath();
|
|
var radians = Math.PI + angle * Math.PI / 180.0;
|
|
iframe.moveTo(Math.cos(radians) * 2, Math.sin(radians) * 2 - 0.5);
|
|
iframe.lineTo(Math.cos(radians) * 10, Math.sin(radians) * 10 - 0.5);
|
|
iframe.stroke();
|
|
iframe.restore();
|
|
}
|
|
|
|
function onMessage(iframe, sender, message) {
|
|
iframe.setFillStyle('#222');
|
|
iframe.fillRect(0, 0, 640, 480);
|
|
|
|
for (let i = 0; i < message.users.length; i++) {
|
|
var tank = message.users[i];
|
|
drawTank(iframe, tank.position.x, tank.position.y, tank.user == core.user.index ? '#f00' : '#0f0', tank.angle);
|
|
}
|
|
iframe.setFillStyle('#0f0');
|
|
for (let i = 0; i < message.terrain.length; i++) {
|
|
let h = message.terrain[i];
|
|
iframe.fillRect(i, 128 - h, i + 1, h);
|
|
}
|
|
}
|
|
} else {
|
|
let users = {};
|
|
let terrain = new Array(128);
|
|
let updating = false;
|
|
|
|
function startUpdating() {
|
|
if (!updating) {
|
|
setTimeout(100, update);
|
|
updating = true;
|
|
}
|
|
}
|
|
|
|
function update() {
|
|
updating = false;
|
|
for (let u of Object.values(users)) {
|
|
user.position.y++;
|
|
updating = true;
|
|
}
|
|
broadcastUsers();
|
|
if (updating) {
|
|
setTimeout(100, update);
|
|
}
|
|
}
|
|
|
|
function initializeTerrain() {
|
|
for (let i = 0; i < terrain.length; i++) {
|
|
terrain[i] = 32;
|
|
}
|
|
}
|
|
|
|
function broadcastUsers() {
|
|
core.broadcast({
|
|
users: Object.keys(users).map(x => ({user: x, position: users[x].position, angle: users[x].angle})),
|
|
terrain: terrain,
|
|
});
|
|
}
|
|
|
|
function placeNewUser() {
|
|
let positions = Object.keys(users).map(x => users[x].position.x);
|
|
var best = 128 / 2;
|
|
var bestDistance = -1;
|
|
if (positions.length) {
|
|
for (var i = 10; i < 118; i++) {
|
|
var thisDistance = Math.min.apply(null, positions.map(x => Math.abs(i - x)));
|
|
if (thisDistance > bestDistance) {
|
|
bestDistance = thisDistance;
|
|
best = i;
|
|
}
|
|
}
|
|
}
|
|
return {x: best, y: 10, d: bestDistance};
|
|
}
|
|
|
|
initializeTerrain();
|
|
|
|
core.register("onMessage", function(sender, message) {
|
|
if (message.ready) {
|
|
users[sender.index] = {
|
|
user: sender,
|
|
angle: 0,
|
|
velocity: 100,
|
|
position: placeNewUser(),
|
|
};
|
|
broadcastUsers();
|
|
startUpdating();
|
|
} else if (message.button) {
|
|
switch (message.button) {
|
|
case "<":
|
|
users[sender.index].angle = Math.round(Math.max(users[sender.index].angle - 5.0, 0.0));
|
|
break;
|
|
case ">":
|
|
users[sender.index].angle = Math.round(Math.min(users[sender.index].angle + 5.0, 180.0));
|
|
break;
|
|
case "^":
|
|
users[sender.index].velocity++;
|
|
break;
|
|
case "v":
|
|
users[sender.index].velocity--;
|
|
break;
|
|
}
|
|
broadcastUsers();
|
|
}
|
|
});
|
|
|
|
core.register("onSessionEnd", function(user) {
|
|
delete users[user.index];
|
|
broadcastUsers();
|
|
});
|
|
} |