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", "collision.js")
31 STORE("descrHdr", "Collision JS file")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "collision.js")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "229bd798ed57b2e08fbbb6ade16088fab89c8dba49662d72638de3f26b84182b")
37 STORE("fileCheckS", "8e8a7e199990abb802effe782188278442e71d8d2ead8c6f576ff178f76b00")
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
/*//--------------------
// Collision detection
function collision(){
playerTerrainCollision();
playerBuildingCollision();
aiPlayerCollision();
aiVsAiCollision();
aiTerrainCollision();
projectileCollision();
}
function circleHit(ax, ay, ar, bx, by, br) {
const dx = ax - bx;
const dy = ay - by;
return dx*dx + dy*dy <= (ar + br) * (ar + br);
}
function polyCircleHit(poly, cx, cy, r) {
// center inside poly
if (pointInPoly(cx, cy, poly)) return true;
// edge distance
for (let i = 0; i < poly.length; i++) {
const a = poly[i];
const b = poly[(i+1) % poly.length];
if (pointLineDistance(cx, cy, a.x, a.y, b.x, b.y) <= r)
return true;
}
return false;
}
function aabbHit(a, b) {
return (
a.x < b.x + b.w &&
a.x + a.w > b.x &&
a.y < b.y + b.h &&
a.y + a.h > b.y
);
}
function pointInPoly(px, py, poly, ox=0, oy=0) {
let inside = false;
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
const xi = poly[i].x + ox;
const yi = poly[i].y + oy;
const xj = poly[j].x + ox;
const yj = poly[j].y + oy;
const intersect =
((yi > py) !== (yj > py)) &&
(px < (xj - xi) * (py - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
}
//SAT collsion poly vs poly
function sat(polyA, polyB) {
let overlap = Infinity;
let smallestAxis = null;
// test both polygons' edges
for (const poly of [polyA, polyB]) {
for (let i = 0; i < poly.length; i++) {
const p1 = poly[i];
const p2 = poly[(i + 1) % poly.length];
// edge normal
const nx = p2.y - p1.y;
const ny = -(p2.x - p1.x);
let [minA, maxA] = project(polyA, nx, ny);
let [minB, maxB] = project(polyB, nx, ny);
if (maxA < minB || maxB < minA) return null;
const o = Math.min(maxA, maxB) - Math.max(minA, minB);
if (o < overlap) {
overlap = o;
smallestAxis = { x: nx, y: ny };
}
}
}
// normalize axis
const len = Math.hypot(smallestAxis.x, smallestAxis.y);
return {
overlap,
nx: smallestAxis.x / len,
ny: smallestAxis.y / len
};
}
function project(poly, nx, ny) {
let min = Infinity, max = -Infinity;
for (const p of poly) {
const dot = p.x * nx + p.y * ny;
if (dot < min) min = dot;
if (dot > max) max = dot;
}
return [min, max];
}
function playerBuildingCollision() {
const p = game.player;
const pPoly = getWorldPoly(p);
for (const obj of game.bases) {
const oPoly = getWorldPoly(obj);
const pen = sat(pPoly, oPoly);
if (!pen) continue;
if (pen.overlap < 0.1) continue;
const push = Math.min(pen.overlap, 3);
// vector from obstacle center to player center
const dx = p.x - obj.x;
const dy = p.y - obj.y;
// flip normal so it always points outward
let nx = pen.nx;
let ny = pen.ny;
if (dx * nx + dy * ny < 0) {
nx = -nx;
ny = -ny;
}
// push out
p.x += nx * push;
p.y += ny * push;
}
}
function playerTerrainCollision() {
const p = game.player;
const pPoly = getWorldPoly(p);
for (const obj of worldObjects) {
const oPoly = getWorldPoly(obj);
const pen = sat(pPoly, oPoly);
if (!pen) continue;
if (pen.overlap < 0.1) continue;
const push = Math.min(pen.overlap, 3);
// vector from obstacle center to player center
const dx = p.x - obj.x;
const dy = p.y - obj.y;
// flip normal so it always points outward
let nx = pen.nx;
let ny = pen.ny;
if (dx * nx + dy * ny < 0) {
nx = -nx;
ny = -ny;
}
// push out
p.x += nx * push;
p.y += ny * push;
}
}
function applyAISteeringAfterCollision(e, nx, ny) {
const hitAngle = Math.atan2(ny, nx);
let diff = hitAngle - e.angle;
diff = Math.atan2(Math.sin(diff), Math.cos(diff));
e.angle += diff * 0.15; // steer away
}
function aiTerrainCollision() {
for (const obj of worldObjects) {
for (const e of game.enemies) {
const oPoly = getWorldPoly(obj);
const aiPoly = getWorldPoly(e);
const pen = sat(aiPoly, oPoly);
if (!pen) continue;
if (pen.overlap < 0.1) continue;
const push = Math.min(pen.overlap, 3);
// vector from obstacle center to player center
const dx = e.x - obj.x;
const dy = e.y - obj.y;
// flip normal so it always points outward
let nx = pen.nx;
let ny = pen.ny;
if (dx * nx + dy * ny < 0) {
nx = -nx;
ny = -ny;
}
// push out
e.x += nx * push;
e.y += ny * push;
applyAISteeringAfterCollision(e, nx, ny);
}
}
}
function aiPlayerCollision() {
const pPoly = getWorldPoly(game.player);
for (const obj of game.enemies) {
const aiPoly = getWorldPoly(obj);
const pen = sat(aiPoly, pPoly);
if (!pen || pen.overlap < 0.1) continue;
const aiPush = Math.min(pen.overlap, obj.weight);
const pPush = Math.min(pen.overlap, 5);
// vector from player to AI
const dx = obj.x - game.player.x;
const dy = obj.y - game.player.y;
let nx = pen.nx;
let ny = pen.ny;
// player AI away from AI
game.player.x += nx * aiPush;
game.player.y += ny * aiPush;
if (dx * nx + dy * ny < 0) {
nx = -nx;
ny = -ny;
}
// push AI away from player
obj.x += nx * pPush;
obj.y += ny * pPush;
}
}
function aiVsAiCollision() {
for (let i = 0; i < game.enemies.length; i++) {
for (let j = i + 1; j < game.enemies.length; j++) {
const a = game.enemies[i];
const b = game.enemies[j];
const aPoly = getWorldPoly(a);
const bPoly = getWorldPoly(b);
const pen = sat(aPoly, bPoly);
if (!pen || pen.overlap < 0.1) continue;
const push = Math.min(pen.overlap, 3);
// vector from b to a
const dx = a.x - b.x;
const dy = a.y - b.y;
let nx = pen.nx;
let ny = pen.ny;
if (dx * nx + dy * ny < 0) {
nx = -nx;
ny = -ny;
}
// split push 50/50
a.x += nx * push * 0.5;
a.y += ny * push * 0.5;
b.x -= nx * push * 0.5;
b.y -= ny * push * 0.5;
}
}
}
function projectileCollision() {
// --- Collision checks ---
for (let p of game.projectiles) {
// Bullet vs Player
if (p.type === "enemy" || p.type === "tank") {
if (pointInPoly(p.x, p.y, game.player.poly, game.player.x, game.player.y)) {
game.player.hp -= p.damage;
p.life = 0;
if (game.player.hp <= 0) {
sfxExplosion();
game.player.dead = true;
spawnParticles(game.player.x, game.player.y, 20);
}
}
}
// Bullet vs Enemies
for (let e of game.enemies) {
if ((p.type === "player" || p.type === "turret") &&
pointInPoly(p.x, p.y, e.poly, e.x, e.y)) {
e.hp -= p.damage;
p.life = 0;
if (e.hp <= 0) {
sfxExplosion();
e.dead = true;
spawnParticles(e.x, e.y, 20);
}
}
}
// Bullet vs Bases
for (let b of game.bases) {
if (p.type !== "player" && p.type !== "turret")continue;
const bPoly = getWorldPoly(b);
if(pointInPoly(p.x, p.y, bPoly)) {
b.hp -= p.damage
p.life = 0;
if (b.hp <= 0) {
sfxExplosion();
b.dead = true;
spawnFireworks(b.x, b.y, 40);
}
}
}
// Bullet vs Terrain
for (let obj of worldObjects) {
if (pointInPoly(p.x, p.y, obj.poly, obj.x, obj.y)) {
p.life = 0;
if (p.type !== "player" && p.type !== "turret") continue;
obj.hp -= p.damage;
if (obj.hp <= 0) {
obj.dead = true;
spawnParticles(obj.x, obj.y, 12);
}
}
}
}
// --- Cleanup ---
game.enemies = game.enemies.filter(e => !e.dead);
game.bases = game.bases.filter(b => !b.dead);
worldObjects = worldObjects.filter(o => !o.dead);
game.projectiles = game.projectiles.filter(p => p.life > 0);
}*/ |
| 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", "collision.js")
31 STORE("descrHdr", "Collision JS file")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "collision.js")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "229bd798ed57b2e08fbbb6ade16088fab89c8dba49662d72638de3f26b84182b")
37 STORE("fileCheckS", "8e8a7e199990abb802effe782188278442e71d8d2ead8c6f576ff178f76b00")
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
/*//--------------------
// Collision detection
function collision(){
playerTerrainCollision();
playerBuildingCollision();
aiPlayerCollision();
aiVsAiCollision();
aiTerrainCollision();
projectileCollision();
}
function circleHit(ax, ay, ar, bx, by, br) {
const dx = ax - bx;
const dy = ay - by;
return dx*dx + dy*dy <= (ar + br) * (ar + br);
}
function polyCircleHit(poly, cx, cy, r) {
// center inside poly
if (pointInPoly(cx, cy, poly)) return true;
// edge distance
for (let i = 0; i < poly.length; i++) {
const a = poly[i];
const b = poly[(i+1) % poly.length];
if (pointLineDistance(cx, cy, a.x, a.y, b.x, b.y) <= r)
return true;
}
return false;
}
function aabbHit(a, b) {
return (
a.x < b.x + b.w &&
a.x + a.w > b.x &&
a.y < b.y + b.h &&
a.y + a.h > b.y
);
}
function pointInPoly(px, py, poly, ox=0, oy=0) {
let inside = false;
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
const xi = poly[i].x + ox;
const yi = poly[i].y + oy;
const xj = poly[j].x + ox;
const yj = poly[j].y + oy;
const intersect =
((yi > py) !== (yj > py)) &&
(px < (xj - xi) * (py - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
}
//SAT collsion poly vs poly
function sat(polyA, polyB) {
let overlap = Infinity;
let smallestAxis = null;
// test both polygons' edges
for (const poly of [polyA, polyB]) {
for (let i = 0; i < poly.length; i++) {
const p1 = poly[i];
const p2 = poly[(i + 1) % poly.length];
// edge normal
const nx = p2.y - p1.y;
const ny = -(p2.x - p1.x);
let [minA, maxA] = project(polyA, nx, ny);
let [minB, maxB] = project(polyB, nx, ny);
if (maxA < minB || maxB < minA) return null;
const o = Math.min(maxA, maxB) - Math.max(minA, minB);
if (o < overlap) {
overlap = o;
smallestAxis = { x: nx, y: ny };
}
}
}
// normalize axis
const len = Math.hypot(smallestAxis.x, smallestAxis.y);
return {
overlap,
nx: smallestAxis.x / len,
ny: smallestAxis.y / len
};
}
function project(poly, nx, ny) {
let min = Infinity, max = -Infinity;
for (const p of poly) {
const dot = p.x * nx + p.y * ny;
if (dot < min) min = dot;
if (dot > max) max = dot;
}
return [min, max];
}
function playerBuildingCollision() {
const p = game.player;
const pPoly = getWorldPoly(p);
for (const obj of game.bases) {
const oPoly = getWorldPoly(obj);
const pen = sat(pPoly, oPoly);
if (!pen) continue;
if (pen.overlap < 0.1) continue;
const push = Math.min(pen.overlap, 3);
// vector from obstacle center to player center
const dx = p.x - obj.x;
const dy = p.y - obj.y;
// flip normal so it always points outward
let nx = pen.nx;
let ny = pen.ny;
if (dx * nx + dy * ny < 0) {
nx = -nx;
ny = -ny;
}
// push out
p.x += nx * push;
p.y += ny * push;
}
}
function playerTerrainCollision() {
const p = game.player;
const pPoly = getWorldPoly(p);
for (const obj of worldObjects) {
const oPoly = getWorldPoly(obj);
const pen = sat(pPoly, oPoly);
if (!pen) continue;
if (pen.overlap < 0.1) continue;
const push = Math.min(pen.overlap, 3);
// vector from obstacle center to player center
const dx = p.x - obj.x;
const dy = p.y - obj.y;
// flip normal so it always points outward
let nx = pen.nx;
let ny = pen.ny;
if (dx * nx + dy * ny < 0) {
nx = -nx;
ny = -ny;
}
// push out
p.x += nx * push;
p.y += ny * push;
}
}
function applyAISteeringAfterCollision(e, nx, ny) {
const hitAngle = Math.atan2(ny, nx);
let diff = hitAngle - e.angle;
diff = Math.atan2(Math.sin(diff), Math.cos(diff));
e.angle += diff * 0.15; // steer away
}
function aiTerrainCollision() {
for (const obj of worldObjects) {
for (const e of game.enemies) {
const oPoly = getWorldPoly(obj);
const aiPoly = getWorldPoly(e);
const pen = sat(aiPoly, oPoly);
if (!pen) continue;
if (pen.overlap < 0.1) continue;
const push = Math.min(pen.overlap, 3);
// vector from obstacle center to player center
const dx = e.x - obj.x;
const dy = e.y - obj.y;
// flip normal so it always points outward
let nx = pen.nx;
let ny = pen.ny;
if (dx * nx + dy * ny < 0) {
nx = -nx;
ny = -ny;
}
// push out
e.x += nx * push;
e.y += ny * push;
applyAISteeringAfterCollision(e, nx, ny);
}
}
}
function aiPlayerCollision() {
const pPoly = getWorldPoly(game.player);
for (const obj of game.enemies) {
const aiPoly = getWorldPoly(obj);
const pen = sat(aiPoly, pPoly);
if (!pen || pen.overlap < 0.1) continue;
const aiPush = Math.min(pen.overlap, obj.weight);
const pPush = Math.min(pen.overlap, 5);
// vector from player to AI
const dx = obj.x - game.player.x;
const dy = obj.y - game.player.y;
let nx = pen.nx;
let ny = pen.ny;
// player AI away from AI
game.player.x += nx * aiPush;
game.player.y += ny * aiPush;
if (dx * nx + dy * ny < 0) {
nx = -nx;
ny = -ny;
}
// push AI away from player
obj.x += nx * pPush;
obj.y += ny * pPush;
}
}
function aiVsAiCollision() {
for (let i = 0; i < game.enemies.length; i++) {
for (let j = i + 1; j < game.enemies.length; j++) {
const a = game.enemies[i];
const b = game.enemies[j];
const aPoly = getWorldPoly(a);
const bPoly = getWorldPoly(b);
const pen = sat(aPoly, bPoly);
if (!pen || pen.overlap < 0.1) continue;
const push = Math.min(pen.overlap, 3);
// vector from b to a
const dx = a.x - b.x;
const dy = a.y - b.y;
let nx = pen.nx;
let ny = pen.ny;
if (dx * nx + dy * ny < 0) {
nx = -nx;
ny = -ny;
}
// split push 50/50
a.x += nx * push * 0.5;
a.y += ny * push * 0.5;
b.x -= nx * push * 0.5;
b.y -= ny * push * 0.5;
}
}
}
function projectileCollision() {
// --- Collision checks ---
for (let p of game.projectiles) {
// Bullet vs Player
if (p.type === "enemy" || p.type === "tank") {
if (pointInPoly(p.x, p.y, game.player.poly, game.player.x, game.player.y)) {
game.player.hp -= p.damage;
p.life = 0;
if (game.player.hp <= 0) {
sfxExplosion();
game.player.dead = true;
spawnParticles(game.player.x, game.player.y, 20);
}
}
}
// Bullet vs Enemies
for (let e of game.enemies) {
if ((p.type === "player" || p.type === "turret") &&
pointInPoly(p.x, p.y, e.poly, e.x, e.y)) {
e.hp -= p.damage;
p.life = 0;
if (e.hp <= 0) {
sfxExplosion();
e.dead = true;
spawnParticles(e.x, e.y, 20);
}
}
}
// Bullet vs Bases
for (let b of game.bases) {
if (p.type !== "player" && p.type !== "turret")continue;
const bPoly = getWorldPoly(b);
if(pointInPoly(p.x, p.y, bPoly)) {
b.hp -= p.damage
p.life = 0;
if (b.hp <= 0) {
sfxExplosion();
b.dead = true;
spawnFireworks(b.x, b.y, 40);
}
}
}
// Bullet vs Terrain
for (let obj of worldObjects) {
if (pointInPoly(p.x, p.y, obj.poly, obj.x, obj.y)) {
p.life = 0;
if (p.type !== "player" && p.type !== "turret") continue;
obj.hp -= p.damage;
if (obj.hp <= 0) {
obj.dead = true;
spawnParticles(obj.x, obj.y, 12);
}
}
}
}
// --- Cleanup ---
game.enemies = game.enemies.filter(e => !e.dead);
game.bases = game.bases.filter(b => !b.dead);
worldObjects = worldObjects.filter(o => !o.dead);
game.projectiles = game.projectiles.filter(p => p.life > 0);
}*/'] |