Java. Collision detection - java

I write a simple collision detection using rectangles. I've to check overlapping in render method. Could you tell me what's faster the first way:
render()
{
Rectangle playerRectangle = new Rectangle(
playerTransformComponent.x,
playerTransformComponent.y,
playerDimensionsComponent.width,
playerDimensionsComponent.height);
for(Rectangle block : blocksList){
//check collision
}
}
Or the second way:
Rectangle playerRectangle = new Rectangle();
render()
{
playerRectangle.x = playerTransformComponent.x;
playerRectangle.y = playerTransformComponent.y;
playerRectangle.width = playerDimensionsComponent.width;
playerRectangle.height = playerDimensionsComponent.height;
for(Rectangle block : blocksList){
//check collision
}
}

The render() function is a loop, so the first way is obviously wrong - you create an object every frame - it's a loss of everything.
The second way is definitely faster.
I hope it helps!
staticcasty

Related

My game collision system doesn't work on more than one tile

I'm working on a collision system for my game, however I can't get it to work, if I add more than one wall (which is the object I'm rendering) the collision system doesn't work and I can get through the block.
However if I leave only one wall the collision works correctly, or if at the end of the loop I add a break;
the collision works but only on the first wall of the map, the others don't get the collision.
Would anyone know how to solve this? I've been trying to solve it for 2 days and I couldn't.
public boolean checkCollisionWall(int xnext, int ynext){
int[] xpoints1 = {xnext+3,xnext+3,xnext+4,xnext+3,xnext+3,xnext+4,xnext+10,xnext+11,xnext+11,xnext+10,xnext+11,xnext+11};
int[] ypoints1 = {ynext+0,ynext+8,ynext+9,ynext+11,ynext+12,ynext+15,ynext+15,ynext+12,ynext+11,ynext+9,ynext+8,ynext+0};
int npoints1 = 12;
Polygon player = new Polygon(xpoints1,ypoints1,npoints1);
Area area = new Area(player);
for(int i = 0; i < Game.walls.size(); i++){
Wall atual = Game.walls.get(i);
int[] xpoints2 = {atual.getX(),atual.getX(),atual.getX()+16,atual.getX()+16};
int[] ypoints2 = {atual.getY(),atual.getY()+16,atual.getY()+16,atual.getY()};
int npoints2 = 4;
Polygon Wall = new Polygon(xpoints2,ypoints2,npoints2);
area.intersect(new Area(Wall));
if(area.isEmpty()){
return true;
}
}
return false;
}
I'm pretty sure the problem is this call:
area.intersect(new Area(Wall));
Here's the JavaDoc for that method:
public void intersect(Area rhs)
Sets the shape of this Area to the intersection of its current shape
and the shape of the specified Area. The resulting shape of this Area
will include only areas that were contained in both this Area and also
in the specified Area.
So area, which represents the shape of your player, is going to be modified by each test with a wall, which is why it's only working with one wall.
You could fix the issue by simply making the player Area the argument of the call, as in:
Area wallArea = new Area(Wall);
wallArea.intersect(area);
if(wallArea.isEmpty()){
return true;
}
By the way, this logic is reversed isn't it. Don't you want to check that the resulting area is not empty, i.e. there was an overlap between the player and the wall?
The other option, if each Wall is actually a rectangle, would be to use the this Area method instead:
public boolean intersects(double x,
double y,
double w,
double h)
Tests if the interior of the Shape intersects the interior of a
specified rectangular area. The rectangular area is considered to
intersect the Shape if any point is contained in both the interior of
the Shape and the specified rectangular area.
Something like this:
if(area.intersects(atual.getX(), atual.getY(), 16, 16)) {
return true;
}
As this avoids the creation of an Area object for each wall, and the intersection test is going to be much simpler, and faster.

Creating a second object makes functions of class not work anymore

I'm trying to write a class that shows vectors. If I create one vector object everything works as intended. In my example code the object lin1 gets drawn with the help of the draw() function.
If I now create a second vector object, the (unchanged) draw-function doesnt do anything anymore, even though the object itself is unchanged. It's the same the other way around: Is the second object the only one existing, then it can be drawn, but only as long as lin1 doesnt exist.
Does anyone know where my mistake is?
vector lin;
vector lin2;
void setup()
{
size(500,500);
background(255);
cenX = width/2;
cenY = height/2;
noLoop();
}
void draw()
{
coordSys();
lin = new vector(0,0,100,100);
lin2 = new vector(0,0,-200,-200);
lin.draw();
lin2.draw();
lin.getAll();
}
class vector
{
float x1,y1,x2,y2;
float length;
float angle;
float gegenK, anK;
vector(float nx1, float ny1, float nx2, float ny2)
{
translate(cenX,cenY);
x1 = nx1; y1 = -ny1; x2 = nx2; y2 = -ny2;
strokeWeight(2);
// Gegenkathete
gegenK = ny2 - ny1;
// Ankathete
anK = x2 - x1;
// length and angle
length = sqrt(sq(anK) + sq(gegenK));
angle = winkel(gegenK, anK);
}
void draw()
{
stroke(0);
line(x1,y1,x2,y2);
}
}
}
Please use standard naming conventions when writing code. Specifically, your class should be Vector with an upper-case V. Also, please post your code in the form of an MCVE that compiles and runs.
Anyway, the first call in your Vector() constructor is this:
translate(cenX,cenY);
This moves the origin of the window halfway across the window. When you do this once, this simply makes your drawing calls relative to the center of the window. But when you do this twice, it moves the origin to the bottom-right corner of the window, so all of your drawings are moved off the edge of the screen.
To fix your problem, you need to move this line so it only happens once (perhaps at the beginning of the draw() function) instead of every single time you draw a Vector. Another way to approach this would be to use the pushMatrix() and popMatrix() functions to avoid this stacking of window translations.

