Sync Object3d rotation (tab level) - javascript

Need help,
I'm trying to sync the rotation of one object loaded in the active browser tab with another object loaded in the second tab. While rotating Object loaded in the active browser tab will send a message to another. In the second tab will listen to the message sent from the first tab and rotate the Object accordingly using rotation values. my code looks like below, (I referred this example)
let objectLoaded;
let previousMousePosition = {x : 0, y : 0 };
function mouseDown(e) {
isDragging = true;
}
function mouseUp() {
isDragging = false;
if (objectLoaded) {
// publishing the rotation value to another tab using 'hermes' package.
hermes.send('rotation', JSON.stringify({
rotation: objectLoaded.rotation,
quaternion: objectLoaded.getWorldQuaternion(),
matrix: objectLoaded.matrixWorld
}));
}
}
function mouseMove(e) {
const deltaMove = { x : e.offsetX - previousMousePosition.x,y : e.offsetY - previousMousePosition.y };
if (isDragging && objectLoaded) {
const deltaRotationQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(toRadians(deltaMove.y * 1), toRadians(deltaMove.x * 1), 0, 'XYZ'));
objectLoaded.quaternion.multiplyQuaternions(deltaRotationQuaternion, objectLoaded.quaternion);
}
previousMousePosition = {x : e.offsetX, y : e.offsetY };
}
function toRadians(angle) {
return angle * (Math.PI / 180);
}
Listener code,
hermes.on('rotation', (rotationObj) => {
// rotationObj structure: {rotation: { _x: 0, _y: 0: _z: 0}, quaternion: { _x: 0, _y: 0: _z: 0, _w: 0}}
const target = JSON.parse(rotationObj);
SecondObject.rotateX(target.rotation._x);
SecondObject.rotateY(target.rotation._y);
SecondObject.rotateZ(target.rotation._z);
})
The issue here is the second object not properly syncing with the first one. Do any one know what i'm doing wrong?
Thanks,

In one tab, you request the current (absolute) rotation. In the other the, you rotate by those values in addition to the current rotation. That will break right after the first time you set a non-zero rotation.
What you want is to assign the rotation, by doing
SecondObject.rotation.copy(target.rotation);

Related

TypeError: Cannot Read Property of Undefined Even Though I Defined It

