Is there a way to detect collision with an object created using a while loop?
I'm repeating an image across the screen using a while loop:
this.spikeX = 0;
while (this.spikeX < this.world._width) {
this.spike = this.add.sprite(this.spikeX, 0, 'spikes');
this.physics.arcade.enable(this.spike);
this.gameObjects.push(this.spike);
this.spikeX += (this.spike.width * 0.75);
}
I have a collision function:
collision: function(obj1, obj2) {
if (obj1.body.x < obj2.body.x + obj2.body.width &&
obj1.body.x + obj1.body.width > obj2.body.x &&
obj1.body.y < obj2.body.y + obj2.body.height &&
obj1.body.height + obj1.body.y > obj2.body.y) {
return true;
}
},
if(this.collision(this.player, this.spike)) {
console.log('spike');
}
When I call this function in the update function it doesn't detect collision but works when I just create a single spike outside the while loop.
That's probably because you have only one this.spike.
If you have multiple sprites, you need to put them into a group, and create them like this:
spike_group = game.add.group();
spike = spikes.create(spikeX, 0, 'spikes');
Then you check collision for each spike inside spike_group and a player.
And, why don't you use arcade collision like this:
// inside update function
physics.arcade.collide(player, spike_group , overlap_spikes, this);
// out of update function
function overlap_spikes()
{
console.log("touch spike");
}
Note: These examples does not use 'this' keyword.
Related
Full code here
I am trying to setup the functions to detect collisions and for now just log to the console. This is the section for checkCollision function;
Player.prototype.update = function(dt) {
checkCollision(this.leftLimit, this.rightLimit);
this.leftLimit = this.x - 40.5;
this.rightLimit = this.x + 40.5;
}
function checkCollision(playerl,playerr) {
for (var i = 0; i < 5; i++) {
var thisEnemy = allEnemies[i];
if (thisEnemy.leftlimit > playerl && thisEnemy.rightLimit < playerr) {console.log("1")}
else {console.log('else')}
}
}
Question
The character is never registering as colliding with the enemy, why is this not working?
Testing/Debugging
I know this function is working as consoles logging else, I've also put logging in other locations and when in the Enemy.prototype.update function, console was showing values like 202.000000093, since the for..else function is using < or >, not absolute values, that should be fine, but still nothing is matching inside the player left and right limits. I also tried changing the Enemy limits to be smaller, +/- 40.5, incase the enemy was too wide to fit inside the player limits.
player.leftLimit and player.rightLimit are undefined when checkCollision method is first running
I added a better if statement to check if there's a collision;
if (
thisEnemy.leftLimit < player.rightLimit &&
thisEnemy.rightLimit > player.leftLimit &&
thisEnemy.upperLimit > player.lowerLimit &&
thisEnemy.lowerLimit < player.upperLimit) {
console.log("collision");
}
I'm working on an action game using the Phaser framework, and I want the player to be able to touch certain switch tiles to turn other enemies off and back on. So it should work like this:
The player overlaps a special switch tile
Execute the switch action, only once
Ignore further overlapping until player moved off of the tile
When player moves off a switch tile, only then should it start checking for overlap again
Repeat from step 1 when player overlaps again (or another switch tile)
I'm using arcade physics and the overlap function is working. But the problem is that the overlap keeps firing over and over again, like every single frame. What would be the best way in Phaser to get the desired result?
See screenshot below of what I mean, and I've created a sandox of my code example here:
https://phaser.io/sandbox/edit/zEVOQfgA
Your code is not working because you are resetting okoverlap to 0 on each update. What you need to do is to set the okoverlap to a state and change that state at suitable time.
I've fixed your code by saving the property in game object in create.
game.flags = {};
game.flags.okoverlap = 0;
Then in update function I've checked that property and current overlap status.
function update() {
if(game.flags.okoverlap === 1 && !checkOverlap(mushroom, theswitch)) {
game.flags.okoverlap = 0;
}
game.physics.arcade.overlap(mushroom, theswitch, handleCollide, null, this);
}
function checkOverlap(spriteA, spriteB) {
var boundsA = spriteA.getBounds();
var boundsB = spriteB.getBounds();
return Phaser.Rectangle.intersects(boundsA, boundsB);
}
The logic inside handleCollide function is changed to
if (game.flags.okoverlap != 1) {
game.flags.okoverlap = 1;
doSwitch();
}
Finally replace okoverlap in render with game.flags.okoverlap to prevent ReferenceError
game.debug.text('overlap: ' + (game.flags.okoverlap == 1 ? 'YES': (game.flags.okoverlap == -1 ? 'partial': 'no')), 20, 40);
Working sample here - https://phaser.io/sandbox/edit/ikJBIznv
I've been playing around some more and found a solution, using 2 global variables. One variable frameoverlap to check if there is an overlap, and one variable doswitch to see if the switch action was already done. Then you can handle it all in the update() function.
function update() {
// assume no overlap
frameoverlap = 0;
// do arcade.overlap
game.physics.arcade.overlap(mushroom, theswitch, handleCollide, null, this);
// check flags after arcade.overlap
if (frameoverlap == 1) {
if (doswitch == 0) {
doswitch = 1; // remember the switch was done
doSwitch();
}
} else {
if (doswitch == 1) {
doswitch = 0; // stepping off the switch tile
}
}
}
See updated code here
https://phaser.io/sandbox/edit/VTenTwgh
firstly
I am not beginner at game development at all - but beginner in web game development specially
I started with Phaser as it looks good and optimized for mobile games
anyway ..
I have a strange behavior with my game - I put a rectangle and trying to move it (when I debugged the X axis already changes correctly , but I can't see the rectangle move!!)
my codes
var game = new Phaser.Game(window.innerWidth,window.innerHeight,Phaser.AUTO);
var colors = ["#FF0000" , "#00FF00" , "#0000FF" , "#FFFF00" , "#00FFFF" , "#FFFF00"];
var lst;
var hlprs = [];
var gameState = {
preload: function () {
this.game.stage.backgroundColor = "#FFFFFF";
},
create: function () {
for (var i = 0 ; i < 8 ; i++)
{
hlprs[i] = new Phaser.Rectangle((i*200),0,100,20);
hlprs[2*i + 1] = new Phaser.Rectangle((i*200),window.innerHeight - 20,100,20);
game.debug.geom(hlprs[i] , colors[Math.floor((Math.random() * 6))]);
game.debug.geom(hlprs[2*i + 1] , colors[Math.floor((Math.random() * 6))]);
}
},
update: function ()
{
moving();// it calls moving function and X axis is changes but (the rectangle does not move !!!)
}
};
function moving()
{
for (var i = 0 ; i < 8 ; i++)
{
hlprs[i].offset(-1,0);
hlprs[2*i + 1].offset(-1,0);
}
}
game.state.add('GameState' , gameState);
game.state.start('GameState');
Without testing it, I'd guess that what happens is the following: you create a bunch of shapes and do a single call to game.debug.geom() for each of the shapes. In the meantime the shapes do start moving, but since you never call game.debug.geom() again, you never see anything moving.
If you intend to use methods from game.debug, they should usually go inside the render() method of your state (which will be called once for every frame).
Note that the debug methods are to be used, well, for debugging. The proper way of displaying a shape is by making a sprite or an image (in which case you won't have to update anything manually since Phaser will handle it).
Since the update() function calls moving() you might want to have your game.debug commands within moving
function moving()
{
for (var i = 0 ; i < 8 ; i++)
{
hlprs[i].offset(-1,0);
hlprs[2*i + 1].offset(-1,0);
// update here
game.debug.geom(hlprs[i] , colors[Math.floor((Math.random() * 6))]);
game.debug.geom(hlprs[2*i + 1] , colors[Math.floor((Math.random() * 6))]);
}
}
Here's a demo: https://jsfiddle.net/user2314737/J5fUE/253/
Together with a friend of mine we are creating a multiplayer snake game. We are both beginners with JavaScript, so it is a real challenge for us.
So far I've managed to create this:
http://jsfiddle.net/tbmluijten/RG76t/3/
This is the collision detection code I have so far:
Snake.prototype.collision = function (x, y, array) {
for(var i = 0; i < Snake.length; i++){
if(Snake.pieces[0].x == x && Snake.pieces[0].y == y)
return true;
}
return false;
};
The problem I have is the collision with the snake itself. I can't figure out what I am doing wrong. Note that I am looking for collision with the snake itself not with the borders since we are going to put a loop into that. :-)
The short answer is - you are not checking for collision at all!
The working collision: http://jsfiddle.net/RG76t/10/
Explanation:
At first you need to put the collision method in the game loop function.
// line 32
if (game.snakes.length !== 0) {
for (i = 0; i < game.snakes.length; i++) {
var s = game.snakes[i];
s.paint(ctx, game);
// Check for collision.
if (s.collision()) {
// Do something, if the collision happens.
alert('collision');
}
}
}
Then in the collision method check if the first piece collides with any other. The loop starts from the 4th piece, since the snake's head can't really touch it's "neck" (2nd and 3rd pieces).
Snake.prototype.collision = function () {
// Loop the snake pieces from the 4th one.
for(var i = 3; i < this.length; i++){
// Check if this piece collides with the first piece.
if(
this.pieces[0].x === this.pieces[i].x &&
this.pieces[0].y === this.pieces[i].y
) {
return true; // collision
}
}
return false;
};
Also notice that Snake.length and Snake.pieces[i] are changed to this.length and this.pieces[i]. The keyword this refers to the instance of a Snake on which you invoke the collision method. When you were using Snake in this piece of code, you were checking the properties of a constructor.
I have an array which is part of a small JS game I am working on I need to check (as often as reasonable) that each of the elements in the array haven't left the "stage" or "playground", so I can remove them and save the script load
I have coded the below and was wondering if anyone knew a faster/more efficient way to calculate this. This is run every 50ms (it deals with the movement).
Where bots[i][1] is movement in X and bots[i][2] is movement in Y (mutually exclusive).
for (var i in bots) {
var left = parseInt($("#" + i).css("left"));
var top = parseInt($("#" + i).css("top"));
var nextleft = left + bots[i][1];
var nexttop = top + bots[i][2];
if(bots[i][1]>0&&nextleft>=PLAYGROUND_WIDTH) { remove_bot(i); }
else if(bots[i][1]<0&&nextleft<=-GRID_SIZE) { remove_bot(i); }
else if(bots[i][2]>0&&nexttop>=PLAYGROUND_HEIGHT) { remove_bot(i); }
else if(bots[i][2]<0&&nexttop<=-GRID_SIZE) { remove_bot(i); }
else {
//alert(nextleft + ":" + nexttop);
$("#" + i).css("left", ""+(nextleft)+"px");
$("#" + i).css("top", ""+(nexttop)+"px");
}
}
On a similar note the remove_bot(i); function is as below, is this correct (I can't splice as it changes all the ID's of the elements in the array.
function remove_bot(i) {
$("#" + i).remove();
bots[i] = false;
}
Many thanks for any advice given!
Cache $("#" + i) in a variable; each time you do this, a new jQuery object is being created.
var self = $('#' + i);
var left = parseInt(self.css("left"));
var top = parseInt(self.css("top"));
Cache bots[i] in a variable:
var current = bots[i];
var nextleft = left + current[1];
var nexttop = top + current[2];
Store (cache) the jQuery object of the DOM element within the bot representation. At the moment it's been created every 50ms.
What I mean by this is that for every iteration of the loop, you're doing $('#' + i). Every time you call this, jQuery is building a jQuery object of the DOM element. This is far from trivial compared to other aspects of JS. DOM traversal/ manipulation is by far the slowest area of JavaScript.
As the result of $('#' + i) never changes for each bot, why not store the result within the bot? This way $('#' + i) gets executed once, instead of every 50ms.
In my example below, I've stored this reference in the element attribute of my Bot objects, but you can add it your bot (i.e in bots[i][3])
Store (cache) the position of the DOM element representing the bot within the bot representation, so the CSS position doesn't have to be calculated all the time.
On a side note, for (.. in ..) should be strictly used for iterating over objects, not arrays. Arrays should be iterated over using for (..;..;..)
Variables are extremely cheap in JavaScript; abuse them.
Here's an implementation I'd choose, which incorporates the suggestions I've made:
function Bot (x, y, movementX, movementY, playground) {
this.x = x;
this.y = y;
this.element = $('<div class="bot"/>').appendTo(playground);
this.movementX = movementX;
this.movementY = movementY;
};
Bot.prototype.update = function () {
this.x += this.movementX,
this.y += this.movementY;
if (this.movementX > 0 && this.x >= PLAYGROUP_WIDTH ||
this.movementX < 0 && this.x <= -GRID_SIZE ||
this.movementY > 0 && this.y >= PLAYGROUND_HEIGHT ||
this.movementY < 0 && this.y <= -GRIDSIZE) {
this.remove();
} else {
this.element.css({
left: this.x,
right: this.y
});
};
};
Bot.prototype.remove = function () {
this.element.remove();
// other stuff?
};
var playground = $('#playground');
var bots = [new Bot(0, 0, 1, 1, playground), new Bot(0, 0, 5, -5, playground), new Bot(10, 10, 10, -10, playground)];
setInterval(function () {
var i = bots.length;
while (i--) {
bots[i].update();
};
}, 50);
You're using parseInt. As far as I know, a bitwise OR 0 is faster than parseInt. So you could write
var left = $("#" + i).css("left") | 0;
instead.
Furthermore, I wouldn't make use of jQuery functions to obtain values like these every 50 ms, as there's always a bit more overhead when using those (the $ function has to parse its arguments, etc.). Just use native JavaScript functions to optimize these lines. Moreover, with your code, the element with id i has to be retrieved several times. Store those elements in a variable:
var item = document.getElementById(i);
var iStyle = item.style;
var left = iStyle.left;
…
(Please note that I'm not a jQuery expert, so I'm not 100% sure this does the same.)
Moreover, decrementing while loops are faster than for loops (reference). If there's no problem with looping through the elements in reverse order, you could rewrite your code to
var i = bots.length;
while (i--) {
…
}
Use offset() or position() depending on if you need coordinates relative to the document or the parent. position() is most likely faster since browsers are efficient at finding offsets relative to the parent. There's no need for parsing the CSS. You also don't need the left and top variables since you only use them once. It may not be as readable but you're going for efficiency:
var left = $("#" + i).position().left + bots[i][1];
var top = $("#" + i).position().top + bots[i][2];
Take a look here for a great comparison of different looping techniques in javascript.
Using for...in has poor performance and isn't recommended on arrays. An alternative to looping backwards and still using a for loop is to cache the length so you don't look it up with each iteration. Something like this:
for(var i, len = bots.length; i < len; i++) { ... }
But there are MANY different ways, as shown in the link above and you might want to test several with your actual application to see what works best in your case.