Making a bullet pass opposite sides of the screen

So, for a coding assignment we have to make a tank game. I created a bullet class using this:
package com.MyName.battletanks;
import com.badlogic.gdx.graphics.g2d.Sprite;
public class Bullet {
public Sprite b;
public float vx = 0;
public float vy = 0;
public Bullet(Sprite temp) { b = temp;}
public void move() { b.translate(vx*3,vy*3);}
}
My variables are as follows:
Sprite Player1;
Sprite Player2;
ArrayList<Bullet> bullets;
Upon Clicking space it creates the bullet using this:
if (Gdx.input.isKeyPressed(Input.Keys.SPACE)) {
Bullet bullet = new Bullet(new Sprite(new Texture("Bullet1.png")));
bullet.b.setPosition(Player1.getX() + Player1.getWidth() / 2, Player1.getY() + Player1.getHeight() / 2);
float rotation = (float) Math.toRadians(Player1.getRotation());
bullet.vx = (float) Math.cos(rotation);
bullet.vy = (float) Math.sin(rotation);
bullets.add(bullet);
}
Now, here is my code for getting my tanks to pass through one side of the screen to another:
if (Player1.getX() > Gdx.graphics.getWidth()){
Player1.setX(-64f);
} else if(Player1.getX()<-64f){
Player1.setX(Gdx.graphics.getWidth());
}
if (Player1.getY() > Gdx.graphics.getHeight()){
Player1.setY(-64);
} else if(Player1.getY() < -64f){
Player1.setY(Gdx.graphics.getHeight());
}
Now, Player 1 is a sprite, however, the bullets are created using an arraylist and a self made bullet class. As a result, I cannot use the code for Player1 that I did for the bullet. SO, my question is, how can I get my bullet to pass to the other side of the screen?
You can use the modulo % operator to do something like this:
bullet.position.x %= Gdx.graphics.getWidth();
bullet.position.y %= Gdx.graphics.getHeight();
This isn't tested but it should work. Also, I noticed you're using 2 floats for your velocity, and you should really be using Vector2 because then you can easily scale and normalise it, which would be useful for a velocity.
It is really the same thing for the Player class and for the Bullet class since you have the same screen-space therefore you can reuse your current code by making it into a function that takes any sprite. This function would be defined as follows:
void fitOnScreen(Sprite sprite) {
if (sprite.getX() > Gdx.graphics.getWidth()){
sprite.setX(-64f);
} else if(sprite.getX()<-64f){
sprite.setX(Gdx.graphics.getWidth());
}
if (sprite.getY() > Gdx.graphics.getHeight()){
sprite.setY(-64);
} else if(sprite.getY() < -64f){
sprite.setY(Gdx.graphics.getHeight());
}
}
You would call this function on the Player as well as loop over every bullet, such as:
fitOnScreen(Player1);
for (Bullet b: bullets) fitOnScreen(b.b);
Well, what you are asking is how can you run through each instance of the bullets and change their properties.
I have to agree #Zac's algorithm would work fine for one bullet, but you need to put it in a loop to go through each and every bullet in order to be effective.
Here is an example of what you could do in your render() method of your game screen:
Iterator<Bullet> it = bullets.iterator();
while(it.hasNext()) {
Bullet bullet = it.next();
// Now you do the position correction
bullet.b.setPosition(bullet.b.getX()%Gdx.graphics.getWidth(), bullet.b.getY()%Gdx.graphics.getHeight());
}
Of course there are other ways of doing this, but this is probably the easiest way. You could also recycle the code you used for you player in this loop too.
Also, note that with this method, the more bullets, the more laggy the application becomes.

why does the collision between two rectangles not work?

I would like to understand one thing , below I saw that a collision between two rectangles works .
create method:
//nave
spaceShip = new Image(new TextureRegion(new Texture(Gdx.files.internal("rocket.png")),98,154));
spaceShip.setOrigin(spaceShip.getWidth()/2, spaceShip.getHeight()/2);
spaceShip.setBounds(spaceShip.getX(),spaceShip.getY(),spaceShip.getWidth(),spaceShip.getHeight());
spaceShip.setZIndex(3);
//meteora
meteora = new Image(new TextureRegion(new Texture(Gdx.files.internal("planet.png")),128,128));
meteora.setOrigin(meteora.getWidth()/2,meteora.getHeight()/2);
meteora.setPosition(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2);
meteora.setBounds(meteora.getX(),meteora.getY(),meteora.getWidth(),meteora.getHeight());
meteora.setZIndex(3);
Render method:
rect1 = new Rectangle(spaceShip.getX(),spaceShip.getY(),spaceShip.getWidth(),spaceShip.getHeight());
rect2 = new Rectangle(meteora.getX(),meteora.getY(),meteora.getWidth(),meteora.getHeight());
if(Intersector.overlaps(rect1,rect2)){
System.out.println("collision");
}
Now , my question is :
as I can see collisions with dynamic objects .
Let me explain, there will be different now created in a random time .
So how can I tell if a collision occurs with one of these objects and understand what it is .
Rectangle has no method .setName , I wanted to use this to figure out which object my ship touched .
Can anyone recommend a solution ?
Thank You
EDIT
add Image object
meteora = new Image(new TextureRegion(new Texture(Gdx.files.internal("planet.png")), 128, 128));
meteora.setOrigin(meteora.getWidth() / 2, meteora.getHeight() / 2);
meteora.setPosition(Gdx.graphics.getWidth() / 2, 100);
meteora.setZIndex(3);
Rectangle rect = new Rectangle(meteora.getX(),meteora.getY(),meteora.getWidth(),meteora.getHeight());
rectangles.add(rect);
I am not entirely sure what the question is, but in answer to what I think you are getting at:
Typically you would want to add all the new randomly created rectangles to a collection of rectangles, then you can iterate through this collection to check for collisions:
List<Rectangle> rectangles = new ArrayList<Rectangle>(); // a field in your class
// inside the method to create random rectangles
Rectangle tmp = new Rectangle(1,2,3,4);
rectangles.add(tmp);
// inside the method to check for collisions
for(Rectangle rect : rectangles) {
if(Intersector.overlaps(rect, shipRect) {
System.out.println("collision");
}
}
Note that your rect1 for your ship's bounds should be saved as a field (shipRect in this example) as well so that you can refer back to it at any time

Animate a propeller in java

I am trying to animate a propeller in java and have come to this code:
int x = 0;
int y = 230;
int h = 40;
int i = 0;
int center = 250;
void setup() {
size(500, 400);
}
void draw () {
if (i == 0) {
if(y>200) {
ellipse(x, y, 20, h);
y--;
h+=2;
x+=1;
} else { i = i + 1; }
}
if (i == 1) {
if(y<=230) {
ellipse(x, y, 20, h);
y++;
h-=2;
x+=1;
} else { i = i + 1; }
}
if (i == 2) {
if(h<70) {
ellipse(x, y, 20, h);
y++;
h+=1;
x+=1;
} else { i = i + 1; }
}
if (i == 3) {
if(h>=40) {
ellipse(x, y, 20, h);
y--;
h-=1;
x+=1;
} else { i = 0; }
}
}
Is there a way of making this shorter, because I want to have 4 propellers and dont want to have so much code for this part.
You're going about this the wrong way. Very wrong, in fact. And the reason might be that you think you're doing this in "Java...in the program 'processing'"
The reason this sort of thinking is wrong is because it is equivalent to someone working with C++ saying, "I am creating classes in C using the program 'C++'". Processing is based on Java but it is a different programming language. If you're uncomfortable stretching the idea of Processing to that of a "programming language" then at least think of it as a framework...a framework that provides you with its own implementation of various tools that are put together to help with the creation of art using computers.
Now your thinking seems to have affected you in your particular case a lot. Just like Jose Gonzalez above suggested, you haven't even thought about rotate(), which is a function built into Processing. Tim B's suggestion about Objects is spot on as well but if you want to do things in Processing, try to do them the Processing way.
Here's a very quick sketch that I did for you to understand what I mean:
Prop myProp1;
Prop myProp2;
Prop myProp3;
Prop myProp4;
float angle;
void setup() {
size(500, 500);
background(255);
angle = 0;
fill(0);
ellipseMode(CENTER);
myProp1 = new Prop(50,50);
myProp2 = new Prop(75,75);
myProp3 = new Prop(100,100);
myProp4 = new Prop(125,125);
}
void draw() {
background(255);
angle = ((angle + 0.1) % 360);
myProp1.buildAndRotate(angle, width*3/4, height/4);
myProp2.buildAndRotate(angle, width/4, height/4);
myProp3.buildAndRotate(angle, width*3/4, height*3/4);
myProp4.buildAndRotate(angle, width/4, height*3/4);
}
class Prop {
int propX;
int propY;
int propW;
int propH;
Prop() {
propX = 0;
propY = 0;
propW = 50;
propH = 50;
}
Prop(int w, int h) {
propX = 0;
propY = 0;
propW = w;
propH = h;
}
void buildAndRotate(float angle, float moveToX, float moveToY) {
pushMatrix();
translate(moveToX, moveToY);
rotate(angle);
ellipse(propX, propY, propW, propH);
ellipse(propX+propW/2, propY+propH/2, propW, propH);
ellipse(propX-propW/2, propY+propH/2, propW, propH);
ellipse(propX+propW/2, propY-propH/2, propW, propH);
ellipse(propX-propW/2, propY-propH/2, propW, propH);
popMatrix();
}
}
Now, this is by no means meant to be the way to do things in Processing but it uses various tools provided by the programming language to do exactly what you want to do. Also, the Object Prop can be built in various different ways and my implementation is not supposed to be top-notch at all.
So what is going on? Well, run the sketch and you will see four propellers rotating on their own axes. I just put four of them there, you can delete them or add more as you please.
What the hell is a Prop made of? It is made of five ellipses. The concept, and this may be different than yours, is based on the idea of a ceiling fan (or other fans for that matter or even a prop engine). These fans have a circular thing in the middle to which all the blades are attached. The center circle rotates and that results in all the blades around it rotating with it. What you get in the end is a rotating fan.
How is this thing rotating? Similar to the fan analogy above, there is an ellipse in the middle that rotates around its center. There are four ellipses "attached" to it that rotate around this center ellipses. This gives the illusion of a prop rotating. What you have to understand is that in Processing rotate() rotates things around the origin. This is the reason the center ellipse starts at (0,0). Then later in buildAndRotate() it is translated using translate(). Using translate() does not move the object, it instead moves the origin resulting in the object moving with it, and then when you execute rotate() it rotates the object around its center. Since all the other ellipses are built around this center ellipse, they all rotate around it too (in actual implementation, they're just rotating around the origin, you can see that by removing the center ellipse). pushMatrix() and popMatrix() are used so all the translate() and rotate() commands don't affect everything else in the sketch and keep all movements and rotations applied to each object to that very object.
What else is going on? The rest is pretty simple (this is all very simple once you get the hang of it). Background is being cleared constantly which is a common animation technique to give the illusion of movement. You can delete the statement for background() from draw() but I wouldn't recommend it because it will leave a big black round circle after a while and you won't be able to see the props. The angle is being changed constantly in the draw() method which is why you see the props rotating. You can speed up or slow down the rotation by changing that + 0.1 value being added to angle if you want.
What else do I do? Read the reference (not the Java reference, Processing has its own reference) by using Google or following links such as: http://www.processing.org/reference/rotate_.html, http://www.processing.org/reference/pushMatrix_.html, http://www.processing.org/reference/popMatrix_.html, http://www.processing.org/reference/translate_.html, and many more.
Hope this helps and leave questions in the comment if you need clarification on something.
You need to think in terms of objects and iteration rather than writing out everything explicitly. You are correct that the code you have above contains a lot of un-needed duplication, which is a bad thing.
For a more complex case you would define each part of the propeller as an object. Have an array of parts within the Propeller object. Each time to do the draw you run through the list of objects and render each one out.
In this case it can be even simpler, just use a for loop.
At the top of your program define:
private static final int NUM_BLADES = 4;
Then you want a loop that looks something like this:
for (int i=0;i<360;i+=360/NUM_BLADES) {
// Draw elipse at current rotation position + the angle for this blade
}
Now you can change the number of blades just by changing the static define as well.

Categories

Resources