I started a project using the raycasting technique GitHub Project
To find the length of the ray (distance from players pos to wall) I just increment by one. But there are several problems with that, its time consuming, inaccurate & will be difficult for texturing.
I tried to implement the daa algorithm, which doesnt just increments by 1 -> he goes through the grids and returns exact positions.
http://www.geeksforgeeks.org/dda-line-generation-algorithm-computer-graphics/
Has anyone experience with that or any tips?
No algorithm way:
for(let resolution = 0; resolution < display.width / 2; resolution++){ //every 2nd px gets scanned
let ray = this.pov + (-this.fov / 2 + this.fov / (display.width / 2) * resolution);
let distance = 0, hit = false;
/*ugly way of raycasting!*/
do{
let x = this.x + distance * Math.cos(ray * (Math.PI / 180));
let y = this.y + distance * Math.sin(ray * (Math.PI / 180));
if(map[Math.floor(x / block)][Math.floor(y / block)]){
distance = Math.sqrt(Math.pow(this.x - x, 2) + Math.pow(this.y - y, 2));
hit = true
}
distance += 1;
}while(!hit);
distance = convert / distance;
canvas.fillStyle = "#fff";
canvas.fillRect(resolution * 2, display.height / 2 - distance / 2, 2, distance);
}
You don't need DDA or Bresenham algorithm to find intersections of the ray with walls.
If you need one intersection with given border (or box edges) - just calculate it with ray equation and border position.
If you want to get intersections with grid cells - use voxelization algorithm like Amanatides-Woo
Related
I am creating my own game engine in Java Script. I have many things working great but one problem I am haveing is converting game space coordinates into screen space coordinates.
In my camera class I calulate the screen position of any given entity like so
draw(Engine, Entity, FollowEntity){
var x = Entity.render_position.x - (FollowEntity.render_position.x - Engine.rendersize.x / 2) - (Entity._get_render_size().x / 2);
var y = Entity.render_position.y - (FollowEntity.render_position.y - Engine.rendersize.y / 2) - (Entity._get_render_size().y / 2);
var _x = Entity.render_position.x - (FollowEntity.render_position.x - Engine.rendersize.x / 2);
var _y = Entity.render_position.y - (FollowEntity.render_position.y - Engine.rendersize.y / 2);
Engine.ctx.save();
Engine.ctx.translate(_x, _y);
Engine.ctx.rotate(Entity.rotation * Math.PI / 180);
Engine.ctx.translate(-_x, -_y);
Engine.ctx.drawImage(Engine.rasterizer.get_cached_img(Entity), x, y); /**/
Engine.ctx.restore();
}
I have tried extensively to aid myself in solving this with ChatGPT to no avail.
here is my current attempt
// Calculate the position of the entity in the game world
var gameX = this.ContextEntity.position.x;
var gameY = this.ContextEntity.position.y;
// Calculate the position of the camera in the game world
var cameraX = this.Engine.follow_entity.position.x;
var cameraY = this.Engine.follow_entity.position.y;
// Calculate the position of the entity on the screen, taking into account the difference in pixel size between the game entities and the GUI elements
var screenX = (gameX - cameraX) * this.GUI.rasterizer.pixel_size / this.Engine.rasterizer.pixel_size;
var screenY = (gameY - cameraY) * this.GUI.rasterizer.pixel_size / this.Engine.rasterizer.pixel_size;
// Adjust the position of the entity on the screen to take into account the size of the entity
screenX -= this.ContextEntity._get_render_size().x / 2;
screenY -= this.ContextEntity._get_render_size().y / 2;
gameToScreen(game) {
var game1 = (typeof game.x !== 'undefined') ? game.x : game[0];
var game2 = (typeof game.y !== 'undefined') ? game.y : game[1];
var x = game1 - (this.control_entity._get_render_midpoint().x - (this.rendersize.x / 2)) / this.rasterizer.pixel_size;
var y = game2 - (this.control_entity._get_render_midpoint().y - (this.rendersize.y / 2)) / this.rasterizer.pixel_size;
return new Vec2(Math.floor(x), Math.floor(y));
}
and here is another previous attempt which only seems to work when my pixel multipliers for the Engine entities are 0
the engine is running at https://soft-crab-57.telebit.io
Any help would be greatly appriciated.
I'm attempting to write code that will generate fractals according to the Chaos game
In particular, I'm trying to debug the faulty generation/rendering of this fractal:
I'm doing this with Javascript in a Canvas element. The relevant Javascript is below:
canvas = document.getElementById('myCanvas');
context = canvas.getContext('2d');
//constants
border = 10 //cardinal distance between vertices and nearest edge(s)
class Point{
constructor(_x, _y){
this.x = _x;
this.y = _y;
}
}
vertices = []
secondLastVertex = 0;
lastVertex = 0;
//vertices in clockwise order (for ease of checking adjacency)
vertices.push(new Point(canvas.width / 2, border)); //top
vertices.push(new Point(canvas.width - border, canvas.height * Math.tan(36 * Math.PI / 180) / 2)); //upper right
vertices.push(new Point(canvas.width * Math.cos(36 * Math.PI / 180), canvas.height - border)); //lower right
vertices.push(new Point(canvas.width * (1 - (Math.cos(36 * Math.PI / 180))), canvas.height - border)); //lower left
vertices.push(new Point(border, canvas.height * Math.tan(36 * Math.PI / 180) / 2)); //upper left
//move half distance towards random vertex but it can't neighbor the last one IF the last two were the same
function updatePoint(){
//pick a random vertex
v = Math.floor(Math.random() * vertices.length);
if(lastVertex == secondLastVertex)
//while randomly selected vertex is adjacent to the last approached vertex
while((v == (lastVertex - 1) % 5) || (v == (lastVertex + 1) % 5))
//pick another random vertex
v = Math.floor(Math.random() * vertices.length);
//cycle the last two vertices
secondLastVertex = lastVertex;
lastVertex = v;
//move half way towards the chosen vertex
point.x = (vertices[v].x + point.x) / 2;
point.y = (vertices[v].y + point.y) / 2;
}
//starting point (doesn't matter where)
point = new Point(canvas.width / 2, canvas.height / 2);
for (var i = 0; i < 1000000; i++){
//get point's next location
updatePoint();
//draw the point
context.fillRect(Math.round(point.x), Math.round(point.y), 1, 1);
}
The rendering that is produced looks like this:
So far I haven't been able to determine what is causing the rendering to be so skewed and wrong. One possibility is that I've misunderstood the rules that generate this fractal (i.e. "move half the distance from the current position towards a random vertex that is not adjacent to the last vertex IF the last two vertices were the same")
Another is that I have some bug in how I'm drawing fractals. But the same code with rule/starting-vertex modifications is able to draw things like the Sierpinkski triangle/carpet and even other pentagonal fractals apparently perfectly. Though one other pentagonal fractal ended up with some weird skewing and "lower right fourth of each self-similar substructure" weirdness.
I tried making some slight modifications to how I interpreted the rules (e.g. "next vertex can't be adjacent OR EQUAL TO previous vertex if last two vertices were the same") but nothing like that helped. I also tried not rounding the coordinates of the target point before plotting it, but though this slightly changed the character/sharpness of the details, it didn't change any larger scale features of the plot.
My issue as kindly pointed out by ggorlen, was that I wasn't comparing vertices for adjacency correctly. I mistakenly thought Javascript evaluated something like (-1 % 5) as 4, rather than -1.
To fix this, I add 4 to the index instead of subtracting 1, before modding it against 5 (the number of vertices)
This completely fixed the render. (in not just this case but other cases I'd been testing with different fractals)
A typical random walk does not care about direction changes. Each iteration generates a new direction. But if you imagine a point animated on a random walk, it will mostly jump around. So, the goal is to have a smoother curve depending on the previously calculated points.
How to adjust a random walk function to have smoother directional changes?
My main idea is to have a method that generates a new point with x and y coordinates, but looks after the previous step and decreases the size of the next step (const radius), if the rotation (directional change) comes closer to 180°.
Therefore, I am using D3js to randomly take a new step in any x and y direction. At the end I'll get an array of all past steps limited by the maximum amount of steps. The radius gives an orientation how long an average step should be taking on the x and y axis'.
const history = [];
const steps = 10;
const radius = 1;
let point = {
x: 0,
y: 0,
radians: null
};
for (let i = 0; i < steps; i++) {
console.log(point);
history.push(point);
const previousPoint = Object.assign({}, point);
point.x += radius * d3.randomNormal(0, 1)();
point.y += radius * d3.randomNormal(0, 1)();
point.radians = Math.atan2(
point.y - previousPoint.y,
point.x - previousPoint.x
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.8.0/d3.js"></script>
Instead of using a coordinates based random walk, I decided to randomly generate each iteration a new radians. So the new and previous radians can be compared to each others to decide with velocity the new point will get. Depending on the minimum range between these radians' the volicity will be set. Afterwards a simple sine and cosine calculation have to be down to generate the coordinates of the new point.
At least I've achieved my final goal: https://beta.observablehq.com/#nextlevelshit/gentlemans-random-walk-part-3
const steps = 10;
const stepSize = 10;
let point = {
x: 0,
y: 0,
radians: randomRadians(),
velocity: 0
};
for (let i = 0; i < steps; i++) {
console.log(point);
const radians = randomRadians();
const velocity = 1 - minimumDifference(radians, point.radians) / Math.PI;
point = {
// Coordinates calculated depending on random radians and velocity
x: Math.sin(radians * Math.PI) * stepSize * velocity + point.x,
y: Math.cos(radians * Math.PI) * stepSize * velocity + point.y,
radians: radians, // Randomly generated radians
velocity: velocity // Velocity in comparison to previous point
};
}
function randomRadians() {
return randomFloat(- Math.PI, Math.PI);
}
function randomFloat(min, max) {
return Math.random() * (max - min) + min;
}
function minimumDifference(x, y) {
return Math.min((2 * Math.PI) - Math.abs(x - y), Math.abs(x - y));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.8.0/d3.js"></script>
I have one circle, which grows and shrinks by manipulating the radius in a loop.
While growing and shrinking, I draw a point on that circle. And within the same loop, increasing the angle for a next point.
The setup is like this:
let radius = 0;
let circleAngle = 0;
let radiusAngle = 0;
let speed = 0.02;
let radiusSpeed = 4;
let circleSpeed = 2;
And in the loop:
radius = Math.cos(radiusAngle) * 100;
// creating new point for line
let pointOnCircle = {
x: midX + Math.cos(circleAngle) * radius,
y: midY + Math.sin(circleAngle) * radius
};
circleAngle += speed * circleSpeed;
radiusAngle += speed * radiusSpeed;
This produces some kind of flower / pattern to be drawn.
After unknown rotations, the drawing line connects to the point from where it started, closing the path perfectly.
Now I would like to know how many rotations must occure, before the line is back to it's beginning.
A working example can be found here:
http://codepen.io/anon/pen/RGKOjP
The console logs the current rotations of both the circle and the line.
Full cycle is over, when both radius and point returns to the starting point. So
speed * circleSpeed * K = 360 * N
speed * radiusSpeed * K = 360 * M
Here K is unknown number of turns, N and M are integer numbers.
Divide the first equation by the second
circleSpeed / radiusSpeed = N / M
If speed values are integers, divide them by LCM to get minimal valid N and M values, if they are rational, multiply them to get integer proportion.
For your example minimal integers N=1,M=2, so we can get
K = 360 * 1 / (0.02 * 2) = 9000 loop turns
Yes theres a few threads on this, but not many using angles and I'm really trying to figure it out this way,
I'm now stuck on setting the new velocity angles for the circles. I have been looking at:
http://www.hoomanr.com/Demos/Elastic2/
as a reference to it, but I'm stuck now.
Can anybody shed some light?
cx/cy/cx2/cy2 = center x/y for balls 1 and 2.
vx/vy/vx2/vy2 = velocities for x/y for balls 1 and 2
function checkCollision() {
var dx = cx2 - cx; //distance between x
var dy = cy2 - cy; // distance between y
var distance = Math.sqrt(dx * dx + dy * dy);
var ang = Math.atan2(cy - cy2, cx - cx2);
// was displaying these in a div to check
var d1 = Math.atan2(vx, vy); //ball 1 direction
var d2 = Math.atan2(vx2, vy2); //ball 2 direction
// this is where I am stuck, and i've worked out this is completely wrong now
// how do i set up the new velocities for
var newvx = vx * Math.cos(d1 - ang);
var newvy = vy * Math.sin(d1 - ang);
var newvx2 = vx2 * Math.cos(d2 - ang);
var newvy2 = vy2 * Math.sin(d2 - ang);
if (distance <= (radius1 + radius2)) {
//Set new velocity angles here at collision..
}
Heres a codepen link:
http://codepen.io/anon/pen/MwbMxX
A few directions :
• As mentioned in the comments, use only radians (no more *180/PI).
• atan2 takes y as first param, x as second param.
var d1 = Math.atan2(vy, vx); //ball 1 direction in angles
var d2 = Math.atan2(vy2, vx2); //ball 2 direction in angles
• to rotate a vector, compute first its norm, then only project it with the new angle :
var v1 = Math.sqrt(vx*vx+vy*vy);
var v2 = Math.sqrt(vx2*vx2+vy2*vy2);
var newvx = v1 * Math.cos(d1 - ang);
var newvy = v1 * Math.sin(d1 - ang);
var newvx2 = v2 * Math.cos(d2 - ang);
var newvy2 = v2 * Math.sin(d2 - ang);
• You are detecting the collision when it already happened, so both circles overlap, but you do NOT solve the collision, meaning the circles might still overlap on next iteration, leading to a new collision and a new direction taken, ... not solved, etc..
-->> You need to ensure both circles are not colliding any more after you solved the collision.
• Last issue, but not a small one, is how you compute the angle. No more time for you sorry, but it would be helpful both for you and us to build one (several) scheme showing how you compute the angles.
Updated (but not working) codepen here :
http://codepen.io/anon/pen/eNgmaY
Good luck.
Edit :
Your code at codepen.io/anon/pen/oXZvoe simplify to this :
var angle = Math.atan2(dy, dx),
spread = minDistance - distance,
ax = spread * Math.cos(angle),
ay = spread * Math.sin(angle);
vx -= ax;
vy -= ay;
vx2 += ax;
vy2 += ay;
You are substracting the gap between both circles from the speed. Since later you add the speed to the position, that will do the spatial separation (=> no more collision).
I think to understand what vx-=ax means, we have to remember newton : v = a*t, where a is the acceleration, so basically doing vx=-ax means applying a force having the direction between both centers as direction, and the amount by which both circle collided (spread) as intensity. That amount is obviously quite random, hence the numerical instability that you see : sometimes a small effect, sometimes a big one.
look here for a constant punch version :
http://codepen.io/anon/pen/WvpjeK
var angle = Math.atan2(dy, dx),
spread = minDistance - distance,
ax = spread * Math.cos(angle),
ay = spread * Math.sin(angle);
// solve collision (separation)
cx -= ax;
cy -= ay;
// give a punch to the speed
var punch = 2;
vx -= punch*Math.cos(angle);
vy -= punch*Math.sin(angle);
vx2 += punch*Math.cos(angle);
vy2 += punch*Math.sin(angle);