I am doing a small game based on this tutorial http://code.tutsplus.com/tutorials/learn-createjs-by-building-an-html5-pong-game--active-11845
I made my changes but this line is buggy
if(ball.x <= player.x + 22 && ball.x > player.x && ball.y >= player.y && ball.y < player.y + 75)
whenever the user hit it fast from the left or the right the ball keep bouncing even in the tutorial, the bug is there, can anybody help me with this ?
Thanks
I think the easiest solution would be to add a direction variable to the ball and test it. If it's towards the player do the check you've coded, else ignore. If the check passes, change the direction when the player intercepts it. Then when it bounces back, change the direction again. This will also simplify your code a lot and reduce the number of checks going on.
I have found right solution for your problum
you should add one more condition that is xSpeed<0 so that your if statement changes to as shown bellow
if(xSpeed<0 && ball.x <= player.x + 22 && ball.x > player.x && ball.y >= player.y && ball.y < player.y + 75 )
{
xSpeed *= -1;
SoundJS.play('hit');
}
I have given you this solution after testing the code.
I think this is because ball goes in too far for some reason and it does multiple *= -1; run.
so you should measure distance and bring it back and then *= -1
code would be like this:
if(ball.x <= player.x + 22 && ball.x > player.x && ball.y >= player.y && ball.y < player.y + 75)
{
ball.x += ball.x-player.x;
xSpeed *= -1;
SoundJS.play('hit');
}
so then we can make sure ball is out whenever it is inside bar.
** edited code from the link you posted.
There are two main methods of detecting collisions in 2D:
Pixel by pixel. You should use this method only if you have complex shapes, because this algorithm has O(Height*Width) complexity where Height and Width are sizes of smaller sprite in pixels.
By formulas. You should always use this method when possible. This will usually result in O(1) complexity.
In your case ball is circle(obviously) and player is rectangle, I think.
Answer to question "How to check by formulas if rectangle and circle intersect?" was answered here.
Umm If the problem is that the "too fast" ball will go inside paddles, you have three options:
make collision tests with mathematics ie. calculate if the ball will draw a line through the paddle during the current timestep.
make the timestep smaller , ie move the ball in smaller increments and collision check each step.
make the timestep adaptable , so it gets smaller when stuff gets faster and the ball will move approximately the same amount per timestep, regardless of it's speed.
Related
I am currently developing a kind of 2d game from a certain perspective (camera) and making it look like a 3d game.
The perspective never changes (turns).
Whatever. I have now reached the point of coding the hitboxes and the player is already able to recognize Colissions with other objects (Entitys).
Now I want to keep the player from running into other entities (hitboxes). My idea was to perform a colission detection as described below and then calculate the intersection so that I know on which side of the hitbox the player and the entity collide. Finally, I set the x or y speed of the player to 0, depending on where the overlap occurs.
I don't really know how to detect the Overlapping Axis / Axes, all I've found so far is that there is a Colission.
Colission:
function getColission(a, b) {
return (a.x <= b.x+b.sizeX && a.x+a.sizeX >= b.x) &&
(a.y <= b.y+b.sizeY && a.y+a.sizeY >= b.y) &&
(a.z <= b.z+b.sizeX && a.z+a.sizeZ >= b.z);
}
Currently I am working on a 2D particle simulator. I have each particle moving on a unique angle. I found a basic formula to change x and y velocity, but I currently have a set velocity that moves according to the angle.
particles[a][3] += particles[a][1] * cos(radians(particles[a][5]));//move X
particles[a][4] += particles[a][1] * sin(radians(particles[a][5]));//move Y
I have a basic collision for collisions on walls, but can't find the best way to sort the collisions out. Currently I just multiply the rotation by -1, but that only works on the top and bottom. Note: The particle will always move after running the collision (its not getting stuck in the collision boxes and bugging out).
if(particles[a][3] < 0 || particles[a][3] > windowWidth/2 || particles[a][4] < 0 || particles[a][4] > windowHeight/2) {
/*windowWidth and windowHeight are divided by 2 to find the canvas size. In the setup() I have the canvas set to that value).*/
particles[a][5] *= -1;
}
Array values:
particles[a][1] = speed
particles[a][3] = x position
particles[a][4] = y position
particles[a][5] = rotation
My question is what is the best way to run these collision tests. I understand that collisions bounce at 90 degrees, but I'd like to use as few if statements as possible (simpler the better) instead of a tedious bunch.
Merry Christmas, and thanks in advance!
Figured it out!
Final code:
if(particles[a][4] < 0 || particles[a][4] > windowHeight/2) {
particles[a][5] *= -1;
} else if(particles[a][3] < 0 || particles[a][3] > windowWidth/2) {
particles[a][5] = 180 - particles[a][5];
}
Try googling "javascript reflect angle" and you'll find formulas for reflecting around both the X and Y axis. You do one when you collide with the top or bottom, and you do the other when you collide with the left or right.
Also, you probably shouldn't be using an array to hold your data. Create a class that holds your values, and then create instances of that class. Using magic array indexes is a recipe for headaches.
If you still can't get it working, then please post an MCVE and we'll go from there. Good luck.
I'm working on an HTML5-canvas game, where the map is randomly generated 10px by 10px tiles which the player can then dig and build upon. The tiles are stored in an array of objects and a small map contains about 23000 tiles. My collision detection function checks the players position against all non-air tiles every run through (using requestAnimationFrame()), and it works perfectly but I feel like it's CPU intensive. Collision function is as follows (code came from an online tutorial):
function colCheck(shapeA, shapeB) {
var vX = (shapeA.x + (shapeA.width / 2)) - (shapeB.x + (shapeB.width / 2)),
vY = (shapeA.y + (shapeA.height / 2)) - (shapeB.y + (shapeB.height / 2)),
hWidths = (shapeA.width / 2) + (shapeB.width / 2),
hHeights = (shapeA.height / 2) + (shapeB.height / 2),
colDir = null;
// if the x and y vector are less than the half width or half height, they we must be inside the object, causing a collision
if (Math.abs(vX) < hWidths && Math.abs(vY) < hHeights) {
// figures out on which side we are colliding (top, bottom, left, or right)
var oX = hWidths - Math.abs(vX),
oY = hHeights - Math.abs(vY);
if (oX >= oY) {
if (vY > 0) {
colDir = "t";
shapeA.y += oY;
} else {
colDir = "b";
shapeA.y -= oY;
}
} else {
if (vX > 0) {
colDir = "l";
shapeA.x += oX;
} else {
colDir = "r";
shapeA.x -= oX;
}
}
}
return colDir;
};
Then within my update function I run this function with the player and tiles as arguments:
for (var i = 0; i < tiles.length; i++) {
//the tiles tag attribute determines rendering colour and how the player can interact with it ie. dirt, rock, etc.
//anything except "none" is solid and therefore needs collision
if (tiles[i].tag !== "none") {
dir = colCheck(player, tiles[i]);
if (dir === "l"){
player.velX = 0;
player.jumping = false;
} else if (dir === "r") {
player.velX = 0;
player.jumping = false;
} else if (dir === "b") {
player.grounded = true;
player.jumping = false;
} else if (dir === "t") {
player.velY *= -0.3;
}
}
};
So what I'm wondering is if I only check tiles within a certain distance from the player using a condition like Math.abs(tiles[i].x - player.x) < 100 and the same for y, should that make the code more efficient because it will be checking collision against fewer tiles or or is it less efficient to be checking extra parameters?
And if that's difficult to saying without testing, how do I go about finding how well my code is running?
but I feel like it's CPU intensive
CPU's are intended to do a lot of stuff very fast. There is math to determine the efficiency of your algorithm, and it appears that your current implementation is O(n). If you reduce the number of tiles to a constant number, you would achieve O(1), which is better, but may not be noticeable for your application. To achieve O(1), you would have to keep an index of the X closest tiles and incrementally update the index when closest tiles change. I.e. if the player moves to the right, you would modify the index so that the left most column of tiles are removed and you get a new column of tiles on the right. When checking for collisions, you would simply iterate through the fixed number of tiles in the index instead of the entire set of tiles.
...should that make the code more efficient because it will be checking collision against fewer tiles or or is it less efficient to be checking extra parameters?
The best way to answer that is with a profiler, but I expect it would improve performance especially on larger maps. This would be an O(n) solution because you still iterate over the entire tile set, and you can imagine as your tile set approaches infinity, performance would start to degrade again. Your proposed solution may be a good compromise between the O(1) solution I suggested above.
The thing you don't want to do is prematurely optimize code. It's best to optimize when you're actually experiencing performance problems, and you should do so systematically so that you get the most bang for your buck. In other words even if you did have performance problems, the collision detection may not be the source.
how do I go about finding how well my code is running?
The best way to go about optimizing code is to attach a profiler and measure which parts of your code are the most CPU intensive. When you figure out what part of your code is too slow, either figure out a solution yourself, or head over to https://codereview.stackexchange.com/ and ask a very specific about how to improve the section of code that isn't performing well and include your profiler information and the associated section of code.
In response to Samuel's answer suggesting I use a profiler:
With a map made up of ~23 000 tiles in an array:
The original collision code was running 48% time. By changing if (tiles[i].tag !== "none") to the following the amount of time spent checking for collisions dropped to 5%.
if (tiles[i].tag !== "none"
&& Math.abs(tiles[i].x - player.x) < 200
&& Math.abs(tiles[i].y - player.y) < 200)
With a map made up of ~180 000 tiles:
The original collision code was running 60-65% of the time and performance of the game is so low it can't be played. With the updated code the collision function is only running 0.5% of the time but performance is still low, so I would assume that even though less tiles are being checked for collision there are so many tiles that checking their position relative to the player is causing the game to run slowly.
I have searched all over for a solution to my problem on smooth rotation. I can get it 99% working however there is one small issue that keeps messing with me. The rotations works fine except when the target makes a drastic change. The basic idea is I have a ball and a player when the player comes in contact with the ball he changes the balls direction and speed. The player follows the ball correctly however when he comes in contact with the ball or the ball's location is reset thus making the delta between the angles greater than 45 degrees the player instantly jumps to fact the ball. Here is the code that I have partly working. Thank you for any help in advance.
var newFacing = Math.atan2(theBall.y-player.y,theBall.x-player.x);
var diff = (Math.abs(newFacing) - Math.abs(player.facing));
if (diff < Math.PI*0.1 && diff > -Math.PI*0.1){
player.facing = newFacing;
}else if (diff > Math.PI) {
player.facing -= Math.PI*0.1;
} else {
player.facing += Math.PI*0.1;
}
if (player.facing > Math.PI) {
player.facing -= Math.PI*2;
} else if (player.facing < -Math.PI) {
player.facing += Math.PI*2;
}
Updated: Changed the || to && and added a condition to ensure I do not go above or below PI radians. There are still some odd rotational issues at some angles. For example if the ball passes below the player he will rotate clockwise to follow rather than the logical counter clockwise. At times the player will do a full 360 before tracking the ball again. Without tracing it I am not sure what conditions are causing this.
I have an array of objects that are all 'rectangles'. I also have a circle that is the object. The equation I use for gravity is:
newYPos = oldYPos + prevFallingSpeed + gravity
Basically, I am adding the rate of gravity to the number of pixels the circle 'fell' in the previous frame and then adding that to the position of the circle in the last frame.
I am detecting if any part of the ball is inside of any of the objects using this code:
for(var i = 0; i < objects.length; i++){
if(ball.x > objects[i].x - ball.r && ball.y > objects[i].y - ball.r && ball.x < ball.r + objects[i].x + objects[i].w && ball.y < ball.r + objects[i].y + objects[i].h){
alert('test');
gSy = (-1 * gSy);
}
}
The code checks if the circle's coordinates plus or minus the radius is greater than the top/left positions of the walls of the box and less than the right/bottom positions of the walls of the box.
The ball is inside the object at one point, but I never get an alert. I've tried everything I can think of. Hopefully I'm just making some dumb mistake I can't see...
Here is a jsfiddle if you are up for messing with my code or don't understand the variables:
http://jsfiddle.net/JGKx5/
The small problem:
You have four objects.
Two of them (numbers 1 and 3) are tall and thin, and off to the left or right. The ball never goes near them.
One of them (number 2) is short and wide, and at y-coordinates smaller than the ball ever attains.
The other one (number 0) is short and wide, and its y-coordinates are ones that a real physical ball would pass through -- but because your ball moves in discrete steps your script never actually sees it do so. (It goes from y=580.4 to y=601.2.)
The big problem:
In the jsfiddle, all your comparisons in the collision test appear to be exactly the wrong way around :-). (Which is odd since the ones in the code here are the right way around.)
With both of these changed (I made the ball move by 0.1*gSy instead of by gSy, and flipped all the comparison operators), collisions are detected.