2

I have made a very simple 2D Java game class made up of the general 2D game methods such as render and update, I have set up all my if statements so that the player moves around the map with the keyboard arrow input. I am now trying to set up what I have read is a collision detection, I know the basics of what I need to do because I did a lot of reading before I actually came here to ask the question, from what I have read it goes something like this:

Make 2 rectangles

Rectangle rectOne = new Rectangle(playerX, playerY, 40, 40); 
//keep in mind that the variables playerX and playerY are already made previously
Rectangle rectTwo = new Rectangle(50, 50, 100,100);

Then under my update method I would say:

if(rectOne.intersects(rectTwo)){//change the player direction so that he 
can go no further}

I just do not understand what would go inside my if statement, I need something that stops my player from going any further if the intersection occurs but how can I write this because the player can move in 4 different directions (UP, DOWN, LEFT, RIGHT). It would be much simpler if it was just 1 dimensional because I could just change the direction to the opposite of what it was but its two dimensions so it is a bit confusing.

Additional information:

The view my game is played at is similar to the following: http://www.2dplay.com/awesome-tanks/awesome-tanks-play.htm

EDIT 3:

                package javagame;

                import java.awt.Rectangle;

                IMPORTS ARE HERE


public class Play extends BasicGameState{

    Animation bucky, movingUp, movingDown, movingLeft, movingRight;
    Image worldMap;
    boolean quit = false;//gives user to quit the game
    int[] duration = {200, 200};//how long frame stays up for
    int buckyPositionX = 0;
    int buckyPositionY = 0;
    int x = buckyPositionX + 320;//keeps user in the middle of the screem
    int y = buckyPositionY + 160;//the numbers are half of the screen size

    Rectangle rectOne = new Rectangle(x, y,90,90);
    Rectangle rectTwo = new Rectangle(500 + buckyPositionX, 330 + buckyPositionY, 210, 150);



private int xSpeed, ySpeed;///////////////////////////CODE FOR COLLISION


    public Play(int state){
    }   
    public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
          worldMap = new Image("res/world.png");
          Image[] walkUp = {new Image("res/b.png"), new Image("res/b.png")}; //these are the images to be used in the "walkUp" animation
          Image[] walkDown = {new Image("res/f.png"), new Image("res/f.png")};
          Image[] walkLeft = {new Image("res/l.png"), new Image("res/l.png")};
          Image[] walkRight = {new Image("res/r.png"), new Image("res/r.png")};


    movingUp = new Animation(walkUp, duration, false);
    movingDown = new Animation(walkDown, duration, false);  
    movingLeft = new Animation(walkLeft, duration, false);  
    movingRight = new Animation(walkRight, duration, false);

    bucky = movingDown;//facing screen initially on startup
    }


    public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
    worldMap.draw(buckyPositionX, buckyPositionY);//position 0,0
    bucky.draw(x, y);//makes him appear at center of map
    g.fillRect(x, y,90,90);
    g.fillRect(500 + buckyPositionX, 330 + buckyPositionY, 210, 150);


    if(quit==true){
        g.drawString("Resume(R)", 250, 100);
        g.drawString("Main(M)", 250, 150);
        g.drawString("Quit Game(Q)", 250, 200);      
        if(quit==false){
            g.clear();//wipe off everything from screen
        }
    }
    }

public void setSpeedWithDirection(int speed, int direction)////////////CODE FOR COLLISION
{
xSpeed = (int) (Math.cos(direction) * speed);//////////////////////////CODE FOR COLLISION
ySpeed = (int) (Math.sin(direction) * speed);//////////////////////////CODE FOR COLLISION
}

    public void update(GameContainer gc, StateBasedGame sbg, int delta)throws SlickException{
    Input input = gc.getInput();



x += xSpeed;//////////////////////////////////////////CODE FOR COLLISION
y += ySpeed;//////////////////////////////////////////CODE FOR COLLISION

if(rectOne.intersects(rectTwo))///////////////////////CODE FOR COLLISION
{
xSpeed = 0;////////////////////////////CODE FOR COLLISION
ySpeed = 0;////////////////////////////CODE FOR COLLISION
}



    //up
    if(input.isKeyDown(Input.KEY_UP)){
        bucky = movingUp;//changes the image to his back
        buckyPositionY += 2;;//increase the Y coordinates of bucky (move him up)
        if(buckyPositionY>162){//if I reach the top 
            buckyPositionY -= 2;//stops any further movement in that direction
        }
    }

    //down
    if(input.isKeyDown(Input.KEY_DOWN)){
        bucky = movingDown;
        buckyPositionY -= 2;
        if(buckyPositionY<-550){
            buckyPositionY += 2;//basically change the direction if + make -
    }}
    //left
    if(input.isKeyDown(Input.KEY_LEFT)){
        bucky = movingLeft;
        buckyPositionX += 2;
        if(buckyPositionX>324){
            buckyPositionX -= 2;//delta * .1f
    }}
    //right
    if(input.isKeyDown(Input.KEY_RIGHT)){
        bucky = movingRight;
        buckyPositionX -= 2;
        if(buckyPositionX<-776){
            buckyPositionX += 2;
    }}



     //escape
    if(input.isKeyDown(Input.KEY_ESCAPE)){
        quit=true;
    }
    //when the menu is up
    if(quit==true){//is the menu on the screen
        if(input.isKeyDown(Input.KEY_R)){
            quit = false;//resumes the game, makes menu dissapear
        }
        if(input.isKeyDown(Input.KEY_M)){
            sbg.enterState(0);//takes you to the main menu
        }
        if(input.isKeyDown(Input.KEY_Q)){
            System.exit(0);//quits the game
        }
    }

}   


    public int getID(){
        return 1;
    }
}
Rahul Khosla
  • 349
  • 9
  • 21
  • Do you mean the player should 'bounce off' objects? – Martin Wilson Dec 26 '12 at 21:39
  • 1
    You could take a look at [this example](http://stackoverflow.com/questions/13261767/java-ball-object-doesnt-bounce-off-of-drawn-rectangles-like-its-supposed-to/13263022#13263022) which basically uses a collision detection process to determine in which directions that object should move away from the obstacle based it's current direction of movement. – MadProgrammer Dec 26 '12 at 21:49

2 Answers2

4

As a prerequisite, your player class (or one of its superclasses) should have a few fields describing their speed (a pair of fields for x-speed and y-speed works very well, although you'll need trig to set the player in a given direction). Here is an example of a simple player class with x- and y-speed fields:

public class Player
{
     //coordinates of the player 
     private int x, y;

     //horizontal and vertical components of the player's speed.
     private int xSpeed, ySpeed; 

     //call a method similar to this one every time your player updates its position
     public void updatePosition()
     {
          x += xSpeed;
          y += ySpeed;
     }

     //Converts a speed and a direction (much easier to deal with)
     //to an x speed and a y speed (much easier for actually moving) 
     //and sets the player's motion
     public void setSpeedWithDirection(int speed, float direction)
     {
         xSpeed = Math.cos(direction) * speed;
         ySpeed = Math.sin(direction) * speed;
     }
}

In order for this to actually reflect your player's speed, add the x-speed to the player's x-coordinate every and add the y-speed to the player's y-coordinate every time the player updates. Now, there are a lot of things that could happen when the collision occurs. The simplest one is to stop the player by setting its x-speed and y-speed to zero. However, this can look glitchy as the player will stop moving regardless of what direction they are going in. A slightly better approach is to analyze the shape of the intersection (assuming you're using java.awt.Rectangle you can use the intersection() method, pretty much all Rectangle classes have something similar) and determine whether the x-speed, y-speed, or both should be set to zero. For instance, if the intersection is wider than it is tall (larger in the x-axis than the y-axis), you should probably set the y-speed to zero but but the x-speed unaffected. If you want the player to turn around (180 degrees), simply flip the sign of x-speed and y-speed. If you want the player to "bounce" instead of stop, analyze the intersection just as in the previous case but reverse the speed rather than set it to zero. Here are a few code examples (probably won't work exactly as written because I don't know how your classes are set up):

//simple stop
if(rectOne.intersects(rectTwo))
{
    player.xSpeed = 0;
    player.ySpeed = 0;
}

//variable-axis stop
if(rectOne.intersects(rectTwo))
{
    //depending on Rectangle implementation may need to use other method
    Rectangle overlap = rectOne.intersection(rectTwo);
    if (overlap.height >= overlap.width)
    {
        player.xSpeed = 0;
    }
    if (overlap.width >= overlap.height)
    {
        player.ySpeed = 0;
    }
}

//simple turn-around (about face)
if(rectOne.intersects(rectTwo))
{
    player.xSpeed *= -1;
    player.ySpeed *= -1;
}

//bounce (variable-axis turn around)
if(rectOne.intersects(rectTwo))
{
    Rectangle overlap = rectOne.intersection(rectTwo);
    if (overlap.height >= overlap.width)
    {
        player.xSpeed *= -1;
    }
    if (overlap.width >= overlap.height)
    {
        player.ySpeed *= -1;
    }
}

Note that regardless of what you choose to do collisions tend to be very difficult to get working smoothly. I would consider all of these options good starting points that could always be built upon. I hope this helps.

ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79
  • Thank you for taking the time to write me a detailed reply, I understand the basics behind the code for the collisions you have written but as I am new to Java I am a bit confused on exactly how to set up my xSpeed and ySpeed, could you please help me with this? – Rahul Khosla Dec 29 '12 at 22:20
  • @RahulKhosla Edited to include example of such a setup. – ApproachingDarknessFish Dec 30 '12 at 00:18
  • Thank you for helping me by giving me an example, I have tried to use your code to create a collision in my game but am getting an error, I added the private variables to my code, I have made the setSpeedWidthDirection method and have assumed that the code in update position and the if statement can go under my update method that already exists in my code, I replaced player with my buckyPositionX and buckyPositionY but am getting the following error under where you have got player.xSpeed=0; the error says buckyPositionX does not have a xSpeed field, could you please help me fix this? – Rahul Khosla Dec 30 '12 at 14:32
  • I have posted my code for you to help you see how I have set it up, the code you have helped me with is labelled /////////CODE FOR COLLISION. – Rahul Khosla Dec 30 '12 at 14:33
  • @RahulKhosla Ahh. In your setup the xspeed and yspeed are member variables of the game, not the player. I would recommend creating a new class to represent moving entities in your game, and put my code inside that class rather the game class. Or, if the player is the only thing that moves in your game, you can simply take away the `player.`'s and it should work. Make sure that the player is drawn at `x` and `y` though. – ApproachingDarknessFish Dec 30 '12 at 20:51
  • Thank you for replying, I have only one moving object in my game which is the player and have removed the player. as you suggested and it has cleared the errors which is great but when I try the game there is no collision, the rectangles are definitely in the correct places because I drew them and inspected the position but when they intersect no collision occurs, I have updated the code to show how I removed the player. and was left with xSpeed = 0; and ySpeed = 0;. Could you please help me with this? Also, again I just want to say thank you for being so patient with me. – Rahul Khosla Dec 31 '12 at 03:20
  • Not a problem. Are you sure your rectangles are moving? I don't see their positions being modified after their creation. Also I think your `shiftX` and `shiftY` variables might be unnecessary; do they represent the position of the player? if so, you can either replace them with `x` and `y` respectively or simply get rid of `x` and `y` and replace all occurrences with `shiftX` and `shiftY`. – ApproachingDarknessFish Dec 31 '12 at 22:55
  • The way this is set out is I said buckyPositionX and buckyPositionY are 0,0 so they are the top left corner of the screen and then set ShiftX to buckyPositionX+(half of the width of the screen) and ShiftY to buckyPositionY+(half of the height) so that the player was centered on he screen, so yes ShiftX and ShiftY are the player positions. The movement is controlled on the if statements under the update method, it basically says if up key is pressed for example, buckyPositionY+=2 so add 2 to buckyPositionY to move it, the bigger the intiger(in this example 2) the faster the player moves. – Rahul Khosla Jan 01 '13 at 00:33
  • Continuing from last comment: I did as you said and replaced ShiftX and ShiftY with x and y but still no luck, I am still not getting a collision that stops my 2 rectangles from intersecting. I have updated my code, could you please check it over and help me find the problem? Thank you. – Rahul Khosla Jan 01 '13 at 00:35
0

I suggest creating an enum Way.You should know the Way he is going now, Then just change the Way to the opposite Way,or you can lock the current Way and choose a random Way to go.

Salih Erikci
  • 5,076
  • 12
  • 39
  • 69