I am having trouble with testing if a rectangle has collided with another rectangle and where the collision is in relation to each object (Left, right, Top, Bottom).
My code works well in theory but there are logical issues, there are false positives when an object enters the left side of another object. The parameters I have set mean that both the top collision and left collision become true when in truth only the left should be true.
image of problem
How can I stop a double positive happening in my code, I only need basic rectangle collision and nothing more. Thank you.
//Col on top?
if (Obj1.getRect(this).bottom - vSpeed < Obj2.getRect(this).bottom &&
Obj1.getRect(this).bottom - vSpeed > Obj2.getRect(this).top)
{
if (Obj1.getRect(this).right + hSpeed > Obj2.getRect(this).left &&
Obj1.getRect(this).left + hSpeed < Obj2.getRect(this).right)
{
Obj1.y = Obj2.y - Obj1.height;
vSpeed = 0;
colTop = true;
}
}
//Col on Bottom?
else if (Obj1.getRect(this).top - vSpeed > Obj2.getRect(this).top &&
Obj1.getRect(this).top - vSpeed < Obj2.getRect(this).bottom)
{
if (Obj1.getRect(this).right + hSpeed > Obj2.getRect(this).left &&
Obj1.getRect(this).left + hSpeed < Obj2.getRect(this).right)
{
Obj1.y = Obj2.y + Obj2.height;
vSpeed = 0;
colBot = true;
}
}
//Col on left side?
if (Obj1.getRect(this).right + hSpeed > Obj2.getRect(this).left &&
Obj1.getRect(this).right + hSpeed < Obj2.getRect(this).right)
{
if (Obj1.getRect(this).bottom - vSpeed > Obj2.getRect(this).top &&
Obj1.getRect(this).top - vSpeed < Obj2.getRect(this).bottom)
{
Obj1.x = Obj2.x - (Obj2.width * 0.5);
hSpeed = 0;
colLeft = true;
}
}
//Col on right side?
else if (Obj1.getRect(this).left + hSpeed > Obj2.getRect(this).left &&
Obj1.getRect(this).left + hSpeed < Obj2.getRect(this).right)
{
if (Obj1.getRect(this).bottom - vSpeed > Obj2.getRect(this).top &&
Obj1.getRect(this).top - vSpeed < Obj2.getRect(this).bottom)
{
Obj1.x = (Obj2.x + Obj2.width) + (Obj1.width * 0.5);
hSpeed = 0;
colRight = true;
}
}
You need to separate top collision from left collision by parsing the objects' relative speed. You cannot parse top/left collision using coordinates only because they are really both true if one rectangle's top left point goes inside another rectangle. So, move your Obj1 and velocity altering code out of your array of if statements, and leave the rest of the code as is. Then you check for velocities like this:
if (colTop)
if (Obj1.getRect(this).bottom > Obj2.getRect(this).top)
colTop=false;
Etc., for other collision vars. This code means: "If the bottom of Obj1 already was under the top of Obj2, then in this frame we are not hitting the top side". So, only the left side collision flag should remain. And only then you check for resultant collision vars and adjust coordinates and velocities
The starling library provides great collision detection, including simple rectangle collision. Are your methods being called on every frame?
All you would need for Starling collision detection
is:
var bounds1:Rectangle = image1.bounds;
var bounds2:Rectangle = image2.bounds;
if (bounds1.intersects(bounds2))
trace("Collision!");
collision detection
Related
I'm trying to develop a simple snake game with libgdx. My problem is that everytime I want to spawn some apples(texture, 20px width X 20px height) it always overlaps the body of the snake.
I'm trying to avoid this but it keeps occuring during the game.
The snake is compiled of parts - every part is a texture of 20px width X 20px height(The screen width is 480px width X 800px height)
Here is what I have tried so far:
public void addApple() {
accomplishedSnake = false;
accomplishedApples = false;
while (!accomplishedSnake && !accomplishedApples) {
xApple = 20 * MathUtils.random(0, 23);
yApple = 20 * MathUtils.random(20, 36);
if (!accomplishedSnake) {
for (int i = 0; i < snake.getSize(); i++) {
if (snake.getPart(i).getX() <= xApple
&& snake.getPart(i).getX() + 20 >= xApple
&& yApple >= snake.getPart(i).getY()
&& yApple <= snake.getPart(i).getY() + 20)
break;
if (i == snake.getSize() - 1) {
accomplishedSnake = true;
break;
}
}
}
if (!accomplishedApples) {
for (int i = 0; i < apples.size; i++) {
if (apples.get(i).getX() <= xApple && apples.get(i).getX()+20 >= xApple
&& yApple >= apples.get(i).getY() && yApple <= apples.get(i).getY()+20)
break;
if (i == apples.size - 1) {
accomplishedApples = true;
break;
}
}
}
}
apples.add(new Apple(xApple, yApple));
}
The code is pretty self-explanatory. In every moment I have 3 different apples on the screen. This code tries to raffle x-y coordinates to the new apple but before the apple is added to the screen and rendered, I want to make sure that it doesn't overlaps the body of the snake or the other apples.
I just can't see what's wrong with this code.
P.S I tried to use the overlaps method in the Rectangle class but it doesn't work.
You test conditions are too simple. Each item snake body part/apple has size, you need to consider their locus. So [snake.X,snake.X+20] and [snake.Y,snake.Y+20] is occupied by each body part, you need to ensure both apple.X and apple.X+20 aren't in range, the same for apple.Y
try this ..
if (snake.getPart(i).getX() >= xApple
&& snake.getPart(i).getX() + 20 <= xApple
&& snake.getPart(i).getX() >= xApple+20
&& snake.getPart(i).getX() + 20 <= xApple+20
&& snake.getPart(i).getY() >= yApple
&& snake.getPart(i).getY() + 20 <= yApple
&& snake.getPart(i).getY() >= yApple +20
&& snake.getPart(i).getY() + 20 <= yApple +20)
break;
also you need to ensure accomplishedApple and accomplishedSnake are set to false both before entering the while loop and after each calculation of random coordinates.
you also need to mimic this logic when establishing accomplishedApple further down your code.
This game should be tile-based.
This means, that the game is organized as a grid, where every cell has the same size.
This is done by using a camera:
OrthographicCamera cam = new OrthographicCamera(viewportWidth, viewportHeight)
The viewportWidth and viewportHeight define how many cells there should be in x and y.
As you are using a resolution of 480*800px and pictures with a size of 20*20px, the viewportWidth should be 480/20=24 and the viewportHeight should be 800/20 = 40.
Note, that the cameras P(0/0) is in the middle of the screen and you see objects from -12 to 12 (x) and -20 to 20 (y). Just set the position of the camera to P(12/20) and the P(0/0) is the lower left corner, as usual.
Now the spawning would be easy:
I use a int[][] world, where i store, if there is a:
Snakepart at P(x,y) (world[x][y] == 1)
Apple at P(x,y) (world[x][y] == 2)
Nothing at P(x,y) (world[x][y] == 0)
This means, that if the snake leaves a tile, you need to set its value to 0 (world[x][y] = 0) and every tile it enters to 1 (world[x][y] = 1)
public void spawnApple() {
boolean spawned = false;
while(!spawned) {
// The lower left corner is always an int-value
int x = (int)MathUtils.random(0, 23);
int y = (int)MathUtils.random(0, 40);
if (world[x][y] == 0) {
// Add Apple at x,y
world[x][y] = 2;
}
}
}
Hope it helps!
private void checkAndPlaceApple() {
if(!appleAvailable) {
do {
appleX = MathUtils.random(Gdx.graphics.getWidth / 20 - 1) * 20;
appleY = MathUtils.random(Gdx.graphics.getHeight / 20 - 1) * 20;
appleAvailable = true;
} while(appleX == snakeX && appleY == snakeY);
}
}
The previous code shows the required rule for placing the apple on the
screen. First, we check whether we need to place an apple, then we randomly pick
a location on the screen, which is a multiple of 20, and we repick it if the picked location contains the snake. As we are working in a 0-indexed environment we need to subtract one (1-20 becomes 0-19 and 1-15 becomes 0-14).
So I have been searching for a way to have a background orbit around a centerpoint. I came across the greensock blitmask that does an amazing job of wrapping the bitmap data to do infinte scrolling effects. However, I can't figure out a way to use this blitmask to rotate the bitmap data and still have the wrapping effect. Below is a link to my SWF.
The image that moves is the one that I wish to wrap and have the infinite scrolling effect. The problem is dealing with repositioning after the image has moved off the screen since it has been rotated.
EDIT: I totally forgot about this issue and decided put it on the backburner for my game since it was taking too long to figure. I recently returned to this concept because I had an idea to make it work. Below is a link to the .SWF that shows what I was trying to accomplish. Though this example works, I dont feel its the best solution.
"WASD" control movement
Orbiting Background
I used some trigonometry to calculate the distance a star is from the player. If that star is beyond that distance, reposition it using it's angle * -1. The code for this is under the link.
var travelVal:Number = 0;
var turnVal:Number = 0;
var currentChild:DisplayObject;
var currentStar:Star;
var childIndex:int = 0;
var angle:Number = 0;
var distance:Number = 0;
if (controller.isKeyDown(Keyboard.A))
{
turnVal += TURN_SPEED;
}
if (controller.isKeyDown(Keyboard.D))
{
turnVal -= TURN_SPEED;
}
if (controller.isKeyDown(Keyboard.W))
{
travelVal += PLAYER_SPEED;
}
if (controller.isKeyDown(Keyboard.S))
{
travelVal -= PLAYER_SPEED
}
for (childIndex = 0; childIndex < numChildren; childIndex++)
{
currentChild = getChildAt(childIndex);
//if (currentChild != player && currentChild != debugOutput && currentChild != blackBkgd)
if(currentChild is Star)
{
currentStar = currentChild as Star;
//move this child based on the travel value
currentChild.y += travelVal * currentStar.speed;
//calculate the orbiting
distance = Math2.distanceBetweenObjects(player, currentChild);
angle = Math.atan2(currentChild.y - player.y, currentChild.x - player.x);
if (distance > STAGE_WIDTH ) angle = angle * -1;
//get orginal angle in radians
//angle = Math.atan2(currentChild.y - player.y , currentChild.x - player.x);
angle = Math2.radiansToDegress(angle);
angle += turnVal;
//currentStar.rotation = angle;
angle = Math2.degreesToRadians(angle);
currentChild.x = player.x + (distance * Math.cos(angle));
currentChild.y = player.y + (distance * Math.sin(angle));
}
}
In order to rotate around a certain centerpoint, you first translate by (-centerpoint.x,-centerpoint.y), then rotate around (0,0) and then translate back by (centerpoint.x,centerpoint.y).
Demo
I am trying to make a "snake" game in html 5 canvas. But i have a problem getting the snake to move the right direction. I would assume that the following code would make the snake move horizontal on 0 and 180 degrees, and vertical on 90 and 270 degrees, this is however not the case. What am i doing wrong here? (Use the left and right arrows to navigate).
function move(direction) {
if(direction == left) {
angel = (angel - 5) % 360;
if(angel < 0) angel += 360;
} else if (direction == right) {
angel = (angel + 5) % 360;
}
x = x + Math.floor(Math.cos(angel*0.0174532925)*5);
y = y + Math.floor(Math.sin(angel*0.0174532925)*5);
$("#infoBar").html("Direction: " + direction + " angel: " + angel);
drawPoint(x,y);
}
The multiplier is of course degrees to radiant. But somehow 270 degrees is not a straight vertical line, as i would assumed that it was. What am i doing wrong?
Javascript file.
Html file.
Because of floating point math.
cos(270 degrees) = 0
Buuuut:
Math.cos((Math.PI/180)*270) is not 0. It is: -1.836909530733566e-16
In other words it is -0.000000000000000183, etc. Very close to zero, but slightly less than zero!
But you're using Math.floor, and Math.floor that number (or Math.floor(-0.1) for that matter) = -1.
You don't want that.
Use Math.round instead of Math.floor.
Here's a live example of it fixed for you: http://jsfiddle.net/UtPJz/3/
I haven't compiled the code segment but you could do somehting like this:
function move(direction) {
switch(direction)
{
case RIGHT:
stepX = 1;
stepY = 0;
break;
case LEFT:
stepX = -1;
stepY = 0;
break;
case UP:
stepX = 0;
stepY = -1;
break;
case DOWN:
stepX = 0;
stepY = 1;
break;
}
x += stepX;
y += stepY;
drawPoint(x,y);
}
I'm working on a space shooter and have this problem:
My space ship fires bullets. The bullets are centered in reference to the ship. Currently all bullets are single shots.
Now what I'd like to have is dual fire for the ship. Basically that means I have to double the shots and place them at the left and right
side of the ship, right? But I don't know how to do it exactly.
The other problem I have is that when I change the x and y-coordinates of the bullet in order to move the bullets from the center of the ship to the left (or right) and rotate the ship and fire I get a strange behavior of the bullets. In this case they move from the left to the center and vice versa referring to the ship (while rotating and firing).
Please - has anyone any idea where the problems might be and how to do it? I appreciate very much any help. TIA!:)
private function autoShoot(step:Number):void {
projectileManager.projectilePoolCount = projectileManager.projectilePool.length - 1;
asteroidManager.asteroidCount = asteroidManager.asteroids.length;
if (projectileManager.lastProjectileShot > projectileOffset && projectileManager.projectilePoolCount > 0 &&
playerStarted && asteroidManager.asteroidCount > 0 && projNumber < projectileNumber)
{
dispatchEvent(new CustomEventSound(CustomEventSound.PLAY_SOUND, Main.SOUND_PLAYER_SHOOT,
false, 0, 8, 1));
tempProjectile = projectileManager.projectilePool.pop();
tempProjectile.projectileDelayCount = 0;
var projectileRadians:Number = (player.frame / 360) * 6.28;
projShots++;
projNumber++;
if (projNumber >= projectileNumber)
{
player.startDelay = true;
}
tempProjectile.x = (player.point.x) + Math.cos(projectileRadians);
tempProjectile.y = (player.point.y) + Math.sin(projectileRadians);
tempProjectile.x = player.x + 13;
tempProjectile.y = player.y + 13;
tempProjectile.nextX = tempProjectile.x;
tempProjectile.nextY = tempProjectile.y;
tempProjectile.dx = rotationVectorList[player.frame].x;
tempProjectile.dy = rotationVectorList[player.frame].y;
tempProjectile.speed = projectileSpeed;
tempProjectile.frame = 0;
tempProjectile.bitmapData = tempProjectile.animationList[0];
tempProjectile.projectileDelay = 10;
projectileManager.projectiles.push(tempProjectile);
projectileManager.lastProjectileShot = 0;
} else {
projectileManager.lastProjectileShot += step;
}
}
The autoShoot function only fires one projectile each time it is called. There is only one tempProjectile per call to push to the projectiles list.
So one fix can be to add a tempProjectile2 (in the same place tempProjectile is defined) as a variable that can be used. Now in each call the projectile pool gets depleted by two, as long an adequate number of projectiles are popped
tempProjectile = projectileManager.projectilePool.pop();
tempProjectile2 = projectileManager.projectilePool.pop();
then adjust the offset accordingly
tempProjectile.x
tempProjectile.y
tempProjectile2.x
tempProjectile2.y
And so on with the rest of the code. The only thing I am unclear about is why tempProjectile.x and y are assigned twice.
tempProjectile.x = (player.point.x) + Math.cos(projectileRadians);
tempProjectile.y = (player.point.y) + Math.sin(projectileRadians);
tempProjectile.x = player.x + 13;
tempProjectile.y = player.y + 13;
only the second pair will be used, I think.
Hopefully the rest of the functions should not change because at the end the projectiles are pushed to the projectiles list
projectileManager.projectiles.push(tempProjectile);
projectileManager.projectiles.push(tempProjectile2);
So the whatever function used to update and render should remain the same, assuming tempProjectile is not tied down elsewhere in the program.
I'm trying to scroll a series of thumbnails horizontally based on the mouseX position. I can get it to scroll but it's very choppy and for some reason it's not reading my start and end numbers so it will stop scrolling. Can anyone point me in the right direction? Thanks.
var thumbBounds:Object = new Object();
thumbBounds = thumbContainer.getBounds(this);
thumbContainer.addEventListener(MouseEvent.MOUSE_OVER, setScrolling);
private function setScrolling(me:MouseEvent):void
{
thumbContainer.removeEventListener(MouseEvent.MOUSE_OVER, setScrolling);
stage.addEventListener(Event.ENTER_FRAME, scrollThumbs);
}
private function scrollThumbs(e:Event):void
{
if(mouseX <= thumbBounds.x || mouseX > thumbBounds.width ||
mouseX < thumbBounds.y || mouseX > thumbBounds.height)
{
thumbContainer.addEventListener(MouseEvent.MOUSE_OVER, setScrolling);
stage.removeEventListener(Event.ENTER_FRAME, scrollThumbs);
}
if(thumbContainer.x >= 0)
{
thumbContainer.x = 0;
}
if(thumbContainer.x <= -842)
{
thumbContainer.x = -842;
}
var xdist:Number = new Number();
xdist = mouseX - 382;
thumbContainer.x += Math.round(-xdist / 10);
}
One error I see immediately is:
if(mouseX <= thumbBounds.x || mouseX > thumbBounds.width ||
mouseX < thumbBounds.y || mouseX > thumbBounds.height)
Shouldn't you be checking the mouseY agains the thumbBounds.y and thumbBounds.height?
As for the choppyness, that could be related to the framerate of the movie, the size and the number of the images. It also depends on the magnitude of your xdist value. I'd try and use interpolation (tweening) some how. Calculate the end destination of the container and animate it towards there using Tweener or TweenLite.
e.g.
TweenLite.to(thumbContainer.x, 0.5, { x: thumbContainer.x + Math.round(-xdist / 10) });
This will cause the movement between the thumbcontainer current position and the new position will happen smoothly over half a second (instead of immediately).