Detect Collision of multiple BufferedImages Java - java

I am making a 2d rpg game in java and I have run into a problem. I can make the player move around the stage and I have rocks, trees, walls, etc. on the stage as well. I don't know how to detect the collision and make it to where the player can't move through the object. The code that reads map file and draws image on the canvas is as follows:
public void loadLevel(BufferedImage levelImage){
tiles = new int[levelImage.getWidth()][levelImage.getHeight()];
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Color c = new Color(levelImage.getRGB(x, y));
String h = String.format("%02x%02x%02x", c.getRed(),c.getGreen(),c.getBlue());
switch(h){
case "00ff00"://GRASS Tile - 1
tiles[x][y] = 1;
break;
case "808080"://Stone -2
tiles[x][y] = 2;
break;
case "894627"://Dirt -3
tiles[x][y] = 3;
break;
case "404040"://Rock on Grass -4
tiles[x][y] = 4;
break;
case "00b700"://Tree -5
tiles[x][y] = 5;
break;
case"000000"://Wall -6
tiles[x][y] = 6;
break;
case "cccccc"://Rock on stone -7
tiles[x][y] = 7;
break;
default:
tiles[x][y] = 1;
System.out.println(h);
break;
}
}
}
}
And the player class is as follows:
public class Player {
private int x,y;
public int locx,locy;
private Rectangle playerR;
private ImageManager im;
public boolean up =false,dn = false,lt=false,rt=false,moving = false,canMove = true;
private final int SPEED =2;
public Player(int x, int y, ImageManager im){
this.x = x;
this.y = y;
this.im = im;
locx = x;
locy = y;
playerR = new Rectangle(x,y,16,16);
}
public void tick(){
if (up) {
if(canMove){
y -= SPEED;
locx = x;
locy = y;
playerR.setLocation(locx, locy);
moving = true;
}
else{
y += 1;
canMove=true;
}
}
if (dn) {
y +=SPEED;
locx = x;
locy = y;
moving = true;
}
}
if (lt) {
x -= SPEED;
locx = x;
locy = y;
moving = true;
}
if (rt) {
x+=SPEED;
locx = x;
locy = y;
moving = true;
}
}
if(moving){
System.out.println("PLAYER\tX:"+locx+" Y:"+locy);
moving = false;
}
}
public void render(Graphics g){
g.drawImage(im.player, x, y, Game.TILESIZE*Game.SCALE, Game.TILESIZE*Game.SCALE, null);
}
}
I don't really know how to do collision, but i googled it and people said to make a rectangle for the player and all the objects that the player should collide with, and every time the player moves, move the player's rectangle. Is this the right way to do this?
EDIT EDIT EDIT EDIT
code for when collision is true:
if (rt) {
x+=SPEED;
locx = x;
locy = y;
playerR.setLocation(locx, locy);
for(int i = 0;i<Level.collisions.size();i++){
if(intersects(playerR,Level.collisions.get(i))==true){
x-=SPEED;
locx = x;
playerR.setLocation(locx, locy);
}
}
moving = true;
}
And the intersects method is as follows:
private boolean intersects(Rectangle r1, Rectangle r2){
return r1.intersects(r2);
}

I'm going to focus on your tick method since that is where most of this logic is going. There are a couple changes here. Most notably, we only move the rectangle before checking for collisions. Then loop through all the collideable objects in your level. Once one is found, we reset our x and y and break out of the loop (no sense in looking at any of the other objects since we already found the one we collided with). Then we update our player position. By doing it this way, I centralized the code so it is not being repeated. If you ever see yourself repeating code, there is a pretty good chance that it can be pulled out to a common place, or to a method.
public void tick() {
if (up) {
y -= SPEED;
} else if (dn) {
y += SPEED;
} else if (lt) {
x -= SPEED;
} else if (rt) {
x += SPEED;
}
playerR.setLocation(x, y);
for (Rectangle collideable : Level.collisions) {
if (intersects(playerR, collideable)) {
x = locx;
y = locy;
playerR.setLocation(x, y);
break;
}
}
locx = x;
locy = y;
}

There are different ways to do that. As you talk about a "rpg" i think your view is Isometric (45° top down).
I would do the collision detection in pure 90° top down, as it is easier and, imho, more realistic.
We have 2 possibilities:
Move your Player to the next position. If there is a collision, reset his position.
Calculate the next position, if there would be a collision don't move.
If you want to have a "gliding" collision response, you have to check in which axis the collision will happen, and stop / reset movement for this axis only.
To have a more efficient collision detection only check near objects, which will possibly collide.
Do this by comparing a squared "dangerRadius" with the squared distance between your player and the object:
if ((player.x - object.x)² + (player.y - object.y)² <= dangerRadius²)
// Check for intersection
This will sort out most of the objects by using a simple calculation of:
2 subtractions
1 addition
3 multiplications (the ²)
1 compare (<=)
In your game you should sepparate the logic and the view. So basicly you don't detect, if the two images overlapp, but you check, if the objects in your logic overlap. Then you draw the images on the right position.
Hope this helps.
EDIT: Important: If you update your character, depending on the time between the last and this frame (1/FPS) you have to limit the max timestep. Why? Because if for some reason (maybe slow device?) the FPS are really low, it is possible, that the character moves verry far between 2 frames and for that he could go through an object in 1 frame.
Also if you simply reset the movement on collision or just don't move the distance between you and the object could be big for low FPS. For normal FPS and not to high movementspeed this won't happen/ be noticeable.

I personally am fairly new to Java, though I have worked with C# in the past. I am making a similar game, and for collision detection I just check the locations of the player and objects:
if (z.gettileX() == p.gettileX()){
if (z.gettileY() == p.gettileY()){
System.out.println("Collision!");
}
}
If the player (p) has equal X coordinates and Y coordinates to z(the bad guy), it will send this message and confirm that the two have, in fact, collided. If you can make it inherent in the actual class behind z to check if the coordinates a equal, you can create an unlimited number of in-game objects that detect collision and react in the same way, i.e. walls.

This is probably what your looking for. I've made this class spicificly for collision of multiple objects and for individual side collisions.
abstract class Entity {
private Line2D topLine;
private Line2D bottomLine;
private Line2D leftLine;
private Line2D rightLine;
private Rectangle rectangle;
private Entity entity;
protected boolean top;
protected boolean bottom;
protected boolean left;
protected boolean right;
protected int x;
protected int y;
protected int width;
protected int height;
public Entity(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
updateLinesAndRects();
}
public void updateLinesAndRects() {
topLine = new Line(x + 1, y, width - 2, 0);
bottomLine = new Line(x + 1, y + height, width - 2, height);
leftLine = new Line(x, y + 1, 0, height - 2);
rightLine = new Line(x + width, y + 1, 0, height - 2);
rectangle = new Rectangle(x, y, width, height)
}
public void setCollision(Entity entity) {
this.entity = entity;
top = isColliding(new Line2D[]{topLine, bottomLine, leftLine, rightLine});
bottom = isColliding(new Line2D[]{bottomLine, topLine, leftLine, rightLine});
left = isColliding(new Line2D[]{leftLine, topLine, bottomLine, rightLine});
right = isColliding(new Line2D[]{rightLine, topLine, bottomLine, leftLine});
}
public void updateBounds() {
if(top) y = entity.y + entity.height;
if(bottom) y = entity.y - height;
if(left) x = entity.x + entity.width;
if(right) x = entity.x - width;
}
public boolean isColliding() {
return rectangle.intersects(entity.rect);
}
private boolean isLinesColliding(Line2D[] lines) {
Rectangle rect = entity.getRectangle();
return lines[0].intersects(rect) && !lines[1].intersects(rect) && !lines[2].intersects(rect) && !lines[3].intersects(rect);
}
private Line2D line(float x, float y, float width, float height) {
return new Line2D(new Point2D.Float(x, y), new Point2D.Float(x + width, x + height));
}
public Rectangle getRectangle() {
return rectangle;
}
}
Example:
class Player extends Entity{
Entity[] entities;
public Player(int x, int y, int width, int height) {
super(x, y, width, height);
}
public void update() {
updateLinesAndRects();
for(Entity entity : entities) {
setCollision(entity);
if(top) system.out.println("player is colliding from the top!");
if(isColliding()) system.out.println("player is colliding!");
updateBounds(); // updates the collision bounds for the player from the entities when colliding.
}
}
public void setEntities(Entity[] entities) {
this.entities = entities;
}
}

Related

Processing - Add hitTest and mousePressed to an Animation with 100 balls

I want to create an ArrayList of ball objects, which should be in a loop until there are 100 pieces.
Now my problem: I must implement a function hitTest, so that when you click on a ball it gets removed. In the same position, there should appear two balls then, which go into a different direction.
Can someone help me? I am so lost...
Here's my code so far:
Ball b;
ArrayList<Ball> balls;
void setup() {
size(800, 800);
balls = new ArrayList<Ball>();
for (int i = 0; i<100; i++) {
drawBall();
}
}
void draw() {
background(255);
//b.update();
for (int i= 0; i<balls.size(); i++) {
balls.get(i).update();
}
}
void drawBall() {
Ball b = new Ball();
balls.add(b);
}
class Ball {
private float x;
private float y;
private float ballSize;
private float dirX;
private float dirY;
private boolean moving = true;
Ball() {
this.x = width/2;
this.y = height/2;
this.ballSize = random(10.0, 30.0);
this.dirX = random(-3.0, 3.0);
this.dirY = random(-3.0, 3.0);
if (this.dirX<1.0 && this.dirX>1.0) //1 statt -1 macht zufälliger { this.dirX = 1.0; }
if (this.dirY<1.0 && this.dirY>1.0) {
this.dirY = 1.0;
}
}
public void update() {
stroke(255);
fill(random(255), random(255), random(255), random(255));
ellipse( this.x, this.y, this.ballSize, this.ballSize);
if (this.moving == true) {
this.x += this.dirX;
this.y += this.dirY;
}
if (this.x+ this.ballSize/2> width ||this.x- this.ballSize/2<0) {
this.dirX= dirX*-1;
}
if (this.y+ this.ballSize/2> height ||this.y- this.ballSize/2<0) {
this.dirY= dirY*-1;
}
}
}
Break your problem down into smaller, simpler steps.
e.g.
when you click on a ball, it gets removed. In the same position, there should appear two balls then, which go into a different direction.
when you click on a ball: you can mix the dist() function (to check if the distance between the mouse and a ball is smaller then the radius) with mouseClicked() (or mousePressed() / mouseReleased())
it gets removed: you already called balls.add(). Similarly you can call balls.remove() passing the ball object or index to remove (depending on the case)
same position: you need to remember (store the coordinates) of the ball that was clicked to add two balls at the same position
different direction: you already do that in the Ball() constructor: you can apply the same logic on each new ball.
Here's a basic sketch to illustrate point 1, using dist():
void draw(){
background(255);
int ballX = 50;
int ballY = 50;
int ballRadius = 35;
if(dist(ballX, ballY, mouseX, mouseY) < ballRadius){
fill(0,192,0);
}else{
fill(192,0,0);
}
ellipse(ballX,ballY, ballRadius * 2, ballRadius * 2);
}
Paste this in a new sketch, run it and you should get the hang of using dist() in the context of your problem.
Regarding points 2,3,4 here's a modified version of your sketch with comments and a slightly different approach: instead of removing a ball to add a new one at the exact location with a different direction, simply randomise the direction. Visually it will look similar to a new ball (except the random size/colour). With the clicked ball being re-used, only a second one is added:
Ball b;
ArrayList<Ball> balls;
void setup() {
size(800, 800);
balls = new ArrayList<Ball>();
for (int i = 0; i<100; i++) {
drawBall();
}
}
void draw() {
background(255);
//b.update();
for (int i= 0; i<balls.size(); i++) {
// pass the mouse coordinates to each ball to check if it's hovered or not
balls.get(i).update(mouseX, mouseY);
}
}
// on mouse pressed
void mousePressed(){
for (int i= 0; i<balls.size(); i++) {
// make current ball reusable in this loop
Ball ball = balls.get(i);
// if ball is hovered
if(ball.isHovered){
// randomize direction of current ball
ball.setRandomDirection();
// add a new ball from the current location
balls.add(ball.copy());
}
}
}
void drawBall() {
Ball b = new Ball();
balls.add(b);
}
class Ball {
private float x;
private float y;
private float ballSize;
private float dirX;
private float dirY;
private boolean moving = true;
private color fillColor;
// property to keep track if the ball is hovered or not
private boolean isHovered;
Ball() {
this.x = width/2;
this.y = height/2;
this.ballSize = random(10.0, 30.0);
this.setRandomDirection();
this.fillColor = color(random(255), random(255), random(255), random(255));
}
// extract random direction calls into a re-usable function (handy for click / collision)
void setRandomDirection(){
this.dirX = random(-3.0, 3.0);
this.dirY = random(-3.0, 3.0);
if (this.dirX<1.0 && this.dirX>1.0) { //1 statt -1 macht zufälliger { this.dirX = 1.0; }
if (this.dirY<1.0 && this.dirY>1.0) {
this.dirY = 1.0;
}
}
}
public void update(int x, int y) {
// euclidean distance between this ball's coordinates a given x y position (e.g. mouse)
isHovered = dist(this.x, this.y, x, y) < this.ballSize / 2;
// optional: use stroke color to visually display highlighted ball
if(isHovered){
stroke(0);
}else{
stroke(255);
}
fill(fillColor);
ellipse( this.x, this.y, this.ballSize, this.ballSize);
if (this.moving == true) {
this.x += this.dirX;
this.y += this.dirY;
}
if (this.x + this.ballSize / 2 > width ||
this.x - this.ballSize / 2 < 0) {
this.dirX= dirX*-1;
}
if (this.y + this.ballSize / 2 > height ||
this.y - this.ballSize / 2 < 0) {
this.dirY= dirY*-1;
}
}
// utility function: simply copies this ball's x,y position to the new one
Ball copy(){
Ball clone = new Ball();
clone.x = this.x;
clone.y = this.y;
return clone;
}
}
The copy() method is flexible enough that it's ease to remove one ball to add two more if that is an absolute must. For example:
// on mouse pressed
void mousePressed(){
for (int i= 0; i<balls.size(); i++) {
// make current ball reusable in this loop
Ball ball = balls.get(i);
// if ball is hovered
if(ball.isHovered){
// add two new balls from the current location
balls.add(ball.copy());
balls.add(ball.copy());
// remove ball
balls.remove(i);
}
}
}

