Cannon.js loop (requestAnimationFrame) dosent work on node.js? - node.js

I'm using this solution: https://github.com/nodejs/help/issues/2483
to calculate frames. Here is my code.
//cannon
const CANNON = require('cannon');
const world = new CANNON.World(),
fixedTimeStep = 1.0/60.0,
maxSubSteps = 7;
//animation
var lastTime = undefined;
const fps = 40,
funcs = [],
skip = Symbol('skip'),
start = Date.now();
let time = start;
const animFrame = () => {
const fns = funcs.slice();
funcs.length = 0;
const t = Date.now();
const dt = t - start;
const t1 = 1e3 / fps;
for(const f of fns)
if(f !== skip) f(dt);
while(time <= t + t1 / 4) time += t1;
setTimeout(animFrame, time - t);
};
const requestAnimationFrame = func => {
funcs.push(func);
return funcs.length - 1;
};
const cancelAnimationFrame = id => {
funcs[id] = skip;
};
class World{
#world;
#shape;
constructor(){
this.#world = new CANNON.World()
this.#shape = new CANNON.Body({mass: 5, shape: new CANNON.Sphere(1)});
this.#shape.position.set(0,0,0);
this.#world.add(this.#shape);
this.setPhysics();
this.updatePhysics();
}
get world(){
return this.#world;
}
setPhysics(){
world.gravity.set(0, 0, -10); // Gravity pulls things down
world.broadphase = new CANNON.NaiveBroadphase();
world.solver.iterations = 40;
}
updatePhysics(time){
requestAnimationFrame(this.updatePhysics);
if(lastTime !== undefined){
var dt = (time - lastTime) / 1000;
this.#world.step(fixedTimeStep, dt, maxSubSteps);
}
lastTime = time;
};
}
animFrame();
var world1 = new World();
var world2 = new World();
When i try to run it with node i get this error
C:\testy_game\cannon (2).js:63
requestAnimationFrame(this.updatePhysics);
^
TypeError: Cannot read properties of undefined (reading
'updatePhysics')
at updatePhysics (C:\testy_game\cannon (2).js:63:32)
at Timeout.animFrame [as _onTimeout] (C:\testy_game\cannon (2).js:25:20) ←[90m at listOnTimeout
(node:internal/timers:557:17)←[39m ←[90m at processTimers
(node:internal/timers:500:7)←[39m
Please help solve the problem

Related

Script works in Greasemonkey but not Tampermonkey

I've found a script that works within Greasemonkey on Firefox but doesn't work on Tampermonkey in Chrome. The only thing i've found online to try is changing "unsafewindow" to "window" as it doesnt work in chrome, which didnt work. Beyond that i have no idea and i'd really appreciate some help.
And i've gotta try and fill the wordcount because it wont let me post.
// ==UserScript==
// #name Haggler
// #version 1.1.0
// #namespace Shinzan
// #Description Neopets autohaggler
// #Match http://www.neopets.com/haggle.phtml*
// #Match http://www.neopets.com/haggle.phtml
// #include http://www.neopets.com/objects.phtml?obj_type=*&type=shop
// #include http://www.neopets.com/objects.phtml?type=shop&obj_type=*
// #require https://raw.githubusercontent.com/hectorvazc/jsfun/master/jsfun.min.js
// ==/UserScript==
var url = document.URL;
var OCR = true;
var return_ab = true;
var haggle_type = 1;
function solve_captcha(url, callback) {
var captcha = new Image();
captcha.src = url;
captcha.onload = function(){
var width = captcha.width;
var height = captcha.height;
var canvas = unsafeWindow.document.createElement('canvas');
canvas.width = width;
canvas.height = width;
canvas.getContext("2d").drawImage(captcha, 0, 0);
var imgData = canvas.getContext("2d").getImageData(0, 0, width, height);
var lowy = 999;
var lowx = 999;
var low = 999;
for (var x = 0; x < imgData.width; x++){
for (var y = 0; y < imgData.height; y++){
var i = x*4+y*4*imgData.width;
var avg = Math.floor((imgData.data[i]+imgData.data[i+1]+imgData.data[i+2])/3);
if (avg < low){
low = avg;
lowx = x;
lowy = y;
}
}
}
callback(lowx, lowy);
};
}
function smart_haggle(haggle_price){
var val = new Array(2);
val[0] = haggle_price.substr(0,1);
val[1] = haggle_price.substr(1,1);
var x = 0;
var end_price = "";
for(x=0; x<haggle_price.length; x++){
end_price += val[(x%2)];
}
return end_price;
}
function pctr_haggle(haggle_price){
var randomPer = (Math.floor(((Math.random()*10) + 90))/ 100);
return Math.floor(parseInt(haggle_price) * randomPer);
}
if(url === 'http://www.neopets.com/haggle.phtml'){
if(return_ab) js().getNode('input[type="submit"]')[1].click();
}else if(url.includes('objects.phtml')){
var content = js().getNode('table[align="center"][cellpadding="4"][border="0"]');
js().here(content).find('tr').each(function(tr){
js().here(tr).find('td').each(function(td){
var a = js().here(td).find('a').detach()[0];
js(a).removeAttribute('onclick');
js(td).insertFirst(a);
});
});
}else if(url.includes('haggle.phtml')){
var src = js().here('div[align=center]').getNode('img[width="450"][height="150"]');
var haggle_price = js().getNode('font')[2];
haggle_price = js().here(haggle_price).getNode('b')[3].innerHTML;
haggle_price = (haggle_price.match("([0-9-,]+)")[0]).replace(",", "");
var value = (haggle_type) == 1 ? smart_haggle(haggle_price) : pctr_haggle(haggle_price);
js().find('input[name=current_offer]').val(value);
if(OCR){
solve_captcha(document.querySelector('input[type="image"]').src, function(x, y) {
setTimeout(function(){
var haggleform = document.querySelector('form[name="haggleform"]');
var newInput = document.createElement("input");
var newInput2 = document.createElement("input");
newInput.type="hidden";
newInput.name="x";
newInput.value=x;
haggleform.appendChild(newInput);
newInput2.type="hidden";
newInput2.name="y";
newInput2.value=y;
haggleform.appendChild(newInput2);
haggleform.submit();
}, 500);
});
}
}

node.js setInterval does not trigger a this. object

When the page loads the console log part of the function works showing me the current seconds + 3, but it does not repeat and the (innerText =....) does not work at all. I only added the console log part to the code to try to troubleshoot, the inner text change is the important part.
class Main {
constructor() {
// Initiate variables
this.TimerTexts = [];
this.infoTexts = [];
this.training = -1; // -1 when no class is being trained
this.videoPlaying = false;
this.currentTime2 = new Date(Date.now());
this.currentTime = new Date(Date.now());
this.remTime = this.currentTime.getSeconds() + 3;
this.looper = window.setInterval(this.intervalfunc(), 1000);
}
// ...
intervalfunc() {
this.TimerTexts.innerText = `Time: ${this.remTime} `;
console.log(this.remTime);
}
// ...
}
The problem is you're calling intervalfunc, not passing in as the function for setInterval.
In addition, you'll need to bind the function to your instance.
this.looper = window.setInterval(this.intervalfunc.bind(this), 1000);
You can use arrow function, inside arrow function you can call intervalfunc.
class Main {
constructor() {
// Initiate variables
this.TimerTexts = [];
this.infoTexts = [];
this.training = -1; // -1 when no class is being trained
this.videoPlaying = false;
this.currentTime2 = new Date(Date.now());
this.currentTime = new Date(Date.now());
this.remTime = this.currentTime.getSeconds() + 3;
this.looper = window.setInterval(()=>this.intervalfunc(), 1000);
}
intervalfunc() {
this.TimerTexts.innerText = `Time: ${this.remTime} `;
console.log(this.remTime);
this.remTime += 3;
}
}
new Main()
OR you can do
class Main {
constructor() {
// Initiate variables
this.TimerTexts = [];
this.infoTexts = [];
this.training = -1; // -1 when no class is being trained
this.videoPlaying = false;
this.currentTime2 = new Date(Date.now());
this.currentTime = new Date(Date.now());
this.remTime = this.currentTime.getSeconds() + 3;
var self = this;
this.looper = window.setInterval(this.intervalfunc.bind(self), 1000);
}
intervalfunc() {
this.TimerTexts.innerText = `Time: ${this.remTime} `;
console.log(this.remTime);
this.remTime += 3;
}
}
new Main()

CreateJS/TweenJS Losing Scope with "change" on Tween

I am on a frame in Animate by Adobe. When I add a "change" listener to my tween I lose scope when I hit the change function called animateParticle. Also related, the tween attached to the particle doesn't recognize .setPaused(true) function.
this.stop();
that = this;
var particleCount = 0;
var aParticle;
var mySpeed = 12;
var myRotation = 4;
var totalParticles = 5;
var stopParticles = false;
var particleHolder = new createjs.Container();
var mc_coll1 = this.parent.mc_coll0;
mc_coll1.setBounds(0,0,156,34);
var collission_ar = [this.parent.mc_coll0, this.parent.mc_coll1, this.parent.mc_coll2, this.parent.mc_coll3, this.parent.mc_coll4, this.parent.mc_coll5, this.parent.mc_coll6, this.parent.mc_coll7, this.parent.mc_coll8, this.parent.mc_coll9, this.parent.mc_coll10, this.parent.mc_coll11, this.parent.mc_coll12, this.parent.mc_coll13, this.parent.mc_coll14];
var totalCollisions = collission_ar.length;
this.addChild(particleHolder);
var xRange = width;
var yRange = height;
var scaleNum = 1;
//var collisionMethod = ndgmr.checkPixelCollision;
this.scaleX = 1;
this.scaleY = 1;
createParticles()
setTimeout(function(){
removeTimer();
//clearTimeout(that.pauseVar);
}, 2000)
function createParticles(){
var particle_ar = [];
var randNum = Math.ceil(Math.random() * totalParticles);
aParticle = new lib['MC_leaf'+randNum]();
aParticle.name = 'aParticle'+particleCount;
aParticle.x = Math.random() * xRange;
aParticle.y = -Math.random() * 15;
theNum = Math.random() * scaleNum;
aParticle.scaleX = theNum
aParticle.scaleY = theNum
aParticle.alpha = 1;
aParticle.collision = Math.floor(Math.random() * 2);
particleHolder.addChild(aParticle);
particleCount++;
var tween2 = createjs.Tween.get(aParticle).wait(0).to({y:yRange}, 2000, createjs.Ease.easeOut).call(removeObj,[aParticle], that).addEventListener('change', animateParticle.bind(that));
aParticle.tween = tween2;
if(!stopParticles){
timer = setTimeout(function() { createParticles() }, 100);
}
}
function animateParticle (event){
var part = event.currentTarget;
var mc_newColl;
console.log('part '+part.name);
for(var i=0; i < totalCollisions; i++){
// collision checking
mc_newColl = collission_ar[i];
var intersection = checkIntersection(part,mc_newColl);
if (intersection){
part.tween.setPaused(true);
//part.removeEventListener("tick", animateParticle.bind(that));
}
}
}
function checkIntersection(part, coll) {
if ( part.x >= coll.x + coll.width || part.x + part.width <= coll.x || part.y >= coll.y + coll.height || part.y + part.height <= coll.y ) return false;
return true;
}
function removeObj(part){
particleHolder.removeChild(part);
}
function removeTimer() {
stopParticles = true;
timer = clearInterval();
//var tween2 = createjs.Tween.get(particleHolder).wait(0).to({alpha:0}, 2000, createjs.Ease.easeOut);
}
//var timer = setInterval(function() { createParticles() }, 200, that);
var timer = setTimeout(function() { createParticles() }, 100, this);
In animateParticle, part is undefined.
The target of the change event will not be the particle, but the tween itself, since it is the dispatching object.
createjs.Tween.get(particle).to({x:1000}, 2000)
.on("change", function(event) {
console.log(event.target); // Tween
console.log(event.target.name); // undefined
console.log(event.target.target); // particle
console.log(event.target.target.name); // particle's name
}, that);
The undefined you are seeing is not the particle, but the name that you are logging.
Note that using on instead of addEventListener lets you pass a scope as a parameter instead of using bind.
Hope that helps.

How to iterate in Group in Phaser.js

I have create a group in phaserjs
this.fruitsOutline = this.game.add.group();
After that I have added few sprites in it. Everything is working correctly. Now if want to access this.fruitsOutline, from inside of a onDragStart event handler, it is giving undefined
var GameState = {
init:function(){
this.physics.startSystem(Phaser.Physics.ARCADE);
},
create: function () {
var innerImgPos = {x:150,y:200};
var outlineImgPos = {x:460,y:200};
var FIXED_DISTANCE_Y = 150;
var gameData = [
//...some data
];
this.background = this.game.add.sprite(0, 0, 'background');
this.overlapHappen = false;
this.startPos = {x:150,y:197};
this.fruitsOutline = this.game.add.group();
this.fruitsInner = this.game.add.group();
for(var i=0; i<gameData.length; i++){
fruitOuter = this.fruitsOutline.create(outlineImgPos.x,((outlineImgPos.y+25)*i)+FIXED_DISTANCE_Y,gameData[i].fruit_outline.img);
fruitOuter.name = gameData[i].fruitName;
fruitOuter.anchor.setTo(.5);
fruitOuter.customParams = {myName:gameData[i].fruit_outline.name};
this.game.physics.arcade.enable(fruitOuter);
fruitOuter.body.setSize(100,100,50,50);
fruitInner = this.fruitsInner.create(innerImgPos.x,((innerImgPos.y+25)*i)+FIXED_DISTANCE_Y,gameData[i].fruit_inner.img);
fruitInner.name = gameData[i].fruitName;
fruitInner.anchor.setTo(0.5);
fruitInner.inputEnabled = true;
fruitInner.input.enableDrag();
fruitInner.input.pixelPerfectOver = true;
fruitInner.originalPos = {x:fruitInner.position.x,y:fruitInner.position.y};
this.game.physics.arcade.enable(fruitInner);
fruitInner.body.setSize(100,100,50,50);
fruitInner.customParams = {myName:gameData[i].fruit_inner.name,targetKey:fruitOuter,targetImg:gameData[i].fruit_outline.name};
fruitInner.events.onDragStart.add(this.onDragStart);
fruitInner.events.onDragStop.add(this.onDragStop,this);
}
},
update: function () {
},
onDragStart:function(sprite,pointer){
console.log(this.fruitsInner) //this gives undefined I expect an array
},
onDragStop:function(sprite,pointer){
var endSprite = sprite.customParams.targetKey;
console.log(endSprite);
this.stopDrag(sprite,endSprite)
},
stopDrag:function(currentSprite,endSprite){
var currentSpriteRight = currentSprite.position.x + (currentSprite.width / 2);
if (!this.game.physics.arcade.overlap(currentSprite, endSprite, function() {
var currentSpriteTarget = currentSprite.customParams.targetImg;
var endSpriteName = endSprite.customParams.myName;
console.log(currentSpriteTarget,endSpriteName);
if(currentSpriteTarget === endSpriteName){
currentSprite.input.draggable = false;
currentSprite.position.copyFrom(endSprite.position);
currentSprite.anchor.setTo(endSprite.anchor.x, endSprite.anchor.y);
}
console.log(currentSprite.width);
})) {
//currentSprite.position.copyFrom(currentSprite.originalPosition);
currentSprite.position.x = currentSprite.originalPos.x;
currentSprite.position.y = currentSprite.originalPos.y;
}
},
render:function(){
game.debug.body(this.fruitsInner);
//game.debug.body(this.orange_outline);
}
}
You're missing the context when adding the drag callback.
Try that (adding this as the second argument):
fruitInner.events.onDragStart.add(this.onDragStart, this);
Oh, and inside the callback (or anywhere in the state) this.fruitsInner will be an instance of Phaser.Group, not an array like that comment says. The array you're looking for is probably this.fruitsInner.children.

Calculate the bounding box of STL file with JavaScript

So I am using this npm package: node-stl
And its working great. However the regexp syntax, mathematics and geometrical calculations are somewhat confusing to me. Especially all at the same time.
Basically what I want to achieve is to extend the script to calculate the bounding box of the STL.
Here is the main file that calculates the volume and weight of the STL being parsed/read.
var fs = require('fs');
// Vertex
function Vertex (v1,v2,v3) {
this.v1 = Number(v1);
this.v2 = Number(v2);
this.v3 = Number(v3);
}
// Vertex Holder
function VertexHolder (vertex1,vertex2,vertex3) {
this.vert1 = vertex1;
this.vert2 = vertex2;
this.vert3 = vertex3;
}
// transforming a Node.js Buffer into a V8 array buffer
function _toArrayBuffer (buffer) {
var
ab = new ArrayBuffer(buffer.length),
view = new Uint8Array(ab);
for (var i = 0; i < buffer.length; ++i) {
view[i] = buffer[i];
}
return ab;
}
// calculation of the triangle volume
// source: http://stackoverflow.com/questions/6518404/how-do-i-calculate-the-volume-of-an-object-stored-in-stl-files
function _triangleVolume (vertexHolder) {
var
v321 = Number(vertexHolder.vert3.v1 * vertexHolder.vert2.v2 * vertexHolder.vert1.v3),
v231 = Number(vertexHolder.vert2.v1 * vertexHolder.vert3.v2 * vertexHolder.vert1.v3),
v312 = Number(vertexHolder.vert3.v1 * vertexHolder.vert1.v2 * vertexHolder.vert2.v3),
v132 = Number(vertexHolder.vert1.v1 * vertexHolder.vert3.v2 * vertexHolder.vert2.v3),
v213 = Number(vertexHolder.vert2.v1 * vertexHolder.vert1.v2 * vertexHolder.vert3.v3),
v123 = Number(vertexHolder.vert1.v1 * vertexHolder.vert2.v2 * vertexHolder.vert3.v3);
return Number(1.0/6.0)*(-v321 + v231 + v312 - v132 - v213 + v123);
}
// parsing an STL ASCII string
function _parseSTLString (stl) {
var totalVol = 0;
// yes, this is the regular expression, matching the vertexes
// it was kind of tricky but it is fast and does the job
var vertexes = stl.match(/facet\s+normal\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+outer\s+loop\s+vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+endloop\s+endfacet/g);
vertexes.forEach(function (vert) {
var preVertexHolder = new VertexHolder();
vert.match(/vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s/g).forEach(function (vertex, i) {
var tempVertex = vertex.replace('vertex', '').match(/[-+]?[0-9]*\.?[0-9]+/g);
var preVertex = new Vertex(tempVertex[0],tempVertex[1],tempVertex[2]);
preVertexHolder['vert'+(i+1)] = preVertex;
});
var partVolume = _triangleVolume(preVertexHolder);
totalVol += Number(partVolume);
})
var volumeTotal = Math.abs(totalVol)/1000;
return {
volume: volumeTotal, // cubic cm
weight: volumeTotal * 1.04 // gm
}
}
// parsing an STL Binary File
// (borrowed some code from here: https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/STLLoader.js)
function _parseSTLBinary (buf) {
buf = _toArrayBuffer(buf);
var
headerLength = 80,
dataOffset = 84,
faceLength = 12*4 + 2,
le = true; // is little-endian
var
dvTriangleCount = new DataView(buf, headerLength, 4),
numTriangles = dvTriangleCount.getUint32(0, le),
totalVol = 0;
for (var i = 0; i < numTriangles; i++) {
var
dv = new DataView(buf, dataOffset + i*faceLength, faceLength),
normal = new Vertex(dv.getFloat32(0, le), dv.getFloat32(4, le), dv.getFloat32(8, le)),
vertHolder = new VertexHolder();
for(var v = 3; v < 12; v+=3) {
var vert = new Vertex(dv.getFloat32(v*4, le), dv.getFloat32((v+1)*4, le), dv.getFloat32( (v+2)*4, le ) );
vertHolder['vert'+(v/3)] = vert;
}
totalVol += _triangleVolume(vertHolder);
}
var volumeTotal = Math.abs(totalVol)/1000;
return {
volume: volumeTotal, // cubic cm
weight: volumeTotal * 1.04 // gm
}
}
// NodeStl
// =======
// > var stl = NodeStl(__dirname + '/myCool.stl');
// > console.log(stl.volume + 'cm^3');
// > console.log(stl.weight + 'gm');
function NodeStl (stlPath) {
var
buf = fs.readFileSync(stlPath),
isAscii = true;
for (var i=0, len=buf.length; i<len; i++) {
if (buf[i] > 127) { isAscii=false; break; }
}
if (isAscii)
return _parseSTLString(buf.toString());
else
return _parseSTLBinary(buf);
}
module.exports = NodeStl;
If anyone could help me with this it would be great. I know and it feels like it simple. That I just need to know max/min of the different directions(x,y,z) and could then calculate the bounding box.
But I do not understand what the max/min for x,y and z is here. Please answer if you have an idea.
I've made a new branch https://github.com/johannesboyne/node-stl/tree/boundingbox could you please verify whether the applied algorithm works?
Best,
Johannes
Edit: If the branch is stable -> works I'll push it into v.0.1.0 (don't know why it is still 0.0.1)

Resources