I have made a simple 2D state change game using Bucky\'s slick Java tutorials, I modified this game and now want to set collisions on the map so that my player can not go th
if(house.getBounds().contains(player.getX(),player.getY()){//do something}
as long as your house and your player rectangles are defined in different classes, java will be able to tell the difference
create a class first that is a base class for dealing with rectangles:
public class Rectanglebase{
public void getBounds(){//write method}
//write other methods you will need to use for both rectangles here
public Rectanglebase{//default constructor}
}//end class definition
now write classes for the house and player:
public class House extends Rectanglebase{
//getBounds() is inherited, so just write stuff to do with the graphics of the house here
}
when you generate the house in your main code, you can make your own:
House house = new House();
then generate the class for the player in a similar way, then construct in in your main code:
Player player = new Player()
house
and player
are different variables, this is how java will tell the difference between your house and player
Here is an example of a Game Loop / Game Logic and collision detection via Rectangle2D#intersects(..)
method .
It uses JPanel
to draw everything on and Rectangle2D
is used for Entity
class (which is any object needed to be drawn to GamePanel
which is our JPanel where everything is drawn).
The updateGame()
method is where you will find the collision checking:
private void updateGame() {
if (entities.get(0).intersects(entities.get(1))) {
System.out.println("Intersecting");
}
....
}
You are Player 1 and move with W,A,S,D. When you intersect Player 2, a println()
will confirm the intersection.
GameLogic.java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
/**
*
* @author David Kroukamp
*/
public class GameLogic {
public GameLogic() {
initComponents();
}
final GamePanel gp = new GamePanel(500, 500);
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Entity entity1 = new Entity(100, 100, 100, 100, createWhiteImage());
Entity entity2 = new Entity(300, 200, 100, 100, createBlackImage());
gp.addEntity(entity1);
gp.addEntity(entity2);//just a standing still JPanel
setGamePanelKeyBindings(gp, entity1);
frame.add(gp);
frame.pack();
frame.setVisible(true);
//start the game loop which will repaint the screen
runGameLoop();
}
//Starts a new thread and runs the game loop in it.
public void runGameLoop() {
Thread loop = new Thread(new Runnable() {
@Override
public void run() {
gp.running.set(true);
gp.gameLoop();
}
});
loop.start();
}
private void setGamePanelKeyBindings(GamePanel gp, final Entity entity) {
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "D pressed");
gp.getActionMap().put("D pressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.RIGHT = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "A pressed");
gp.getActionMap().put("A pressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.LEFT = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "W pressed");
gp.getActionMap().put("W pressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.UP = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "S pressed");
gp.getActionMap().put("S pressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.DOWN = true;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "D released");
gp.getActionMap().put("D released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.RIGHT = false;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released A"), "A released");
gp.getActionMap().put("A released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.LEFT = false;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"), "W released");
gp.getActionMap().put("W released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.UP = false;
}
});
gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released S"), "S released");
gp.getActionMap().put("S released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
entity.DOWN = false;
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new GameLogic();
}
});
}
private BufferedImage createWhiteImage() {
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, img.getWidth(), img.getHeight());
return img;
}
private BufferedImage createBlackImage() {
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, img.getWidth(), img.getHeight());
return img;
}
}
class Entity extends Rectangle2D.Double {
private int speed = 5;
public boolean UP = false,
DOWN = false,
LEFT = false,
RIGHT = false;
private final BufferedImage image;
public Entity(int x, int y, int width, int height, BufferedImage image) {
super(x, y, width, height);
this.width = width;
this.height = height;
this.image = image;
}
public BufferedImage getImage() {
return image;
}
public void move() {
if (UP) {
y -= speed;
}
if (DOWN) {
y += speed;
}
if (LEFT) {
x -= speed;
}
if (RIGHT) {
x += speed;
}
}
}
class GamePanel extends JPanel {
private int width, height;
private int frameCount = 0;
private int fps = 0;
public static AtomicBoolean running = new AtomicBoolean(false), paused = new AtomicBoolean(false);
final ArrayList<Entity> entities = new ArrayList<>();
GamePanel(int w, int h) {
super(true);
setIgnoreRepaint(true);//mustnt repaint itself the gameloop will do that
setLayout(null);
width = w;
height = h;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void addEntity(Entity e) {
entities.add(e);
}
//Only run this in another Thread!
public void gameLoop() {
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;
//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime / 1000000000);
while (running.get()) {
double now = System.nanoTime();
int updateCount = 0;
if (!paused.get()) {
//Do as many game updates as we need to, potentially playing catchup.
while (now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER) {
updateGame();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if (now - lastUpdateTime > TIME_BETWEEN_UPDATES) {
lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}
drawGame();
lastRenderTime = now;
//Update the frames we got.
int thisSecond = (int) (lastUpdateTime / 1000000000);
if (thisSecond > lastSecondTime) {
System.out.println("NEW SECOND " + thisSecond + " " + frameCount);
fps = frameCount;
frameCount = 0;
lastSecondTime = thisSecond;
}
//Yield until it has been at least the target time between renders. This saves the CPU from hogging.
while (now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES) {
//allow the threading system to play threads that are waiting to run.
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
//On my OS it does not unpuase the game if i take this away
try {
Thread.sleep(1);
} catch (Exception e) {
}
now = System.nanoTime();
}
}
}
}
private void drawGame() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
repaint();
}
});
}
private void updateGame() {
if (entities.get(0).intersects(entities.get(1))) {
System.out.println("Intersecting");
}
for (Entity e : entities) {
e.move();
}
}
@Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
applyRenderHints(g2d);
g2d.setColor(Color.GREEN);
g2d.fillRect(0, 0, getWidth(), getHeight());
for (Entity e : entities) {
g2d.drawImage(e.getImage(), (int) e.getX(), (int) e.getY(), null);
}
g2d.setColor(Color.BLACK);
g2d.drawString("FPS: " + fps, 5, 10);
frameCount++;
}
private final static RenderingHints textRenderHints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
private final static RenderingHints imageRenderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
private final static RenderingHints colorRenderHints = new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
private final static RenderingHints interpolationRenderHints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
private final static RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
public static void applyRenderHints(Graphics2D g2d) {
g2d.setRenderingHints(textRenderHints);
g2d.setRenderingHints(imageRenderHints);
g2d.setRenderingHints(colorRenderHints);
g2d.setRenderingHints(interpolationRenderHints);
g2d.setRenderingHints(renderHints);
}
}