Java Graphics2D - Detecting collisions between two objects - java

I'm creating a trial game where a spacecraft fires missiles to a stationary enemy spacecraft. The missile moves from left to right, and the enemy spacecraft is positioned on the right side. If a missile hits the enemy craft, it "explodes" (disappears from the screen). My problem is when should I execute the explode method because it is kinda tricky to tell if one of the missiles's plot coincides with that of the enemy craft. In my main program, I have the following:
private void updateMissiles(){
ArrayList ms = craft.getMissiles();
for(int i = 0; i < ms.size(); i++){
Missile m = (Missile) ms.get(i);
if(m.getX() == enemcraft.getX() && m.getY() == enemcraft.getY()){
enemcraft.explode();
}
if(m.isVisible()){
m.move();
}else{
ms.remove(i);
}
}
}
This does not work especially because the missile and the enemy spacecraft have different dimensions (8x5 pixels and 20x20 pixels, respectively). However, when I changed if(m.getX() == enemcraft.getX() && m.getY() == enemcraft.getY()) to simply if(m.getX() == enemcraft.getX()), the program works, but it disregards the y position of the missile and will make the enemy craft explode as long as the missile reaches the same x position of the enemy.
I tried experimenting with different ranges of the x and y positions, but to no avail. Is there an intuitive way to tell when the missile "hits" the enemy craft?

AABB (Axis Aligned Bounding Boxes)
You have not given much to go by but making a comparison based on position is not going to solve your problem.
The line
if(m.getX() == enemcraft.getX() && m.getY() == enemcraft.getY()){
Requires that the missile and enemy have the same position (x,y), there is only one point on the screen that has that coordinate so it's going to be hard to hit. You have effectively made your bad guy and missiles one pixel width and one pixel in height.
Bounding boxes
Both the missile and enemy have a size (area) you need to test if these areas hit. Imagine two rectangles each containing the missile and enemy. When these two rectangles overlap you can count that as a collision.
As I dont know where the x,y of the missile and enemy are (top left or center or something else) I will assume that you use the top left. Nor do I know if the two objects provide a width and height so I will hard code that. (20,20) and for missile (8,5)
private void updateMissiles () {
ArrayList ms = craft.getMissiles();
int mLeft = enemyCraft.getX(); // guessing position is an int . Set the correct type when you copy this
int mTop = enemyCraft.getY();
int mRight = mLeft + 20;
int mBottom = mTop + 20;
for (int i = 0; i < ms.size(); i++) {
Missile m = (Missile) ms.get(i);
// only test if both missile and enemyCraft are visible
// I am guessing that enemyCraft has a isVisible method
if(m.isVisible() && enemyCraft.isVisible()){
int mx = m.getX(); // Again I am guessing the type as int
int my = m.getY();
if ( ! (my > mBottom || mx > mRight || mx + 8 < mLeft || my + 5 < mTop)) {
enemyCraft.explode();
ms.remove(i); // remove missile
}
}
if (m.isVisible()) {
m.move();
}
}
}
Better fit.
There is a problem with this method. The missiles and bad guys may not be the same shape as the bounding box. This will result in a collision even if they are not actually touching. But that is easily solved.
Do the test as above, this will let you know if you should do more testing. When you find a collision divide the two objects into a few smaller bounding boxes and test if they overlap. That will improve the accuracy.

Related

libgdx pixel collision on very simple 2D game

I'm very new to libgdx and game dev. Ive been tasked with an assignment where I am given a very simple 2D game which has rectangular collision detection already implemented.
The game is just made up of a square which can be controlled by the player, which is inside of walls with other scattered squares within the walls. I now need to implement pixel perfect collision between the player square and the scattered squares/walls.
I originally tried using Pixmap and tried to check if the pixels of the current coordinate were transparent for the player rectangle and whichever rectangle it is colliding with but am having trouble implementing the code correctly.
I understand that I must just check the pixel colors for both objects at a certain coordinate and see if they both are not transparent for a collision to occur but I am having trouble. I have spent a very long time researching and looking online so any help or advice on how to execute this would be greatly appreciated!
public boolean entityCollision(Entity e1, Direction direction, float newX, float newY) {
boolean collision = false;
for(int i = 0; i < entities.size(); i++) {
Entity e2 = entities.get(i);
if (e1 != e2) {
if (newX < e2.x + e2.width && e2.x < newX + e1.width &&
newY < e2.y + e2.height && e2.y < newY + e1.height) {
collision = true;
int colorOne = player.getPixel((int)newX,(int)newY);
int colorTwo = enemy.getPixel((int)e2.x,(int)e2.y);
if (colorOne != 0 && colorTwo != 0) {
collision = true;
e1.entityCollision(e2, newX, newY, direction);
}
}
}
}
return collision;
}
Take a look at the Rectangle implementation of libgdx. It allows you to do something like this:
Rectangle e1Rec = new Rectangle(e1.x, e1.y, e1.width, e1.height);
Rectangle e2Rec = new Rectangle(e2.x, e2.y, e2.width, e2.height);
if (e1Rec.contains(e2Rec)) {
// Collision!
}
If you want collisions with a sprite, you get the sprite rectangle and check for collisions inside of that rectangle.
sprite.getboundingrectangle().contains(x, y) ; //returns a boolean

Java Objects in Array - collision detection

Let's say that I have code like this:
private void actuallyDrawGraphics(Canvas canvas) {
canvas.drawColor(Color.WHITE);
for(Ball ball : balls){
canvas.drawBitmap(ballBitmap,
-16 + (ball.x / 100f) * canvas.getWidth(),
-16 + (ball.y / 100f) * canvas.getHeight(),
paint
);
}
}
Every ball is registered in an array. I need to make a collision (when one collides with the second) and everything goes well, until I have more balls, for example 10. It's not efficient to make a check like:
ball 1 with 2, 3, 4...
ball 2 with 1, 3, 4...
Is there any way that this can be done?
for (int i = 0; i < balls.size(); i++) {
Ball ball = balls[i];
for (int a = i + 1; a < balls.size(); a++) {
Ball ball2 = balls[a];
// check for collision with ball and ball2.
}
}
Like Nacho was saying, I believe that this would be a better way to check every possible collision, but if you have a very large number of balls, then you may need to do something to reduce the number of checks you are making here. Or, you may need to improve your code that checks for a collision.
You need another data structure. For example an object Collision containing a List<Ball> ballsThatCollide; or something similar. Or for each Ball to have List<Ball> inCollisionWith. If you want simple arrays, then you'll need a N dimensional array where the dimensions are the balls and the intersection are collisions.

Collision detection strategy for a pong game

I'm trying to implement a simple pong game. I want the ball to change X direction or Y direction depending what side of the ball was hit.
The ball moves at 3 pixels per second and has a width of 22 and height of 22. The paddles have a width and height of 32.
For collision detection on the ball, should I just create one rectangle and check for collision with the center point?
Alternatively I could create 4 rectangles around the ball to represent the sides, with an appropriate width, given that the ball moves at 3 pixels per frame.
Another option is to create a method that will check for collision at least 2 pixels in the direction of motion of the ball.
If the ball is moving to the right, and the x-position is 16, the next frame will be 19.
Should I create a method that will check x for 16, 17 and 18, to make sure if there is a collision it will hit the right side and not cause the ball to actually go inside the cube?
#Sig
I now have this as my collision detection
if(Rect.intersects(balls.get(j).ball, levelBlocks.blocks.get(i).rect))
{
//Bottom
if(balls.get(j).yPos <= levelBlocks.blocks.get(i).yPos - (32/2))
{
balls.get(j).ySpeed = balls.get(j).ySpeed * -1;
}
//Top
if(balls.get(j).yPos >= levelBlocks.blocks.get(i).yPos + (32/2))
{
balls.get(j).ySpeed = balls.get(j).ySpeed * -1;
}
//Left
if(balls.get(j).xPos < levelBlocks.blocks.get(i).xPos)
{
balls.get(j).xSpeed = balls.get(j).xSpeed * -1;
}
//Right
if(balls.get(j).xPos > levelBlocks.blocks.get(i).xPos)
{
balls.get(j).xSpeed = balls.get(j).xSpeed * -1;
}
This works, but not 100%, it still seems abit off. if the ball hits two blocks at the same time, it will invert the invert so the direction will go back again.
I then changed it to this
if(Rect.intersects(balls.get(j).ball, levelBlocks.blocks.get(i).rect))
{
//Bottom
if(balls.get(j).yPos <= levelBlocks.blocks.get(i).yPos - (32/2))
{
collision = 2;
}
//Top
if(balls.get(j).yPos >= levelBlocks.blocks.get(i).yPos + (32/2))
{
collision = 2;
}
//Left
if(balls.get(j).xPos <= levelBlocks.blocks.get(i).xPos + (32/2))
{
collision = 1;
}
//Right
if(balls.get(j).xPos >= levelBlocks.blocks.get(i).xPos + (32/2))
{
collision = 1;
}
temp = levelBlocks.blocks.get(i);
levelBlocks.blocks.remove(i);
combo.blocksDestroied += 1;
Assets.score += 10 * combo.comboMultiplier;
}
}
if(collision == 1)
{
balls.get(j).xSpeed = balls.get(j).xSpeed * -1;
collision = 0;
}
if(collision == 2)
{
balls.get(j).ySpeed = balls.get(j).ySpeed * -1;
collision = 0;
}
This does work, but every now and then the ball will just start randomly going through blocks, it is very odd to look at, really confused on why it is doing it, but I do feel it is because of the 3 pixels per frame
Because the shapes you're working with are so simple, why not be perfect? Use a rectangle for the paddles and a circle for the ball when performing hit detection. Start by checking for collisions on a frame-by-frame basis; at the speeds you're working with, you shouldn't need to "look into the future" for future collisions.

How to do collision detection with many walls (maze)?

In my game, the player navigates a maze. I can't figure out how to do proper collision detection with the walls. It is easy to do collision detection for staying in a certain area:
if (x > rightWallX - playerWidth) x = rightWallX - playerWidth;
if (x < leftWallX) x = leftWallX;
//...
But how would I do collision detection for many walls?
I can do plain collision detection without correction (like if (intersecting) return true;), but I can't correct this correctly. If I just store the old x and y and reset them, then
The object never actually touches the wall
If the object can go up but is blocked to the right, it won't go up, it will just not move.
How is collision detection in a maze done?
The easiest way, once you have solved collision detection, to fix the collision is to move the actor to the closest valid position to where the actor would be were it not for the object it collides with. This assumes no inertia, but it is sufficient for maze-like games or top-down map-crawling games.
If you want to simplify your calculations further, you can limit yourself to detecting if changing the actor's x or y coordinate would be better. If your actor has an axis-aligned rectangular hit-box and all obstacles are axis-aligned rectangular as well (the simplest case), this assumption is indeed correct. However, the results might not be satisfactory in some other cases (potential artifact: speed boost from gliding diagonal walls - not the case in most maze games).
Keep in mind multiple collisions could happen concurrently (pushing against two walls). If there are no sharp angles between two walls that an actor could both intersect (say, if all your obstacles are axis aligned and sufficiently spaced), fixing each collision in turn will suffice - just don't stop after the first collision.
You can use Rectangle.intersects() method:
public Rectangle Player(){
return new Rectangle(PlayerX,PlayerY,PlayerWidth,PlayerHeight);
//we do this for getting players x and y values every tick
}
if(Player().intersects(new Rectangle(0,0,100,50)))//if(player touching wall)
new Rectangle(0,0,100,50) is just an example you can change it.
Ok so i'm currently making a 2D top down view game and I'm not sure how you created your maze. However, in my game my Level is created from a Tile[][] tiles = new Tile[levelWidth][levelHeight]; array. The way i handled collision detection was by checking the surrounding tiles to see if they were solid.
This is my getTile method.
public Tile[][] getTile(int x, int y) {
if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) {
return new VoidTile();
} else {
return tiles[x][y];
}
}
In my Tile.java class i have a isSolid() method which returns whether the tile is solid or not. All of my tiles extend my Tile.java so they inherit this method and I override it in their constructor. As i said previously, I am not sure whether or not you use the same style of level implementation as i do. However, It is good practice to do it this way :)
Personally, I am not a big fan of using the .intersects() and .contains() methods for Sprite collision detection. I mainly use them for buttons and alike.
Ok so,
In my player.java class i have a checkBlockedDirection(int x, int y) method and it looks like this.
public void checkBlockedDirection(int x, int y) {
boolean u = map.getTile(x, y - 1).isSolid();
boolean d = map.getTile(x, y + 1).isSolid();
boolean l = map.getTile(x - 1, y).isSolid();
boolean r = map.getTile(x + 1, y).isSolid();
if (u) {
uBlocked = true;
System.out.println("up tile blocked");
} else {
uBlocked = false;
}
if (d) {
dBlocked = true;
System.out.println("down tile blocked");
} else {
dBlocked = false;
}
if (l) {
lBlocked = true;
System.out.println("left tile blocked");
} else {
lBlocked = false;
}
if (r) {
rBlocked = true;
System.out.println("right tile blocked");
} else {
rBlocked = false;
}
}
Then in my player update method i have this
public void tick() {
float dx = 0;
float dy = 0;
if (input.up.isPressed()) {
direction = 0;
} else if (input.down.isPressed()) {
direction = 2;
} else if (input.left.isPressed()) {
direction = 3;
} else if (input.right.isPressed()) {
direction = 1;
} else {
direction = 4; // standing
}
checkBlockedDirection((int)x, (int)y);
if (input.up.isPressed() && y > 0 && !uBlocked) {
dy += -speed;
} else if (input.down.isPressed() && y < map.getHeight() - 1 && !dBlocked) {
dy += speed;
} else if (input.left.isPressed() && x > 0 && !lBlocked) {
dx += -speed;
} else if (input.right.isPressed() && x < map.getWidth() - 1 && !rBlocked) {
dx += speed;
}
x += dx;
y += dy;
}
Basically it just checks whether or not the blocks up, down, left, or right are solid. If they are solid then it wont move and if they arent solid then you can move in the desired direction.
Not sure if this helps or not but it's just my take on this kind of grid collision detection :)
Hope this helps :)
Enjoy

inclusion/exclusion on toroid plane using java

I wrote a program to solve the following:
Implement a diffusion limited aggregation simulation on a toroid plane where seeds are randomly created, and particles move randomly. they move if they particles do not land near a seed or a particle. where user inputs seeds (red pixels), particles (black pixels), steps (no or iterations), plane size.
My code is very slow. How can I make it faster?
I randomly created x and y coordinates and drew red pixels (seeds), then randomly created x and y for black pixels (particles), if a black pixel lands where there is a red or black pixel it can stay, otherwise it moves randomly again until there are no more particles . If the pixel lands out of borders like x > border then x=0; if x <1 then x= border. The same for y.
This just means that if it lands on the border I move it to the opposite border. Then checks for the neighboring pixels again. I have an outer loop to create the seeds, and inner loop for the particles. In the inner loop I check for the x,y positions:
//Place, move, and "stick" the particles; stop if either steps or particles = 0
for (int p = 0; p < particles; p++) {
for (int s = 0; s < steps; s++) {
if (xPos > image.getWidth() ) {
do something
}
else if (xPos < 1) {
do something
}
if (yPos > image.getHeight() - 2) {
do something
}
else if (yPos < 1) {
do something
}
else if (xPos > image.getWidth() && yPos > image.getHeight()) {
do something
}
else if (xPos < 1 && yPos < 1) {
do something
}
//If the surrounding pixels' color is not white, make that particle stick.
if (moveValid()) {
image.setRGB(xPos, yPos, 0xFF000000);
}
//Otherwise, move in a random direction
else {
if(xPos == 1 && image.getRGB(size - 2, yPos) != 0xFFFFFFFF){
draw(xPos,yPos);
}
else if(xPos == size - 2 && image.getRGB(1,yPos) != 0xFFFFFFFF){
draw(xPos,yPos);
}
if(yPos == 1 && image.getRGB(xPos, size - 2) != 0xFFFFFFFF){
draw(xPos,yPos);
}
else if(yPos == size - 2 && image.getRGB(xPos,1) != 0xFFFFFFFF){
draw(xPos,yPos);
}
else {
move();
}
}
}
//Regenerate random x and y positions for the next particle
xPos = random.nextInt(size);
yPos = random.nextInt(size);
}
Although the implementation of draw() is not shown, it looks like you're updating a BufferedImage and then rendering it.
The first step is always to profile your existing code, looking for easily implemented optimizations.
The second step is sometimes to set aside the existing code and try a different approach.
You may be able to leverage the Mode-View-Controller pattern, outlined here and discussed here. In particular, let your DLA model evolve on a background thread at full speed, while updating your view at a more sustainable rate. This article suggests several approaches to synchronization and includes a related example that uses javax.swing.Timer to pace the updates.

Categories

Resources