I have an object (a function) called 'Game' which has a prototype method called 'gameLoop.' I need this loop to be called in an interval, so I attempt to do this:
setInterval(game.gameLoop,setIntervalAmount);
but receive a "TypeError: Cannot read property 'clearRect' of undefined(…)"
Here is the prototype method:
Game.prototype.gameLoop = function()
{
this.context.clearRect(0,0,this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width/2, this.canvas.height/2);
this.context.scale(this.camera.scale,this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x,this.camera.y);
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].updateSprite();
this.objects[i].drawSprite(this.context);
}
this.context.restore();
}
I am still having difficulty understanding Object Oriented Programming in Javascript. I had a working version where the function was just a regular function and I passed in a game object. Any ideas?
By the way, here is some additional code that may be helpful.
function Sprite(imgg,w,h)
{
this.img = imgg;
this.x = 350;//Math.random()*700;
this.y = 350;//Math.random()*700;
this.vx = 0;//Math.random()*8-4;
this.vy = 0;//Math.random()*8-4;
this.width = w;
this.height = h;
this.rotatespeed = 0.01;
this.rotate = 40;
}
Sprite.prototype.drawSprite = function(ctx)
{
ctx.save();
ctx.translate(this.x,this.y);
ctx.rotate(this.rotate);
ctx.drawImage(this.img,0,0,this.img.width,this.img.height,-this.width/2,-this.height/2,this.width,this.height);
ctx.restore();
}
Sprite.prototype.updateSprite = function()
{
this.x += this.vx;
this.y += this.vy;
this.rotate += this.rotatespeed;
if(this.x > 700)
this.vx = -this.vx;
if(this.x < 0)
this.vx = -this.vy;
if(this.y > 700)
this.vy = -this.vy;
if(this.y < 0)
this.vy = -this.vy;
}
Sprite.prototype.mouseEventListener = function(evt, type)
{
console.log("Hello");
}
//------------------------------------------
//GLOBAL VARIALBES
var setIntervalAmount = 30;
var scrollAmount = 0.5;
var game;
function Game()
{
this.camera = new Object();
this.camera.x = -350;
this.camera.y = -350;
this.camera.scale = 1;
this.camera.rotate = 0;
this.canvas = document.createElement("canvas");
document.body.appendChild(this.canvas);
this.canvas.id="mycanvas";
this.canvas.width = 700;
this.canvas.height = 700;
this.context = this.canvas.getContext("2d");
var ctx = this.context;
ctx.canvas.addEventListener('mousemove', function(event){
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
var canvasX = mouseX * ctx.canvas.width / ctx.canvas.clientWidth;
var canvasY = mouseY * ctx.canvas.height / ctx.canvas.clientHeight;
//console.log(canvasX+" | "+canvasY);
});
this.objects = new Array();
}
Game.prototype.handleMouse = function(evt,type)
{
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].mouseEventListener(evt,type);
}
};
Game.prototype.gameLoop = function()
{
this.context.clearRect(0,0,this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width/2, this.canvas.height/2);
this.context.scale(this.camera.scale,this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x,this.camera.y);
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].updateSprite();
this.objects[i].drawSprite(this.context);
}
this.context.restore();
}
/*Game.prototype.drawGame = function()
{
var gameLoop = setInterval(function(){
this.context.clearRect(0,0,this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width/2, this.canvas.height/2);
this.context.scale(this.camera.scale,this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x,this.camera.y);
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].updateSprite();
this.objects[i].drawSprite(this.context);
}
this.context.restore();
},setIntervalAmount);
}*/
function mouseWheelListener()
{
var evt = window.event;
console.log(evt.wheelDelta);
if(evt.wheelDelta < 0)
game.camera.scale /= (1+scrollAmount);
else
game.camera.scale *= (1+scrollAmount);
}
function mouseDownListener()
{
var evt = window.event;
var type = "down"
game.handleMouse(evt,type);
}
function mouseUpListener()
{
var evt = window.event;
var type = "up"
game.handleMouse(evt,type);
}
function mouseMoveListener()
{
var evt = window.event;
var type = "move"
game.handleMouse(evt,type);
}
//------------------
window.addEventListener('load',function(event){startgame();});
var dog = new Image();
dog.src = "grid.gif";
function startgame()
{
game = new Game();
for(var i=0;i<1;i++)
game.objects.push(new Sprite(dog,250,250));
setInterval(game.gameLoop,setIntervalAmount);
document.getElementById("mycanvas").addEventListener("wheel", mouseWheelListener);
document.getElementById("mycanvas").addEventListener("mousedown", mouseDownListener);
document.getElementById("mycanvas").addEventListener("mouseup", mouseUpListener);
document.getElementById("mycanvas").addEventListener("mousemove", mouseMoveListener);
}
Only issue, with your code is the context on which you are executing the gameloop method.
usually setInterval, setTimeout functions are executed under the global / window context. Hence, if you specify this inside the method, you are technically referring to global context, even though you are executing it on an object.
So, just to make sure you don't run into issues, always have a method as a first argument to setInterval, that would execute the necessary functions, instead of a method reference, something like
setInterval(function(){/*
game.gameLoop()
*/}, 1000);
This way you are executing the setInterval function in the global context but you are calling a method on game object explicitly.
function Sprite(imgg, w, h) {
this.img = imgg;
this.x = 350; //Math.random()*700;
this.y = 350; //Math.random()*700;
this.vx = 0; //Math.random()*8-4;
this.vy = 0; //Math.random()*8-4;
this.width = w;
this.height = h;
this.rotatespeed = 0.01;
this.rotate = 40;
}
Sprite.prototype.drawSprite = function(ctx) {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.rotate);
ctx.drawImage(this.img, 0, 0, this.img.width, this.img.height, -this.width / 2, -this.height / 2, this.width, this.height);
ctx.restore();
}
Sprite.prototype.updateSprite = function() {
this.x += this.vx;
this.y += this.vy;
this.rotate += this.rotatespeed;
if (this.x > 700)
this.vx = -this.vx;
if (this.x < 0)
this.vx = -this.vy;
if (this.y > 700)
this.vy = -this.vy;
if (this.y < 0)
this.vy = -this.vy;
}
Sprite.prototype.mouseEventListener = function(evt, type) {
//console.log("Hello");
}
//------------------------------------------
////GLOBAL VARIALBES
var setIntervalAmount = 200;
var scrollAmount = 0.5;
var game;
function Game() {
this.camera = new Object();
this.camera.x = -350;
this.camera.y = -350;
this.camera.scale = 1;
this.camera.rotate = 0;
this.canvas = document.createElement("canvas");
document.body.appendChild(this.canvas);
this.canvas.id = "mycanvas";
this.canvas.width = 700;
this.canvas.height = 700;
this.context = this.canvas.getContext("2d");
var ctx = this.context;
ctx.canvas.addEventListener('mousemove', function(event) {
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
var canvasX = mouseX * ctx.canvas.width / ctx.canvas.clientWidth;
var canvasY = mouseY * ctx.canvas.height / ctx.canvas.clientHeight;
//console.log(canvasX+" | "+canvasY);
});
this.objects = new Array();
}
Game.prototype.handleMouse = function(evt, type) {
for (var i = 0; i < this.objects.length; i++) {
this.objects[i].mouseEventListener(evt, type);
}
};
Game.prototype.gameLoop = function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width / 2, this.canvas.height / 2);
this.context.scale(this.camera.scale, this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x, this.camera.y);
for (var i = 0; i < this.objects.length; i++) {
this.objects[i].updateSprite();
this.objects[i].drawSprite(this.context);
}
this.context.restore();
}
/*Game.prototype.drawGame = function()
{
var gameLoop = setInterval(function(){
this.context.clearRect(0,0,this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width/2, this.canvas.height/2);
this.context.scale(this.camera.scale,this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x,this.camera.y);
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].updateSprite();
this.objects[i].drawSprite(this.context);
}
this.context.restore();
},setIntervalAmount);
}*/
function mouseWheelListener() {
var evt = window.event;
console.log(evt.wheelDelta);
if (evt.wheelDelta < 0)
game.camera.scale /= (1 + scrollAmount);
else
game.camera.scale *= (1 + scrollAmount);
}
function mouseDownListener() {
var evt = window.event;
var type = "down"
game.handleMouse(evt, type);
}
function mouseUpListener() {
var evt = window.event;
var type = "up"
game.handleMouse(evt, type);
}
function mouseMoveListener() {
var evt = window.event;
var type = "move"
game.handleMouse(evt, type);
}
//------------------
window.addEventListener('load', function(event) {
startgame();
});
var dog = new Image();
dog.src = "https://i.stack.imgur.com/W0mIA.png";
function startgame() {
game = new Game();
for (var i = 0; i < 1; i++)
game.objects.push(new Sprite(dog, 250, 250));
setInterval(function() {
game.gameLoop();
}, setIntervalAmount);
document.getElementById("mycanvas").addEventListener("wheel", mouseWheelListener);
document.getElementById("mycanvas").addEventListener("mousedown", mouseDownListener);
document.getElementById("mycanvas").addEventListener("mouseup", mouseUpListener);
document.getElementById("mycanvas").addEventListener("mousemove", mouseMoveListener);
}
setInterval will call game.gameloop at the global scope which means the value of this inside the function is not what you expect it to be. This can be fixed by binding the function to the desired object.
E.g. change setInterval(game.gameLoop,setIntervalAmount); to setInterval(game.gameLoop.bind(game),setIntervalAmount);.
This example from MDN may provide some clarity for your code's current behaviour:
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var retrieveX = module.getX;
retrieveX();
// returns 9 - The function gets invoked at the global scope
// Create a new function with 'this' bound to module
// New programmers might confuse the
// global var x with module's property x
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
Related
I just made this animation using canvas. Shows a number of bubbles scrolling from top to bottom. Clicking on any bubble starts it moving top to bottom again.
I plan to add a counter of the number of bubbles clicked/picked with a localStorage but I have difficulties implementing it.
Here is how I implemented it.
Each bubble now has id property.
Every time you run the script, it puts empty array to localStorage.clickedBubbles.
When a bubble is clicked, the array is checked if it contains the id. If not, the id is pushed to local storage.
Also, each click the count is logged to console.
const INITIALIZATION = 100;
const STEP1 = 200;
const BUBBLES = 10;
const SPEED = 10;
let counter = 0;
localStorage.setItem("clickedBubbles", "[]");
function Bubble(x, y, radio) {
this.id = counter++;
this.x = x;
this.y = y;
this.radio = radio;
this.color = "blue";
this.speed = 5;
this.getId = function () {
return this.id;
};
this.getX = function () {
return this.x;
};
this.getY = function () {
return this.y;
};
this.getRadio = function () {
return this.radio;
};
this.getColor = function () {
return this.color;
};
this.getspeed = function () {
return this.speed;
};
this.setX = function (x) {
this.x = x;
};
this.setY = function (y) {
this.y = y;
};
this.setRadio = function (radio) {
this.radio = radio;
};
this.setColor = function (color) {
this.color = color;
};
this.setSpeed = function (speed) {
this.speed = speed;
};
this.draw = function (ctx) {
ctx.save();
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radio, 0, Math.PI * 2, true);
ctx.fill();
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(
this.x + this.radio / 3,
this.y - this.radio / 3,
this.radio / 4,
0,
Math.PI * 2,
true
);
ctx.fill();
ctx.restore();
};
this.coordinates = function (x, y) {
var ax = this.getX() - this.getRadio();
var ay = this.getY() - this.getRadio();
return (
x >= ax &&
x <= ax + 2 * this.getRadio() &&
y >= ay &&
y <= ay + 2 * this.getRadio()
);
};
}
function animationBubbles() {
var bubbles = [];
var arrayColors;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var status = INITIALIZATION;
var app = this;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
this.click = function (e) {
var x = e.x || e.pageX || e.clientX;
var y = e.y || e.clientY || e.pageY;
const clickedArr = JSON.parse(localStorage.getItem("clickedBubbles"));
for (var i = 0; i < bubbles.length; i++) {
var aux = bubbles[i];
if (aux.coordinates(x, y)) {
if (!clickedArr.includes(aux.getId())) {
clickedArr.push(aux.getId());
localStorage.setItem("clickedBubbles", JSON.stringify(clickedArr));
}
aux.setY(0);
break;
}
}
console.log("Clicked count: " + clickedArr.length);
};
canvas.addEventListener("mousedown", this.click, false);
this.realizeAnimation = function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < bubbles.length; i++) {
var aux = bubbles[i];
if (aux.getY() < canvas.height) {
aux.setY(aux.getY() + aux.getspeed());
} else {
aux.setY(0);
aux.setColor(arrayColors[Math.floor(Math.random() * 4)]);
}
aux.draw(ctx);
}
setTimeout(app.realizeAnimation, 100);
};
this.createBubbles = function () {
for (var i = 1; i <= BUBBLES; i++) {
var burbuja = new Bubble(
canvas.width * (i / BUBBLES),
0,
this.generateRandom(Math.floor(canvas.width / 20))
);
burbuja.setSpeed(SPEED);
burbuja.setColor(arrayColors[this.generateRandom(4)]);
bubbles.push(burbuja);
}
};
this.generateRandom = function (num) {
return Math.floor(Math.random() * num);
};
this.initColor = function () {
arrayColors[0] = "#C923C9";
arrayColors[1] = "#FAEF20";
arrayColors[2] = "#20ECFA";
arrayColors[3] = "#FA209C";
};
this.machineStates = function () {
if (status === INITIALIZATION) {
arrayColors = [];
this.initColor();
this.createBubbles();
status = STEP1;
setTimeout(app.machineStates, 100);
} else {
app.realizeAnimation();
}
};
this.machineStates();
}
new animationBubbles();
I'm trying to create an idle animation where the red rectangle moves back and forth slightly in a loop. For some reason once it reaches the specified threshhold instead of proceeding to move in the opposite direction, it just stops.
What did I do wrong?
<canvas id="myCanvas" width="1500" height="500" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
// Spaceship structure
var shipWidth = 250;
var shipHeight = 100;
// Canvas parameters
var cWidth = canvas.width;
var cHeight = canvas.height;
// Positioning variables
var centerWidthPosition = (cWidth / 2) - (shipWidth / 2);
var centerHeightPosition = (cHeight / 2) - (shipHeight / 2);
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
function drawShip(){
ctx.clearRect(0, 0, cWidth, cHeight);
ctx.fillStyle = "#FF0000";
ctx.fillRect(centerWidthPosition,centerHeightPosition,shipWidth,shipHeight);
centerWidthPosition--;
if (centerWidthPosition < 400){
++centerWidthPosition;
}
requestAnimationFrame(drawShip);
}
drawShip();
</script>
#TheAmberlamps explained why it's doing that. Here I offer you a solution to achieve what I believe you are trying to do.
Use a velocity variable that changes magnitude. X position always increases by velocity value. Velocity changes directions at screen edges.
// use a velocity variable
var xspeed = 1;
// always increase by velocity
centerWidthPosition += xspeed;
// screen edges are 0 and 400 in this example
if (centerWidthPosition > 400 || centerWidthPosition < 0){
xspeed *= -1; // change velocity direction
}
I added another condition in your if that causes the object to bounce back and forth. Remove the selection after || if you don't want it doing that.
Your function is caught in a loop; once centerWidthPosition reaches 399 your conditional makes it increment back up to 400, and then it decrements back to 399.
here is another one as a brain teaser - how would go by making this animation bounce in the loop - basically turn text into particles and then reverse back to text and reverse back to particles and back to text and so on and on and on infinitely:
var random = Math.random;
window.onresize = function () {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
window.onresize();
var ctx = canvas.getContext('2d');
ctx.font = 'bold 50px "somefont"';
ctx.textBaseline = 'center';
ctx.fillStyle = 'rgba(255,255,255,1)';
var _particles = [];
var particlesLength = 0;
var currentText = "SOMETEXT";
var createParticle = function createParticle(x, y) {_particles.push(new Particle(x, y));};
var checkAlpha = function checkAlpha(pixels, i) {return pixels[i * 4 + 3] > 0;};
var createParticles = function createParticles() {
var textSize = ctx.measureText(currentText);
ctx.fillText(currentText,Math.round((canvas.width / 2) - (textSize.width / 2)),Math.round(canvas.height / 2));
var imageData = ctx.getImageData(1, 1, canvas.width, canvas.height);
var pixels = imageData.data;
var dataLength = imageData.width * imageData.height;
for (var i = 0; i < dataLength; i++) {
var currentRow = Math.floor(i / imageData.width);
var currentColumn = i - Math.floor(i / imageData.height);
if (currentRow % 2 || currentColumn % 2) continue;
if (checkAlpha(pixels, i)) {
var cy = ~~(i / imageData.width);
var cx = ~~(i - (cy * imageData.width));
createParticle(cx, cy);
}}
particlesLength = _particles.length;
};
var Point = function Point(x, y) {
this.set(x, y);
};
Point.prototype = {
set: function (x, y) {
x = x || 0;
y = y || x || 0;
this._sX = x;
this._sY = y;
this.reset();
},
add: function (point) {
this.x += point.x;
this.y += point.y;
},
multiply: function (point) {
this.x *= point.x;
this.y *= point.y;
},
reset: function () {
this.x = this._sX;
this.y = this._sY;
return this;
},
};
var FRICT = new Point(0.98);//set to 0 if no flying needed
var Particle = function Particle(x, y) {
this.startPos = new Point(x, y);
this.v = new Point();
this.a = new Point();
this.reset();
};
Particle.prototype = {
reset: function () {
this.x = this.startPos.x;
this.y = this.startPos.y;
this.life = Math.round(random() * 300);
this.isActive = true;
this.v.reset();
this.a.reset();
},
tick: function () {
if (!this.isActive) return;
this.physics();
this.checkLife();
this.draw();
return this.isActive;
},
checkLife: function () {
this.life -= 1;
this.isActive = !(this.life < 1);
},
draw: function () {
ctx.fillRect(this.x, this.y, 1, 1);
},
physics: function () {
if (performance.now()<nextTime) return;
this.a.x = (random() - 0.5) * 0.8;
this.a.y = (random() - 0.5) * 0.8;
this.v.add(this.a);
this.v.multiply(FRICT);
this.x += this.v.x;
this.y += this.v.y;
this.x = Math.round(this.x * 10) / 10;
this.y = Math.round(this.y * 10) / 10;
}
};
var nextTime = performance.now()+3000;
createParticles();
function clearCanvas() {
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
(function clearLoop() {
clearCanvas();
requestAnimationFrame(clearLoop);
})();
(function animLoop(time) {
ctx.fillStyle = 'rgba(255,255,255,1)';
var isAlive = true;
for (var i = 0; i < particlesLength; i++) {
if (_particles[i].tick()) isAlive = true;
}
requestAnimationFrame(animLoop);
})();
function resetParticles() {
for (var i = 0; i < particlesLength; i++) {
_particles[i].reset();
}}
I am using a canvas with clickable elements that was added using for loop, I added a resizing event that redrawing the canvas after user window was resized, When the window is loading for the first time the canvas and click listeners works great, My problem starts after the window resizing, I getting wrong click coordinates and bad behavior, It looks the click event have sort of a backlog for all the times that the screen was resized
Here is the full code on stackblitz
The resize function
#HostListener('window:resize', ['$event'])
onResize(event) {
this.innerWidth = window.innerWidth;
this.innerHeight = window.innerHeight;
this.canvas.width = this.innerWidth;
this.canvas.height = this.innerHeight
this.cleardraw()
this.draw()
}
cleardraw(){
var ctx = this.canvas.getContext('2d');
ctx.clearRect(0, 0, this.innerWidth, this.innerHeight);
}
The draw function
draw() {
var ctx = this.canvas.getContext('2d');
ctx.font = "15px Arial";
var seats = []
var tempOrderArrey = []
var orderSeatsClinet = []
var selectedSeatsClient = []
var numberOfSeats = 10
var numberOfRows = 10
var canvasWidth = this.innerWidth
var canvasHight = this.innerHeight
function Seat(x, y, w, h, id, line, seatNum, color) {
this.x = x - 160
this.y = y ;
this.w = w;
this.h = h;
this.id = id;
this.line = line
this.seatNo = seatNum + 1 ;
this.color = color
}
Seat.prototype.draw = function () {
ctx.fillStyle = this.color
ctx.fillRect(this.x, this.y, this.w, this.h)
}
function drawAll() {
for (var i = 0; i < seats.length; i++) {
seats[i].draw();
}
}
var id = 1;
var xPad = canvasWidth / 30
function addSeats(value, ch) {
for (let i = 0; i <= 15; i++)
seats.push(new Seat( (canvasWidth / 3) + (i * xPad), value, canvasWidth/ 37, canvasWidth/ 37, id++, ch, i, "#998515"));
}
var start = 60, diff = canvasWidth/30, ch = 0;
for (let i = 0; i < 2; i++) {
//60 + (40 * i)
addSeats(start + (diff * i), ch++);
}
drawAll()
The click event function
this.renderer.listen(this.canvasRef.nativeElement, 'click', (event) => {
let cX = event.layerX;
let cY = event.layerY;
const offsetLeft = this.canvasRef.nativeElement.offsetLeft;
const offsetTop = this.canvasRef.nativeElement.offsetTop;
this.cX = cX - offsetLeft;
this.cY = cY - offsetTop;
for (var i = 0; i < seats.length; i++) {
var s = seats[i];
if (cX >= s.x && cX < s.x + s.w && cY >= s.y && cY < s.y + s.h) {
if (s.color == '#998515') { // If green
tempOrderArrey.push({ "id": s.id, "seatNum": s.seatNo, "rowNum": s.line })
s.color = '#ff0000'
ctx.fillStyle = '#ff0000'
ctx.fillRect(s.x, s.y, s.w, s.h)
}
else if (s.color == '#ff0000') { // If red
tempOrderArrey = tempOrderArrey.filter(seat => seat.id != s.id);
ctx.fillStyle = '#998515'
s.color = '#998515'
ctx.fillRect(s.x, s.y, s.w, s.h)
}
}
this.tempOrderArrey = tempOrderArrey
}})
}
The reason is that each time you resize, renderer.listen is called again, so for one click there are many events being fired.
You need to make sure that you clear the listener before creating a new one
// Check if the reference exists
if (this.reference != null) {
this.reference; // Clear the listener
}
// Store a reference to the listener
this.reference = this.renderer.listen(this.canvasRef.nativeElement, 'click', (event) => {
Here is a fork of the StackBlitz
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 creating a basic game that draws squares at random positions on a canvas, but sometimes the shape gets cut off because it's outside of the canvas' boundaries. Can any one explain how I could go about getting the square to be drawn on the other side of the canvas (similar to how it's done in asteroids)? The searches I've come up with haven't been helpful. Any help is appreciated.
OK I think I've solved this one. Basically this code only draws the square whilst it is inside the canvas, if it leaves the canvas it checks which boundaries it is leaving and updates the position. The looped variable is needed because otherwise the square will be always leaving the canvas.
var canvas = document.getElementById('bg');
var ctx = canvas.getContext('2d');
var squares = [];
squares[squares.length] = new Square(200, 200, 20, 'red', 0.785398164);
function Square(x, y, size, colour, angle)
{
this.x = x;
this.y = y;
this.size = size;
this.colour = colour;
this.speed = 5;
this.angle = angle;
this.looped = false;
}
Square.prototype.update = function()
{
this.x += (Math.cos(this.angle) * this.speed);
this.y += (Math.sin(this.angle) * this.speed);
if (this.x < canvas.width && this.x + this.size > 0 &&
this.y < canvas.height && this.y + this.size > 0)
{
this.draw();
this.looped = false;
}
else
{
if (this.x > canvas.width && !this.looped)
{
this.x = -this.size;
}
if (this.x + this.size < 0 && !this.looped)
{
this.x = this.size + canvas.width;
}
if (this.y > canvas.height && !this.looped)
{
this.y = -this.size;
}
if (this.y + this.size < 0 && !this.looped)
{
this.y = this.size + canvas.height;
}
this.looped = true;
}
}
Square.prototype.draw = function()
{
ctx.fillStyle = this.colour;
ctx.fillRect(this.x, this.y, this.size, this.size);
}
function gameLoop()
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < squares.length; i++)
{
squares[i].update();
}
requestAnimationFrame(gameLoop);
}
gameLoop();
(function()
{
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x)
{
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element)
{
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function()
{
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id)
{
clearTimeout(id);
};
}());
I'd do a JSFiddle but requestAnimationFrame doesn't play nice with it.