preface

So far, we’ve probably been able to make a little game like Google Dinosaur, but when it comes to the real thing: How do you detect collisions between dinosaurs and obstacles? Won’t you? Collision detection is complicated. Why build your own wheels? No, no, no, libGDX itself provides a collision detection method: using com. Badlogic. Etf has. Math. A Rectangle class.

Rectangle collision Detection

– Rectangle() : Creates an empty Rectangle with coordinates of 0 and width. – Rectangle(Rect) : creates an empty Rectangle with coordinates of 0 and width. Rectangle(float x,float y,float width,float height) : Create a Rectangle(x,y) with width*height

Use a Rectangle DE

The Rectangle class contains various operations on rectangles:

// Set the coordinates
rect.setX(x);
rect.x=x;
rect.setY(y);
rect.y=y;
rect.setPosition(x,y);
// Set the size
rect.setWidth(width);
rect.width=width;
rect.setHeight(height);
rect.height=height;
rect.setSize(width,height);

rect.setBounds(x,y,width,height);

// Get the property's abbreviated......
Copy the code

Rectangle also has the same collision detection method as described above:

// Check whether the point at (x,y) is inside the rectangle
boolean isContains=rect.contains(x,y);
/ / vec2 is com badloc. Etf has. Math. Vector2 variables, also said a coordinates
isContains=rect.contains(vec2);
// Check that rect2(Rectangle) is completely inside the Rectangle
isContains=rect.contains(rect2);
// Check whether rect and rect2 are exactly the same (size, coordinates)
isEquals=rect.equals(rect2);
// Check whether rect and rect2 overlap.
isOverlaps=rect.overlaps(rect2);
Copy the code

Depth of collision detection

In the game, a lot of objects don’t die on impact, more of them just intercept, i.e. crash boxes, but libGDX doesn’t provide crash boxes, so we need to build wheels.

The purpose of the collision box is to make two Rectangle objects cannot overlap, so we only need to find the depth of the collision between two Rectangle objects, and then move one Rectangle according to the depth to achieve the collision box, just two methods:

// Check the collision y depth
public float testCollisionHeight(Rectangle rect,Rectangle otherRect) {
    if(! (rect.overlaps(otherRect)))return 0;    // There is no contact
    
    if(rect.y>otherRect.y)
        / / this on
        return ( ( otherRect.height + otherRect.y ) - rect.y );
    else
        / / this next
        return  - ( ( rect.height + rect.y ) - otherRect.y ) ;
}
    
// Check collision x depth
public float testCollisionWidth(Rectangle rect,Rectangle otherRect) {
    if(! (rect.overlaps(otherRect)))return 0;    // There is no contact
    
    if(rect.x>otherRect.x)
        / / this is right
        return  ( ( otherRect.width + otherRect.x ) - rect.x );
    else
        / / this on the left
        return -( ( rect.width + rect.x ) - otherRect.x );
}
Copy the code

The above two methods return how much rect should move toward X and y (plus), that is, rect is passive, such as the boxes that can be pushed in the game, etc., while otherRect is active, such as the role pushing the boxes, etc.

Example: Push each other

To test if they really work, let’s take an example: download this image, name it badlogic.png and put it in the asset folder

package com.libGDX.test;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;

// Apply the main class
public class Test extends ApplicationAdapter {
    private SpriteBatch batch;
    // Raw texture
    private Texture texture;
    // Sprites on the left and right
    private Sprite left;
    private Sprite right;
    // Priority, whether left priority
    private boolean before;
    @Override
    public void create(a) {
        batch=new SpriteBatch();
        // Load the texture
        texture=new Texture(Gdx.files.internal("badlogic.png"));
        
        // Create Sprite from texture
        left=new Sprite(texture);
        right=new Sprite(texture);
        
        // Set the size and position
        left.setBounds(0.200.100.100);
        right.setBounds(400.200.100.100);
        
        / / the left is preferred
        before=true;
    }
    
    @Override
    public void render(a) {
        // White clear screen
        Gdx.gl.glClearColor(1.1.1.1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        / / etf has. Graphics. GetDeltaTime () is the time increment
        act(Gdx.graphics.getDeltaTime());
        
        batch.begin();
        / / draw the Sprite
        left.draw(batch);
        right.draw(batch);
        batch.end();
    }
    
    // Update the status
    private void act(float delta) {
        // Click to reverse the priority
        if(Gdx.input.justTouched())before=! before;/* Move left and right, multiply the distance by the incremental time, * to ensure that you can move the distance per second regardless of performance (frame rate) */
        left.setX(left.getX()+100*delta);
        right.setX(right.getX()-100*delta);
        
        if(before)
            Sprite's getBoundRectangle() method returns a Rectangle */ based on its own size
            right.setX(right.getX()+testCollisionWidth(right.getBoundingRectangle(), left.getBoundingRectangle()));
        else 
            / / right priority
            left.setX(left.getX()+testCollisionWidth(left.getBoundingRectangle(),right.getBoundingRectangle()));
    
    
    // Check the collision y depth
    public float testCollisionHeight(Rectangle rect,Rectangle otherRect) {
        if(! (rect.overlaps(otherRect)))return 0;    // There is no contact
        
        if(rect.y>otherRect.y)
            / / this on
            return ( ( otherRect.height + otherRect.y ) - rect.y );
        else
            / / this next
            return  - ( ( rect.height + rect.y ) - otherRect.y ) ;
    }
    
    // Check collision x depth
    public float testCollisionWidth(Rectangle rect,Rectangle otherRect) {
        if(! (rect.overlaps(otherRect)))return 0;    // There is no contact
        
        if(rect.x>otherRect.x)
            / / this is right
            return  ( ( otherRect.width + otherRect.x ) - rect.x );
        else
            / / this on the left
            return -( ( rect.width + rect.x ) - otherRect.x );
    }
    @Override
    public void dispose(a){
        batch.dispose();
        texture.dispose();
    }
Copy the code

Running results:

Example: Little dinosaur dodges obstacles

How could you not do something with six batches like that? So, let’s do a small dinosaur to avoid obstacles (similar to Google small dinosaurs) of the small game! Download the following two images named dinasour. PNG and cacti.png and place them in the asset folder

Create a data folder under your project and add scoremax. TXT:

package com.libGDX.test;
import java.util.Random;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Array;

// Apply the main class
public class Test extends ApplicationAdapter {
    private SpriteBatch batch;
    / / texture
    private Texture cactiTexture;
    private Texture dinasourTexture;
    private Array<Sprite> cactis;    / / the cactus
    private Sprite dinasour;    / / small dinosaur
    private Random r;    // Random number generation instance
    private int time;    // add time
    private int jump;    // Jump height
    private int score;    // Match score
    private FileHandle scoreFile;    // The.txt file that stores the score
    private BitmapFont font;    // Bitmap font
    private int maxScore;    // The highest score ever
    // The world is wide and high
    public final int WORLD_WIDTH=500;    
    public final int WORLD_HEIGHT=200;
    
    @Override
    public void create(a) {
        batch=new SpriteBatch();
        // Load the texture
        cactiTexture=new Texture(Gdx.files.internal("cacti.png"));
        dinasourTexture=new Texture(Gdx.files.internal("dinasour.png"));
        cactis=new Array<>();
        dinasour=new Sprite(dinasourTexture);
        
        r=new Random();
        
        // Get the highest score in history, data/ scoremax. TXT score file
        scoreFile=new FileHandle("data/scoreMax.txt");
        String str=scoreFile.readString();
        if(str.equals(""))maxScore=0;    Zero if scoreMax has no content
        else maxScore=Integer.valueOf(str);
        
        font=new BitmapFont();
        font.setColor(Color.BLACK);
        font.getData().setScale(3);
        reset();
    }
    
    @Override
    public void render(a) {
        Gdx.gl.glClearColor(1.1.1.1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        act(Gdx.graphics.getDeltaTime());
        batch.begin();    
        
        for(Sprite s : cactis)
            s.draw(batch);
        
        dinasour.draw(batch);
        font.draw(batch,"UI "+String.valueOf(maxScore)+""+String.valueOf(score),150.170);
        batch.end();
    }
    
    // Reset the property
    private void reset(a) {
        // Set the attributes of the little dinosaur
        dinasour.setBounds(50.0.60.60);
        // Set the maximum score to display
        maxScore=Integer.valueOf(scoreFile.readString());
        // Reset the score to zero
        score=0;
        // Reset no jump
        jump=0;
        // Time is cleared
        time=0;
        // Empty the cactus
        for(int i=cactis.size-1; i>=0;--i) {
            cactis.removeIndex(i);
        }
    }
    
    // Update the game logic
    private void act(float delta) {
        // Total time (*100)
        time+=delta*100;
        // Click to jump
        if(dinasour.getY()==0&&Gdx.input.justTouched())jump=18;
        // Small dinosaur y coordinates change, positive jump, negative drop
        dinasour.setY(dinasour.getY()+jump);
        // If the baby dinosaur doesn't land, keep reducing jump
        if(dinasour.getY()>0)jump-=delta*60;
        else {    // Otherwise, jump to the ground
            dinasour.setY(0);
            jump=0;
        }
        
        // Add one point for every 0.1s(10/100)
        if(time%10= =0)score++;
        
        // Cactus has a 50% chance to refresh every 0.4 seconds
        if(time%40= =0&&r.nextInt(2) = =0) {
            Sprite cacti=new Sprite(cactiTexture);
            // Set the cactus to a height between 40 and 60
            cacti.setBounds(WORLD_WIDTH, 0.50,r.nextInt(20) +40);
            // Add to array
            cactis.add(cacti);
        }
        
        Sprite cacti;
        // Walk through the cactus array
        for(int i=cactis.size-1; i>=0; --i) {// Get cactus
            cacti=cactis.get(i);
            // Move left
            cacti.setX(cacti.getX()-500*delta);
            // If you make contact with a small dinosaur, restart the game
            if(dinasour.getBoundingRectangle().overlaps(cacti.getBoundingRectangle())) {
                // If the current is the highest score, write a new highest score
                if(score>maxScore)scoreFile.writeString(String.valueOf(score),false);
                    reset();
            }
            // Off screen delete cactus
            if(cacti.getX()<0-50) cactis.removeIndex(i); }}@Override
    public void dispose(a) { batch.dispose(); dinasourTexture.dispose(); cactiTexture.dispose(); }}Copy the code

Running results: