I'm trying to implement Collision detection using Rectangles for my game but can't seem to get it to work.
Bullets are updated when pressing space every frame so they move across the screen. Apparently so I've been told on here, the collisionbox moves with it as well. I'm getting this by using sprite.getBoundingBox() which sets a datafield Rectangle to this value for each instance.
I have two Arraylists, one holding instances of Monsters and one holding instances of Bullets. They all have collisionRectangles associated with them.
I'm calling the checkCollisions() method from my main render loop every frame as long as there's something in the bullets or monsters arraylist.
/*this handles collisions between bullets and enemies*/
public static void checkCollisions(){
for (int i = 0; i < Main.currentBullets.size(); i++){
for (int k = 0; k < Main.currentMonsters.size(); k++){
if (Intersector.overlaps(Main.currentBullets.get(i).collisionBoxBullet,
Main.currentMonsters.get(k).collisionBoxMonster)){
System.out.println("Boom headshot");
}
}
}
Shouldn't this do Boom Headshot every time it overlaps? Instead it always seems to keep evaluating to true.
Why does it keep evaluating to true and writing boom headshot?
What I didn't do is set the position of the rectangle of the sprite which was at 0.0. I also then didn't move the collision box properly with collisionBox.setPosition().
It initially checking to see if sprite at 0/0 is colliding with collision box at 0.0 which is always true, hence always saying it's overlapping.
Related
I have a GUI Maze game that I am creating and I am having trouble implementing walls that prevent the player from moving. The walls are rectangles but the player is a circle so I had to create a collision detection method between a rectangle and a circle. The problem I am having is that my collidesWith() method is in the player class and it takes a single wall as a parameter and returns a string that tells you which side of the wall is the player intersecting with. This means I can only check if the player is colliding with one wall at a time. Here is the code for the collidesWith() method. x and y are the x and y coordinates of the player since this method is in the player class:
I should mention that the code above doesn't exactly work how I wanted it to since it only works when the player is coming from the sides. If the player is coming from the top or bottom, the player just goes through the wall.
The reason I need this method to return a string to tell me where the player is coming from is so that I can explicitly restrict the movement of the player when the up, down, left, right keys are pressed. This is in another class where all the GUI components are. Here is the code for that. I have created a wall object on top so that it can be passed as a parameter here when checking for intersection:
In my view, it is better to avoid to iterate through the whole array of wallsArraylist. If I understood correctly, it is necessary to explore neighbour cells, if yes, then you can explore neighbours in a two-dimensional array using this approach:
(pseudo-code)
row_limit = count(array);
if(row_limit > 0){
column_limit = count(array[0]);
for(x = max(0, i-1); x <= min(i+1, row_limit); x++){
for(y = max(0, j-1); y <= min(j+1, column_limit); y++){
if(x != i || y != j){
print array[x][y];
}
}
}
}
In addition, try to avoid magic strings. Replace "comingFromRight" and etc to constant string:
public static final String COMING_FROM_RIGHT = "comingFromRight";
I am making a simple game with JavaFX, where a ball bounces around the screen after being released from the bottom (via a button). When the ball is bouncing around the pane, if it hits a Rectangle it changes its color to blue.
I am attempting to add a method called checkBounds to keep track of when the ball (a Circle) hits the Rectangle. As soon as the ball comes into contact with the rectangle, the score should increase by 10. The scoring mechanism works, but it continues to increment with each frame that the ball takes through the Rectangle, instead of only incrementing once when it enters. (eg. It should only go up by 10 one time, not continue going up by 10 the whole time the ball passes through). I callcheckBounds() 3 times in my timeline loop to check each rectangle on each loop iteration.
checkBounds(ball, gameSquare);
checkBounds(ball, gameSquare2);
checkBounds(ball, gameSquare3);
How would I fix this logic error? I've attempted several different options, but none seem to work.
private void checkBounds(Shape block, Rectangle rect) {
boolean collisionDetected = false;
Shape intersect = Shape.intersect(block, rect);
if (intersect.getBoundsInLocal().getWidth() != -1) {
collisionDetected = true;
}
if (collisionDetected) {
score.setText(Integer.toString(currentScore.getCurrentValue()));
currentScore.incrementBy(10);
rect.setFill(Color.BLUE);
}
}
I believe what you want to detect is the state change of your collisionDetected from false to true. One way to do this is to keep the state of the previous value as a member variable for each collision object. To do this, we need some identifying id for the rectangle, so you may want to pass in the id into the checkBounds method:
private void checkBounds(Shape block, Rectangle rect, int id) {
we also need to create a member variable to store the states:
private HashMap<Integer,Boolean> previousCollisionStateMap = new HashMap<>();
and then inside your checkBounds code, you can modify the condition to check for changes
Boolean prevState = previousCollisionStateMap.get(id);
if (prevState == null) { // this is just to initialize value
prevState = false;
previousCollisionStateMap.put(id,false);
}
if (!prevState && collisionDetected) {
score.setText(Integer.toString(currentScore.getCurrentValue()));
currentScore.incrementBy(10);
rect.setFill(Color.BLUE);
}
and don't forget to update the state at the end
previousCollisionStateMap.put(id,collisionDetected);
I have a TiledMap map with some object layers like "wall", "door", "spike"...
Each layer has only rectangles, at their specific positions.
What is the best way I could check if a specific cell of the tile layer contains an object from a specific object layer?
To do something like if Cell of the tile layer at (x,y) contains an object from a object layer "wall", say "can't move there".
I just started using libGDX and Tiles, and the current way of detecting something like this that I can think of would be to create all those rectangles and check if they overlap with the player rectangle each time a player moves to the next cell.
But that would be checking every single object, and I need to just check the one cell the player is currently in.
One way you could reduce computation (this only works if the walls/doors/etc. are all static and don't move or change shape) is by keeping a 2D array of booleans (basically your TiledMap) with true meaning that tile is blocked and vice versa.
In pseudocode:
// Initially all grid cells are un-blocked
boolean[][] gridBlockedByWall = new boolean[MAP_HEIGHT][MAP_WIDTH]; //Replace with your grid size
// Loop over each wall and set array (change depending on your implementation)
for (Rectangle wall: walls) {
// Here we run over every wall and column covered by this rectangle and set it as blocked
for (int row = wall.y; row < wall.y + wall.height; row++) {
for (int col = wall.x; col < wall.x + wall.width; col++) {
gridBlockedByWall[row][col] = true;
}
}
}
Now to test if position (x, y) is blocked by a wall simply do gridBlockedByWall[y][x] which will run in constant time.
I'm having some difficulty implementing very basic collision within libGDX. The update code for the "player" is as so:
private void updatePosition(float _dt)
{
Vector2 _oldPos = _pos;
_pos.add(_mov.scl(_dt*50));
_bounds.setPosition(_pos.x-8, _pos.y-12);
if(_game.getMap().checkCollision(_bounds))
{
System.out.println("Collision Detected");
_pos = _oldPos;
_bounds.setPosition(_pos.x-8, _pos.y-12);
}
}
So, initially _oldPos is stored as the values of _pos position vector before applying any movement.
Movement is then performed by adding the movement vector _mov (multiplied by the delta-time * 50) to the position vector, the player's bounding rectange _bounds is then updated to this new position.
After this, the player's new bounding Rectangle is checked for intersections against every tile in the game's "map", if an intersection is detected, the player cannot move in that direction, so their position is set to the previous position _oldPos and the bounding rectangle's position is also set to the previous position.
Unfortunately, this doesn't work, the player is able to travel straight through tiles, as seen in this image:
So what is happening here? Am I correct in thinking this code should resolve the detected collision?
What is strange, is that replacing
_pos = _oldPos;
with (making the same move just made in reverse)
_pos.sub(_mov.scl(_dt*50));
Yields very different results, where the player still can travel through solid blocks, but encounters resistance.
This is very confusing, as the following statement should be true:
_oldPos == _pos.sub(_mov.scl(_dt*50));
A better solution for collision detection would be to have a Vector2 velocity, and every frame add velocity to position. You can have a method that tests if Up arrow key is pressed, add 1 (or whatever speed you would like) to velocity. And if down is pressed, subtract 1 (or whatever speed). Then you can have 4 collision rectangles on player, 1 on top of player, bottom, left, and right. You can say
if(top collides with bounds){
if(velocity.y > 0){
set velocity.y = 0.
}
}
And do the same for down, left and right (eg... for bottom, make sure to test if(velocity.y < 0) instead of if(velocity.y > 0).
EDIT: You code is not working because you set oldPos = pos without instantiating a new Vector2. Which means when you add onto pos, it also changes oldPos. So say oldPos = new Vector2(pos);
try to test future position before move. If collision, don't move.
Background:
I have two 2d arrays. Each index within each 2d array represents a tile which is drawn on a square canvas suitable for 8 x 8 tiles.
The first 2d array represents the ground tiles and is looped and drawn on the canvas using the following code:
//Draw the map from the land 2d array
map = new Canvas(mainFrame, 20, 260, 281, 281);
for(int i=0; i < world.length; i++){
for(int j=0; j < world[i].length; j++){
for(int x=0; x < 280; x=x+35){
for(int y=0; y < 280; y=y+35){
Point p = new Point(x,y);
map.add(new RectangleObject(p,35,35,Colour.green));
}
}
}
}
This creates a grid of green tiles 8 x 8 across as intended.
The second 2d array represents the position on the ground. This 2d array has everyone of its indexes as null apart from one which is comprised of a Person class.
Problem
I am unsure of how I can draw the position on the grid. I was thinking of a similar loop, so it draws over the previous 2d array another set of 64 tiles. Only this time they are all transparent but the one tile which isn't null. In other words, the tile where Person is located.
I wanted to use a search throughout the loop using a comparative if statement along the lines of
if(!(world[] == null)){
map.add(new RectangleObject(p,35,35,Colour.red));}
However my knowledge is limited and I am confused on how to implement it.
Do not use a second Array at all. Simply create a RectangleObject named, for example, currentPosition or activeTile or personPosition.
You, however, do not really need to store the Point in the RectangleObject. Either use a 2D RectangleObject array for that (so that you can use the indexes to access them) and exclude the Point information in the RectangleObject,
or
create a List of RectangleObjects and add the Point information - but do not increment by 35, but rather by 1. When you're drawing the tiles, you can still (by knowing the index) figure out where to put the tile (e.g. indexX*tileWidth, indexY*tileHeight).
(It's not quite clear from what you've written what world and map are used for. Please explain so I can give a better answer)