Point-to-Point Line-of-Sight* [size=1]Oops[/size]
Man that sounds so cool.
edit:
Since this original post I have learnt of the world of Raycasting. You can see my attempts of it in this post:
Here’s the script. I have used Flash 8’s BitmapData and Rectangle classes, but the theory could easily be applied to another tile-based world without any of these, these classes were simply used to display everything.
Use the Arrow keys to move the character, and the character aims to the mouse position.
http://icio.co.uk/random/files/flash/sight.swf
import flash.display.BitmapData;
import flash.geom.Rectangle;
Stage.scaleMode = "noScale";
Mouse.hide();
//*********************************************************
// Variables
var tileSize:Number = 10;
var map:Array = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1], [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1], [1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1], [1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]; // This is an awesomely-long line, y0. (762 characters before comment)
var baseBitmap:BitmapData = new BitmapData(map[0].length*tileSize, map.length*tileSize, false, 0xEEEEEE); _root.attachBitmap(baseBitmap, _root.getNextHighestDepth()); // \
var objBitmap:BitmapData = new BitmapData(baseBitmap.width, baseBitmap.height, true, 0x00000000); _root.attachBitmap(objBitmap, _root.getNextHighestDepth()); // |- The bitmaps used in the game
var hitBitmap:BitmapData = new BitmapData(baseBitmap.width, baseBitmap.height, true, 0x0000FF00); _root.attachBitmap(hitBitmap, _root.getNextHighestDepth()); // /
var tileRectangle:Rectangle = new Rectangle(0, 0, tileSize, tileSize); // A Rectangle object for drawing tiles onto the base bitmap.
var objects:Array = []; // An array of all the objects
var player:Object = {y:10*tileSize, x:1*tileSize, color:0xFFFF3399, xspd:0, yspd:0}; objects.push(player); // The player object
for (y=0; y<map.length; y++) { for (x=0; x<map[0].length; x++) { if (map[y][x] == 1) { // Cycle through the numbers in the map and process, then
tileRectangle.x = x*tileSize; tileRectangle.y = y*tileSize; // Reposition the tile rectangle
baseBitmap.fillRect(tileRectangle, 0x999999); // Draw it onto the base bitmap
} } }
// Draw the objects onto the object bitmap
function drawObjects() { objBitmap.fillRect(objBitmap.rectangle, 0x00000000); for (i in objects) { objBitmap.fillRect(new Rectangle(objects*.x, objects*.y, tileSize, tileSize), objects*.color); } objBitmap.fillRect(new Rectangle(_xmouse-1, _ymouse-1, 3, 3), 0xFFFF0000); }
//****************************************************************************************
// THE IMPORTANT FUNCTION - THIS IS WHAT IT'S ALL ABOUT !! *******************************
//****************************************************************************************
function lineOfSite(x1:Number, y1:Number, x2:Number, y2:Number) {
var dist:Number = Math.sqrt(Math.pow(x2-x1, 2)+Math.pow(y2-y1, 2)); // The distance from the start point to end point
var angle:Number = Math.atan((y2-y1)/(x2-x1)); // The angle from start point to end point (in radians)
angle += x2-x1<0 ? Math.PI : 0; // angle correction
angle += x2-x1>=0 && y2-y1<0 ? 2*Math.PI : 0; // angle correction
hitBitmap.fillRect(hitBitmap.rectangle, 0x0000FF00); // (Eye-Candy)
var pos:Number = 0; // Where we're going to start from on the line
while (pos < dist) { // Loop until we've tested further than, or to the same distance as, the total distance
pos = pos+1<=dist ? pos+1 : dist; // Move onto the test position. (Increasing/Decreasing '1' increases/decreases accuracy)
var x:Number = Math.floor(pos*Math.cos(angle)+x1); // Calculate the new x-coordinate for testing
var y:Number = Math.floor(pos*Math.sin(angle)+y1); // Calculate the new y-coordinate for testing
if (map[Math.floor(y/tileSize)][Math.floor(x/tileSize)] == 1) { // Check to see if the current point's relative tile is '1' or '0'
break; // Exit the loop if the tile is a '1'. Upon exitting, `x` and `y` maintain the coordinates
}
hitBitmap.setPixel32(x, y, 0xFF666666); // (Eye-Candy)
}
hitBitmap.fillRect(new Rectangle((pos==dist?x2: x)-1, (pos==dist?y2:y)-1, 3, 3), pos==dist?0xFF0000FF:0xFF000000); // (Eye-Candy)
return pos==dist; // Will return true if the target was reachable and false otherwise.
}
//****************************************************************************************
//*********************************************************
// Player Movement - Can't be assed commenting all of this.
function movePlayer() {
player.xspd += Key.isDown(Key.RIGHT)?1: (Key.isDown(Key.LEFT)?-1:0); player.xspd = Math.abs(player.xspd)>tileSize?tileSize*player.xspd/Math.abs(player.xspd):player.xspd;
player.yspd += Key.isDown(Key.DOWN)?1: (Key.isDown(Key.UP)?-1:0); player.yspd = Math.abs(player.yspd)>tileSize?tileSize*player.yspd/Math.abs(player.yspd):player.yspd;
if (!Key.isDown(Key.RIGHT) && !Key.isDown(Key.LEFT)) { player.xspd *= Math.abs(player.xspd)<0.1?0:0.8; }
if (!Key.isDown(Key.UP) && !Key.isDown(Key.DOWN)) { player.yspd *= Math.abs(player.yspd)<0.1?0:0.8; }
var xL:Number = Math.floor(player.x / tileSize); var xR:Number = Math.floor((player.x+tileSize-1) / tileSize);
var yT:Number = Math.floor(player.y / tileSize); var yB:Number = Math.floor((player.y+tileSize-1) / tileSize);
var maxL:Number = xL*tileSize; var maxR:Number = xR*tileSize;
var maxU:Number = yT*tileSize; var maxD:Number = yB*tileSize;
var cL:Boolean = !(map[yT][xL-1]==1 || map[yB][xL-1]==1);
var cR:Boolean = !(map[yT][xR+1]==1 || map[yB][xR+1]==1);
var cU:Boolean = !(map[yT-1][xL]==1 || map[yT-1][xR]==1);
var cD:Boolean = !(map[yB+1][xL]==1 || map[yB+1][xR]==1);
var xmove:Number = player.xspd; var ymove:Number = player.yspd;
if (!cL && player.x+player.xspd < maxL) { xmove = maxL - player.x; player.xspd = 0; }
if (!cR && player.x+player.xspd > maxR) { xmove = maxR - player.x; player.xspd = 0; }
if (!cU && player.y+player.yspd < maxU) { ymove = maxU - player.y; player.yspd = 0; }
if (!cD && player.y+player.yspd > maxD) { ymove = maxD - player.y; player.yspd = 0; }
player.x += xmove; player.y += ymove;
}
// Call Everything
_root.onEnterFrame = function() { movePlayer(); drawObjects(); lineOfSite(player.x+tileSize/2, player.y+tileSize/2, _xmouse, _ymouse); }
[size=1]Dam, smilies make it difficult to post code :P[/size]
Update:
Problems upload .swf at the moment, so here’s the .fla: