|
||||||
| Java Tutorials Tutorials and Code for Java |
![]() |
|
|
LinkBack | Thread Tools | Search this Thread | Display Modes |
|
|||
|
Double buffering, movement, and collision detection.
Welcome to this exciting Java tutorial!
Those looking to get into game programming with java will likely find this tutorial more interesting than others. This tutorial will cover: Collision detection, movement via keyboard, double buffered animation, and a basic game loop. We are basically going to create a window with swing, actively render two double-buffered rectangles, move them around the screen, and check for collisions between them, all while using a basic game loop. I am going to be as Object Oriented (OO) as I can, so we will be creating a few classes. The very first thing we need to do is get something on the screen. Let's create a window with Swing. I am going to assume that everyone knows at least a little swing. Create a new java class named Gui.java with your favorite ide or editor. I'm a newb, so I use netbeans. ![]() Code:
package collide;
import javax.swing.*;
public class Gui
{
JFrame window;
public Gui()
{
window = new JFrame("Collision detection, movement, double buffering, and a game loop!");
window.setSize(800,600);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
public static void main(String[]args)
{
Gui game = new Gui();
}
}
Go ahead and compile/run. This should pop up a window. If not, check your code and fix it. O.K. good. Next, we need a surface on which to draw and in this case we'll use a JPanel. Go ahead and create another class, name it DrawPanel.java, then add this code: Code:
package collide;
import java.awt.event.*;
import javax.swing.*;
public class DrawPanel extends JPanel implements KeyListener
{
public DrawPanel()
{
setIgnoreRepaint(true);
addKeyListener(this);
setFocusable(true);
}
public void keyTyped(KeyEvent e)
{
}
public void keyPressed(KeyEvent e)
{
}
public void keyReleased(KeyEvent e)
{
}
}
We implement KeyListener to let the JVM know that we are going to be processing keyboard input. KeyListener is an interface, and whenever we implement an interface in java, we must also override all of that interface's methods. In this case, there are only 3, which are: keyTyped(), keyPressed(), and keyReleased(). I am sure you can figure out what they do just by reading their names. We need to do two more things to ensure that our keyListener works, and they are both shown in DrawPanel's constructor. addKeyListener(this) and setFocusable(true). the method addKeyListener(this) does just what it looks like. It tell the JVM to listen for keys in this class. SetFocusable(true) says "Hey, concentrate on me!" Now we need to create a DrawPanel object and add it to the content pane of the JFrame. Our Gui.java code changes to this: Code:
package collide;
import javax.swing.*;
/**
*
* @author Tom
*/
public class Gui
{
JFrame window;
DrawPanel panel;
public Gui()
{
window = new JFrame("Collision detection, movement, double buffering, and a game loop!");
panel = new DrawPanel();
window.setSize(800,600);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().add(panel);
window.setVisible(true);
}
public static void main(String[]args)
{
Gui game = new Gui();
}
}
Now we need to get things drawn to the JPanel, but first, I'd like to get the outline for our game loop going. A typical game loop basically consists of this: 1. Initialize the game. 2. Update the game. 3. Check for collisions. 4. Draw to the screen. 5. Wait for a bit, then do again and again. Our DrawPanel class will handle all of this, so add these methods to it: Code:
public void Initialize()
{
}
public void update()
{
}
public void checkCollisions()
{
}
public void drawBuffer()
{
}
public void drawScreen()
{
}
public void startGame()
{
}
Code:
initialize();
while(true)
{
try
{
update();
checkCollisions();
drawBuffer();
drawScreen();
Thread.sleep(15);
}
catch(Exception e)
{
e.printStackTrace();
}
}
O.K. now we're going to start drawing things on the screen. We're going to use a tried and true technique called double buffering. Double buffering will help us to avoid flickering when we start moving things around. The idea behind double buffering is this: Instead of drawing all of our movement updates directly to the screen, which takes a lot of time and causes annoying, ugly flicker, we draw out movements to an image that is the same size as our window 800x600 in ram, then just copy that single image to our screen. It takes much less time drawing to an image in memory than it does to the screen, so this technique avoids that annoying flicker effect. The first thing we need to do is to create an image the size of our window. I like to use a BufferedImage. We need to make an instance variable at the beginning of our DrawPanel class, just above the DrawPanel() constructor. Code:
BufferedImage buffer; Now, in our initialize method(), we do: buffer = new BufferedImage(800,600,BufferedImage.TYPE_INT_RGB); This creates a buffered image in which we can draw our game updates ![]() Now we need to get a graphics2d object from our DrawPanel class that we can use to draw into the BufferedImage (buffer). In our drawBuffer() method, add this: Code:
Graphics2D b = buffer.createGraphics(); Code:
Graphics2D g = (Graphics2D)this.getGraphics(); We have almost everything we need to start doing some drawing, but first we need to make a few modifications to our Gui.java class. Open Gui.java and above our main method, add: Code:
public void go()
{
panel.startGame();
}
Code:
game.go(); Code:
b.setColor(Color.bkack); b.fillRect(0,0,800,600); b.dispose(); Code:
g.drawImage(buffer,0,0,this); Toolkit.getDefaultToolkit().sync(); g.dispose(); Let's move on to some more Drawing. We're going to create two rectangles on screen. One will represent our player, and the other will represent an enemy. You'll be able to move the player with the up, down, left, and right arrow keys. When our player bumps into our obstacle, our player will be stopped in his tracks! The first thing we need to do is create a new class to represent our player and our enemy. I am calling this new class Entity.java. Here is the code for it: Code:
package collide;
import java.awt.Rectangle;
public class Entity
{
int x,y,speed,width,height;
boolean up, down, left, right,stop;
public Entity(int x, int y)
{
this.x = x;
this.y = y;
speed = 3;
width = 100;
height = 100;
up = false;
down = false;
left = false;
right = false;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public Rectangle getBounds()
{
return new Rectangle(getX(),getY(),getWidth(),getHeight());
}
public void move()
{
if (up)
y -= speed;
if (down)
y += speed;
if (left)
x -= speed;
if (right)
x += speed;
}
}
Let's get our player and enemy draw on the screen. Open up DrawPanel.java and under BufferedImage buffer; add: Code:
Entity player; Entity enemy; Code:
player = new Entity(100,100); enemy = new Entity(400,400); Code:
public void drawBuffer()
{
Graphics2D b = buffer.createGraphics();
b.setColor(Color.black);
b.fillRect(0,0,800,600);
b.setColor(Color.red);
b.fillRect(player.getX(),player.getY(),player.getWidth(),player.getHeight());
b.setColor(Color.blue);
b.fillRect(enemy.getX(),enemy.getY(),enemy.getWidth(),enemy.getHeight());
b.dispose();
}
Head on over to the keyPressed() method in DrawPanel. The first thing you should notice is that the method accepts an argument, which is KeyEvent e. When you press or release a button on the keyboard, java fires off a KeyEvent object to whichever method is appropriate. If you just pressed a key, it sends it to keyPressed(). If you released a key, it sends an event to keyReleased(). Our keyPressed() and keyReleased methods should look like this. While this is not technically the ideal way to move objects, as I am breaking an important rule of encapsulation, I found it to be easier to understand when I was first learning. Code:
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
player.left = true;
if (key == KeyEvent.VK_RIGHT)
player.right = true;
if (key == KeyEvent.VK_UP)
player.up = true;
if (key == KeyEvent.VK_DOWN)
player.down = true;
}
public void keyReleased(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
player.left = false;
if (key == KeyEvent.VK_RIGHT)
player.right = false;
if (key == KeyEvent.VK_UP)
player.up = false;
if (key == KeyEvent.VK_DOWN)
player.down = false;
}
Code:
public void update()
{
player.move();
}
Now it's time to check for collisions! First, we have to make a few small changes to our Entity class,though. Add a boolean instance variable to the Entity class. Find where we have: Code:
boolean up, down, left, right; Code:
boolean up, down, left, right,collision; Code:
collision = false; Code:
if (player.getBounds().intersects(enemy.getBounds()))
player.collision = true;
else
player.collision = false;
![]() Now, head on over drawBuffer() method. We'll use the value of player.collision to do something when it's true, this way we'll have a visual indicator showing that both objects are colliding. Modify the drawBuffer() method as such: Code:
public void drawBuffer()
{
Graphics2D b = buffer.createGraphics();
b.setColor(Color.black);
b.fillRect(0,0,800,600);
if (player.collision == false)
{
b.setColor(Color.red);
b.fillRect(player.getX(),player.getY(),player.getWidth(),player.getHeight());
b.setColor(Color.blue);
b.fillRect(enemy.getX(),enemy.getY(),enemy.getWidth(),enemy.getHeight());
b.dispose();
}
else
b.setColor(Color.white);
b.drawString("C O L L I S I O N !",350,300);
b.dispose();
}
Last edited by farrell2k; 05-07-2009 at 05:46 PM.. |
|
||||
|
Re: Double buffering, movement, and collision detection.
Nicely done!
__________________
CodeCall Blog | CodeCall Wiki | Shareware Programming is a branch of mathematics. My CodeCall Blog | My Personal Blog |
|
|||
|
Re: Double buffering, movement, and collision detection.
I should have written a mutator/setter method in the player class that modifies the values of the booleans up, down, left, and right, instead of toggling their values trough direct manipulation. i.e. player.left = true.
|
![]() |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | Search this Thread |
| Display Modes | |
|
|
All times are GMT -5. The time now is 09:27 AM.
Amrosama.cc
Arekbulski.cc
Debtboy.cc
Guest.cc
Jaan.cc
James.cc
Mathx.cc
Tsz.cc
Vswe.cc