SC CODE: // Copyright 2024. Civilware. All rights reserved.
// TELA Decentralized Web Document (TELA-DOC-1)
Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("nameHdr", "render.js")
31 STORE("descrHdr", "Render JS file")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "render.js")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "10b44b024d75648f61f836b669932e55096c11fa08bc7f2d3f96b4d8b4f320ca")
37 STORE("fileCheckS", "270c108d5304063fa78086811fa47db21ea7f14776c1b91517355143370171d4")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*//----------
// Rendering
function render() {
let svgContent = `<defs>
<filter id="shadow45" x="-50%" y="-50%" width="200%" height="200%">
<feDropShadow dx="6" dy="6" stdDeviation="4" flood-color="rgba(0,0,0,0.4)" />
</filter>
<radialGradient id="turretDome" cx="0.5" cy="0.5" r="0.5">
<stop offset="0%" stop-color="white" stop-opacity="0.8" />
<stop offset="25%" stop-color="white" stop-opacity="0.8" />
<stop offset="100%" stop-color="black" stop-opacity="1" />
</radialGradient>
</defs>
`;
svgContent += renderBackground();
svgContent += renderWorldObjects();
svgContent += renderBases();
svgContent += renderEnemies();
svgContent += renderPlayer();
svgContent += renderTurret();
svgContent += renderProjectiles();
svgContent += renderParticles();
svg.innerHTML = svgContent;
renderMinimap();
renderState();
}
function setState(s) {
game.state = s;
}
function renderState() {
if (game.state === STATE.MENU) {
hud.innerHTML = `
<text x="100" y="40" fill="white" text-anchor="middle" font-size="24" font-weight="bold" stroke="black" stroke-width=".2">
FULL TANK
</text>
<text x="100" y="60" fill="yellow" text-anchor="middle" font-size="16" font-weight="bold" stroke="black" stroke-width=".2">
Press ENTER to Begin
</text>
<text x="100" y="80" fill="yellow" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
Movement: w, a, s, d | Turret: l, '
</text>
<text x="100" y="100" fill="yellow" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
Shoot: Space, Turret: ;
</text>
`;
}
else if (game.state === STATE.MISSION_SELECT) {
hud.innerHTML = `
<text x="100" y="30" fill="white" text-anchor="middle" font-size="20" font-weight="bold" stroke="black" stroke-width=".2">
Select Mission
</text>`;
const scenarios = getScenario();
let y = 30;
for (const key in scenarios) {
const scen = scenarios[key];
y += 20;
let tColor = "yellow";
if (levelSelector == scen.id) {
tColor = "orange";
}
hud.innerHTML += `<text x="100" y="${y}" fill="${tColor}" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
${scen.id} - ${scen.mission}
</text>`;
}
}
else if (game.state === STATE.DEAD) {
hud.innerHTML = `
<text x="100" y="40" fill="red" text-anchor="middle" font-size="24" font-weight="bold" stroke="black" stroke-width=".2">
YOU DIED
</text>
<text x="100" y="80" fill="white" text-anchor="middle" font-size="16" font-weight="bold" stroke="black" stroke-width=".2">
Press R to Restart
</text>`;
}
else if (game.state === STATE.WIN) {
let t1 = "MISSION COMPLETE";
let t2 = "to Continue";
if(scenario.id == Object.keys(getScenario()).length) {
t1 = "YOU BEAT THE GAME!";
t2 = "for Menu";
}
hud.innerHTML = `
<text x="100" y="40" fill="lime" text-anchor="middle" font-size="18" font-weight="bold" stroke="black" stroke-width=".2">
${t1}
</text>
<text x="100" y="80" fill="white" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
Press ENTER or START
</text>
<text x="100" y="100" fill="white" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
${t2}
</text>`;
}
else if (game.state === STATE.PAUSED) {
let out = `
<text x="100" y="40" fill="lime" text-anchor="middle" font-size="20" font-weight="bold" stroke="black" stroke-width=".2">
PAUSED
</text>
<text x="100" y="80" fill="white" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
Press Esc or START to Resume
</text>`;
if (game.state === STATE.PAUSED) {
out +=`<text x="100" y="120" fill="white" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
VOLUME: ${(volume * 100)|0}%
</text>`;
}
hud.innerHTML = out;
}
else {
renderHUD();
}
}
function renderHUD() {
const p = game.player;
const hpPercent = p.hp / p.maxHp;
const ammoPercent = p.ammo / p.maxAmmo;
if (hpPercent < 0 | ammoPercent < 0) return;
hud.innerHTML = `
<rect x="20" y="20" width="200" height="20" fill="black" opacity="0.5"/>
<rect x="20" y="20" width="${200 * hpPercent}" height="20" fill="red"/>
<text x="125" y="35" fill="white" font-size="14" text-anchor="middle">
HP: ${p.hp}/${p.maxHp}
</text>
<rect x="20" y="50" width="200" height="20" fill="black" opacity="0.5"/>
<rect x="20" y="50" width="${200 * ammoPercent}" height="20" fill="yellow"/>
<text x="125" y="65" fill="black" font-size="14" text-anchor="middle">
Ammo: ${p.ammo}/${p.maxAmmo}
</text>`;
}
// Mini map
function mapX(x) { return x * mapScaleX; }
function mapY(y) { return y * mapScaleY; }
function renderMinimap() {
let out = "";
// Background
out += `<rect x="0" y="0" width="${MAP_W}" height="${MAP_H}" fill="#222" stroke="#555" />`;
// Bases
for (const b of game.bases) {
// Transform each polygon vertex into minimap space
let pts = b.poly
.map(p => {
const wx = b.x + p.x; // world X
const wy = b.y + p.y; // world Y
return `${mapX(wx)},${mapY(wy)}`;
})
.join(" ");
out += `<polygon points="${pts}" fill="rgba(255,0,0,0.5)" />`;
}
// Enemies
for (const e of game.enemies) {
out += `<circle cx="${mapX(e.x)}" cy="${mapY(e.y)}" r="2" fill="red" />`;
}
// Player
out += `<circle cx="${mapX(game.player.x)}" cy="${mapY(game.player.y)}" r="3" fill="cyan" />`;
// Camera view rectangle
out += `
<rect x="${mapX(camLeft)}"
y="${mapY(camTop)}"
width="${(camRight - camLeft) * mapScaleX}"
height="${(camBottom - camTop) * mapScaleY}"
fill="none" stroke="white" stroke-width="1" />
`;
map.innerHTML = out;
}
// Game rendering
function inView(obj, margin = 200) {
let left, right, top, bottom;
if (obj.w !== undefined) {
// Rectangle
left = obj.x;
right = obj.x + obj.w;
top = obj.y;
bottom = obj.y + obj.h;
} else if (obj.r !== undefined) {
// Circle
left = obj.x - obj.r;
right = obj.x + obj.r;
top = obj.y - obj.r;
bottom = obj.y + obj.r;
} else {
// Point-like (enemy, projectile)
left = right = obj.x;
top = bottom = obj.y;
}
return (
right > camLeft - margin &&
left < camRight + margin &&
bottom > camTop - margin &&
top < camBottom + margin
);
}
// Get world entity polygon
function getWorldPoly(entity) {
const cos = Math.cos(entity.angle);
const sin = Math.sin(entity.angle);
return entity.poly.map(p => ({
x: entity.x + p.x * cos - p.y * sin,
y: entity.y + p.x * sin + p.y * cos
}));
}
// Render entities svgs
function renderBases() {
let svgContent = "";
for (const b of game.bases) {
if (!inView(b)) continue;
const pts = getWorldPoly(b)
.map(p => `${p.x},${p.y}`)
.join(" ");
svgContent += `<polygon points="${pts}" fill="brown" filter="url(#shadow45)" />`
}
return svgContent;
}
function renderEnemies(){
let svgContent = "";
for (const e of game.enemies) {
if (!inView(e)) continue;
const pts = getWorldPoly(e)
.map(p => `${p.x},${p.y}`)
.join(" ");
svgContent += `<polygon points="${pts}" stroke="black" stroke-width="0.5" fill="#913d00" filter="url(#shadow45)" />`;
if(e.type !== "tank"){
const wsObj = {
x: e.x,
y: e.y,
angle: e.angle,
poly: e.windshield
};
const wsPts = getWorldPoly(wsObj)
.map(p => `${p.x},${p.y}`)
.join(" ");
svgContent += `
<polygon points="${wsPts}"
fill="gray"
stroke="black"
stroke-width="0.5" />
`;
} else {
const turretObj = {
x: e.x,
y: e.y,
angle: e.turret.angle,
poly: e.turret.poly
};
const pts = getWorldPoly(turretObj)
.map(p => `${p.x},${p.y}`)
.join(" ");
svgContent += `<circle cx="${e.x}" cy="${e.y}" r="10" fill="url(#turretDome)" />
<polygon points="${pts}" fill="gray" stroke="black" stroke-width="0.5" />`;
}
}
return svgContent;
}
function renderPlayer() {
const pts = getWorldPoly(game.player)
.map(p => `${p.x},${p.y}`)
.join(" ");
return `<polygon points="${pts}" stroke="black" stroke-width="0.5" fill="#123472" filter="url(#shadow45)" />
<circle cx="${game.player.x}" cy="${game.player.y}" r="10" fill="url(#turretDome)" />`;
}
function renderTurret() {
const turretObj = {
x: game.player.x,
y: game.player.y,
angle: game.player.angle + game.player.turret.offset,
poly: game.player.turret.poly
};
const tp = getWorldPoly(turretObj);
return `<polygon points="${tp.map(p => `${p.x},${p.y}`).join(' ')}"
fill="gray" stroke="black" stroke-width="1" />`;
}
// non-rotating
function renderWorldObjects(){
let svgContent = "";
// draw some world objects for testing
for (const obj of worldObjects) {
if (!inView(obj)) continue;
const pts = getWorldPoly(obj)
.map(p => `${p.x},${p.y}`)
.join(" ");
let fill = treeColors[scenario.terrain];
if(obj.type == "rock"){fill = "grey";}
// Shadow first
svgContent += `
<polygon points="${pts}"
fill="black"
opacity="0.25"
transform="translate(4,4)" />
`;
svgContent += `<polygon points="${pts}" fill="${fill}" />`;
}
return svgContent;
}
function renderProjectiles(){
let svgContent = "";
for (const p of game.projectiles) {
const maxLen = 50;
// vector from start -> current
const vx = p.x - p.startX;
const vy = p.y - p.startY;
const dist = Math.hypot(vx, vy);
let tx, ty;
if (dist <= maxLen) {
tx = p.startX;
ty = p.startY;
} else {
const scale = maxLen / dist;
tx = p.x - vx * scale;
ty = p.y - vy * scale;
}
// draw trail
svgContent += `
<line x1="${tx}" y1="${ty}"
x2="${p.x}" y2="${p.y}"
stroke="grey" stroke-width="2" opacity="0.2" />
`;
// draw bullet
if(p.type === "player"){
svgContent += `<circle cx="${p.x}" cy="${p.y}" r="2" fill="yellow" />`;
} else if(p.type === "turret" | p.type === "tank"){
svgContent += `<circle cx="${p.x}" cy="${p.y}" r="4" fill="red" /><circle cx="${p.x}" cy="${p.y}" r="2" fill="orange" />`;
} else if(p.type === "enemy"){
svgContent += `<circle cx="${p.x}" cy="${p.y}" r="2" fill="red" /><circle cx="${p.x}" cy="${p.y}" r="1" fill="orange" />`;
}
}
return svgContent;
}
function renderParticles() {
let svgContent = "";
for (let p of game.particles) {
svgContent += `<circle cx="${p.x}" cy="${p.y}" r="${p.size}"
fill="${p.color}" opacity="${p.life / 60}" />`;
}
return svgContent;
}
function renderBackground(){
return bgDefs[scenario.terrain]+`<rect x="0" y="0" width="${WORLD_W}" height="${WORLD_H}"
fill="${bgColors[scenario.terrain]}" filter="url(#${scenario.terrain})" />`;
}
*/ |
| SC Arguments: [Name:SC_ACTION Type:uint64 Value:'1' Name:SC_CODE Type:string Value:'// Copyright 2024. Civilware. All rights reserved.
// TELA Decentralized Web Document (TELA-DOC-1)
Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("nameHdr", "render.js")
31 STORE("descrHdr", "Render JS file")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "render.js")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "10b44b024d75648f61f836b669932e55096c11fa08bc7f2d3f96b4d8b4f320ca")
37 STORE("fileCheckS", "270c108d5304063fa78086811fa47db21ea7f14776c1b91517355143370171d4")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*//----------
// Rendering
function render() {
let svgContent = `<defs>
<filter id="shadow45" x="-50%" y="-50%" width="200%" height="200%">
<feDropShadow dx="6" dy="6" stdDeviation="4" flood-color="rgba(0,0,0,0.4)" />
</filter>
<radialGradient id="turretDome" cx="0.5" cy="0.5" r="0.5">
<stop offset="0%" stop-color="white" stop-opacity="0.8" />
<stop offset="25%" stop-color="white" stop-opacity="0.8" />
<stop offset="100%" stop-color="black" stop-opacity="1" />
</radialGradient>
</defs>
`;
svgContent += renderBackground();
svgContent += renderWorldObjects();
svgContent += renderBases();
svgContent += renderEnemies();
svgContent += renderPlayer();
svgContent += renderTurret();
svgContent += renderProjectiles();
svgContent += renderParticles();
svg.innerHTML = svgContent;
renderMinimap();
renderState();
}
function setState(s) {
game.state = s;
}
function renderState() {
if (game.state === STATE.MENU) {
hud.innerHTML = `
<text x="100" y="40" fill="white" text-anchor="middle" font-size="24" font-weight="bold" stroke="black" stroke-width=".2">
FULL TANK
</text>
<text x="100" y="60" fill="yellow" text-anchor="middle" font-size="16" font-weight="bold" stroke="black" stroke-width=".2">
Press ENTER to Begin
</text>
<text x="100" y="80" fill="yellow" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
Movement: w, a, s, d | Turret: l, '
</text>
<text x="100" y="100" fill="yellow" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
Shoot: Space, Turret: ;
</text>
`;
}
else if (game.state === STATE.MISSION_SELECT) {
hud.innerHTML = `
<text x="100" y="30" fill="white" text-anchor="middle" font-size="20" font-weight="bold" stroke="black" stroke-width=".2">
Select Mission
</text>`;
const scenarios = getScenario();
let y = 30;
for (const key in scenarios) {
const scen = scenarios[key];
y += 20;
let tColor = "yellow";
if (levelSelector == scen.id) {
tColor = "orange";
}
hud.innerHTML += `<text x="100" y="${y}" fill="${tColor}" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
${scen.id} - ${scen.mission}
</text>`;
}
}
else if (game.state === STATE.DEAD) {
hud.innerHTML = `
<text x="100" y="40" fill="red" text-anchor="middle" font-size="24" font-weight="bold" stroke="black" stroke-width=".2">
YOU DIED
</text>
<text x="100" y="80" fill="white" text-anchor="middle" font-size="16" font-weight="bold" stroke="black" stroke-width=".2">
Press R to Restart
</text>`;
}
else if (game.state === STATE.WIN) {
let t1 = "MISSION COMPLETE";
let t2 = "to Continue";
if(scenario.id == Object.keys(getScenario()).length) {
t1 = "YOU BEAT THE GAME!";
t2 = "for Menu";
}
hud.innerHTML = `
<text x="100" y="40" fill="lime" text-anchor="middle" font-size="18" font-weight="bold" stroke="black" stroke-width=".2">
${t1}
</text>
<text x="100" y="80" fill="white" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
Press ENTER or START
</text>
<text x="100" y="100" fill="white" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
${t2}
</text>`;
}
else if (game.state === STATE.PAUSED) {
let out = `
<text x="100" y="40" fill="lime" text-anchor="middle" font-size="20" font-weight="bold" stroke="black" stroke-width=".2">
PAUSED
</text>
<text x="100" y="80" fill="white" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
Press Esc or START to Resume
</text>`;
if (game.state === STATE.PAUSED) {
out +=`<text x="100" y="120" fill="white" text-anchor="middle" font-size="14" font-weight="bold" stroke="black" stroke-width=".2">
VOLUME: ${(volume * 100)|0}%
</text>`;
}
hud.innerHTML = out;
}
else {
renderHUD();
}
}
function renderHUD() {
const p = game.player;
const hpPercent = p.hp / p.maxHp;
const ammoPercent = p.ammo / p.maxAmmo;
if (hpPercent < 0 | ammoPercent < 0) return;
hud.innerHTML = `
<rect x="20" y="20" width="200" height="20" fill="black" opacity="0.5"/>
<rect x="20" y="20" width="${200 * hpPercent}" height="20" fill="red"/>
<text x="125" y="35" fill="white" font-size="14" text-anchor="middle">
HP: ${p.hp}/${p.maxHp}
</text>
<rect x="20" y="50" width="200" height="20" fill="black" opacity="0.5"/>
<rect x="20" y="50" width="${200 * ammoPercent}" height="20" fill="yellow"/>
<text x="125" y="65" fill="black" font-size="14" text-anchor="middle">
Ammo: ${p.ammo}/${p.maxAmmo}
</text>`;
}
// Mini map
function mapX(x) { return x * mapScaleX; }
function mapY(y) { return y * mapScaleY; }
function renderMinimap() {
let out = "";
// Background
out += `<rect x="0" y="0" width="${MAP_W}" height="${MAP_H}" fill="#222" stroke="#555" />`;
// Bases
for (const b of game.bases) {
// Transform each polygon vertex into minimap space
let pts = b.poly
.map(p => {
const wx = b.x + p.x; // world X
const wy = b.y + p.y; // world Y
return `${mapX(wx)},${mapY(wy)}`;
})
.join(" ");
out += `<polygon points="${pts}" fill="rgba(255,0,0,0.5)" />`;
}
// Enemies
for (const e of game.enemies) {
out += `<circle cx="${mapX(e.x)}" cy="${mapY(e.y)}" r="2" fill="red" />`;
}
// Player
out += `<circle cx="${mapX(game.player.x)}" cy="${mapY(game.player.y)}" r="3" fill="cyan" />`;
// Camera view rectangle
out += `
<rect x="${mapX(camLeft)}"
y="${mapY(camTop)}"
width="${(camRight - camLeft) * mapScaleX}"
height="${(camBottom - camTop) * mapScaleY}"
fill="none" stroke="white" stroke-width="1" />
`;
map.innerHTML = out;
}
// Game rendering
function inView(obj, margin = 200) {
let left, right, top, bottom;
if (obj.w !== undefined) {
// Rectangle
left = obj.x;
right = obj.x + obj.w;
top = obj.y;
bottom = obj.y + obj.h;
} else if (obj.r !== undefined) {
// Circle
left = obj.x - obj.r;
right = obj.x + obj.r;
top = obj.y - obj.r;
bottom = obj.y + obj.r;
} else {
// Point-like (enemy, projectile)
left = right = obj.x;
top = bottom = obj.y;
}
return (
right > camLeft - margin &&
left < camRight + margin &&
bottom > camTop - margin &&
top < camBottom + margin
);
}
// Get world entity polygon
function getWorldPoly(entity) {
const cos = Math.cos(entity.angle);
const sin = Math.sin(entity.angle);
return entity.poly.map(p => ({
x: entity.x + p.x * cos - p.y * sin,
y: entity.y + p.x * sin + p.y * cos
}));
}
// Render entities svgs
function renderBases() {
let svgContent = "";
for (const b of game.bases) {
if (!inView(b)) continue;
const pts = getWorldPoly(b)
.map(p => `${p.x},${p.y}`)
.join(" ");
svgContent += `<polygon points="${pts}" fill="brown" filter="url(#shadow45)" />`
}
return svgContent;
}
function renderEnemies(){
let svgContent = "";
for (const e of game.enemies) {
if (!inView(e)) continue;
const pts = getWorldPoly(e)
.map(p => `${p.x},${p.y}`)
.join(" ");
svgContent += `<polygon points="${pts}" stroke="black" stroke-width="0.5" fill="#913d00" filter="url(#shadow45)" />`;
if(e.type !== "tank"){
const wsObj = {
x: e.x,
y: e.y,
angle: e.angle,
poly: e.windshield
};
const wsPts = getWorldPoly(wsObj)
.map(p => `${p.x},${p.y}`)
.join(" ");
svgContent += `
<polygon points="${wsPts}"
fill="gray"
stroke="black"
stroke-width="0.5" />
`;
} else {
const turretObj = {
x: e.x,
y: e.y,
angle: e.turret.angle,
poly: e.turret.poly
};
const pts = getWorldPoly(turretObj)
.map(p => `${p.x},${p.y}`)
.join(" ");
svgContent += `<circle cx="${e.x}" cy="${e.y}" r="10" fill="url(#turretDome)" />
<polygon points="${pts}" fill="gray" stroke="black" stroke-width="0.5" />`;
}
}
return svgContent;
}
function renderPlayer() {
const pts = getWorldPoly(game.player)
.map(p => `${p.x},${p.y}`)
.join(" ");
return `<polygon points="${pts}" stroke="black" stroke-width="0.5" fill="#123472" filter="url(#shadow45)" />
<circle cx="${game.player.x}" cy="${game.player.y}" r="10" fill="url(#turretDome)" />`;
}
function renderTurret() {
const turretObj = {
x: game.player.x,
y: game.player.y,
angle: game.player.angle + game.player.turret.offset,
poly: game.player.turret.poly
};
const tp = getWorldPoly(turretObj);
return `<polygon points="${tp.map(p => `${p.x},${p.y}`).join(' ')}"
fill="gray" stroke="black" stroke-width="1" />`;
}
// non-rotating
function renderWorldObjects(){
let svgContent = "";
// draw some world objects for testing
for (const obj of worldObjects) {
if (!inView(obj)) continue;
const pts = getWorldPoly(obj)
.map(p => `${p.x},${p.y}`)
.join(" ");
let fill = treeColors[scenario.terrain];
if(obj.type == "rock"){fill = "grey";}
// Shadow first
svgContent += `
<polygon points="${pts}"
fill="black"
opacity="0.25"
transform="translate(4,4)" />
`;
svgContent += `<polygon points="${pts}" fill="${fill}" />`;
}
return svgContent;
}
function renderProjectiles(){
let svgContent = "";
for (const p of game.projectiles) {
const maxLen = 50;
// vector from start -> current
const vx = p.x - p.startX;
const vy = p.y - p.startY;
const dist = Math.hypot(vx, vy);
let tx, ty;
if (dist <= maxLen) {
tx = p.startX;
ty = p.startY;
} else {
const scale = maxLen / dist;
tx = p.x - vx * scale;
ty = p.y - vy * scale;
}
// draw trail
svgContent += `
<line x1="${tx}" y1="${ty}"
x2="${p.x}" y2="${p.y}"
stroke="grey" stroke-width="2" opacity="0.2" />
`;
// draw bullet
if(p.type === "player"){
svgContent += `<circle cx="${p.x}" cy="${p.y}" r="2" fill="yellow" />`;
} else if(p.type === "turret" | p.type === "tank"){
svgContent += `<circle cx="${p.x}" cy="${p.y}" r="4" fill="red" /><circle cx="${p.x}" cy="${p.y}" r="2" fill="orange" />`;
} else if(p.type === "enemy"){
svgContent += `<circle cx="${p.x}" cy="${p.y}" r="2" fill="red" /><circle cx="${p.x}" cy="${p.y}" r="1" fill="orange" />`;
}
}
return svgContent;
}
function renderParticles() {
let svgContent = "";
for (let p of game.particles) {
svgContent += `<circle cx="${p.x}" cy="${p.y}" r="${p.size}"
fill="${p.color}" opacity="${p.life / 60}" />`;
}
return svgContent;
}
function renderBackground(){
return bgDefs[scenario.terrain]+`<rect x="0" y="0" width="${WORLD_W}" height="${WORLD_H}"
fill="${bgColors[scenario.terrain]}" filter="url(#${scenario.terrain})" />`;
}
*/'] |