Calculating relative item positions based on camera position and rotation - javascript

For a 2d game, I have these concepts:
stage: container in which items and cameras are placed.
item: a visible entity, located on a certain point in the world, anchored from center.
camera: an invisible entity, used to generate relative images of world, located on a certain point in the world, anchored from center.
In the illustrations, you can see how they are related, and what the end result should be.
Here is the code I have: (dumbed down to make it easier to read)
Note1: This is not happening on canvas, so I will not use canvas translation or rotation (and even then, I don't think it would make the problem any easier).
Note2: Item and camera positions are center coordinates.
var sin = Math.sin(rotationRad);
var cos = Math.cos(rotationRad);
var difX = item.x - camera.x;
var difY = item.y - camera.y;
var offsetX = camera.width / 2;
var offsetY = camera.height / 2;
var view.x = (cos * difX) - (sin * difY) + _Ax + _Bx;
var view.y = (sin * difX) + (cos * difY) + _Ay + _By;
This is supposed to calculate an items new position by:
calculating new position of item by rotating it around camera center
(_A*) adjusting item position by offsetting camera position
(_B*) adjusting item position by offsetting camera size
I tried several different solutions to use for _A* and _B* here, but none of them work.
What is the correct way to do this, and if possible, what is the explanation?

You first subtract new origin position from object position. You then rotate it by the inverse of the rotation. New origin can be camera position of top left corner of viewport. Of course if you know viewport center its top left corner is computed by subtracting half of its dimensions.
Like this:
var topLeft = Camera.Position - Camera.Size / 2;
var newPosition = Object.Position - topLeft;
newPosition = Rotate(newPosition, -camera.Angle);
Rotation is very simple:
rotatedX = x * cos(angle) - y * sin(angle)
rotatedY = y * cos(angle) + x * sin(angle)

Related

Three.js manipulate 3D mouse coordinates by new direction

i have a problem at setting a new mouse position. I have an Object which is moving and rotating free in a Space and following the position of the pointerlocked cursor. Targetposition is a Vector3 positioned behind the object. Now i want to make an Animation which moves the object in the opposite direction by rotating it smoothly. So I disable my mouseListener and rotate the object with the given Three.js functions. But after I enable my listener the targetPosition turns back to the mouse position and makes the move useless. So now i want to calculate the mouse Position for my new Targetposition after the animation. How can i do that ?
The function for the 3D mouse coordinates looks something like this:
enter code here
mouseY = Math.max(-85, Math.min(70, -mouseY));
phi = THREE.Math.degToRad(90 + mouseY);
theta = THREE.Math.degToRad(mouseX);
targetPosition.x = object.position.x + 100 * Math.sin(phi) * Math.cos(theta);
targetPosition.y = object.position.y + 100 * Math.cos(phi);
targetPosition.z = object.position.z + 100 * Math.sin(phi) * Math.sin(theta);
object.lookAt(targetPosition);

Trigonometry Issue causing distortion when drawing floor textures in raycaster

I'm creating a game with raycasted 3D graphics like Wolfenstein 3D but using line segments instead of a grid of blocks for walls. Everything is fine when drawing the floors until rotating the player view.
the floor should be aligned against the walls
Here is the view in 2D, with each pixel on the floor on the screen rendered as a blue point:
In the top image is when the player's rotation is Math.PI. In the bottom image it is rotated slightly.
A significant feature of this is the beginning of the cone of points is aligned along the y axis. It should look like a frustrum.
Here is the code I am using to find the x and y coordinates of each point where a texture is drawn on the floor. This code is run for each x value on the screen.
The variable "projPlane" is the projection plane, which is the size of the screen.
projDistance is the distance from the player to the projection plane so that it fits within the field of view, or (projPlane.width/2)/Math.tan(VectorMath.toRadians(fov/2))
pHeight is the players height.
The variable "x" is the x value of the row being rendered on the screen.
//FLOOR TEXTURE
var floorSize = Math.floor((projPlane.height-wallSize)/2); //draw the floor from under the wall
var floorTextureIndex = 1;
//for texture y
if(floorSize > 0){ // values need to be positive
//find the point on the floor
var textureWidth = textures[floorTextureIndex].textureImage.width;
var textureHeight = textures[floorTextureIndex].textureImage.height;
//console.log(coordX);
for (var ty = 0; ty < floorSize; ty++){
//angle is tan
var yAngle = projPlane.distance / (ty + wallSize/2); //ty + wallSize/2 is the point on the projection plane
var yDistance = yAngle * pHeight; //pHeight is player height
var worldY = player.y + Math.sin(player.vector)*yDistance;
var coordY = Math.floor(worldY % (textureHeight));
var xAngle = Math.atan((projPlane.width/2 - x)/projPlane.distance);
/*if(x < projPlane.width/2){//tangent of the angle in the projectionPlane
xAngle = (x) / projPlane.distance;
}
else{
xAngle = (x-projPlane.width) / projPlane.distance;
}*/
var xDistance = yDistance/Math.cos(xAngle);
var worldX = player.x + Math.cos(player.vector - xAngle)*xDistance;
//console.log(xDistance);
var coordX = Math.floor(worldX % (textureWidth));//disable until I can get y
floorPoints.push(new Point(worldX,worldY));
var tempTexture = textures[floorTextureIndex];
if(tempTexture.textureData[coordX] != undefined){
// a different function drawns these to the screen in descending order
floorTextureColors.push(tempTexture.textureData[coordX][coordY]);
}
};
}
It doesn't seem to be an issue with the y value since the y coordinates of the floor texture seem to appear where they should.(EDIT: it actually was to do with the y value. Adding the xAngle to the player.vector when finding the y position returns a correct y position but there is still a "curved" distortion. I hope one of you can propose a more concrete solution.)
What I do to find the X coordinate is form a triangle with the distance from the player to the floor point as the opposite side the angle that the point makes with the player. The hypotenuse should be the magnitude of the distance to the point's x coordinate.
Then I multiply the cosine of the angle by the magnitude to get the x value.
It works whenever the character isn't pointing west and east. What is causing all the first points to have the same y value? I think that's the biggest clue on the distortion occurring here.

Connect two circles with a line (with DOM elements)

I am struggling with connecting two circles with a line. I am using the famo.us library.
DEMO on Codepen
a.k.a. "Two balls, one line."
The Problem
Angle and length of the line are correct, but the position is wrong.
First attempt
The important part should be lines 114-116:
connection.origin = [.5, .5];
connection.align = [.5, .5];
connection.body.setPosition([
Math.min(sourcePos.x, targetPos.x),
Math.min(sourcePos.y, targetPos.y)
]);
Appearently i am doing something wrong with the math. Playing around with those values gives me all kinds of results, but nothing is close to correct.
Intended solution
(1) The minimal solution would be to connect the centres of the circles with the line.
(2) The better solution would be a line that is only touching the surface of both circles instead of going to the center.
(3) The ideal solution would have arrows on each end of the line to look like a directed graph.
This fixes it :
connection.body.setPosition([
sourcePos.x * Math.cos(angle) + sourcePos.y * Math.sin(angle),
sourcePos.x * Math.sin(-angle)+ sourcePos.y * Math.cos(angle)
]);
Your segment is defined by its extrimity in sourceand the angle and distance to target, thus you have to set its origin to be that of source
The rotation seems to not only rotate the object, but also rotate the coordinates around the origin, so I rotated them by -angle to compensate.
There might be a more famo.usesque way to do it (maybe you can get it to rotate before setting the position, or have the position be 0,0 and add the coordinates as a translation in the transformation).
To get your better solution, still with mostly math, you may keep the same code but
with r the radius of the source ball, remove [r * distX / distance, r * distY / distance] to the coordinates of the segment, to put it in contact with the outer part of the ball
remove both balls' radius from the distance
With that, we get :
var distX = sourcePos.x - targetPos.x;
var distY = sourcePos.y - targetPos.y;
var norm = Math.sqrt(distX * distX + distY * distY);
var distance = norm - (source.size[0]+target.size[0])/2;
var angle = -Math.atan2(-distY, distX);
connection.angle = angle;
connection.size = [distance, 2, 0];
connection.align = [.5, .5];
connection.origin = [.5, .5];
var posX = sourcePos.x - source.size[0]/2 * (distX / norm);
var posY = sourcePos.y - source.size[0]/2 * (distY / norm);
connection.body.setPosition([
posX * Math.cos(angle) + posY * Math.sin(angle),
posX * Math.sin(-angle)+ posY * Math.cos(angle)
]);
result on this fork : http://codepen.io/anon/pen/qEjPLg
I think the fact that the line length is off when the balls go fast is a timing issue. Most probably you compute the segment's length and position at a moment when the ball's centres are not yet updated for that frame.

mouse coordinates to isometric coordinates

I'm trying to get the right tile in the isometric world by mouse position.
I've read some theads about this, but it doesn't seem to work for me.
The basic Idea is to recalculate the normal mouse coordinates to the isometric tile-coordinates.
As you can see the mouse cursor is at the tile 5/4 and the recalculation is wrong (the tile selected is 4/5). This is my Code:
var params.tx = 100, params.ty=54,
PI = 3.14152,
x1 = x_mouse - params.tx*5,
y1 = y_mouse * -2,
xr = Math.cos(PI/4)*x1 - Math.sin(PI/4)*y1,
yr = Math.sin(PI/4)*x1 + Math.cos(PI/4)*y1,
diag = (params.ty) * Math.sqrt(2),
x2 = parseInt(xr / diag)+1,
y2 = parseInt(yr * -1 / diag)+1;
The original height of a tile is 54px, but as you can see, only the border tiles show their full height. The rest of the tiles are cut by 4 pixels.
Please help me - may be my whole formula is wrong.

ThreeJS: Screen position to camera position

I've seen a lot of posts people want to have the camera position to screen position. My question is how to do the contrary.
What I currently want to achieve is set the "door" position to a % of the screen, this calculation is ready, and I do have the final screen X, Y (px) position. The current Z offset = 250 of the camera.
I've found this code to convert camera position to screen position:
var vector = projector.projectVector(door.position.clone(), camera);
vector.x = (vector.x + 1) / 2 * window.innerWidth;
vector.y = -(vector.y - 1) / 2 * window.innerHeight;
To do the reversie I tried this, but does not give the result I expect:
var mouseX = ((perc.x) / window.innerWidth) * 2 - 1,
mouseY = -((perc.y) / window.innerHeight) * 2 + 1;
var vector = new THREE.Vector3(mouseX, mouseY, 1);
projector.unprojectVector(vector, camera);
return vector.sub(camera.position).normalize()
I have tried several ways and tried to Google, but didn't found an answer.
Q: How to convert screen position to camera position?
Well, as posted by Gero3, what you want to do is to create a plane that will cover all of your visible camera area (something like new THREE.PlaneGeometry(5000,5000); and then use raycaster to locate screen coordinated on that plane.
Here is an example from another similar question:
http://jsfiddle.net/PwWbT/
Hope that helps.
Use a large invisble plane that defines in which direction the door can expand and then use a raycaster on the plane to search for the position to where the door object should extend.

Categories

Resources