Extending JavaScript Classes for use on Canvas - javascript

I am working on a project to help me gain a better understanding of JavaScript and building applications with it. I am currently making a game utilizing createjs. I'd like to extend the Shape "class" by adding some additional methods to it but can't seem to get my head around the issue.
I am not getting any runtime errors by this approach, however I think it's failing silently at a particular point.
My Subclass:
ShipGFX.prototype = new createjs.Shape();
function ShipGFX()
{
createjs.Shape.apply( this );
this.draw = function()
{
var g = this.graphics;
g.clear();
g.setStrokeStyle( 1 );
g.beginStroke( createjs.Graphics.getRGB( 0x00ff00 ) );
g.beginFill( createjs.Graphics.getRGB( 0x00ff00, 0.5 ) );
g.moveTo( 0, 0 );
g.lineTo( -5, -5 );
g.lineTo( 10, 0 );
g.lineTo( -5, 5 );
g.lineTo( 0, 0 );
g.endFill();
}
}
Where it's used:
var shape = new ShipGFX();
shape.draw();
So the console logs no errors and I can even log via the draw command. I think the issue is scope of this.graphics even though it doesn't fail there either. Is it a matter of scope? Is the this.graphics a reference to the prototype instance (if I understand that correctly). I'd ideally like to use Class-js as I have a better understanding of how it works but I can't even get this way to work.
Any input would be great. Thank you.

The reason why this was failing silently was because little did I realize that the draw function was preexisting in the createjs.Shape APIs. Changing the name to "render" solved my issue.

Related

three.js: How can I target object's position to another (grouped) object, while allowing rotation to follow AR camera?

I'm using an augmented reality library that does some fancy image tracking stuff. After learning a whole lot about this project, I'm now beyond my current ability and could use some help. For our purposes, the library creates an (empty) anchor point at the center of an IRL image target in-camera. Then moves the virtual world around the IRL camera.
My goal is to drive plane.rotation to always face the camera, while keeping plane.position locked to the anchor point. Additionally, plane.rotation values will be referenced later in development.
const THREE = window.MINDAR.IMAGE.THREE;
document.addEventListener('DOMContentLoaded', () => {
const start = async() => {
// initialize MindAR
const mindarThree = new window.MINDAR.IMAGE.MindARThree({
container: document.body,
imageTargetSrc: '../../assets/targets/testQR.mind',
});
const {renderer, scene, camera} = mindarThree;
// create AR object
const geometry = new THREE.PlaneGeometry(1, 1.25);
const material = new THREE.MeshBasicMaterial({color: 0x00ffff, transparent: true, opacity: 0.5});
const plane = new THREE.Mesh(geometry, material);
// create anchor
const anchor = mindarThree.addAnchor(0);
anchor.group.add(plane);
// start AR
await mindarThree.start();
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
}
start();
});
Everything I've tried so far went into the solutions already massaged into the (functioning draft) code. I have, however, done some research and found a couple avenues that might or might not work. Just tossing them out to see what might stick or inspire another solution. Skill-wise, I'm still in the beginner category, so any help figuring this out is much appreciated.
identify plane object by its group index number;
drive (override lib?) object rotation (x, y, z) to face camera;
possible solutions from dev:
"You can get those values through the anchor object, e.g. anchor.group.position. Meaning that you can use the current three.js API and get those values but without using it for rendering i.e. don't append the renderer.domElement to document."
"You can hack into the source code of mindar (it's open source)."
"Another way might be easier for you to try is to just create another camera yourself. I believe you can have multiple cameras, and just render another layer on top using your new camera."
I think it may be as simple as calling lookAt in the animation loop function:
// start AR
await mindarThree.start();
renderer.setAnimationLoop(() => {
plane.lookAt(new THREE.Vector3());
renderer.render(scene, camera);
});
This assumes the camera is always located at (0,0,0) (i.e., new THREE.Vector3()). This seems to be true from my limited testing. I found it helpful to debug by copy-pasting the MindAR three.js example into this codepen and printing some relevant values to the console.
Also note that, internally, MindAR's three.js module seems to directly modify the world matrix of the anchor.group object without modifying the position/rotation/scale parameters.

javascript games ThreeJS and Box2D conflicts?

I've been trying to experiment with box2d and threejs.
So box2d has a series of js iterations, I've been successful at using them so far in projects as well as threejs in others, but I'm finding when including the latest instance of threejs and box2dweb, threejs seems to be mis-performing when just close to box2dweb but maybe I'm missing something really simple, like a better way to load them in together, or section them off from one another?
I've tried a few iterations of the box2d js code now and I always seemed to run into the same problem with later versions of threejs and box2d together! - currently version 91 threejs.
The problem I'm seeing is very weird.
I'm really hoping someone from either the box2d camp or threejs camp can help me out with this one, please?
Below is a very simple example where I don't initialize anything to do with box2d, but just by having the library included theres problems and you can test by removing that resource, then it behaves like it should.
The below demo uses threejs 91 and box2dweb. It is supposed to every couple of seconds create a box or a simple sphere each with a random colour. Very simple demo, you will see the mesh type never changes and the colour seems to propagate across all mesh instances. However if you remove the box2dweb resource from the left tab then it functions absolutely fine, very odd :/
jsfiddle link here
class Main {
constructor(){
this._container = null;
this._scene = null;
this._camera = null;
this._renderer = null;
console.log('| Main |');
this.init();
}
init(){
this.initScene();
this.addBox(0, 0, 0);
this.animate();
}
initScene() {
this._container = document.getElementById('viewport');
this._scene = new THREE.Scene();
this._camera = new THREE.PerspectiveCamera(75, 600 / 400, 0.1, 1000);
this._camera.position.z = 15;
this._camera.position.y = -100;
this._camera.lookAt(new THREE.Vector3());
this._renderer = new THREE.WebGLRenderer({antialias:true});
this._renderer.setPixelRatio( 1 );
this._renderer.setSize( 600, 400 );
this._renderer.setClearColor( 0x000000, 1 );
this._container.appendChild( this._renderer.domElement );
}
addBox(x,y,z) {
var boxGeom = new THREE.BoxGeometry(5,5,5);
var sphereGeom = new THREE.SphereGeometry(2, 5, 5);
var colour = parseInt(Math.random()*999999);
var boxMat = new THREE.MeshBasicMaterial({color:colour});
var rand = parseInt(Math.random()*2);
var mesh = null;
if(rand == 1) {
mesh = new THREE.Mesh(boxGeom, boxMat);
}
else {
mesh = new THREE.Mesh(sphereGeom, boxMat);
}
this._scene.add(mesh);
mesh.position.x = x;
mesh.position.y = y;
mesh.position.z = z;
}
animate() {
requestAnimationFrame( this.animate.bind(this) );
this._renderer.render( this._scene, this._camera );
}
}
var main = new Main();
window.onload = main.init;
//add either a box or a sphere with a random colour every now and again
setInterval(function() {
main.addBox(((Math.random()*100)-50), ((Math.random()*100)-50), ((Math.random()*100)-50));
}.bind(this), 4000);
so the way im including the library locally is just a simple...
<script src="js/vendor/box2dweb.js"></script>
So just by including the box2d library threejs starts to act weird, I have tested this across multiple computers too and multiple version of both box2d (mainly box2dweb) and threejs.
So with later versions of threejs it seems to have some comflicts with box2d.
I found from research that most of the box2d conversions to js are sort of marked as not safe for thread conflicts.
Im not sure if this could be the cause.
I also found examples where people have successfully used box2d with threejs but the threejs is always quite an old version, however you can see exactly the same problems occurring in my example, when I update them.
So below is a demo I found and I wish I could credit the author, but here is a copy of the fiddle using threejs 49
jsfiddle here
.....and then below just swapping the resource of threejs from 49 to 91
jsfiddle here
its quite an odd one and maybe the two libraries just don't play together anymore but would be great if someone can help or has a working example of them working together on latest threejs version.
I have tried a lot of different box2d versions but always found the same problem, could this be a problem with conflicting libraries or unsafe threads?
but also tried linking to the resource include in the fiddles provided.
Any help really appreciated!!

