Trying to get vision cone working, it's not going well

This commit is contained in:
2023-08-06 16:09:39 +10:00
parent 1f32e800c0
commit 33a9c2f0d1
3 changed files with 183 additions and 42 deletions

2
Box

Submodule Box updated: 443b373c87...ed1da29186

View File

@@ -15,28 +15,32 @@ var mapGridHeight: int = null;
//entities //entities
var player: opaque = null; var player: opaque = null;
var renderer: opaque = null;
//lifetime functions //lifetime functions
fn onInit(node: opaque) { fn onLoad(node: opaque) {
//init the rng with a seed (random) //init the rng with a seed (random)
if (rng != null) { if (rng != null) {
rng.freeRandomGenerator(); rng.freeRandomGenerator();
} }
rng = createRandomGenerator(clock().hash()); rng = createRandomGenerator(clock().hash());
//generate the level, filling out the entity data
node.generateLevel(rng);
//generate the child node to render the map //generate the child node to render the map
var renderer: opaque = node.loadChildNode("scripts:/tilemap/renderer.toy"); renderer = node.loadChildNode("scripts:/tilemap/renderer.toy");
renderer.callNodeFn("setTilemap", tilemap);
//load the music //load the music
loadMusic("music:/Music_Skylands_placeholder.ogg"); loadMusic("music:/Music_Skylands_placeholder.ogg");
playMusic(); playMusic();
} }
fn onInit(node: opaque) {
//generate the level, filling out the entity data
node.generateLevel(rng);
//update the visible area from the player's perspective
updateVisible();
}
fn onStep(node: opaque) { fn onStep(node: opaque) {
for (var i: int = 0; i < node.getChildNodeCount(); i++) { for (var i: int = 0; i < node.getChildNodeCount(); i++) {
var child = node.getChildNode(i); var child = node.getChildNode(i);
@@ -162,6 +166,14 @@ fn runAI(node: opaque) {
} }
} }
//update the visible portions of the map
fn updateVisible() {
var playerX: int = player.callNodeFn("getGridPositionX");
var playerY: int = player.callNodeFn("getGridPositionY");
renderer.callNodeFn("updateVisble", playerX, playerY, tilemap);
}
//for collisions //for collisions
fn getWalkableAt(node: opaque, x: int, y: int) { fn getWalkableAt(node: opaque, x: int, y: int) {
@@ -205,3 +217,4 @@ fn depthComparator(lhs: opaque, rhs: opaque) {
return lhsPositionY < rhsPositionY; return lhsPositionY < rhsPositionY;
} }

View File

@@ -1,6 +1,7 @@
import standard; import standard;
import engine; import engine;
import node; import node;
import math;
//constants for generating maps //constants for generating maps
@@ -23,6 +24,9 @@ var MAP_GRID_WIDTH: int const = CELL_WIDTH * CELL_COUNT_X;
var MAP_GRID_HEIGHT: int const = CELL_HEIGHT * CELL_COUNT_Y; var MAP_GRID_HEIGHT: int const = CELL_HEIGHT * CELL_COUNT_Y;
var tilemapCache = [];
//lifecycle functions //lifecycle functions
fn onLoad(node: opaque) { fn onLoad(node: opaque) {
//load the atlas into this node //load the atlas into this node
@@ -31,28 +35,74 @@ fn onLoad(node: opaque) {
//create a child as a render target //create a child as a render target
var child: opaque = node.loadChildNode("scripts:/tilemap/renderer-child.toy"); var child: opaque = node.loadChildNode("scripts:/tilemap/renderer-child.toy");
child.createNodeTexture(MAP_GRID_WIDTH * TILE_PIXEL_WIDTH, MAP_GRID_HEIGHT * TILE_PIXEL_HEIGHT); child.createNodeTexture(MAP_GRID_WIDTH * TILE_PIXEL_WIDTH, MAP_GRID_HEIGHT * TILE_PIXEL_HEIGHT);
//generate a grid filled with only empty tiles, as a starting point
for (var j: int = 0; j < MAP_GRID_HEIGHT; j++) {
for (var i: int = 0; i < MAP_GRID_WIDTH; i++) {
tilemapCache.push(-1); //x
tilemapCache.push(-1); //y
// tilemapCache.push(0); //collision
}
}
} }
//TODO: lazily render //lazily render
fn setTilemap(node: opaque, tilemap: [int]) { fn updateVisble(node: opaque, x: int, y: int, tilemap) {
assert tilemap, "provided tilemap is null (in setTilemap)"; print clock() + " - start updateVisible()";
print clock() + " - begin rendering map";
var child: opaque = node.getChildNode(0); var child: opaque = node.getChildNode(0);
setRenderTarget(child); setRenderTarget(child);
//draw the tilemap to the child //divide the regions into octants & determine what is visible
for (var j = 0; j < MAP_GRID_HEIGHT; j++) { node.shadowCastOctant(x, y, 1, 1, 10, tilemap);
for (var i = 0; i < MAP_GRID_WIDTH; i++) { node.shadowCastOctant(x, y, -1, 1, 10, tilemap);
//don't recalculate this every time node.shadowCastOctant(x, y, 1, -1, 10, tilemap);
var ITERATION: int const = j * MAP_GRID_WIDTH * 3 + i * 3; node.shadowCastOctant(x, y, -1, -1, 10, tilemap);
//reset the render target to the screen
setRenderTarget(null);
print clock() + " - end updateVisible()";
}
fn shadowCastOctant(node: opaque, x: int, y: int, dirX: int, dirY: int, depth: int, tilemap) {
var shadows = [];
//for each tile, cast its shadow, and see if its already obscured
for (var j: int = 0; abs(j) < depth; j += dirY) {
for (var i: int = 0; abs(i) < depth; i += dirX) {
//make sure this tile can actually cast a shadow
var CACHE_ITERATION: int const = (y + j) * MAP_GRID_WIDTH * 2 + (x + i) * 2;
var ITERATION: int const = (y + j) * MAP_GRID_WIDTH * 3 + (x + i) * 3;
//don't render empty tiles //don't render empty tiles
if (tilemap[ITERATION] < 0 || tilemap[ITERATION + 1] < 0) { if (ITERATION < 0 || ITERATION >= MAP_GRID_WIDTH * MAP_GRID_HEIGHT * 3 || tilemap[ITERATION] < 0 || tilemap[ITERATION + 1] < 0) {
continue; //break?
}
//don't re-render already drawn tiles
if (tilemapCache[CACHE_ITERATION] == tilemap[ITERATION] && tilemapCache[CACHE_ITERATION + 1] == tilemap[ITERATION + 1]) {
continue; continue;
} }
//cast the shadow
var shadow = shadowCastTile(i + x, j + y, dirX, dirY, depth);
//merge shadows if needed
var index: int = 0;
//find the insertion point
for (; index < shadows.length(); index++) {
if (shadows[index][0] >= shadow[0]) break;
}
print shadows.toString() + " " + string index;
//check to see if the tile should be rendered (prev iterations would have merged shadows)
if (shadows.length() == 0 || (shadows.length() > index && (index == 0 || shadows[index-1][1] <= shadow[1])) || (shadows.length() > index && (shadows.length() == index + 1 || shadows[index][0] >= shadow[0]) )) {
print "first bracket";
tilemapCache[CACHE_ITERATION] = tilemap[ITERATION];
tilemapCache[CACHE_ITERATION + 1] = tilemap[ITERATION + 1];
//set the rect of the node on the tilesheet - the "tilemap" var is a single blob of data //set the rect of the node on the tilesheet - the "tilemap" var is a single blob of data
node.setNodeRect( node.setNodeRect(
tilemap[ITERATION] * TILE_PIXEL_WIDTH, tilemap[ITERATION] * TILE_PIXEL_WIDTH,
@@ -60,18 +110,96 @@ fn setTilemap(node: opaque, tilemap: [int]) {
TILE_PIXEL_WIDTH, TILE_PIXEL_HEIGHT TILE_PIXEL_WIDTH, TILE_PIXEL_HEIGHT
); );
print string((x + i) * TILE_PIXEL_WIDTH) + ", " + string((y + j) * TILE_PIXEL_HEIGHT);
//draw to the screen //draw to the screen
node.drawNode( node.drawNode(
(i * TILE_PIXEL_WIDTH), ((x + i) * TILE_PIXEL_WIDTH),
(j * TILE_PIXEL_HEIGHT), ((y + j) * TILE_PIXEL_HEIGHT),
TILE_PIXEL_WIDTH, TILE_PIXEL_WIDTH,
TILE_PIXEL_HEIGHT TILE_PIXEL_HEIGHT
); );
} }
var overlapping = false;
//see if the new shadow overlaps the previous
if (index > 0 && shadows.length() > index && shadows[index -1][1] > shadow[0]) {
print "second bracket";
overlapping = true;
shadows[index-1][1] = shadow[1]; //extend the prev shadow
//see if the newly extended prev overlaps the shadow at "index"
if (shadows[index-1][1] >= shadows[index][0]) {
//merge the two
shadows[index-1][1] = shadows[index][1];
shadows = shadows.remove(index);
}
} }
//reset the render target to the screen //see if the new shadow overlaps the one at "index"
setRenderTarget(null); else if (shadows.length() > index && shadows[index][1] <= shadow[0]) {
print "third bracket";
overlapping = true;
//extend the next shadow
shadows[index][1] = shadow[0];
}
print clock() + " - end rendering map"; if (!overlapping) {
print "fourth bracket";
//insert at this position
shadows = shadows.insert(index, shadow);
}
}
}
}
fn shadowCastTile(x: int, y: int, dirX: int, dirY: int, depth: int) {
//top-left corner & bottom-right corner forms a triangle with the player
//top-left = x & y
//bottom-right = x + sign(dirX) & y + sign(dirY)
var start = abs(shadowCastPoint(x, y, depth));
var end = abs(shadowCastPoint(x + sign(dirX), y + sign(dirY), depth));
return [start, end];
}
fn shadowCastPoint(x: float, y: float, depth: int) {
// if (y == 0) {
// return sin(tan(INFINITY));
// }
return sin(tan(x/y)) * depth;
}
//polyfill the insert function
fn insert(self, k, v) {
//eew
var tmp1 = v;
var tmp2;
for (var i = k; i < self.length(); i++) {
tmp2 = self[i];
self[i] = tmp1;
tmp1 = tmp2;
}
self.push(tmp1);
return self;
}
//polyfill the remove function
fn remove(self, k) {
//double eew
var result = [];
for (var i = 0; i <= k - 1; i++) {
result.push( self[i] );
}
for (var i = k + 1; i < self.length(); i++) {
result.push( self[i] );
}
return result;
} }