Related
I have the following code that i've roughly redone from someone else to help learn javascript. I am getting the following error:
Uncaught TypeError: flock.addBoid is not a function
at setup (boids.js:15)
at boids.js:1
The function in question is called at the beginning in setup() and defined shortly after in the section labeled FLOCK. It is definitely not misspelled and these are the only occurrences of addBoid in the document. I'll include the whole document in case its relevant but the problem should just lie in the beginning.
I am not looking for any advice about my code other than the source and solution to this error, thanks.
setup();
draw();
//////////////////// SETUP ///////////////////////
var flock;
var ctx;
var c;
function setup(){
c = document.getElementById("boidCanvas");
ctx = c.getContext("2d");
flock = new Flock();
for(var i = 0; i < 100; i++){
var b = new Boid(ctx.width / 2, ctx.height / 2);
flock.addBoid(b);
}
}
function draw() {
ctx.fillStyle = "Blue";
ctx.fillRect(0,0,c.width,c.height);
//flock.run()
}
//////////////////// FLOCK ///////////////////////
function Flock(){
this.boids = [];
}
Flock.prototype.run = function(){
for(var i = 0; i < this.boids.length; i++){
this.boids[i].run(this.boids);
}
}
Flock.prototype.addBoid = function(b){
this.boids.push(b);
}
//////////////////// BOID ///////////////////////
function Boid(setx,sety){
this.acceleration = { x:0, y:0 };
this.velocity = { x:Math.floor(Math.random()*3)-1, y:Math.floor(Math.random()*3)-1 };
this.position = { x:setx, y:sety };
this.r = 3;
this.maxSpeed = 3;
this.maxForce = .05;
}
Boid.prototype.run = function(boids){
this.evaluate(boids);
this.update();
this.wrap();
this.render();
}
// force is a vector [x,y]
Boid.prototype.applyForce = function(force){
this.acceleration.x += force[0];
this.acceleration.y += force[1];
}
Boid.prototype.evaluate = function(boids){
var seperate = this.seperate(boids);
var align = this.align(boids);
var cohesion = this.cohesion(boids);
// Arbitrary Weights
seperate *= 1.5;
align *= 1.0;
cohesion *= 1.0;
this.applyForce(seperate);
this.applyForce(align);
this.applyForce(cohesion);
}
Boid.prototype.update = function(){
//update velocity
this.velocity += this.acceleration;
//fix velocity to max speed
var normal = normalize([this.velocity.x, this.velocity.y]);
this.velocity = constantMult(normal, this.maxSpeed);
//update position
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
//reset acceleration;
this.acceleration.x = 0;
this.acceleration.y = 0;
}
// target is a vector [x,y]
Boid.prototype.seek = function(target){
var desired = sub(target, [this.position.x, this.position.y]);
var normal = normalize(desired);
desired = constantMult(normal, this.maxSpeed);
var steer = sub(desired,[this.velocity.x, this.velocity.y])
normal = normalize(steer);
steer[0] = normal[0] * this.maxForce;
steer[1] = normal[1] * this.maxForce;
return steer;
}
Boid.prototype.render = function(){
var triangle = drawTriangle(this.velocity);
for(var i = 0; i < triangle.length; i++){
triangle[i] = constantMult(triangle[i], this.r);
}
for(i = 0; i < triangle.length; i++){
triangle[i] = add(triangle[i], this.position);
}
ctx.beginPath();
ctx.moveTo(triangle[0][0], triangle[0][1]);
for(i = 1; i < triangle.length; i++){
ctx.lineTo(triangle[i][0], triangle[i][1]);
}
ctx.closePath();
ctx.fillStyle = "White";
ctx.fill();
}
Boid.prototype.wrap = function(){
if(this.position.x < -this.r)
this.position.x = c.width + this.r;
else if(this.position.x > c.width + this.r)
this.position.x = -this.r;
if(this.position.y < -this.r)
this.position.y = c.height + this.r;
else if(this.position.y > c.height + this.r)
this.position.y = -this.r;
}
Boid.prototype.seperate = function(boids){
var desiredSeperation = 25.0;
var steer = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var d = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(d < desiredSeperation){
var normalDiff = normalize(difference);
normalDiff = constantMult(normalDiff, 1/d);
steer = add(steer, normalDiff);
count++;
}
}
if(count > 0){
steer = constantMult(steer, 1/count);
steer = normalize(steer);
steer = constantMult(steer, this.maxSpeed);
steer = sub(steer, this.velocity);
steer = normalize(steer);
steer = constantMult(steer, this.maxForce);
}
return steer;
}
Boid.prototype.align = function(boids){
var neighborDistance = 50;
var sum = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(dist < neighborDistance){
sum = sum(sum, boids[i].velocity);
count++;
}
}
if(count > 0){
sum = constantMult(sum, 1/count);
sum = normalize(sum);
sum = constantMult(this.maxSpeed);
var steer = sub(sum, this.velocity);
steer = normalize(steer);
steer = constantMult(steer, this.maxForce);
return steer;
}
else
return [0,0];
}
Boid.prototype.cohesion = function(boids){
var neighborDistance = 50;
var sum = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(dist < neighborDistance){
sum = add(sum, boids[i].position);
count++;
}
}
if(count > 0){
sum = constantMult(sum, 1/count);
return this.seek(sum);
}
else
return [0,0];
}
//////////////////// HELPERS ///////////////////////
// returns the vector with the same direction as v but with magnitude 1 in the form [x,y]
// v is a vector in the form [x,y]
function normalize(v){
var magnitude = Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2))
var normalX = v[0] / magnitude;
var normalY = v[1] / magnitude;
return [normalX, normalY];
}
function add(a,b){
var x = a[0]+b[0];
var y = a[1]+b[1];
return [x,y];
}
// returns a-b, [ax-bx, ay-by]
function sub(a,b){
var x = a[0]-b[0];
var y = a[1]-b[1];
return [x,y];
}
function mult(a,b){
var x = a[0]*b[0];
var y = a[1]*b[1];
return [x,y];
}
function constantMult(a, n){
for(var i = 0; i < a.length; i++){
a[i] *= n;
}
}
// creates an unscaled issoceles triangle centered at the origin
// returns a list of 3 lists, each containing the coordinates of a vertex, the first being the tip
// ie. [ [x1,y1], [x2,y2], [x3,y3] ]
// heading is a vector describing the direction of the triangle in the form [x,y]
// heading does not need to be normalized
function drawTriangle(heading){
heading = normalize(heading);
var v1 = [1,0];
var v2 = [-1, .5];
var v3 = [-1,-.5];
var thetaX = Math.acos(heading[0]);
var thetaY = Math.asin(heading[1]);
var theta;
if(thetaX >= 0)
theta = (Math.PI / 2) - thetaY;
else
theta = (Math.PI / 2) - thetaX;
function rotate(v){
var xp = (v[0] * Math.cos(theta)) - (v[1] * Math.sin(theta));
var yp = (v[1] * Math.cos(theta)) + (v[0] * Math.sin(theta));
return [xp, yp];
}
v1 = rotate(v1);
v2 = rotate(v2);
v3 = rotate(v3);
return [v1,v2,v3];
}
Move the functions setup(); and draw(); to the end of the JavaScript file. The issue was that the function addBoid() was not hoisted to the top, making it undefined by setup(); and draw();.
You function declaration gets hoisted on the top of block.
function Flock(){
this.boids = [];
}
when you add properties to prototype those properties are not eligible for hoisting, its like accessing variables (let declared cause var is eligible for hoisting) before declaring them.
Flock.prototype.run = function(){
for(var i = 0; i < this.boids.length; i++){
this.boids[i].run(this.boids);
}
}
Flock.prototype.addBoid = function(b){
this.boids.push(b);
}
Add above lines before you call flock.addBoid i.e. move setup and draw call to the end of Javascript
//////////////////// SETUP ///////////////////////
var flock;
var ctx;
var c;
//////////////////// FLOCK ///////////////////////
function Flock(){
this.boids = [];
}
Flock.prototype.run = function(){
for(var i = 0; i < this.boids.length; i++){
this.boids[i].run(this.boids);
}
}
Flock.prototype.addBoid = function(b){
this.boids.push(b);
}
function setup(){
c = document.getElementById("boidCanvas");
ctx = c.getContext("2d");
flock = new Flock();
for(var i = 0; i < 100; i++){
var b = new Boid(ctx.width / 2, ctx.height / 2);
flock.addBoid(b);
}
}
function draw() {
ctx.fillStyle = "Blue";
ctx.fillRect(0,0,c.width,c.height);
//flock.run()
}
//////////////////// BOID ///////////////////////
function Boid(setx,sety){
this.acceleration = { x:0, y:0 };
this.velocity = { x:Math.floor(Math.random()*3)-1, y:Math.floor(Math.random()*3)-1 };
this.position = { x:setx, y:sety };
this.r = 3;
this.maxSpeed = 3;
this.maxForce = .05;
}
Boid.prototype.run = function(boids){
this.evaluate(boids);
this.update();
this.wrap();
this.render();
}
// force is a vector [x,y]
Boid.prototype.applyForce = function(force){
this.acceleration.x += force[0];
this.acceleration.y += force[1];
}
Boid.prototype.evaluate = function(boids){
var seperate = this.seperate(boids);
var align = this.align(boids);
var cohesion = this.cohesion(boids);
// Arbitrary Weights
seperate *= 1.5;
align *= 1.0;
cohesion *= 1.0;
this.applyForce(seperate);
this.applyForce(align);
this.applyForce(cohesion);
}
Boid.prototype.update = function(){
//update velocity
this.velocity += this.acceleration;
//fix velocity to max speed
var normal = normalize([this.velocity.x, this.velocity.y]);
this.velocity = constantMult(normal, this.maxSpeed);
//update position
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
//reset acceleration;
this.acceleration.x = 0;
this.acceleration.y = 0;
}
// target is a vector [x,y]
Boid.prototype.seek = function(target){
var desired = sub(target, [this.position.x, this.position.y]);
var normal = normalize(desired);
desired = constantMult(normal, this.maxSpeed);
var steer = sub(desired,[this.velocity.x, this.velocity.y])
normal = normalize(steer);
steer[0] = normal[0] * this.maxForce;
steer[1] = normal[1] * this.maxForce;
return steer;
}
Boid.prototype.render = function(){
var triangle = drawTriangle(this.velocity);
for(var i = 0; i < triangle.length; i++){
triangle[i] = constantMult(triangle[i], this.r);
}
for(i = 0; i < triangle.length; i++){
triangle[i] = add(triangle[i], this.position);
}
ctx.beginPath();
ctx.moveTo(triangle[0][0], triangle[0][1]);
for(i = 1; i < triangle.length; i++){
ctx.lineTo(triangle[i][0], triangle[i][1]);
}
ctx.closePath();
ctx.fillStyle = "White";
ctx.fill();
}
Boid.prototype.wrap = function(){
if(this.position.x < -this.r)
this.position.x = c.width + this.r;
else if(this.position.x > c.width + this.r)
this.position.x = -this.r;
if(this.position.y < -this.r)
this.position.y = c.height + this.r;
else if(this.position.y > c.height + this.r)
this.position.y = -this.r;
}
Boid.prototype.seperate = function(boids){
var desiredSeperation = 25.0;
var steer = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var d = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(d < desiredSeperation){
var normalDiff = normalize(difference);
normalDiff = constantMult(normalDiff, 1/d);
steer = add(steer, normalDiff);
count++;
}
}
if(count > 0){
steer = constantMult(steer, 1/count);
steer = normalize(steer);
steer = constantMult(steer, this.maxSpeed);
steer = sub(steer, this.velocity);
steer = normalize(steer);
steer = constantMult(steer, this.maxForce);
}
return steer;
}
Boid.prototype.align = function(boids){
var neighborDistance = 50;
var sum = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(dist < neighborDistance){
sum = sum(sum, boids[i].velocity);
count++;
}
}
if(count > 0){
sum = constantMult(sum, 1/count);
sum = normalize(sum);
sum = constantMult(this.maxSpeed);
var steer = sub(sum, this.velocity);
steer = normalize(steer);
steer = constantMult(steer, this.maxForce);
return steer;
}
else
return [0,0];
}
Boid.prototype.cohesion = function(boids){
var neighborDistance = 50;
var sum = [0,0];
var count = 0;
for(var i = 0; i < boids.length; i++){
var difference = sub(this.position, boids[i].position);
var dist = Math.sqrt(Math.pow(difference[0],2), Math.pow(difference[1],2));
if(dist < neighborDistance){
sum = add(sum, boids[i].position);
count++;
}
}
if(count > 0){
sum = constantMult(sum, 1/count);
return this.seek(sum);
}
else
return [0,0];
}
//////////////////// HELPERS ///////////////////////
// returns the vector with the same direction as v but with magnitude 1 in the form [x,y]
// v is a vector in the form [x,y]
function normalize(v){
var magnitude = Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2))
var normalX = v[0] / magnitude;
var normalY = v[1] / magnitude;
return [normalX, normalY];
}
function add(a,b){
var x = a[0]+b[0];
var y = a[1]+b[1];
return [x,y];
}
// returns a-b, [ax-bx, ay-by]
function sub(a,b){
var x = a[0]-b[0];
var y = a[1]-b[1];
return [x,y];
}
function mult(a,b){
var x = a[0]*b[0];
var y = a[1]*b[1];
return [x,y];
}
function constantMult(a, n){
for(var i = 0; i < a.length; i++){
a[i] *= n;
}
}
// creates an unscaled issoceles triangle centered at the origin
// returns a list of 3 lists, each containing the coordinates of a vertex, the first being the tip
// ie. [ [x1,y1], [x2,y2], [x3,y3] ]
// heading is a vector describing the direction of the triangle in the form [x,y]
// heading does not need to be normalized
function drawTriangle(heading){
heading = normalize(heading);
var v1 = [1,0];
var v2 = [-1, .5];
var v3 = [-1,-.5];
var thetaX = Math.acos(heading[0]);
var thetaY = Math.asin(heading[1]);
var theta;
if(thetaX >= 0)
theta = (Math.PI / 2) - thetaY;
else
theta = (Math.PI / 2) - thetaX;
function rotate(v){
var xp = (v[0] * Math.cos(theta)) - (v[1] * Math.sin(theta));
var yp = (v[1] * Math.cos(theta)) + (v[0] * Math.sin(theta));
return [xp, yp];
}
v1 = rotate(v1);
v2 = rotate(v2);
v3 = rotate(v3);
return [v1,v2,v3];
}
setup();
draw();
I am developing a animation in javascript where a car moves towards a person and picks but currently instead of a path I am just driving diagonally to the person with below code.
Car.prototype.main = function() {
var angle = angleBetweenTwoPoints(this.target.position, this.position);
var cos = Math.cos(degreeToRadian(angle)) * -1;
var sin = Math.sin(degreeToRadian(angle));
var _this = _super.call(this) || this;
this.angle = angle;
this.position.x += cos * this.speed;
this.position.y -= sin * this.speed;
if (distance(this.position, this.target.position) < 10 && this.image == GameImage.getImage("hero") ) {
this.target.position.x = Math.random() * mainCanvas.width;
this.target.position.y = Math.random() * mainCanvas.height;
this.hitCount++;
console.log(hitCount);
ctx.fillText("points : " + hitCount, 32, 32);
this.changeImage = true;
_this.speed = 3;
this.changeImageTime = Date.now() + 600; //0.5 sec from now.
this.image = (this.image == GameImage.getImage("hero"))? GameImage.getImage("hero_other") : GameImage.getImage("hero");
}
if(this.changeImage){
if(Date.now() > this.changeImageTime){
this.changeImage = false;
_this.speed = 9;
this.image = (this.image == GameImage.getImage("hero_other"))? GameImage.getImage("hero") : GameImage.getImage("hero_other");
}
}
};
return Car;
}(Actor));
But instaed of this I want to follow a path.I also created some grids when u click the image it logs the console which grid it is.But I am unable move the car in a path.For complete understanding the animation is in
animation.
Any help is appreciated
Waypoints as a queue.
For waypoints path following you use a type of array called a queue. As the name suggests the queue holds items that need to be used, specifically they need to be used in the order in which they arrive. The first object on the queue is the first object out (unless you push in line)
In javascript a queue is easy to implement using an array.
const path = {
points : [],
currentPos : null,
dist : 0,
totalDistMoved : 0,
atEnd : false,
addPoint(x,y) {
if(this.currentPos === null){
this.currentPos = { x :0,y : 0};
this.dist = 0;
this.totalDistMoved = 0;
}
this.points.push({x,y}) ;
},
moveAlong(dist){
if(dist > 0){
if(this.points.length > 1){
var x = this.points[1].x - this.points[0].x;
var y = this.points[1].y - this.points[0].y;
var len = Math.sqrt(x*x+y*y) ;
if(len - this.dist < dist){
this.points.shift();
dist -= (len - this.dist);
this.totalDistMoved += (len - this.dist);
this.dist = 0;
this.moveAlong(dist);
return;
}
const frac = this.dist + dist / len;
this.currentPos.x = this.points[0].x + x * frac;
this.currentPos.y = this.points[0].y + y * frac;
this.dist += dist;
this.totalDistMoved += dist;
}else{
this.currentPos.x = this.points[0].x;
this.currentPos.y = this.points[0].y;
this.dist = 0;
this.atEnd = true;
}
}
}
}
To use
Add some way points.
path.addPoint(1,1);
path.addPoint(100,20);
path.addPoint(110,120);
path.addPoint(210,120);
path.addPoint(250,420);
Then for each step of the animations get a distance along
path.moveAlong(10); // move ten pixels
and use the current position
ctx.drawImage(car,path.currentPos.x,path.currentPos.y);
You know you have reached the end of the path when.
if(path.atEnd) {
// you have arrived
}
And at any time you know how far you have moved with
path.totalDistMoved
This is meant for animations that only play forward. It will ignore negative distances as way points are dumped when you have passed them
You will need to make some modifications if you wish to reuse the path object, or if the waypoints are being added as you go
A simple example.
Thing moves along at constant speed. Click on page to add more waypoints.
const ctx = canvas.getContext("2d");
requestAnimationFrame(mainLoop);
function mainLoop(time){
gTime = !gTime ? time : gTime;
fTime = time - gTime;
gTime = time;
if(canvas.width !== innerWidth || canvas.height !== innerHeight){
canvas.width = innerWidth;
canvas.height = innerHeight;
}else{
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,canvas.width,canvas.height);
}
if(mouse.button){
if(!point){
point = {x:0,y:0};
path.addPoint(point);
}
point.x = mouse.x;
point.y = mouse.y;
}else{
if(point){ point = null }
}
ctx.beginPath();
var i = 0;
while(i < path.points.length){ ctx.lineTo(path.points[i].x,path.points[i++].y)}
ctx.strokeStyle = "blue";
ctx.lineWidth = 2;
ctx.stroke();
var i = 0;
while(i < path.points.length){ ctx.strokeRect(path.points[i].x-4,path.points[i++].y-4,8,8)}
path.moveAlong(4 * fTime / 100);
var x = path.currentPos.x - thingPos.x;
var y = path.currentPos.y - thingPos.y;
thingPos.x = path.currentPos.x;
thingPos.y = path.currentPos.y;
drawThing(thingPos.x,thingPos.y,Math.atan2(y,x));
requestAnimationFrame(mainLoop);
}
var point;
const thingPos = {x:0,y:0};
const path = {
points : [],
currentPos : null,
distAlong : 0,
totalDistMoved : 0,
atEnd : false,
addPoint(x,y) {
if(y === undefined){
this.points.push(x); // add point as object
return;
}
if(this.currentPos === null){
this.currentPos = { x :0,y : 0};
this.distAlong = 0;
this.totalDistMoved = 0;
}
this.points.push({x,y}) ;
},
moveAlong(dist){
if(dist > 0){
if(this.points.length > 1){
var x = this.points[1].x - this.points[0].x;
var y = this.points[1].y - this.points[0].y;
var len = Math.sqrt(x*x+y*y) ;
if(len - this.distAlong < dist){
this.points.shift();
dist -= (len - this.distAlong);
this.totalDistMoved += (len - this.distAlong);
this.distAlong = 0;
this.moveAlong(dist);
return;
}
const frac = (this.distAlong + dist) / len;
this.currentPos.x = this.points[0].x + x * frac;
this.currentPos.y = this.points[0].y + y * frac;
this.distAlong += dist;
this.totalDistMoved += dist;
}else{
this.currentPos.x = this.points[0].x;
this.currentPos.y = this.points[0].y;
this.distAlong = 0;
this.atEnd = true;
}
}
}
}
path.addPoint(20,20);
path.addPoint(120,20);
path.addPoint(220,120);
path.addPoint(320,120);
path.addPoint(420,20);
function mouseEvents(e) {
const m = mouse;
m.x = e.pageX;
m.y = e.pageY;
m.button = e.type === "mousemove" ? m.button : e.type === "mousedown";
}
function drawThing(x,y,dir) {
ctx.setTransform(1,0,0,1,x,y);
ctx.rotate(dir);
ctx.fillStyle = "red";
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.beginPath();
var i = 0;
while(i < thing.length){ ctx.lineTo(thing[i++],thing[i++]) };
ctx.closePath();
ctx.fill();
ctx.stroke();
}
const thing = [-20,-10,20,-10,22,-7,22,7,20,10,-20,10];
var gTime; // global and frame time
var fTime;
const mouse = { x:0,y:0,button:false};
["mousemove","mousedown","mouseup"].forEach(t=>document.addEventListener(t,mouseEvents));
canvas {
position: absolute;
top : 0px;
left : 0px;
}
<canvas id="canvas"></canvas>
click drag to add waypoints.
I have a sorting game with 10 elements to drag and drop in the correct order.
When i begin to drag an object i want it to appear in front of all the other objects. Since createjs does not have a zindex property I was told to readd the item to the stage with stage.adchild(sequenceNumbers);
How do I properly add this to the mousedown or pressmove function?
for (var a = 0; a < gameData.Terms.length; a++) {
rect = new createjs.Shape();
rect.graphics.beginFill("blue").drawRoundRect(0, 0, 350, 30, 8);
rect.name = a;
var name = new createjs.Text(gameData.Terms[a].Definition, "14pt arial bold", "white");
name.id = gameData.Terms[a].Name;
name.textAlign = "left";
name.y = rect.y + 2;
name.x = rect.x + 4;
var sequenceNumbers = new createjs.Container();
sequenceNumbers.landingSpot = landingSpots[a];
landingSpots[a].sequenceNumber = sequenceNumbers;
sequenceNumbers.addChild(rect, name);
stage.addChild(sequenceNumbers);
sequenceNumbers.x = 300;
sequenceNumbers.y = xOffset;
xOffset += 40;
var startPositionX;
var startPostitionY;
sequenceNumbers.on('mousedown', function (e) {
stage.adchild(sequenceNumbers);
var posX = e.stageX;
var posY = e.stageY;
startPositionX = e.stageX;
startPositionY = e.stageY;
this.offset = { x: this.x - posX, y: this.y - posY };
});
sequenceNumbers.on("pressmove", function (evt) {
evt.currentTarget.x = evt.stageX;
evt.currentTarget.y = evt.stageY;
var posX = evt.stageX;
var posY = evt.stageY;
this.x = posX + this.offset.x;
this.y = posY + this.offset.y;
stage.update();
});
sequenceNumbers.on("pressup", function (evt) {
var stuffUnderMouse = landingSpotContainer.getObjectsUnderPoint(evt.rawX, evt.rawY, 0);
var oldSpot = evt.currentTarget.landingSpot;
var spotToMoveTo = null;
for (var i = 0; i < stuffUnderMouse.length; ++i) {
if (typeof stuffUnderMouse[i].landingSpot !== 'undefined' && stuffUnderMouse[i].landingSpot != oldSpot) {
spotToMoveTo = stuffUnderMouse[i].landingSpot;
break;
}
}
}
Just add the child again to its parent container:
evt.currentTarget.parent.addChild(evt.currentTarget);
should do the trick inside the mouse event function.
Notice the function is called addChild and not adchild.
I'm new to html5 and trying to display an array of code in a graph. It works for a line graph but for some reason unknown to me not for an exponential one. this my code.
My question is, is there a fault in the code that would break the graph?(i'm sure there's a metric ton of mistakes in the code).
I also got a lot of my code here.
thanks in advance for any help I receive.
<canvas id="graph5" width="400" height="300"></canvas>
function generateTestData5() // generates the array
{
var data = [];
for(var i=0; i<300; i++){
var sensfi = ((document.getElementById("f5").value)*(document.getElementById("xPos5").value)*(document.getElementById("f5").value))/((i*i*document.getElementById("sDI5").value)/(document.getElementById("rI5").value));
data[i] = sensfi;
}
return data;
}
var graph;
var xPadding = 40;
var yPadding = 40;
function getMaxY5() {
var data = generateTestData5();
var max = 0;
for(var i = 0; i < data.length; i ++) {
if(data[i] > max) {
max = data[i];
}
}
max += 10 - max % 10;
return max;
}
function getXPixel5(val) {
var data = generateTestData5();
return ((graph.width() - 20) / data.length) * val + (20 * 1.5);
}
function getYPixel5(val) {
var data = generateTestData5();
return graph.height() - (((graph.height() - 20) / getMaxY5()) * val) - 20;
}
function draw5(){
var data = generateTestData5();
graph = $('#graph5');
var c = graph[0].getContext('2d');
c.lineWidth = 2;
c.strokeStyle = '#333';
c.font = 'italic 8pt sans-serif';
c.textAlign = "center";
c.beginPath();
c.moveTo(xPadding, 0);
c.lineTo(xPadding, graph.height() - yPadding);
c.lineTo(graph.width(), graph.height() - yPadding);
c.stroke();
var x = 0;
for(var i = 0; i < data.length + 1; i ++) {
if(x==30) {
c.fillText(i, getXPixel5(i), graph.height() - yPadding + 20);
x=0;}
else {
x++;
}
}
c.textAlign = "right";
c.textBaseline = "middle";
for(var i = 0; i < getMaxY5(); i += getMaxY5()/10) {
c.fillText(i, xPadding-10, getYPixel5(i));
}
c.strokeStyle = '#f00';
c.beginPath();
c.moveTo(getXPixel5(0)+10, getYPixel5(data[0])-20);
for(var i = 1; i < data.length + 1; i ++) {
c.lineTo(getXPixel5(i)+10, getYPixel5(data[i])-20);
}
c.stroke();
//c.clearRect(0,0,graph.width(),graph.height());
}
I had to change width() and height() to width and height a few times (they are simple properties), start the test data at 1 because otherwise the first value is always +infinity", and store data and max instead of generating them multiple times, but now it seems to work.
var data; /* KEEP DATA AS A GLOBAL VARIABLE INSTEAD OF GENERATING IT AGAIN EACH TIME */
var graph;
var xPadding = 40;
var yPadding = 40;
function generateTestData5() // generates the array
{
var data = [];
for(var i=1; i<=300; i++){
var sensfi = ((document.getElementById("f5").value)*(document.getElementById("xPos5").value)*(document.getElementById("f5").value))/((i*i*document.getElementById("sDI5").value)/(document.getElementById("rI5").value));
data[i-1] = sensfi;
}
return data;
}
function getMaxY5() {
var max = 0;
for(var i = 0; i < data.length; i ++) {
if(data[i] > max) {
max = data[i];
}
}
max += 10 - max % 10;
return max;
}
function getXPixel5(val) {
return ((graph.width - 20) / data.length) * val + (20 * 1.5);
}
function getYPixel5(val) {
return graph.height - (((graph.height - 20) / getMaxY5()) * val) - 20;
}
function draw5(){
data = generateTestData5(); /* USE THE GLOBAL VARIABLE */
var max = getMaxY5(); /* STORE MAX INSTEAD OF CHECKING IT MULTIPLE TIMES */
graph = document.getElementById("graph5");
var c = graph.getContext('2d');
c.lineWidth = 2;
c.strokeStyle = '#333';
c.font = 'italic 8pt sans-serif';
c.textAlign = "center";
c.beginPath();
c.moveTo(xPadding, 0);
c.lineTo(xPadding, graph.height - yPadding);
c.lineTo(graph.width, graph.height - yPadding);
c.stroke();
var x = 0;
for(var i = 0; i < data.length + 1; i ++) {
if(x==30) {
c.fillText(i, getXPixel5(i), graph.height - yPadding + 20);
x=0;}
else {
x++;
}
}
c.textAlign = "right";
c.textBaseline = "middle";
for(var i = 0; i < max; i += max/10) {
c.fillText(i, xPadding-10, getYPixel5(i));
}
c.strokeStyle = '#f00';
c.beginPath();
c.moveTo(getXPixel5(0)+10, getYPixel5(data[0])-20);
for(var i = 1; i < data.length + 1; i ++) {
c.lineTo(getXPixel5(i)+10, getYPixel5(data[i])-20);
}
c.stroke();
//c.clearRect(0,0,graph.width,graph.height);
}
draw5();
<form>
<input name="f5" id="f5" value=8>
<input name="xpos5" id="xPos5" value=100>
<input name="sDI5" id="sDI5" value=6.4>
<input name="rI5" id="rI5" value=1280>
</form>
<canvas id="graph5" width="400" height="300"></canvas>
I want to change the color of the balls to red when they collide. I tried using my function check() to change the color of the balls when they collide using balls[i].color but how do I know the positions of the balls to compare when they collide?
function randomXToY(minVal,maxVal,floatVal)
{
var randVal = minVal+(Math.random()*(maxVal-minVal));
return typeof floatVal=='undefined'?Math.round(randVal):randVal.toFixed(floatVal);
}
// The Ball class
Ball = (function() {
// constructor
function Ball(x,y,radius,color){
this.center = {x:x, y:y};
this.radius = radius;
this.color = color;
this.dx = 2;
this.dy = 2;
this.boundaryHeight = $('#ground').height();
this.boundaryWidth = $('#ground').width();
this.dom = $('<p class="circle"></p>').appendTo('#ground');
// the rectange div a circle
this.dom.width(radius*2);
this.dom.height(radius*2);
this.dom.css({'border-radius':radius,background:color});
this.placeAtCenter(x,y);
}
// Place the ball at center x, y
Ball.prototype.placeAtCenter = function(x,y){
this.dom.css({top: Math.round(y- this.radius), left: Math.round(x - this.radius)});
this.center.x = Math.round(x);
this.center.y = Math.round(y);
};
Ball.prototype.setColor = function(color) {
if(color) {
this.dom.css('background',color);
} else {
this.dom.css('background',this.color);
}
};
// move and bounce the ball
Ball.prototype.move = function(){
var diameter = this.radius * 2;
var radius = this.radius;
if (this.center.x - radius < 0 || this.center.x + radius > this.boundaryWidth ) {
this.dx = -this.dx;
}
if (this.center.y - radius < 0 || this.center.y + radius > this.boundaryHeight ) {
this.dy = -this.dy;
}
this.placeAtCenter(this.center.x + this.dx ,this.center.y +this.dy);
};
return Ball;
})();
var number_of_balls = 5;
var balls = [];
var x;
var y;
$('document').ready(function(){
for (i = 0; i < number_of_balls; i++) {
var boundaryHeight = $('#ground').height();
var boundaryWidth = $('#ground').width();
y = randomXToY(30,boundaryHeight - 50);
x = randomXToY(30,boundaryWidth - 50);
var radius = randomXToY(15,30);
balls.push(new Ball(x,y,radius, '#'+Math.floor(Math.random()*16777215).toString(16)));
}
loop();
check();
});
check = function(){
for (var i = 0; i < balls.length; i++){
for(var j=0;j<balls.length;j++){
if(x==y){
balls[i].color='#ff0000';
alert("y");
}
else{
}
}}
setTimeout(check,8);
};
loop = function(){
for (var i = 0; i < balls.length; i++){
balls[i].move();
}
setTimeout(loop, 8);
};
http://jsbin.com/imofat/743/edit
Calculate the Eucledian distance between the centers of each ball. Then, when this distance is smaller or equal to the sum of their radiuses, there's a collision:
check = function() {
for (var i = 0; i < balls.length; i++) {
for(var j = 0; j < balls.length; j++) {
if (i != j) { // ignore self-collision
if (Math.pow(balls[j].center.x - balls[i].center.x, 2) + Math.pow(balls[j].center.y - balls[i].center.y, 2) <= Math.pow(balls[i].radius + balls[j].radius, 2)) {
balls[j].setColor('red');
} else {
balls[j].setColor(balls[j].color);
}
}
}}
Here's a DEMO.
Edit:
for colliding with other balls, it will require more work.. check this post: Ball to Ball Collision
just setColor when the direction changes, assuming "collide" means "hit the wall":
// move and bounce the ball
Ball.prototype.move = function(){
var diameter = this.radius * 2;
var radius = this.radius;
if (this.center.x - radius < 0 || this.center.x + radius > this.boundaryWidth ) {
this.dx = -this.dx;
this.setColor( 'red' );
}
if (this.center.y - radius < 0 || this.center.y + radius > this.boundaryHeight ) {
this.dy = -this.dy;
this.setColor( 'red' );
}
this.placeAtCenter(this.center.x + this.dx ,this.center.y +this.dy);
};
I added an actual ball collision check inside the check method:
check = function(){
var dx, dy;
var x1, x2, y1, y2, r1, r2;
for (var i = 0; i < balls.length; i++){
x1 = balls[i].center.x;y1=balls[i].center.y;r1=balls[i].radius;
for(var j=0;j<balls.length;j++){
if (i===j) {continue;} // collision with self
x2 = balls[j].center.x;y2=balls[j].center.y;r2=balls[j].radius;
if( Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) <=(r1+r2) ){ // check collision
balls[i].setColor('#ff0000');
}
else{
}
}
}
setTimeout(check,8);
};