When does "Argument 2 of WebGLRenderingContext.uniform4fv could not [...]" appear using three.js?

I am trying to extend a JS game that uses Three.js as API. A problem that has occured recently is this error:
TypeError: Argument 2 of WebGLRenderingContext.uniform4fv could not be converted to any of: Float32Array, UnrestrictedFloatSequence.
The line in the code causing this is the basic render call of the game:
renderer.render(scene, camera);
I could now paste the messy code here but thats not why I am here. I hope somebody has ever experienced that too and can tell me what the problem is.
Note:
I. The original error is from within Three.js (The internal render stuff)
three.min.js:7:118
II.The first frame can be rendered without any problem, after that the error occurs
III. The scene is made of a few simple objects, but the source of the problem is this object:
this.geometry = new THREE.PlaneGeometry(0.8, 0.8);
this.texture = new THREE.TextureLoader().load("graphics/racers/" + racer + ".png", function () { return;});
this.texture.generateMipmaps = false;
this.texture.minFilter = THREE.NearestFilter;
this.texture.magFilter = THREE.NearestFilter;
this.texture.repeat.set(0.25, 1);
this.material = new THREE.MeshBasicMaterial({ map: this.texture, transparent: true });
this.mesh = new THREE.Mesh(this.geometry, this.material);
scene.add(this.mesh);
If you need anything else feel free to ask.
Thanks in advance!
EDIT:
I found out that the error only appears when the Mesh-Object (mentioned above) is seen by the camera!
It turns out I was a fool all along ^^
I used
texture.offset = 0.25;
instead of
texture.offset.x = 0.25;
Wow! Feels great losing time for such a mistake :D Anyway: Won't do it again. A lesson for life!
Asset loading is asynchronous and most probably your texture has not loaded by the time you are using it. Use the example at https://threejs.org/docs/index.html?q=TextureL#api/loaders/TextureLoader

Three.js object definition not defining

I am working my way through a set of tutorials and have come across an error I cant figure out...
I know it is probably me being blind due to my lazy upbringing with IDE's that have red underlines for syntax errors but I kinda need this done soon!
The error is
TypeError: Tetris.boundingBoxConfig is undefined
file:///C:/Users/Timmy/Documents/Emergent%20Tech/Tetris/js/tetris.js
Line 127
here i define Tetris.boundingBoxConfig
var boundingBoxConfig = {
width: 360,
height: 360,
depth: 1200,
splitX: 6,
splitY: 6,
splitZ: 20
};
Tetris.boundingBoxConfig = boundingBoxConfig;
and here is line 127
mesh.position.x = (x - Tetris.boundingBoxConfig.splitX/2)*Tetris.blockSize + Tetris.blockSize/2;
if you need more of the code let me know and I will edit. Any Help would be much appreciated! please only constructive criticism
EDIT Definition of Tetris Object
var Tetris = {};
There was a second suggested way of doing it like this:
window.Tetris = window.Tetris || {};
but i don't really get how that way works
EDIT 2
Not sure if this helps the clarify the issue
var boundingBox = new THREE.Mesh(
new THREE.CubeGeometry(
boundingBoxConfig.width, boundingBoxConfig.height, boundingBoxConfig.depth,
boundingBoxConfig.splitX, boundingBoxConfig.splitY, boundingBoxConfig.splitZ),
new THREE.MeshBasicMaterial( { color: 0xffaa00, wireframe: true } )
);
Tetris.scene.add(boundingBox);
Inside your Tetris function, try changing
Tetris.boundingBoxConfig = boundingBoxConfig;
To
this.boundingBoxConfig = { //your definition };
so that your property becomes public.
Turns out this was due to me using local files in Firefox. I knew that Chrome had security issues when loading the files from a local disk so went with Firefox believing there was not a similar problem due to other projects working. I was wrong.
Lesson: Never use local files always use a server.
Could you please include the code where you have defined the "Tetris" object? (ie var Tetris blah blah blah)

how to use TDD in complex system?

So I have been making a game up to a point where I want to try TDD, so most of my working code don't have any test but I would like to try TDD for every new features.
My problem is my game comprises of tons of interdependent systems (sort of like I can't use the camera without the level in place, objects keep lots of references and initializing things take other things as argument). So just to test the fog system I need to initialize the level, the physic, the camera, the collision (because they all depend on each other to some degrees) and that create lots of duplications. Here's the code:
test( "shadow test", function() {
var b2world=new b2World(new b2Vec2(0, 0), false);
var contactListener = new collisionHandler.CollisionHandler(MASK_BITS);
b2world.SetContactListener(contactListener);
var map = gamejs.http.load('images/prot8.json');
var level = new Level.Level({
map: map,
size: 0.5,
nMaskBits: MASK_BITS.node,
nCategoryBits: MASK_BITS.player | MASK_BITS.birdy | MASK_BITS.innerBody,
world: b2world,
scale: SCALE});
var cam = new Camera.Camera({
lvlWid: this.level.width*SCALE*this.level.blockSize,
lvlHei: this.level.height*SCALE*this.level.blockSize,
yBand: 2,
maxSpeed: 20,
peerWindow: new b2Vec2(350, 300),
scrWid: scrWid,
scrHei: scrHei});
var shadow = new Shadow.Shadow({
width : 300,
height : 300,
level : level,
eye : new b2Vec2(600, 600),
});
ok( shadow.blit, "Shadow is extended from surface" );
ok( shadow.level, "Shadow has reference to the level" );
ok( shadow.eye, "Shadow has reference to player's eye" );
ok( (function() {
for (var i = 0; i < shadow.onScreenBlocks.length; i++) {
var rect = level.boxes[ shadow.onScreenBlocks[i] ];
//this is half finished
}
return true;
}), "Shadow do picks the blocks that are visible on screen" );
ok( (function() {
for (var i = 0; i < level.boxes.length; i++) if ( shadow.notProcessBlock(i) ) {
var rect = level.boxes[i];
if (rect.left < cam.offsetX //at this point I just realized that camera need to be setup in a more complex way...
}
return true;
}), "Shadow only process those blocks that are visible on screen" );
});
overall it just has a bad vibe to it. It's harder to wrap my mind around and harder to maintain I think.
When writing unit testing in a non-TDD way, you have to ask yourself for each piece of code you write: 'How can I test this'. This forces you to look at your code and make sure that all dependencies can be replaced when testing.
When doing TDD, this 'How can I test this' is baked in from the beginning. Introducing TDD in the middle of a project leads to problems when you can't replace all dependencies.
When Unit Testing, you need to make sure that you can test a unit in complete isolation and replace all dependencies with mocks or fakes. Then you can control all the inputs to your unit test so can you make sure that all code paths are tested.
To make unit testing work in your project you will have to refactor your code to really support unit testing.
I think TDD is not the main issue in this case. The question is if you want to use Unit testing at all and I think the answer to that question should be yes! Unit testing has many advantages. Now, you face the problem that the code you have written is hard to test. Making sure your code is testable is something that can be done after you've written your code but as you now experience that's quite hard. That's the point where TDD can help. TDD will make sure your code is easily testable so you can have all the benefits of unit testing.
I wrote a blog some time ago about unit testing.. maybe it can help: Unit Testing, hell or heaven?

Categories

Resources