I'm a beginner to JavaScript. I've looked through a few questions on here regarding "TypeError: ... undefined even though the property is defined" but their examples are either too dense for me to grasp or they realize they've incorrectly assigned something downstream. Here I think my example is quite simple, and I don't think I've incorrectly assigned anything.
I've defined position in my class MoveableObjects and when I call player = new MoveableObject(position, other params ...) I don't get any errors.
When I change this to player = new Sprite(position, other params ...) where Sprite extends MoveableObjects and then try to call a function inside Sprite it tells me position.x is undefined. I put console.log(player) immediately after the declaration and it does in fact show position as undefined, but I don't understand why it does since I've clearly defined it.
Here is the constructor of MoveableObjects
class MoveableObject {
constructor({ colorRGB, width, height, position, velocity}) {
this.width = width;
this.height = height;
this.position = position;
this.velocity = velocity;
this.colorRGB = colorRGB;
// If the side of the object is touching or beyond the side of the canvas it is flagged as bounded.
this.inUpLimit = false;
this.inDownLimit = false;
this.inLeftLimit = false;
this.inRightLimit = false;
// Translate the velocity into directional words
this.movingLeft = false;
this.movingRight = false;
this.movingUp = false;
this.movingDown = false;
}
Here is the constructor of Sprite and the draw() function it uses.
// Sprite represents moveable objects with an animated image.
class Sprite extends MoveableObject {
constructor({ imageSrc, numRows = 1, numCols = 1, spacing = 0, margin = 0, animationSpeed = 10, position, velocity}) {
super(position, velocity)
this.image = new Image() // Image can be a single image or a spritesheet.
this.image.src = imageSrc
this.numRows = numRows // # animation sequences in the spritesheet
this.numCols = numCols // # frames in an animation sequence
this.spacing = spacing // # pixels between each frame
this.margin = margin // # pixels between image border and sprite border. Vertical and horizontal margins should be equal.
this.animation = new Object()
this.animation.speed = animationSpeed // # times draw function is called before the next frame in the animation sequence is called.
this.animation.counter = 0 // # times the draw function has been called
this.animation.enabled = false // Whether or not the animation sequence is currently running
this.animation.row = 1; // The row of the current frame being drawn
this.animation.col = 1; // The column of the current frame being drawn
this.animation.firstRow = 1; // The row of the frame to initialize the animation loop on
this.animation.firstCol = 1; // The column of the frame to initialize the animation loop on
this.animation.lastRow = 1; // The row of the frame to restart the animation loop on
this.animation.lastCol = 1; // The column of the frame to restart the animation loop on
this.frame = new Object();
this.frame.width = 0; // Init image.onload
this.frame.height = 0; // Init image.onload
this.image.onload = () => { // Calculates width and height of animation frame based on numRows, numColumns, spacing, and margin
let imageWidth = this.image.width;
let spriteSheetWidth = imageWidth - (2 * this.margin);
let widthNoSpacing = spriteSheetWidth - this.spacing * (this.numCols - 1);
let frameWidth = widthNoSpacing / this.numCols;
let imageHeight = this.image.height;
let spriteSheetHeight = imageHeight - (2 * this.margin);
let heightNoSpacing = spriteSheetHeight - this.spacing * (this.numRows - 1);
let frameHeight = heightNoSpacing / numRows;
this.frame.width = frameWidth;
this.frame.height = frameHeight;
}
}
draw() {
// Draw the frame at the current row and column.
context.drawImage(
this.image, // the entire image being loaded
this.animation.col * this.frame.width, // sx, x coordinate to begin crop
this.animation.row * this.frame.height, // sy, y coordinate to begin crop
this.frame.width, // swidth, width of cropped image
this.frame.height, // sheight, height of cropped image
this.position.x, // x coordinate where to place image on canvas
this.position.y, // y coordinate where to place image on canvas
this.frame.width, // the width to stretch/shrink it to
this.frame.height // the height to stretch/shrink it to
)
Here I create a new MoveableObject with position defined and then console.log() it. It shows position to be what I set it to. I copy/paste that declaration and change "new MoveableObject" to "new Sprite" (with a new variable name of course) and print that, and it shows position is undefined:
// Initializers for main()
const gravity = 0.8;
const player = new Sprite({
imageSrc: './lib/img/template.png',
numRows: 21,
numCols: 4,
spacing: 0,
margin: 0,
position: {
x: 0,
y: 0
},
velocity: {
x: 0,
y: 0
}
})
console.log(player)
const enemy = new MoveableObject({
colorRGB: 'blue',
width: 50,
height: 150,
position: {
x: 150,
y: 50
},
velocity: {
x: 0,
y: 0
}
})
console.log(enemy)
const moveableObjects = [player, enemy];
// The main function of the script updates the game state every frame.
function main() {
// When the game starts the canvas, then player, then enemy are rendered.
context.fillStyle = 'black';
context.fillRect(0, 0, canvas.width, canvas.height);
player.draw();
enemy.draw();
The error is raised on player.draw() and reads "Uncaught TypeError: Cannot read properties of undefined (reading 'x')"
Does anyone understand why this is the case? It seems to me like the error is maybe produced by not properly extending my class or using super() incorrectly to pass attributes, but I haven't found an example that proves that.

JavaScript moving objects from starting location to ending locations

I am taking a course online and I can't find help if am stuck..... I am using brackets and p5.js
these are the instructions i have:
Edit the spotlight object by creating x and y properties initialised to your location. Also endX and endY properties initialised to one of the Minsky's location.
Assign the other 2 spotlights and create the required properties.
Make the spotlight move perfectly from you towards the Minskys by adjusting the increments of x and y properties.
If you get everything correct then it will stop over the target.
Adjust x and y properties using
"+=" or "+"
"-=" or "-"
*/
(the minsky brothers are the targets i need the spotlight to be on, the "your location" is the start location)
i will copy and paste my code and the message i get when i submit :
// other variables, you don't need to change these
var img, spotlight_image;
var spotlight1;
var spotlight2;
var spotlight3;
function preload()
{
img = loadImage('scene.png');
spotlight_image = loadImage('spotlight.png')
}
function setup()
{
createCanvas(img.width, img.height);
//complete the initialisation of the first spotlight
//with properties x, y, endX and endY
spotlight1 = {
image: spotlight_image
x: 164,
y: 810,
endX: 780,
endY: 640,
}
//Initialize the second and third spotlights
spotlight2 = {
image: spotlight_image
x: 164,
y: 810,
endX: 480,
endY: 474,
}
spotlight3 = {
image: spotlight_image
x: 164,
y: 810,
endX:766,
endY: 290,
}
}
function draw()
{
image(img, 0, 0);
// alter the properties x and y of the objects below to animate the spotlights
spotlight.x += 1;
spotlight.y += 1;
////////// DO NOT CHANGE ANYTHING BELOW /////////////
var spotlights = [spotlight1, spotlight2, spotlight3];
var spotlightSize = 300;
blendMode(BLEND);
background(30);
for (var i = 0; i < spotlights.length; i++)
{
var spotlight = spotlights[i];
//stop the spotlight if it's near enough to endx and endy
if(spotlight)
{
//stop the spotlight if it goes off of the screen
spotlight.x = min(spotlight.x, 960);
spotlight.y = min(spotlight.y, 945);
spotlight.x = max(spotlight.x, 0);
spotlight.y = max(spotlight.y, 0);
if (abs(spotlight.endX - spotlight.x) < 50
&& abs(spotlight.endY - spotlight.y) < 50)
{
spotlight.x = spotlight.endX;
spotlight.y = spotlight.endY;
}
image(spotlight.image, spotlight.x-spotlightSize/2,
spotlight.y-spotlightSize/2, spotlightSize, spotlightSize);
}
}
blendMode(DARKEST);
image(img, 0, 0);
////////// DONOT CHANGE ANYTHING ABOVE /////////////
}
the message i get when submitting:
Error in compile
SyntaxError: Unexpected identifier
Blockquote
This is fairly easy to do. If I understand correctly, you want to move an object towards a point over a certain amount of time. All you have to do is get the range between the two X coordinates and the two Y coordinates, divide them by how many frames you want it to be moving for, and update its position by that amount every frame until it reaches its destination.

Three.js - rotating a camera around a point

I have my custom Navigation control similar to Trackball but with additional functionality.
One of the features I want to implement is the specifying center of rotation of the camera and when we pan a camera, the rotation maintained around the specified point.
Here is the code of my update() function:
update(): this {
const camera = this.camera
if (this._enabled && camera && this._isInvalid) {
const cameraObject = camera.object
// validate all navigation changes
{
const {
offset,
panOffset,
axis,
tempVector3,
tempSpherical,
deltaRotation,
deltaPan,
quaternion
} = this.computeHelpers
// offset vector from eye to target
offset.subVectors(this._eye, this._target)
// apply rotation
if (deltaRotation.isInvalid) {
const { x: theta, y: phi } = deltaRotation.get()
// rotate around screen-space y-axis
if (theta) {
axis.set(0, 1, 0).applyQuaternion(cameraObject.quaternion)
quaternion.setFromAxisAngle(axis, theta)
offset.applyQuaternion(quaternion)
this._up.applyQuaternion(quaternion)
}
// rotate around screen-space x-axis
if (phi) {
axis.set(1, 0, 0).applyQuaternion(cameraObject.quaternion)
quaternion.setFromAxisAngle(axis, phi)
offset.applyQuaternion(quaternion)
this._up.applyQuaternion(quaternion)
}
// mark compute objects as valid
deltaRotation.set({ x: 0, y: 0 })
deltaRotation.isInvalid = false
}
// apply panning
if (deltaPan.isInvalid) {
cameraObject.updateMatrix()
const matrix = cameraObject.matrix
const { x: deltaPanX, y: deltaPanY } = deltaPan.get()
// pan screen space x-direction
{
tempVector3
// get x-column of local transform matrix
.setFromMatrixColumn(matrix, 0)
.multiplyScalar(deltaPanX)
panOffset.add(tempVector3)
}
// pan screen space y-direction
{
tempVector3
// get y-column of local transform matrix
.setFromMatrixColumn(matrix, 1)
.multiplyScalar(-deltaPanY)
panOffset.add(tempVector3)
}
this._target.add(panOffset)
// mark compute objects as valid
panOffset.set(0, 0, 0)
deltaPan.set({ x: 0, y: 0 })
deltaPan.isInvalid = false
}
// assemble new eye (camera) position
this._eye.addVectors(offset, this._target)
this._eyeSpherical.setFromVector3(this._eye)
this._direction.copy(this._eye).normalize()
}
// update camera position
cameraObject.position.copy(this._eye)
cameraObject.up.copy(this._up)
cameraObject.lookAt(this._target)
// mark the controller as valid
this._isInvalid = false
}
return this
}
How can I apply the translation?
Expected result:
Thanks a lot in advance

button move camera THREE.js

I want to have the separate buttons on my website, and each button moves the camera to a different position. How do I go about doing this. Currently, I have it set up so that when I press a button, the camera follows a chain of camera positions I have set, But I do not know how to separate these so each button moves the camera to a different spot in my scene.
Here is the code I currently have:
camera.position.set(100, 0, 400);
}
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
TWEEN.update();
}
function moveCam() {
var pos1 = new TWEEN.Tween(camera.position).to({
y: 300
}, 3000).easing(TWEEN.Easing.Quadratic.InOut);
var pos2 = new TWEEN.Tween(camera.position).to({
x: -400
}, 4000).easing(TWEEN.Easing.Quadratic.InOut);
var pos3 = new TWEEN.Tween(camera.position).to({
y: -10
}, 4000).easing(TWEEN.Easing.Quadratic.InOut);
var rot1 = new TWEEN.Tween(camera.rotation).to({
y: -1
}, 4000).easing(TWEEN.Easing.Quadratic.InOut);
var pos4 = new TWEEN.Tween(camera.position).to({
x: 600
}, 6000).easing(TWEEN.Easing.Quadratic.InOut);
var pos5 = new TWEEN.Tween(camera.position).to({
y: -400
}, 2000).easing(TWEEN.Easing.Quadratic.InOut);
var rot2 = new TWEEN.Tween(camera.rotation).to({
y: -5
}, 2000).easing(TWEEN.Easing.Quadratic.InOut);
var pos6 = new TWEEN.Tween(camera.position).to({
z: 10
}, 5000).easing(TWEEN.Easing.Quadratic.InOut);
var rot3 = new TWEEN.Tween(camera.rotation).to({
y: 0
}, 2000).easing(TWEEN.Easing.Quadratic.InOut);
pos1.start();
pos1.chain(pos2);
pos2.chain(pos3, rot1)
rot1.chain(pos4)
pos4.chain(pos5, rot2)
rot2.chain(pos6)
pos6.chain(rot3)
Maybe try the following:
Use a single tween instead of one per button. This way you can make sure they won't interfere:
var positionTween = new TWEEN.Tween(camera.position)
.easing(TWEEN.Easing.Quadratic.InOut);
var rotationTween = new TWEEN.Tween(camera.rotation)
.easing(TWEEN.Easing.Quadratic.InOut);
And define the positions and rotations for each of the buttons in their complete form. So, if you define a position, always define it with all three components. Same goes for the rotation. If you don't specify a value, it will not be changed so the position would then depend on where the camera was before.
Here, I'm using the buttons id-attribute to retrieve the position. So I'm assuming the HTML for the buttons looks something like this:
<button id="button1" class="camera-button">Position 1</button>
And the JS would be:
var buttonCameraSettings = {
button1: {
position: {x: 1, y: 0, z: 0},
rotation: {x: 0, y: Math.PI, z: 0}
},
button2: {
// ...
}
};
You can now register an event-handler for all buttons and lookup the settings for the button:
var button1 = document.getElementById('button1');
button1.addEventListener('click', function(ev) {
var buttonId = ev.target.id;
var cameraSettings = buttonCameraSettings[buttonId];
updateCameraTweens(cameraSettings);
});
Now for the last part, the function updateCameraTweens would look like this:
function updateCameraTweens(params) {
if (params.position) {
positionTween.stop();
positionTween.to(params.position, 1000).start();
}
if (params.rotation) {
rotationTween.stop();
rotationTween.to(params.rotation, 1000).start();
}
}
If you need different durations per animation, you could just add those numbers to the parameters as well.
Another note regarding the rotations. For some mathematical reason it is generally not the best idea to animate the Euler-angles stored in camera.rotation. Animations tend to look better if the quaternion of the object is animated instead.
var quatTween = new TWEEN.Tween(camera.quaternion);
var toQuaternion = new THREE.Quaternion();
var toEuler = new THREE.Eueler();
// in updateCameraTweens()
toEuler.set(rotation.x, rotation.y, rotation.z);
toQuaternion.setFromEuler(toEuler);
quatTween.to(toQuaternion, 1000).start();
For your scene is render auto, so just change the camere like this:
html:
<button onclick="move()">Move</button>
js:
function move()
{
camera.position += 10;
}

Trying to draw multiple level scene in html5 canvas

this is my jsfiddle : jsfiddle.net/V8eKp/5/show
// START -- MOVE CAMERA
var p = new b2Vec2();
p = (ball.body.GetWorldCenter().x) * physics.scale;
pos.push(p);
var length = pos.length;
var s = (pos[length - 1] - pos[length - 2]); //in pixels
if ((halfwidth < (dw - p)) && (p > halfwidth)) {
ctx.translate(-s, 0);
}
I followed the code in here : http://www.codingowl.com/readblog.php?blogid=128
the rendering of the ball is acting weirdly and slow
i saw this example : http://www.emanueleferonato.com/2010/05/04/following-a-body-with-the-camera-in-box2d-the-smart-way/ but i didn't figure out how he do it he used 3 variables stage,x,y wish are undefined in the code he wrote.
and check out this demo by Impactjs and look how the camera move with the player movement i need this functionality : http://impactjs.com/demos/physics/
please can anyone help me in this
As long as ball.body.GetPosition().x > 48, this.current will start incrementing on each update, right? But your draw() only handles 0, 1 and 2.
Got a (kind of) working fix here: http://jsfiddle.net/u4Mv5/
You already got most of it right, just need a bit of work on the scene change logic.
My logic is, whenever the scene change, remove everything, manually shift the ball back or forward, and completely redraw the new scene.
As we are manually shifting the ball, the canvas does not need to be translated.
Draw and loop code: (Simplified)
draw: function () {
this.clear();
new Body(physics, { name: "Ground" });
ball = new Body(physics, { shape: "circle", x: ballx, y: bally, radius: 0.5 });
switch ( this.current ) {
case 0: // First scene
new Body(physics, { name: "Scene0Wall" });
new Body(physics, { name: "Scene0bricks0" });
new Body(physics, { name: "Scene0bricks1" });
break;
case 1: // Second scene
new Body(physics, { name: "Scene1bricks0" });
break;
case 2: // Third scene
new Body(physics, { name: "Scene2bricks0" });
break;
}
},
update: function () {
ballx = ball.body.GetPosition().x;
bally = ball.body.GetPosition().y;
if ( ballx > scene_width ) {
++this.current;
ballx -= scene_width;
this.draw();
}
if ( ballx < 0 && this.current > 0) {
--this.current;
ballx += scene_width;
this.draw();
}
},
This is also easier on scene layout since each scene's origin is [0,0].
I'm only preserving the balls' position, not its state and velocity, which you should implement. The scene layout (and scene cut off point) should also be adjusted to make sure the ball can continue its journey instead of getting stuck in a block.

Categories