Changing height of texture makes texture appear above the ground

I want to change the height of my texture to a random height (with a specified range), and I almost figured out how, but the problem I have is that the texture (tower) is now above the ground. I want to stretch the texture while it remains on the same position, but changes height length.
I have a Tower class and a Scrollable class. In the Tower class I generate a random height in the reset method, but the problem is that I don't know what exactly I have to add or write to put the texture on the correct position (so that it isn't above the ground).
Here is the Tower class:
public class Tower extends Scrollable {
private Random r;
// When Tower's constructor is invoked, invoke the super (Scrollable)
// constructor
public Tower(float x, float y, int width, int height, float scrollSpeed) {
super(x, y, width, height, scrollSpeed);
// Initialize a Random object for Random number generation
r = new Random();
}
#Override
public void reset(float newX) {
// Call the reset method in the superclass (Scrollable)
super.reset(newX); // newX
// Change the height to a random number
Random r = new Random();
int low = 0;
int high = 15;
int result = r.nextInt(high-low) + low;
height = result;
}
}
And here's the Scrollable class:
public class Scrollable {
protected Vector2 position;
protected Vector2 velocity;
protected int width;
protected int height;
protected boolean isScrolledLeft;
public Scrollable(float x, float y, int width, int height, float scrollSpeed) {
position = new Vector2(x, y);
velocity = new Vector2(scrollSpeed, 0);
this.width = width;
this.height = height;
isScrolledLeft = false;
}
public void update(float delta) {
position.add(velocity.cpy().scl(delta));
// If the Scrollable object is no longer visible:
if (position.x + width < 0) {
isScrolledLeft = true;
}
}
// Reset: Should Override in subclass for more specific behavior.
public void reset(float newX) {
position.x = newX;
isScrolledLeft = false;
}
public boolean isScrolledLeft() {
return isScrolledLeft;
}
public float getTailX() {
return position.x + width;
}
public float getX() {
return position.x;
}
public float getY() {
return position.y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
Maybe it's important to know that I have a GameRenderer class which has a drawTowers() method, which is then used in a render() method.
That's my drawTowers() method:
private void drawTowers() {
batcher.draw(AssetLoader.texture1, tower1.getX(), tower1.getY() + tower1.getHeight(),
tower1.getWidth(), midPointY - (tower1.getHeight()));
batcher.draw(AssetLoader.texture2, tower2.getX(), tower2.getY() + tower2.getHeight(),
tower2.getWidth(), midPointY - (tower2.getHeight()));
batcher.draw(AssetLoader.texture3, tower3.getX(), tower3.getY() + tower3.getHeight(),
tower3.getWidth(), midPointY - (tower3.getHeight()));
batcher.draw(AssetLoader.texture4, tower4.getX(), tower4.getY() + tower4.getHeight(),
tower4.getWidth(), midPointY - (tower4.getHeight()));
}
You are drawing the tower too high, you need to be adding half the height rather than the whole height.
Here in drawTowers():
batcher.draw(AssetLoader.texture1, tower1.getX(), tower1.getY() + tower1.getHeight() / 2, tower1.getWidth(), midPointY - (tower1.getHeight()));
Do the same for the other towers.
This may not be perfectly correct but it shouldn't be far off.

Implementing pixel-perfect collision - Libgdx

I just started learning game programming through the libgdx framework and I am at the collision detection stage of development. I made a pretty simple game that has some basic bounding-box collision detection system. However, I want to implement pixel-perfect collision for accuracy.
I will be showing snippets of code that I think are important to help you understand what is going on.
A two-dimensional array is created to define the position of the tiles on the screen:
int[][] map = {
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,1,1,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,1,1,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
};
This create() method from my main game class adds a player and three entities to an ArrayList of type Entity.
#Override
public void create () {
batch = new SpriteBatch();
tileTexture = new Texture("block.png");
screenWidth = Gdx.graphics.getWidth();
screenHeight = Gdx.graphics.getHeight();
// add some entities including a player
entities.add(new Player(this, 100, 150, 20, 20, 120.0f, new Texture("player.png")));
entities.add(new Entity(this, 50, 150, 20, 20, 120.0f, new Texture("enemy.png")));
entities.add(new Entity(this, 200, 200, 20, 20, 120.0f, new Texture("enemy.png")));
entities.add(new Entity(this, 180, 50, 20, 20, 120.0f, new Texture("enemy.png")));
}
The render() method draws the tile map and the entities when the game is run. Another class named Entity holds the data of a particular entity (can be a block/player). The data can be the x and y position of that entity.
// draw tile map
// go over each row bottom to top
for(int y = 0; y < mapHeight; y++) {
// go over each column left to right
for(int x = 0; x < mapWidth; x++) {
// tile
if(map[x][y] == 1) {
batch.draw(tileTexture, x * tileSize, y * tileSize);
}
}
}
// draw all entities
for(int i = entities.size() - 1; i >= 0; i--) {
Entity e = entities.get(i);
batch.draw(e.texture, e.x, e.y);
}
This produces:
To check for collision when the player (green block) moves, I have two methods that check if the player is colliding with an entity or a tile.
The tileCollision() method:
public boolean tileCollision(Entity e, Direction direction, float newX, float newY) {
boolean collision = false;
// determine affected tiles
int x1 = (int) Math.floor(Math.min(e.x, newX) / tileSize);
int y1 = (int) Math.floor(Math.min(e.y, newY) / tileSize);
int x2 = (int) Math.floor((Math.max(e.x, newX) + e.width - 0.1f) / tileSize);
int y2 = (int) Math.floor((Math.max(e.y, newY) + e.height - 0.1f) / tileSize);
// tile checks
for(int x = x1; x <= x2; x++) {
for(int y = y1; y <= y2; y++) {
if(map[x][y] == 1) {
collision = true;
e.tileCollision(map[x][y], x, y, newX, newY, direction);
}
}
}
return collision;
}
The line of code e.tileCollision(map[x][y], x, y, newX, newY, direction); in this method calls the tileCollision() method in the Entity class that prints the position of where the block collides with a tile.
To check collisions between entities, we have this method:
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);
// we don't want to check for collisions between the same entity
if(e1 != e2) {
// axis aligned rectangle rectangle collision detection
if(newX < e2.x + e2.width && e2.x < newX + e1.width &&
newY < e2.y + e2.height && e2.y < newY + e1.height) {
collision = true;
e1.entityCollision(e2, newX, newY, direction);
}
}
}
return collision;
}
NOTE: The green block can move across an entity but cannot go through tiles. This is because the line e1.entityCollision(e2, newX, newY, direction); calls the entityCollision() method in the class Entity that lets the green block move.
This type of collision detection seems basic and inefficient (time complexity of O(n^2)).
How do I implement pixel-perfect collision in this context?
Additional question: If I want to improve the efficiency, what collision detection system can I use to eliminate unnecessary checks?

