Jump to content

  • Log In with Google      Sign In   
  • Create Account


Raycasting from scratch (JS)


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
1 reply to this topic

#1 devseer   Members   -  Reputation: 115

Like
2Likes
Like

Posted 29 October 2013 - 04:07 PM

Hi all,

 

I don't usually post on places like this but I'm having some real trouble getting my engine to behave correctly and I've been trying to fix this for several weeks now.

 

I've been building a raycasting / pseudo-3d (Think Wolfenstein, Doom etc.) engine from scratch, in JavaScript. I have a very basic map rendering, with different coloured walls and there is player movement and collision. I'm having two major issues:

  • The camera does not appear to correctly center with the screen - If the player moves, the view appears to move at a slight angle
  • I'm unable to render each slice of my texture without significant fluttering at most angles - Sometimes it draws perfectly and stays still, most of the time is scrolls horizontally for no reason

7FarDP2.png

 

4PdReGY.png

 

I've just made my repo public, to make sharing the code easier:

https://github.com/devseer/dust

 

The main code for rendering is in world.js

 

(Arrow keys to control movement)

 

 

I would greatly appreciate any help anyone has to offer. However, I'm really not interested in using any frameworks, as I'm really doing this for the learning experience. So please do not suggest any frameworks or libraries.

 

Thanks for reading

 

ps. Added code for those who don't want to go to Github:

var World = function() {
	this.viewDistance = 0;
	this.wall = new Image();

	this.map = [
	[1,1,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,1,0,0,1],
	[1,0,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],
	[1,0,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],
	[1,0,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],
	[1,0,0,3,3,0,0,0,0,0,4,4,0,0,0,0,0,0,1,0,0,1],
	[1,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,1],
	[1,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,1],
	[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
	[1,2,2,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
	[1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
	[1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
	[1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
	[1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
	[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
	];

	this.init = function() {
		var fieldOfView = 60 * Math.PI / 180;
		this.viewDistance = 256 / Math.tan((fieldOfView / 2));
		this.wall.src = './img/wall.png';
	};

	this.inc = 0;

	this.drawRay = function(context, x, distance, texture) {
		var width = 8;
		var height = Math.round(this.viewDistance / distance);
		var y = Math.round((512 - height) / 2);

		switch (texture) {
			case 1: context.fillStyle = 'rgb(100, 100, 100)';
				break;
			case 2: context.fillStyle = 'rgb(128, 64, 64)';
				break;
			case 3: context.fillStyle = 'rgb(64, 64, 128)';
				break;
		}

		//if (texture == 1 || texture == 2 || texture == 3)
			context.fillRect(x, y, width, height);

		if (texture == 4) {
			context.drawImage(this.wall, this.inc % 16, 0, 1, 16, x, Math.round((512 - height) / 2), 8, height);
			this.inc++;
		}
	};

	this.castRay = function(rotation, direction, sourcex, sourcey) {
		var x = sourcex;
		var y = sourcey;
		var addx =  Math.cos(direction) * 0.01;
		var addy = Math.sin(direction) * 0.01;
		var outx = Math.floor(x);
		var outy = Math.floor(y);
		var type = 0;


		while (type == 0) {
			type = this.map[outy][outx];

			x += addx;
			y += addy;

			outx = Math.floor(x);
			outy = Math.floor(y);

			if (outx < 1 || outx > 21 || outy < 1 || outy > 14) break;
		}

		return {
			texture: type,
			distance: this.distance(sourcex, sourcey, x, y) * Math.cos(rotation - direction)
		};
	};

	this.distance = function(ax, ay, bx, by) {
		var nx = ax - bx;
		var ny = ay - by;

		return Math.sqrt(nx * nx + ny * ny);
	};

	this.angle = function(rotation, increment) {
		return rotation + Math.asin(increment / Math.sqrt(increment * increment + this.viewDistance * this.viewDistance));
	};

	this.draw = function(context, player) {
		var i, j;

		// Ceiling
		context.fillStyle = 'rgb(150, 150, 180)';
		context.fillRect(0, 0, 512, 256);

		// Floor
		context.fillStyle = 'rgb(32, 64, 32)';
		context.fillRect(0, 256, 512, 256);

		for (i = 0; i < 512; i+= 8) {
			context.fillStyle = 'rgb(100, 100, 100)';
			var surface = this.castRay(player.rot, this.angle(player.rot, i), player.pos.x, player.pos.y);
			this.drawRay(context, i, surface.distance, surface.texture);
		}

		// Mini-map
		for (i = 0; i < 22; i++) {
			for (j = 0; j < 15; j++) {
				if (this.map[j][i] > 0) {
					context.fillStyle = 'rgb(255, 255, 255)';
					context.fillRect(i*8, j*8, 8, 8);
				}
			}
		}
	};
};

Edited by devseer, 29 October 2013 - 04:11 PM.


Sponsor:

#2 Krypt0n   Crossbones+   -  Reputation: 2183

Like
0Likes
Like

Posted 01 November 2013 - 04:46 AM

has been done tons of time before... but I still love it! :)






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS