Ray Casting

Ray Casting Class Day(year) Report on 12/31

The whole class was rewritten. and this time I will do step by step until each function I wrote is tested.
This version still can't do anything about ray casting, but it created a map system that is great for debugging. what I have learned today about coding is read the manual and know what each function does. Like tan() take in radian instead of degree. so deg2rad() will be useful.
After the completion of this, debugging will be a lot easier because I can get a 2D view of the point of view.. I just need to include the field of view in(should be quite soon)
Here is what the map view looks like right now.
raycasting map
And here is the code generates everything.

set_time_limit(5);
class raycasting{
	var $map;
	var $pov;
	var $ceiling = 64;
	var $direction;
	var $scale = 32;
	var $map_image;
	var $color;
//function that import a map
function create_map($string){
	$string = explode("\n",$string);
	$i = 0;
	$count = count($string);
	while($i<$count){
		$string[$i] = explode(' ', $string[$i]);
		++$i;
	}
	//now, it should created an array hold the map, it is acessed like $array[$x][$y]
	$this->map = $string;
}
 
function iswall($x, $y){
	if($this->map[floor($x/$this->scale)][floor($y/$this->scale)]){
		return true;
	}else{
		return false;
	}
}
function create_pov($x, $y, $z, $a){
	//$x, $y will be where the character at on the 2D map. $a is the viewing angle
	//don't care about $z, for now $z is half of the scale
	//each value have to be interger except $a. it also have to exsit inside the map
	$border = count($this->map)*$this->scale;
	if($x>$border){
		die('outside border');
	}else{
		$x = abs(round($x));
	}
	$border = count($this->map[0])*$this->scale;
	if($y>$border){
		die('outside border');
	}else{
		$y = abs(round($y));
	}
	//$x, $y can't be in a wall
	if($this->iswall($x, $y)){
		die('this is wall');
	}
	if($z>$this->ceiling){
		$z = $this->ceiling;
	}else{
		$z = abs(round($z));
	}
	//angle treated differently
	while($a < 0){
		$a += 360;
	}
	while($a >= 360){
		$a -= 360;
	}
	//test for y increase or decrease
	if (180>$a){
		$this->direction['y'] = -1;
	}elseif(180<$a){
		$this->direction['y'] = 1;
	}
	//test for x increase or decrease
	if (270>$a && 90<$a){
		$this->direction['x'] = -1;
	}elseif(($a>270 or $a<90) or $a == 0){
		$this->direction['x'] = 1;
	}
	//so if it's 90, 270 ,180 or 0 degree, x or y can be 0;
 
	//create the tri_a, the angle for the triangle it creates
	$tri_a = $a;
	while($tri_a >= 90){
		$tri_a -= 90;
	}
	//post everything as an array for pov
	$this->pov = array('x' => $x,
						'y' => $y,
						'z' => $z,
						'a' => $a,
						'tri_a' => $tri_a);
}
 
function create_map_image(){
 
	$size = imagesx($this->map_image);
	//find the angle to draw
	if($this->direction['x'] == 1 && $this->direction['y'] == 1){
		$x = $size/2 + tan(deg2rad($this->pov['tri_a']))*$size/2;
		$y = $size;
	}elseif($this->direction['x'] == -1 && $this->direction['y'] == -1 ){
		$x = $size/2 - tan(deg2rad($this->pov['tri_a']))*$size/2;
		$y = 0;
	}elseif($this->direction['x'] == -1 && $this->direction['y'] == 1){
		$x = 0;
		$y = $size/2 + tan(deg2rad($this->pov['tri_a']))*$size/2;
	}elseif($this->direction['x'] == 1 && $this->direction['y'] == -1 ){
		$x = $size;
		$y = $size/2 - tan(deg2rad($this->pov['tri_a']))*$size/2;
	}elseif($this->direction['x'] == 0 && $this->direction['y'] == -1){
		$x = $size/2;
		$y = 0;
	}elseif($this->direction['x'] == 0 && $this->direction['y'] == 1){
		$x = $size/2;
		$y = $size;
	}elseif($this->direction['x'] == 1 && $this->direction['y'] == 0){
		$x = $size;
		$y = $size/2;
	}elseif($this->direction['x'] == -1 && $this->direction['y'] == 0){
		$x = 0;
		$y = $size/2;
	}
	//draw angle
	imageline($this->map_image, $size/2, $size/2, $x, $y, $this->color[1]);
	//draw map
	//draw grid
	$x= $this->pov['x'];
	$y= $this->pov['y'];
	//find where $x is in one scale grid;
	while($x > $this->scale){
		$x -= $this->scale;
	}
	while($y > $this->scale){
		$y -= $this->scale;
	}
	//plot user
	//color
	$user_color = imagecolorallocate($this->map_image, 0, 255, 255);
	//plot
	imagerectangle($this->map_image, $size/2-3,$size/2-3,$size/2+3,$size/2+3, $user_color);
	//plot grid;
	$grid_y = $size/2 + $this->scale - $y;
	while($grid_y > 0){
		$grid_y -= $this->scale;
		imageline($this->map_image, 0, $grid_y, $size, $grid_y, $this->color[1]);
	}
	$grid_y = $size/2 - $y;
	while($grid_y < $size){
		$grid_y += $this->scale;
		imageline($this->map_image, 0, $grid_y, $size, $grid_y, $this->color[1]);
	}
	$grid_x = $size/2 - $x;
	while($grid_x < $size){
		$grid_x += $this->scale;
		imageline($this->map_image, $grid_x, 0, $grid_x, $size, $this->color[1]);
	}
	$grid_x = $size/2 + $this->scale - $x;
	while($grid_x > 0){
		$grid_x -= $this->scale;
		imageline($this->map_image, $grid_x, 0, $grid_x, $size, $this->color[1]);
	}
	//find which piece the item is on
		$scale_x= floor($this->pov['x']/$this->scale);
		$scale_y= floor($this->pov['y']/$this->scale);
	//color the wall present
	$i = 0;
	$count = count($this->map);
	$count2 = count($this->map[0]);
 
 
	$i = 0;
	while($i < $count){
		$n = 0;
		while($n < $count2){
	if($this->map[$i][$n]){
					$wall_x = $size/2 + ($i-$scale_x)* $this->scale - $y;
					$wall_y = $size/2 + ($n-$scale_y)* $this->scale - $x;
					imagefilledrectangle($this->map_image, $wall_y, $wall_x, $wall_y + $this->scale, $wall_x + $this->scale, $this->color[1]);
	}
			++$n;
		}
		++$i;
	}
}
}
 
$world = new raycasting;
$map = 
"1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 1
1 1 0 1 1 0 0 1
1 1 1 1 1 1 1 1";
$world->create_map($map);
 
$world->map_image = imagecreate(400, 400);
 
 
	$world->color[] = imagecolorallocate($world->map_image, 0, 0, 0);
	$world->color[] = imagecolorallocate($world->map_image, 255, 255, 255);
 
	$world->create_pov(33,33,65,60);
	$world->create_map_image();
 
//include_once('dbug.php');
//new dbug($world->map);
//new dbug($world->pov);
//new dbug($world->direction);
 
header("Content-type: image/gif");
imagegif($world->map_image);
imagedestroy($world->map_image);

Last post of the year.. Happy new year!

Writing an 3D Ray Casting Library for PHP

I was inspired by the 3D Ray Casting game, so I decide to write a 3D ray casting engine myself.
First, I have to create a very simple version that only draw wall with one color. and looks like I failed. I will still work on the ray casting system. Can anyone spot why it looks like this? I think I have to work like about another 12 hours on debugging. :noway:
Initial testing result:
Raycasting test No.1
Here is the source:(no highlighting because it make the server slow... and this code is not important...)

	set_time_limit (5);
//error_reporting(0);
	class raycasting{
	var $pov = array('x' => 5, 'y' => 5, 'z' => 32, 'a' => 190);
	var $scale = 64;
	var $fov = 60;
	var $proj = array('w' =>320, 'h' => 200);
	var $map = '';
	var $cons;
 
	function createmap($map){
		$map = explode("\n",$map);
		$i = 0;
		$count = count($map);
		while($i < $count){
			$map[$i] = explode(' ',$map[$i]);
			++$i;
		}
		$this->map = $map;
		}
 
	function iswall($xy){
//	echo 	'x',$xy['x'],'<br />';
//	echo 	'y',$xy['y'],'<br />';
		if($this->map[floor($xy['x']/$this->scale)][floor($xy['y']/$this->scale)]){
			return true;
	}else{
		return false;
	}
	}
 
	function setup(){
		$this->cons['pov2proj'] = abs(0.5*$this->proj['w']/tan(0.5*$this->fov));
		$this->cons['angleinc'] = $this->fov/$this->proj['w'];
		$this->cons['tri_degree'] = 30;
		$this->proj['x'] = floor($this->proj['w']/2);
		$this->proj['y'] = floor($this->proj['h']/2);
		//find type x and y
		if($this->pov['a'] == 0){
			$this->cons['type']['x'] = 1;
			$this->cons['type']['y'] = 0;
		}elseif($this->pov['a'] == 180){
			$this->cons['type']['x'] = -1;
			$this->cons['type']['y'] = 0;
		}elseif($this->pov['a'] == 90){
			$this->cons['type']['x'] = 0;
			$this->cons['type']['y'] = -1;
		}elseif($this->pov['a'] == 270){
			$this->cons['type']['x'] = 0;
			$this->cons['type']['y'] = 1;
		}elseif(90 > $this->pov['a'] && $this->pov['a'] > 0){
			$this->cons['type']['x'] = 1;
			$this->cons['type']['y'] = -1;
		}elseif(180 > $this->pov['a'] && $this->pov['a'] > 90){
			$this->cons['type']['x'] = -1;
			$this->cons['type']['y'] = -1;
		}elseif(270 > $this->pov['a'] && $this->pov['a'] > 180){
			$this->cons['type']['x'] = -1;
			$this->cons['type']['y'] = 1;
		}else{
			$this->cons['type']['x'] = 1;
			$this->cons['type']['y'] = 1;
		}
	}
 
function render(){
	$i = 0;
	while($i < $this->proj['w']){
		//find the x intersect
		//find the y coordinate for the first intersect
		if($this->cons['type']['x'] == 0){
			if($this->cons['type']['y'] == 1){
				$x_intersect['y'] = cell($this->pov['y']/$this->scale)*$this->scale;
			}else{
				$x_intersect['y'] = floor($this->pov['y']/$this->scale)*$this->scale;
			}
		}else{
			if($this->cons['type']['y'] == 1){
				$x_intersect['y'] = floor($this->pov['y']/$this->scale)*$this->scale+$this->scale;
			}else{
				$x_intersect['y'] = floor($this->pov['y']/$this->scale)*$this->scale-1;
			}
		}
		//find the x coordinate of first intersect
		$x_intersect['x'] = floor($this->pov['x'] + ($this->pov['y'] - $x_intersect['y'])/tan($this->cons['tri_degree']));
		//check if it is wall
		if(!$this->iswall($x_intersect)){
			//the loop for intersect that touches the wall
			$y_add = $this->scale * $this->cons['type']['y'];
			$x_add = floor($this->scale/tan($this->cons['tri_degree']));
			while(!$this->iswall($x_intersect)){
				$x_intersect['x'] += $x_add;
				$x_intersect['y'] += $y_add;
			}
		}
 
 
 
 
		//FIND THE Y_INTERSECT THAT TOUCHES A WALL
		//find the y coordinate for the first intersect
		if($this->cons['type']['y'] == 0){
			if($this->cons['type']['x'] == 1){
				$y_intersect['x'] = cell($this->pov['x']/$this->scale)*$this->scale;
 
			}else{
				$y_intersect['x'] = floor($this->pov['x']/$this->scale)*$this->scale;
			}
		}else{
			if($this->cons['type']['x'] == 1){
				$y_intersect['x'] = cell($this->pov['x']/$this->scale)*$this->scale+$this->scale;
 
			}else{
				$y_intersect['x'] = floor($this->pov['x']/$this->scale)*$this->scale-1;
				if($y_intersect['x'] < 0){
					$y_intersect['x'] = 0;
				}
			}
		}
		//find the x coordinate of first intersect
		$y_intersect['y'] = floor($this->pov['y'] + ($this->pov['x'] - $x_intersect['x'])/tan($this->cons['tri_degree']));
		//check if it is wall
		if(!$this->iswall($y_intersect)){
			//the loop for intersect that touches the wall
			$x_add = $this->scale * $this->cons['type']['x'];
			$y_add = floor($this->scale/tan($this->cons['tri_degree']));
			while(!$this->iswall($x_intersect)){
				$y_intersect['x'] += $x_add;
				$y_intersect['y'] += $y_add;
			}
		}
 
		$x_intersect['distance'] = sqrt(pow($this->pov['x']-$x_intersect['x'],2)+pow($this->pov['y']-$x_intersect['y'],2));
		$y_intersect['distance'] = sqrt(pow($this->pov['x']-$y_intersect['x'],2)+pow($this->pov['y']-$y_intersect['y'],2));
		if($x_intersect['distance']<$y_intersect['distance']){
			$distance[$i]['d'] = $x_intersect['distance'];
			$distance[$i]['c'] = 'x';
		}else{
			$distance[$i]['d'] = $y_intersect['distance'];
			$distance[$i]['c'] = 'y';
		}
		++$i;
	}
 
	//remove distortion
	$i = 0;
	$half_fov = $this->fov / 2;
	while($i<$this->proj['x']){
		$product = cos(($this->proj['x']-$i) * $this->cons['angleinc']);
		$distance[$i]['d'] *= $product;
		$distance[$i+$proj['x']]['d'] *= $product;
		++$i;
	}
 
	$product = $this->scale/$this->cons['pov2proj'];
	$i = 0;
	while($i<$this->proj['w']){
		$proj_height[$i] = $product/$distance[$i]['d'];
		++$i;
	}
	//image creation
	$image = imagecreate($this->proj['w'], $this->proj['h']);
	//color
	$god = imagecolorallocate($image, 0xC0, 0xC0, 0xC0);
	$color = imagecolorallocate($image, 0xFF, 0xFF, 0xFF);
	$color2 = imagecolorallocate($image, 0x00, 0x00, 0x00);
	//draw wall
	$i = 0;
	while($i < $this->proj['w']){
		$start_y = ($this->proj['h'] - $proj_height[$i])/2;
		imageline($image, $i+1, $start_y, $i+1, $start_y+$proj_height[$i], $color);
		++$i;
	}
header('Content-type: image/png');
header('Content-Length: ' . strlen($img));
	imagepng($image);
}
	}
 
$modle = new raycasting;
$map = 
"1 1 1 1 1 1
1 0 0 0 0 1
1 0 0 0 0 1
1 0 1 1 0 1
1 1 1 1 1 1";
$modle->createmap($map);
$modle->setup();
$modle->render();

Wolfenstein 5K

Wolfenstein 5K is a javascript game. It is only 5KB in size. It is the winner for the5k. This game is like a minimized version of Wolfenstein that runs in a browser.
Wolf5k Screenshot
Editor Comment:

Again, another impressive job done in Javascript. Try it, you never thought something can be done with 5KB of code.

Canvascape - 3D Walker

Canvascape - "3D Walker"
Very impressive effect, used Canvas tags. The non-textured version have a good enough speed. While textured version is slow(especially on IE)
3D Walker
Editor Comment:

You never know what's the capability of Javascript. This is an experiment that let us know that 3D gaming is possible in a browser without plugins.

Syndicate content
Honey Pot that kill bots