Java Test if circles overlap

I have a program to draw 20 circles w/ random rad x and y. After, I need to test which circles are overlapping and if they are, set them cyan, if not set them black. heres what I have so far, the problem, is it always sets it to cyan overlapping or not.
public class AppletP5 extends JApplet{
MyCircle[] circle = new MyCircle[20];
public AppletP5(){
for(int i = 0; i<20; i++){
int x0= (int) (Math.random()*500);
int y0= (int) (Math.random()*500);
int rad0= (int) (30 + Math.random()*70);
circle[i] = new MyCircle(x0,y0,rad0);
}
}
public void paint(Graphics g){
for(int i = 0; i<20; i++){
if(circle[i].isOverlapping(circle) == true){
g.setColor(Color.CYAN);
g.drawOval(circle[i].x,circle[i].y,circle[i].rad*2,circle[i].rad*2);
} else if(circle[i].isOverlapping(circle) == false){
g.setColor(Color.BLACK);
g.drawOval(circle[i].x,circle[i].y,circle[i].rad*2,circle[i].rad*2);
}
}
}
}
public class MyCircle {
protected int x, y, rad;
public MyCircle(int x, int y, int rad){
this.x = x;
this.y = y;
this.rad = rad;
}
public boolean isOverlapping(MyCircle[] circles){
for(MyCircle c : circles){
if(Math.pow(c.rad - rad , 2) >= Math.sqrt(Math.pow(x - c.x, 2) + Math.pow(y - c.y , 2))){
return true;
}
}
return false;
}
}
You need to exclude the current Circle from the comparison, since a circle trivially overlaps itself.
You could go with an easy check as long as you just have one instance of each Circle:
for (MyCirlce c : circles) {
if (c != this && ...)
In addition you are checking if the difference of radii between two circles squared by two is greater than the distance of the two centres? Shouldn't you check for the sum of the radii, eg:
r1 + r2 <= distance(c1, c2)
isOverLapping is incorrect implemented.
Two circles intersect, if the distance between their centers is smaller than the sum of their radii. So:
int radSum = c.rad + rad;
int radDif = c.rad - rad;
int distX = c.x - x + radDif;
int distY = c.y - y + radDif;
if(radSum * radSum < distX * distX + distY * distY)
return true;
Apart from that you'll have to ensure you don't compare a circle with itself. And finally: Math.pow is rather costly, so replace it with the simpler version, if you only want the square of a number.

Java Mario game collision between enemy and blocks

I'm begginer in java game programming and I have a small actually big problem (for me) with game.
I'm trying making collision between enemy and blocks it doesnt work and i dont know why. It should worked but it just slow game on one fps per second and dont do anything.
I have main class called Game
with this main Init() function
public void init(){
WIDTH = getWidth();
HEIGHT = getHeight();
tex = new Texture();
BufferImageLoader loader = new BufferImageLoader();
level = loader.loadImage("/level.png"); // loading level
cloud = loader.loadImage("/cloud.png"); // loading clouds
handler = new Handler();
cam = new Camera(0,0);
LoadImageLevel(level);
this.addKeyListener(new KeyInput(handler));
}
and than LoadImageLevel function where I read level.png pixel by pixel and by the differents color I'm setting position of every objects.
private void LoadImageLevel (BufferedImage image){
int w = image.getWidth();
int h = image.getHeight();
//System.out.println(w + " , " + h);
for(int xx = 0; xx < h; xx++){
for(int yy = 0; yy < w ; yy++){
int pixel = image.getRGB(xx, yy);
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
if(red == 255 && green == 255 && blue == 255)
handler.addObject(new Block(xx*32,yy*32,1,ObjectId.Block));
if(red == 0 && green == 0 && blue == 255)
handler.addObject(new Player(xx*32,yy*32,1,handler,ObjectId.Player));
if(red == 0 && green == 255 && blue == 0)
handler.addObject(new Enemy(xx*32,yy*32,handler,ObjectId.Enemy));
}
}
}
In class Player is two important functions tick and collision where in tick is collison called.
public class Player extends GameObject{
private float width = 32, // 48
height = 64; // 96
private float gravity = 0.5f;
private final float MAX_SPEED = 10;
private int facing = 1;
private int last = 0; // last position left or right
private Handler handler;
Texture tex = Game.getInstance();
private int type;
private Animation playerWalk, playerWalkLeft,jump;
public Player(float x, float y,int type , Handler handler ,ObjectId id) {
super(x, y, id);
this.handler = handler;
this.type = type;
playerWalk = new Animation(2,tex.player[2],tex.player[3],
tex.player[4],tex.player[5]);
playerWalkLeft = new Animation(2,tex.player[7],tex.player[8],
tex.player[9],tex.player[10]);
jump = new Animation(2,tex.player[11],tex.player[12]);
}
public void tick(LinkedList<GameObject> object) {
x += velX;
y += velY;
if(velX < 0) facing = -1;
else if(velX > 0) facing = 1;
if(falling || jumping){
velY += gravity;
if(velY > MAX_SPEED){
velY = MAX_SPEED;
}
}
Collision(object);
//System.out.println(velX + " " + velY);
playerWalk.runAnimation();
playerWalkLeft.runAnimation();
jump.runAnimation();
}
private void Collision(LinkedList<GameObject> object){
for(int i = 0; i < handler.object.size();i++){
GameObject tempObject = handler.object.get(i);
if(tempObject.getId() == ObjectId.Block ){
if(getBoundsTop().intersects(tempObject.getBounds())){
y = tempObject.getY() + 32;
velY = 0;
}
if(getBounds().intersects(tempObject.getBounds())){
y = tempObject.getY() - height;
velY = 0;
falling = false;
jumping = false;
}else
falling = true;
if(getBoundsRight().intersects(tempObject.getBounds())){
x = tempObject.getX() - width;
}
if(getBoundsLeft().intersects(tempObject.getBounds())){
x = tempObject.getX() + 35;
}
}
/* new */
}
}
public void render(Graphics g) {
/*
g.setColor(Color.blue);
g.fillRect((int)x,(int)y,(int)width,(int)height);
Graphics2D g2d = (Graphics2D) g;
g.setColor(Color.red);
g2d.draw(getBounds());
g2d.draw(getBoundsRight());
g2d.draw(getBoundsLeft());
g2d.draw(getBoundsTop());
*/
if(velX != 0){
if (facing == 1){
playerWalk.drawAnimation(g,(int) x, (int)y,32,64);
last = 1;
}
else{
playerWalkLeft.drawAnimation(g,(int) x, (int)y,32,64);
last = 0;
}
}
else
if (last == 1)
g.drawImage(tex.player[1], (int)x,(int) y,32,64,null);
else
g.drawImage(tex.player[6], (int)x,(int) y,32,64,null); // 6 ,32,64
//System.out.println("Y: " + y); // 513 je max
if (y >= 513){
g.setColor(Color.red);
g.drawString("Game Over", (int) x, 200);
}
}
public Rectangle getBounds() {
return new Rectangle((int) ((int)x+(width/2)-((width/2)/2)),(int) ((int)y+(height/2)),(int)width/2,(int)height/2);
}
public Rectangle getBoundsTop() {
return new Rectangle((int) ((int)x+(width/2)-((width/2)/2)),(int)y,(int)width/2,(int)height/2);
}
public Rectangle getBoundsRight() {
return new Rectangle((int) ((int)x+width-5),(int)y+5,(int)5,(int)height-10);
}
public Rectangle getBoundsLeft() {
return new Rectangle((int)x,(int)y+5,(int)5,(int)height-10);
}
Player dont have any problem with block collision.
public class Block extends GameObject {
Texture tex = Game.getInstance();
private int type;
public Block(float x, float y,int type,ObjectId id) {
super(x, y, id);
this.type = type;
}
public void tick(LinkedList<GameObject> object) {
}
public void render(Graphics g) {
if(type == 0)
g.drawImage(tex.block[0], (int) x, (int) y ,null);
if(type == 1)
g.drawImage(tex.block[1], (int) x, (int) y ,null);
}
public Rectangle getBounds() {
return new Rectangle((int)x,(int)y,32,32);
}
}
But when i tried created Enemy class and make it same like in Player class I mean collision it just make game slower and nothing else.
public class Enemy extends GameObject{
private Handler handler;
public Enemy(float x, float y,Handler handler, ObjectId id) {
super(x, y, id);
this.handler = handler;
}
public void tick(LinkedList<GameObject> object) {
for(int i = 0; i < handler.object.size();i++){
GameObject tempObject = handler.object.get(i);
if(tempObject.getId() == ObjectId.Block ){
if(getBoundsTop().intersects(tempObject.getBounds())){
}
if(getBounds().intersects(tempObject.getBounds())){
}
if(getBoundsRight().intersects(tempObject.getBounds())){
}
if(getBoundsLeft().intersects(tempObject.getBounds())){
}
}
}
}
public void render(Graphics g) {
g.setColor(Color.red);
g.fillRect((int)x,(int) y, 32, 32);
}
public Rectangle getBoundsTop() {
return new Rectangle((int)x,(int)y,32,32);
}
public Rectangle getBoundsLeft() {
return new Rectangle((int)x,(int)y,32,32);
}
public Rectangle getBoundsRight() {
return new Rectangle((int)x,(int)y,32,32);
}
public Rectangle getBounds() {
return new Rectangle((int)x,(int)y,32,32);
}}
I know that bounds should not have return same "new Rectangle" and that theres no any movements of enemy anyway when i set in tick method x--; for just trying if enemy stop when it come to the edge of block but it doesnt work i dont know whats wrong with it i spend more than two days with fixing this. If it can help you there is a link for whole project (Eclipse) You can download it from dropbox
I just wanted to have an enemy which move left and right and have collison with block it means when he "touch" by his left side to the block he "turn around" and move to right side until he "touch" by his right side etc... other collisions between Player and Enemy is not problem for me. But just this.
I'm so thankful for every advice :)
The problem is with your getBounds() method.
You are saying in getBounds() method to return a rectangle with width=32 and height=32. And since your rectangle is 32 by 32 (as mentioned in fillrect(x,y,32,32) ) so getBounds() returns with the intersection in height and width.
In other words, try not to collide the returned Top left bottom or right bounds with themselves.
And in enemy(), you are declaring set.color = red while in loading you are using green. Try red==255, green==0, blue==0 instead of if(red == 0 && green == 255 && blue == 0)

Categories