Thursday, September 2, 2010

Interactive Keyboard Input In Java: KeyListeners

In a console application, you can get keyboard input using the Scanner class, as described in Keyboard Input for Console Apps. In an graphical app, though, you can use one of the classes built to accept text input (e.g. TextArea or JTextField) or add code to your application to respond directly to the keyboard.

Keyboard input in the Java GUI made simple.
Playing with Today's Program

There are two basic ways of doing this. One is to set up Key Bindings, which maps keystrokes to actions in your application similar to accelerator keys or menu keyboard equivalents. The other is to use a Key Listener, similar to the Mouse Listener, which I detailed in Simple Mouse Interaction.

In this example we're going to use Key Listeners. There is less overhead to setting up a KeyListener when you just need to use a few keys. Key Bindings require more overhead to set up, but when you want to bind actions to a lot of different keystrokes, and manage the actions bound to particular keystrokes at a higher level, Key Bindings are better to use than a simple KeyListener.

As its name implies, a KeyListener is an Event Listener. If you're not sure what that is, read my article on Listeners or follow the prior link to Oracle/Sun's description.

Here's a program that demonstrates simple keyboard interaction. It's based on the MousePanel program I presented in Simple Mouse Interaction. It acts as a sort of "Etch-a-Sketch". You can download the KeyPanel program source from my Java code site.

// Import the basic necessary classes.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class KeyPanel extends JPanel implements KeyListener{

public KeyPanel(){
super();
pointX=0;
pointY=0;
oldX=0;
oldY=0;
addKeyListener(this);
}

int pointX, pointY, oldX, oldY;
boolean erase;

public void paintComponent(Graphics g){
// Erase the board if it's been requested.
if (erase) {
g.clearRect(0, 0 , getBounds().width, getBounds().height);
erase = false; // We're done, turn off this flag now.
}

// Draw gray where the pointer was..
g.setColor(Color.GRAY);
g.fillRect(oldX-2, oldY-2, 4, 4);
// Draw "Cursor" at current location in black.
g.setColor(Color.BLACK);
g.fillRect(pointX-2,pointY-2, 4, 4);
}

public void keyPressed(KeyEvent key){

// Copy the last clicked location into the 'old' variables.
oldX=pointX;
oldY=pointY;
// Move the current point depending on which key was pressed.
if (key.getKeyCode() == key.VK_DOWN){
pointY=pointY+5;
if (pointY > getBounds().height){
pointY=getBounds().height;
}
}
if (key.getKeyCode() == key.VK_UP){
pointY=pointY-5;
if (pointY < 0){pointY=0;}
}
if (key.getKeyCode() == key.VK_LEFT){
pointX=pointX-5;
if (pointX < 0){pointX=0;}
}
if (key.getKeyCode() == key.VK_RIGHT){
pointX=pointX+5;
if (pointX > getBounds().width){
pointX=getBounds().width;
}
}

// Set a flag to erase the screen if Space is pressed.
if (key.getKeyCode() == key.VK_SPACE){
erase = true;
}


// Tell the panel that we need to redraw things.
repaint();
}

/* The following methods have to be here to comply
with the MouseListener interface, but we don't
use them, so their code blocks are empty. */
public void keyTyped(KeyEvent key){ }
public void keyReleased(KeyEvent key){ }

public static void main(String arg[]){
JFrame frame = new JFrame("Use Arrows to Draw, Space to Erase.");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(640,480);

KeyPanel panel = new KeyPanel();
frame.setContentPane(panel);
frame.setVisible(true);

// We *must* do this to see KeyEvents.
panel.setFocusable(true);


// Initialize the drawing pointer.
panel.oldX=panel.getBounds().width/2;
panel.oldY=panel.getBounds().height/2;
panel.pointX=panel.oldX;
panel.pointY=panel.oldY;

}
}

Using this technique with the Simple Video Game Kernel would be similar. The VGKernel would extend KeyListener, register itself, and implement the KeyListener methods. But in those methods, rather than performing the operations that result from the keypress, as in this program, you would want to simply set a flag to show that the key has been pressed. Then, in your core game logic you would test to see whether the key has been pressed, and perform the appropriate actions.

That way the actions are performed at the appropriate time in your game, and not just whenever the key happens to get pressed. Reacting to a key when it is pressed is appropriate for a turn-based game, but not for a real-time game. In a real-time game the action happens according to the timing of the TimerTask that drives the game, which is why we just note that a key has been pressed, and wait until the TimerTask occurs to actually conduct the action related to that key. This would be similar to what we do with the space key here, which sets a flag to tell paintComponent() to erase the screen.

Give this program a try, see if you can extend it to allow the user to select colors to draw with or change the size of the drawing pen.
StumbleUpon

Thursday, August 26, 2010

Calling System Commands in Java

Let's suppose you want to run another program on your system from within Java. Personally, I first decided I wanted to do this for the sake of a prank. You may have more businesslike purposes in mind, yourself.

It's not too hard to do this since Java 1.5, which added the Process and ProcessBuilder classes.

Here's an example program that starts up Firefox at a particular website:
public class OpenSite{
public static void main(String arg[]){
try { Process p = new ProcessBuilder("firefox",
"http://beginwithjava.blogspot.com/").start(); }
catch(java.io.IOException io){ }
}
}

I've compressed the various parts of the action down to one line here:
Process p = new ProcessBuilder("firefox", "http://beginwithjava.blogspot.com/").start();

I'm creating an "anonymous" ProcessBuilder object, calling its start() method, which returns a Process, which I name simply "p".

The whole thing is wrapped up in a try...catch structure because javac wants to see us deal with any I/O errors that result. In this program, I just ignore them.

So you'll want to make sure that you either catch those errors and deal with them, or that they will be unimportant enough that they don't matter.

Also note that the Java program's process will last as long as the external program you call. So if you don't shut down this instance of the firefox process, you'll have Java still running.

If you want to see something fun you can do with this on Mac, check out my article on my other blog about adding speech to the Simple Video Game Kernel.
StumbleUpon

Tuesday, August 24, 2010

Using Game Controllers with Java

In the past, I've covered using mice as input devices, and covered the general input mechanism of Listeners. I've also discussed keyboard input for console applications, and I'll soon be covering Key Bindings as a way of using the keyboard in GUI applications.

But there's no facility in Java itself that deals with game pads easily. To date, it's been necessary to create your own ActionListeners from scratch. But not any more. Thanks to the JInput project, there's an easier way to hook up game controllers to your software.

JInput attempts to do discovery on your game controller, to figure out what its setting are, what buttons and controls it has, what the center positions are of analog sticks, and so on. All that messy stuff that makes rolling your own so darn painful. It's not 100% universal, but for most controllers and most games, it will do the job admirably. If you want better for a specific controller of your own, you can extend the classes to handle your stick (and maybe feed that information back to the JInput team so that they can decide whether to include it in future releases.

It's multi-platform, Windows, Mac OS X, and Linux. So it doesn't have the limitations of a lot of the other gamepad code implementations that use native code, thus limiting themselves to one platform (usually Windows.)

If you want to see an implementation using JInput, check out Greenfoot with Gamepads. It's a good, clear example of using JInput in a general fashion.
StumbleUpon

Sunday, August 22, 2010

More Collision Detection: Bouncing the Right Way

A common result of a collision between two objects in a video game is a bounce. To do this right, we have to know which direction to make things bounce. Here's one way to do that easily in Java. I've got a ball that's going to bounce in one of eight directions depending on how it hits a brick.

Diagram showing the results of a ball hitting a brick and bouncing, depending on how it strikes the brick. Collision detection in action.

I've marked the changes to the ball's velocity that will occur as a result of each possible type of collision. The three arrows on the left side all show that the xVel (x velocity) is a negative value, the three arrows on the bottom all show that yVel (y velocity) should become a positive value.

In the cases of the corners, both the x and y velocities are set. The bounces off the middles of the sides all cause one velocity to be set, but the other is left alone. For example, a bounce off the right side of the brick sets the xVel to a positive value, but the yVel is unchanged. So if yVel was a positive value before (meaning the ball is travelling down on screen) then it will keep travelling down. If it was negative--moving up--then it will keep moving up. Only the x direction of movement will change. It will start moving from left to right instead of right to left.

It's really easy to detect a collision, but now we need to know the relationship between the two colliding objects so that we can make the ball bounce in the correct direction. As we learned in Stopping Jonathan Livingston Seagull, the effect of how much we move an object before we check a collision can cause problems if we don't understand the limits of how we detect them.

In this program, our ball's movement is presently set at one quarter of its width. We could go as high as one half its width and still have our collision detection routines work properly here. Fortunately, we want to keep the distance the ball moves each turn short to make the movement look smoother.

When we hit the brick, we want to see where it hits the ball. This will tell the ball which way to bounce, just like a real ball. In the drawing above, we have a red brick on a cyan (blue-green) playfield. The ball is dark blue. Where the ball is intersecting, or overlapping, the brick is shown in yellow. Now we just need to know which side of the ball is getting "pushed in" this way. Then we bounce the opposite way.

Here's the program, the key code we're talking about is highlighted:
/* A simple video game style kernel, revision 4.
by Mark Graybill, August 2010
Has a ball bouncing off a brick.
Because the ball moves at a fixed speed,
slow enough we won't miss a collision,
we can use simple colliision detection.

Uses the Brick class from the article
"Multiple Constructor Methods"
*/

import java.util.*;
import java.awt.*;
import javax.swing.*;
import java.lang.Math;

public class VidBrick extends JPanel{

public Rectangle screen, bounds; // The screen area and boundary.
public JFrame frame; // A JFrame to put the graphics into.
public VGTimerTask vgTask; // The TimerTask that runs the game.
public VGBall ball; // The game ball, a subclass of Rectangle.
private Brick brick; // A brick for the ball to interact with.

/* This sets up the screen area, and creates instances of
the JFrame, VGBall, VGTimerTask, etc that we'll need. */
public VidBrick(){
super();
screen = new Rectangle(0, 0, 600, 400);
bounds = new Rectangle(0, 0, 600, 400); // Give some temporary values.
ball = new VGBall();
frame = new JFrame("VidBrick");
vgTask = new VGTimerTask();
brick = new Brick();
}

class VGTimerTask extends TimerTask{
public void run(){
ball.move();
frame.repaint();
}
}

class VGBall extends Rectangle{
int xVel, yVel; // The ball's velocity.
Color ballColor; // The color of the ball.

/* Create a VGBall with default location of upper left
corner, size of 20x20 pixels, moving at one quarter
its height and width per turn--plus it's blue. */
public VGBall(){
super(0, 0, 20, 20);
xVel = width/4;
yVel = height/4;
ballColor=new Color(0, 0, 128);
}

/* Move the Ball. */
public void move(){
// Move the ball according to the game rules.
x+=xVel; // Move horizontally.
y+=yVel; // Move vertically.

// Detect edges and bounce if necessary.
if (x > (bounds.width - width)){
xVel = -xVel; // reverse movement.
x = bounds.width - width; // Set location to screen edge.
}
if (y > (bounds.height - height)){
yVel = -yVel; // reverse movement.
y = bounds.height - height;
}
if (x <= 0) { xVel = -xVel; x = 0; }
if (y <= 0) { yVel = -yVel; y = 0; }

// Detect Brick and bounce if necessary.
if (intersects(brick)) {
// Get the intersection rectangle to find out which way to bounce.
Rectangle iRect = intersection(brick);
// If we hit on the left side, go left (negative x velocity).
if ((x+(width/2))<(iRect.x+(iRect.width/2))){xVel=(0-Math.abs(xVel));}
// If we hit on the right side, go right (positive x velocity).
if ((x+(width/2))>(iRect.x+(iRect.width/2))){xVel=Math.abs(xVel);}
// If we hit on the top, go up.
if ((y+(height/2))<(iRect.y+(iRect.height/2))){yVel=(0-Math.abs(yVel));}
// If we hit on the bottom, go down.
if ((y+(height/2))>(iRect.y+(iRect.height/2))){yVel=Math.abs(yVel);}
} // if intersects
}

/* Draw the ball into the provided graphics context. Preserves
the context's drawing color setting. */

public void draw(Graphics g){
// the ball draws itself in the graphics context given.
Color gcColor = g.getColor(); // Preserve the present color.
g.setColor(ballColor); // Use the ball's color for the ball.
g.fillRect(x, y, width, height); // Draw the ball.
g.setColor(gcColor); // Restore prior color.
} // end draw()
} // end of class VGBall

public void paintComponent(Graphics g){
// Get the drawing area bounds for game logic.
bounds = g.getClipBounds();
// Clear the drawing area.
g.clearRect(screen.x, screen.y, screen.width, screen.height);
// Draw the brick.
g.setColor(brick.getColor());
g.fillRect(brick.x, brick.y, brick.width, brick.height);
// Draw the ball.
ball.draw(g);
}

/* Main program loop. */
public static void main(String arg[]){

java.util.Timer vgTimer = new java.util.Timer(); // Create a Timer object
VidBrick panel = new VidBrick();

panel.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.frame.setSize(panel.screen.width, panel.screen.height);

panel.frame.setContentPane(panel);
panel.frame.setVisible(true);

// Set up the brick.
panel.brick.x = panel.screen.width/3;
panel.brick.y = panel.screen.height/3;
panel.brick.width = panel.screen.width/3;
panel.brick.height = panel.screen.height/3;

// Set up a timer to do the vgTask regularly.
vgTimer.schedule(panel.vgTask, 0, 33);
}
}

The way we figure out which way to bounce is to find the center of the ball and the center of the intersection rectangle (the yellow box in the picture, where the ball and the brick overlap.) Then if the center of the intersection (shown as an orange dot on the pic) is to the right of the center of the ball (a white dot) we bounce left. If it's to the left, we bounce right, if it's above we bounce down, below we bounce up.

This way we don't have to worry about the size or shape of the brick itself. All we care about is the bit that strikes the ball. Then the ball bounces the correct way.

If we had wanted to get really fancy, we could have made the ball bounce at different angles depending on the angle between the center of the ball and the center of the intersection rectangle. If you're familiar with trigonometry, take a look at the Math class in Java and see if you can implement this.
StumbleUpon

Friday, August 20, 2010

Web Browsing on the Atari 2600???

A recent discussion on an Astronomy forum took a turn for the earthly with the announcement of a new web site at StellarVue Telescopes. People were checking it out, reporting on minor fixes they felt were necessary and trying it with different systems and OSes. Then came the first report of a total crash and burn. From a Commodore 64 user. Next we had reports of failures on Heathkit and Vic-20 systems, too.

"Aha," I thought," a perfect opportunity to try out my Web Surfer cartridge on my Atari 2600!"

Here are the results:

My Atari 2600 with the Web Surfer Cartridge,
Displaying the
StellarVue Web Site.


Check out my Atari web page for more pictures and info on this amazing VCS cart!


Note to those following my Java Programming Stuff: I was supposed to post this over at my other blog, An Infinite Number of Cats on Keyboards, but I punched the wrong button on my Blogger Dashboard, and it ended up here instead. Sorry about that. Now back to our regularly scheduled Java program...

StumbleUpon

Wednesday, August 18, 2010

Stopping Jonathan Livingston Seagull with Java

In Simple Collision Detection we used the intersects() method of two Rectangle subclasses to see if one object struck another on our playfield. It works, in the example given. But in the example given the velocity of the ball is limited.

Simple collision detection works fine, here.
In the VGBKernel.java example, we have a fairly slow-moving ball detecting collisions with a really large object that's hard to miss.

If we have a brick that is small, and a ball that is fast, though, the ball could pass right over the brick without even realizing it should have collided with it. In other words, if we had a brick wall stretching across the screen, the ball might fly "through" it when we want it to stop or bounce. Let's say we're falling and want to detect a brick that acts as a floor. The floor goes across the screen between heights 100 and 105. The ball starts at location 75 and has a velocity of 50. Its new location would be 125. We move it there, and check for a collision as we did in VGBKernel. No collision. The ball just flew "through" the brick wall like Jonathan Livingston Seagull!

Let's make an example program called BallGrav.java to illustrate the problem. BallGrav.java is a slightly modified version of VGBKernel.java. It uses the same Brick class as we've used before, with no modifications.
/* Based on the video game style kernel, revision 3.
by Mark Graybill, August 2010
Demonstrates collision detection problems, and solutions.
*/

// Import Timer and other useful stuff:
import java.util.*;
// Import the basic graphics classes.
import java.awt.*;
import javax.swing.*;
import java.lang.Math;

public class BallGrav extends JPanel{

public Rectangle screen, bounds; // The screen area and boundary.
public JFrame frame; // A JFrame to put the graphics into.
public VGTimerTask vgTask; // The TimerTask that runs the game.
public VGBall ball; // The game ball, a subclass of Rectangle.
private Brick brick; // A brick for the ball to interact with.

// Create a constructor method:
public BallGrav(){
super();
screen = new Rectangle(0, 0, 600, 400);
bounds = new Rectangle(0, 0, 600, 400); // Give some temporary values.
ball = new VGBall();
frame = new JFrame("BallGrav");
vgTask = new VGTimerTask();
brick = new Brick();
}

// Create an inner TimerTask class that has access to the
// members of the BallGrav.
class VGTimerTask extends TimerTask{
public void run(){
ball.move();
frame.repaint();
}
}

// Create an inner VGBall class that has our game logic in it.
class VGBall extends Rectangle{
int xVel, yVel; // The ball's velocity.
Color ballColor; // The color of the ball.

public VGBall(){
super(300, 0, 20, 20);
xVel = 0; // Start with 0 velocity at center top of screen.
yVel = 0;
ballColor=new Color(0, 0, 128);
}

// Instance methods for VGBall
public void move(){
// Accelerate due to "gravity".
yVel+=3;
// Move the ball according to the game rules.
x+=xVel; // Move horizontally.
y+=yVel; // Move vertically, accelerating as we go.
// Detect edges and stop movement if we hit them.
if (x > (bounds.width - width)){
xVel = 0; // stop movement.
x = bounds.width - width; // Set location to screen edge.
}
if (y > (bounds.height - height)){
yVel = 0; // stop movement.
y = bounds.height - height;
}
if (x <= 0) { xVel = 0; x = 0; }
if (y <= 0) { yVel = 0; y = 0; }

// Check for intersection with Brick,
// change color when touching.
if (intersects(brick)) {
//Stop on top of the brick if we hit it.
yVel = 0;
y = brick.y - height;
}

}

public void draw(Graphics g){
// the ball draws itself in the graphics context given.
Color gcColor = g.getColor(); // Preserve the present color.
g.setColor(ballColor); // Use the ball's color for the ball.
g.fillRect(x, y, width, height); // Draw the ball.
g.setColor(gcColor); // Restore prior color.
} // end draw()

} // end of class VGBall

// Now the instance methods:
public void paintComponent(Graphics g){
// Get the drawing area bounds for game logic.
bounds = g.getClipBounds();
// Clear the drawing area.
g.clearRect(screen.x, screen.y, screen.width, screen.height);
// Draw the brick.
g.setColor(brick.getColor());
g.fillRect(brick.x, brick.y, brick.width, brick.height);
// Draw the ball.
ball.draw(g);
}


public static void main(String arg[]){

java.util.Timer vgTimer = new java.util.Timer(); // Create a Timer object
BallGrav panel = new BallGrav();

panel.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.frame.setSize(panel.screen.width, panel.screen.height);

panel.frame.setContentPane(panel);
panel.frame.setVisible(true);

// Set up the brick.
panel.brick.x = 0;
panel.brick.y = 4 * (panel.screen.height/5);
panel.brick.width = panel.screen.width;
panel.brick.height = 5;
panel.brick.brickColor = new Color(200,50,50);

// Set up a timer to do the vgTask regularly.
vgTimer.schedule(panel.vgTask, 250, 200);
}
}
This example functions properly. When the ball falls, it strikes the brick floor and stops.

Image of collision detection working.


But let's make the ball accelerate a bit faster. Make the following change in Ball's move() method:
      // Accelerate due to "gravity".
yVel+=5;


Suddenly, the ball doesn't detect the floor any more, and it goes to the bottom of the screen, right through the floor:

Image showing collision detection failure.


Stopping Jonathan Livingston Gameball from Going Through the Wall

What do we do to keep this from happening? Well, one way is to never let the ball move faster than it can detect collisions. Then we'd never let it move more than its own size in any direction. If it's important that it know what side it hits something on (like when we're going to bounce off it), then we may not want to let it go more than half its size in any direction in any one "move." To do this to BallGrav,java, we'd change the code as follows:
      // Accelerate due to "gravity".
yVel+=5;
// Limit our velocity to preserve collisions.
if (yVel>height) { yVel = height; }

Now the ball will never go so fast it never sees the floor.

But what if we want the ball to move faster?

In this case, there are a number of possible solutions. Many of them are fairly complicated, with lots of math or with lots of iteration checking for collisions at each step along the way. Complexity is something we don't want, for a lot of reasons. Here is one possible solution, that uses collision prediction to see if our ball might hit something along the way:

      // Accelerate due to "gravity".
yVel+=5;
// Limit our velocity.
if (yVel>(height*2)) { yVel = height * 2; }
// Move the ball according to the game rules.
// Check for a collision if we're moving fast.
if (yVel>height) {
Rectangle halfway = new Rectangle(x,y+(yVel/2), width, height);
if (halfway.intersects(brick)) { yVel = yVel/2; }
}
x+=xVel; // Move horizontally.
y+=yVel; // Move vertically, accelerating as we go.

Here, I have a velocity limit twice as high as before. This allows the ball to move along a lot faster (before, I could see the ball slow down.) Now, since the ball can move fast enough to fly through things, we first look ahead to see if there's anything in the way. We do this by seeing if there's something halfway there. If so, we cut our original speed in half before we move. Then the collision (if any) happens "naturally."

This is good enough, if the fastest we can move is twice the ball's height. If we allowed three times its height, we might check at points 1/3 and 2/3 of the way along its path.

If we don't want limits like this, we pay the price by having a more complex method to check for collisions. Here, I've limited things to movement in only one direction, up and down. If we're going side to side as well, I'd have to check for waypoints along a diagonal path. To get really precise, I'd have to do something like project lines along the corners of the ball from its current position to its intended new position and see if they intersect anything. When you get into more complex shapes than the rectangles we're using now, you get a different set of choices.

Fortunately, for video games, simple choices are almost always plenty good enough. Checking for collisions at the minimum number of points along the path is almost always good enough. This can be done by dividing the distance to be moved by the largest safe move distance, and checking that many times for collisions along the path.

Avoiding the Problem Entirely

You can also just use a different sort of movement that never has any of the objects moving more than some small number of pixels at a time--small enough that you'll never fail to detect a collision. I'll give an example in a future article, but for now I'll just describe it.

What you do is set a speed at which you move things only, say, one pixel per "move". But you only move them every so often, depending on what their speed is. The fastest objects get moved on every redraw of the screen. Slower objects only get moved on every other update, or every fifth, or something of that sort. That way an object is never moved across the screen by so many pixels at once that it misses seeing a collision with another object.

Collision Detection: Never "Easy"

Collision detection is one of the programmer's bugaboos. It's one of the places where errors are most prone to occur in code, and it can have terrible effects on a game if it doesn't work properly. The programmer's choices are to accept certain limitations or to make more complex code, or to use a technique of object movement that can either be limiting or eat up a lot of processor time.

When my students program their video game projects in class, one of our biggest problems in implementing those games is dealing with collision detection. Even though we're working in Greenfoot, which does a lot of the work for us. We still need to be aware of the limitations built into the system, and work within them.

Now it's your turn. Try reducing the brick in BallGrav.java to a small platform. Now give the ball a constant x velocity. See if you can get the ball to land on that platform reliably, with successful collision detection.
StumbleUpon

Sunday, August 15, 2010

Simple Collision Detection in Java

Collision detection is a basic element of a video game. It is one of the primary means of determining when objects in a game should interact. In Asteroids, there are collisions between the player's shot and the asteroids themselves. There are collisions between the player's shot and the alien spacecraft (hopefully.) There are collisions between the asteroids and the player's ship (argh!) Each of these is critical to the game.

Screen shot of collision detection in the video game kernel, showing color change of ball when intersecting the brick.

Since we don't have actual physics to determine when there's been a collision, as we have in real life, we need to create a set of rules for when a collision has occured then implement those rules in our code. One way to handle collision detection is to see if two potentially colliding objects intersect at all on the playfield. That is, whether one of them overlays the other.

Previously, we have worked with a simple video game kernel, then updated it to make the addition of game logic simpler. We had also created a Brick class that we can use to interact with the ball in our basic video game kernel.

Here is a slightly changed version of the simple video game kernel. It uses the Brick class, so Brick.class should be in the same directory as your VGBKernel.java and VGBKernel.class (it wouldn't be a bad idea to have Brick.java there, too, in case you want to play around with it at all to get different effects with this program through changes of your own.)
/* A simple video game style kernel, revision 3.
by Mark Graybill, August 2010
Uses an inner class to contain game logic,
with another inner class as a game timer.
*/

// Import Timer and other useful stuff:
import java.util.*;
// Import the basic graphics classes.
import java.awt.*;
import javax.swing.*;
import java.lang.Math;

public class VGBKernel extends JPanel{

public Rectangle screen, bounds; // The screen area and boundary.
public JFrame frame; // A JFrame to put the graphics into.
public VGTimerTask vgTask; // The TimerTask that runs the game.
public VGBall ball; // The game ball, a subclass of Rectangle.
private Brick brick; // A brick for the ball to interact with.

// Create a constructor method:
public VGBKernel(){
super();
screen = new Rectangle(0, 0, 600, 400);
bounds = new Rectangle(0, 0, 600, 400); // Give some temporary values.
ball = new VGBall();
frame = new JFrame("VGBKernel");
vgTask = new VGTimerTask();
brick = new Brick();
}

// Create an inner TimerTask class that has access to the
// members of the VGBKernel.
class VGTimerTask extends TimerTask{
public void run(){
ball.move();
frame.repaint();
}
}

// Create an inner VGBall class that has our game logic in it.
class VGBall extends Rectangle{
int xVel, yVel; // The ball's velocity.
Color ballColor; // The color of the ball.

public VGBall(){
super(0, 0, 20, 20);
xVel = width/4;
yVel = height/4;
ballColor=new Color(0, 0, 128);
}

// Instance methods for VGBall
public void move(){
// Move the ball according to the game rules.
x+=xVel; // Move horizontally.
y+=yVel; // Move vertically.
// Detect edges and bounce if necessary.
if (x > (bounds.width - width)){
xVel = -xVel; // reverse movement.
x = bounds.width - width; // Set location to screen edge.
}
if (y > (bounds.height - height)){
yVel = -yVel; // reverse movement.
y = bounds.height - height;
}
if (x <= 0) { xVel = -xVel; x = 0; }
if (y <= 0) { yVel = -yVel; y = 0; }

// Check for intersection with Brick,
// change color when touching.
if (intersects(brick)) { ballColor=Color.GREEN; }
else { ballColor=Color.BLUE; }

}

public void draw(Graphics g){
// the ball draws itself in the graphics context given.
Color gcColor = g.getColor(); // Preserve the present color.
g.setColor(ballColor); // Use the ball's color for the ball.
g.fillRect(x, y, width, height); // Draw the ball.
g.setColor(gcColor); // Restore prior color.
} // end draw()

} // end of class VGBall

// Now the instance methods:
public void paintComponent(Graphics g){
// Get the drawing area bounds for game logic.
bounds = g.getClipBounds();
// Clear the drawing area.
g.clearRect(screen.x, screen.y, screen.width, screen.height);
// Draw the brick.
g.setColor(brick.getColor());
g.fillRect(brick.x, brick.y, brick.width, brick.height);
// Draw the ball.
ball.draw(g);
}


public static void main(String arg[]){

java.util.Timer vgTimer = new java.util.Timer(); // Create a Timer object
VGBKernel panel = new VGBKernel();

panel.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.frame.setSize(panel.screen.width, panel.screen.height);

panel.frame.setContentPane(panel);
panel.frame.setVisible(true);

// Set up the brick.
panel.brick.x = panel.screen.width/4;
panel.brick.y = panel.screen.height/4;
panel.brick.width = panel.screen.width/2;
panel.brick.height = panel.screen.height/2;

// Set up a timer to do the vgTask regularly.
vgTimer.schedule(panel.vgTask, 0, 33);
}
}

The main changes here are the addition of the brick to the VGBKernel (that's why I renamed VGKernel to VGBKernel, by the way--it's now a Video Game Brick Kernel), and I've changed ball into an extension of Rectangle to make collision detection a bit easier.

To do the actual collision detection, I'm using the method intersects() from the Rectangle class. It tests whether one Rectangle overlaps another in the coordinate space.

In this case, if the ball is on top of the brick (a rather large brick), then the ball turns green. I could have had any of a number of other effects. For example, when I was first testing this routine I didn't change the color of the ball, instead I had the ball send a message to the Java console that read "Ow!". So whenever the ball passed over the brick I'd get a long string of messages in the console like this:

Ow!
Ow!
Ow!
Ow!
Ow!
Ow!
Ow!
Ow!
Ow!

I could just as well have the program play a sound, draw an image, update a score, or any of a number of different things when a collision occurs. Exactly what should happen is determined by the rules of the video game itself.

Going Further

Try changing the effect when the ball strikes the brick. The easiest place to start would be making the ball a different color than green. To get more sophisticated, try things like adding a sound, or counting the number of moves that the ball is in contact with the brick. Change the size and location of the brick. Perhaps try adding additional bricks, and have each create a different effect. Try changing the color of the brick when the ball strikes it.

One thing about the collision detection we are doing here. It only detects when we have actually started to overlap with the brick. In many cases, it's desirable to predict when a collision will occur as a result of a move before that move occurs. Try to develop a solution to this yourself. I'll be addressing this in a future article, so you can compare what you came up with against my method. Remember that in programming there's almost never just one way to accomplish something. The same effect can usually be produced any of a number of different ways effectively enough to use in a finished program.
StumbleUpon

Friday, August 13, 2010

Multiple Constructor Methods

A special type of method that creates an instance of a method is called a Constructor Method. When an object has member variables that are objects, we need to define a constructor method to set up those variables. We'll show how to do that here. If you want a more basic introduction to constructor methods, you may want to take a look at my prior article.

As an example, we're going to create a simple class of object for use with my simple video game kernel in a new version I'll be introducing in an article in the near future. The class definition consists mostly of constructor methods, since the class itself is presently not much more than a Rectangle with an added field.

import java.awt.*;

// A Simple class for use in the simple video game examples.
// Mark Graybill, Aug. 2010

public class Brick extends Rectangle{
Color brickColor;

public Brick(int newX, int newY, int newWidth, int newHeight){
super(newX, newY, newWidth, newHeight);
brickColor = new Color(0, 128, 255);
}

public Brick(int newX, int newY){
this(newX, newY, 10, 10);
}

public Brick(){
this(0,0,10,10);
}

public void setColor(Color newColor){ brickColor=newColor; }
public Color getColor(){ return brickColor; }

} // End Brick

In this class, we have three forms of constructor, each with a different set of parameters. The one that takes the most parameters is the "base" version. It starts with a call to super(). This calls the constructor for Brick's superclass, or parent class, Rectangle. A look at the documentation for Rectangle shows that it has a constructor that takes four integer arguments, as we use here in super().

When we use super(), it must be the first thing we do within our constructor method. If we don't use super(), Java will do it automatically as the first thing in a constructor, calling it with no parameters. Since we want to set values for our inherited fields of x, y, width, and height it's better to call super() with those parameters. Otherwise, we could just as well have done something like this:
  public Brick(int newX, int newY, int newWidth, int newHeight){
x=newX;
y=newY;
width=newWidth;
height=newHeight;
brickColor = new Color(0, 128, 255);
}

This would have the same effect, and Java would insert an invisible call to super() in front of x=newX;.

The other constructors use the first method. To do this, they use another special method that's like super(). It's called this(), and it calls another constructor for this class. We can't do a call to Brick(), if we try, the compiler will see it as an undefined symbol:

>javac Brick.java
Brick.java:11: cannot find symbol
symbol : method Brick(int,int,int,int)
location: class Brick
Brick(0,0,10,10);
^
1 error

So we use this() instead.

Like super(), the this() method must be the first thing called in the constructor method's body. Since don't call super()--it's in the base constructor--so there's no conflict about which goes first. If you use this(), you don't use super().

By using this() with the other constructor methods, we can keep all our key code code for the constructor in one place. If we had each constructor setting member values and constants without calling the base constructor method, then we'd end up with repeated code--a prime opportunity for bugs to enter our code if we update the code in one place, but not another. We don't want repeated code! Multiple independent constructors are used in the Java Tutorials, but I expect they're used to keep the lesson simple, not because they are a good coding practice!

You can find out more about this() and super() in the Java Language Specification, under Explicit Constructor Invocations.

You can probably see that I should really have my base constructor allow a Color to be passed to it, too. Try adding this yourself as an exercise to try out your understanding of constructor methods, then see what javac thinks of your work.
StumbleUpon

Wednesday, August 11, 2010

Java's Inner Classes: The Keys to the Kingdom

In my two most recent code examples I've used inner classes in the program.

Java Video Game Programming: Game Logic

A Simple Java Video Game Kernel

An inner class is a Java class that's defined inside another class. In both the examples above, I have a class called VGKernel, which is the class that implements the video game kernel. Inside that class, I define other classes. This has a special effect on the relationship between those classes and VGKernel.

Normally, our objects are encapsulated, that is, their members (variables and methods) are inaccessible to other classes unless they've been marked as public, and in those cases we take care to make sure that the object can't be messed up using those public members.

Some things in Java don't work very well with the encapsulation. Graphics and Threads are two of them. Fortunately, there's a way around the encapsulation. It lets one object access all the members of another object as if it owned them.

The downside is that this can be a dangerous coding practice, like global variables (check out the sort of problems  JavaScript's had with security, if you want to know why global variables are a problem.) Your inner class has complete control over the outer class. Root access, keys to the kingdom. It could wear the outer class like the alien guy wore the redneck's skin in Men in Black.

If used well inner classes solve a multitude of problems. In the case of the two versions of VGKernel, it solves the problem of the ball being able to access the graphical context (at present, the Ball class doesn't really need to, I'll admit, but we'll see more of why it does this as the code develops in future articles), and it allows VGTimerTask to access the methods of VGKernel.

The Java Tutorial has a pretty good section on inner classes, as one type of nested class.
StumbleUpon

Monday, August 9, 2010

Java Video Game Programming: Game Logic

The simple video game kernel I presented earlier is a good start, but some compromises were made to make it as simple as possible. Now we're going to start adding back some of the complexity to give us more control over what we can do with it.

The first step is to make the game's ball a real object, rather than some variables within our JFrame.

In simple video games, there is usually some object in the game that does most of the "thinking" with respect to the game's rules. In a game like Pong or Breakout, the ball does most of the "thinking". The paddles move according to user input, but they don't really need to know if they've collided with anything in the game (their own logic keeps them from moving off the playfield.) The bricks don't need to know anything about what's going on, they just need to hang around, then disappear when something tells them to, and perhaps return some information about what score they're worth, if there are different scores for hitting different bricks.

The ball, however, is a more active participant in the game. It needs to know about collisions, respond to the other objects in the game, and generally know what's going on. In other words, it is the object that keeps track of most of the game rules. In a video game, this is referred to as the game logic.


A bouncing ball in the simple Java video game kernel program.

This simple kernel improves on the original. Turn it into your own Pong, Breakout, or Tank clone.

In the example below I've made a Ball class. This is where most of the game's logic will reside. Here it is in the ball's move() method. Since the ball will need access to inside information about the playfield and the objects on it, I've made it an inner class of the playfield's class (VGKernel.) As an inner class, it has access to all of VGKernel's members and methods as if it owned them itself. This simplifies the program a lot.

Here is the modified version of the video game kernel. Changes from the original have been highlighted:
/* A simple video game style kernel, revision 2.
   by Mark Graybill, August 2010
   Uses an inner class to contain game logic,
   with another inner class as a game timer.
*/

// Import Timer and other useful stuff:
import java.util.*;
// Import the basic graphics classes.
import java.awt.*;
import javax.swing.*;
import java.lang.Math;

public class VGKernel extends JPanel{

// This is not a recommended coding practice, just a shortcut.
public Rectangle screen, bounds; // The screen area and boundary.
public JFrame frame; // A JFrame to put the graphics into.
public VGTimerTask vgTask; // The TimerTask that runs the game.
public VGBall ball; // The game ball.
// Create a constructor method:
  public VGKernel(){
    super();
    screen = new Rectangle(0, 0, 600, 400);
    bounds = new Rectangle(0, 0, 600, 400); // Give some temporary values.
    ball = new VGBall();
    frame = new JFrame("VGKernel");
    vgTask = new VGTimerTask();
}

  // Create an inner TimerTask class that has access to the
  // members of the VGKernel.
  class VGTimerTask extends TimerTask{
    public void run(){
      ball.move();
      frame.repaint();
    }
  }

  // Create an inner VGBall class that has our game logic in it.
  class VGBall{
    // Accessor methods would be more proper,
    // but for now I just make the needed variables public.
    public int x, y, width, height; // Ball's location and size.
    int xVel, yVel; // The ball's velocity.

    public VGBall(){
      x = 0;
      y = 0;
      width = 20;
      height = 20;
      xVel = width/4;
      yVel = height/4;
    }
    // Instance methods for VGBall
    public void move(){
      // Move the ball according to the game rules.
      x+=xVel; // Move horizontally.
      y+=yVel; // Move vertically.
      // Detect edges and bounce if necessary.
      if (x > (bounds.width - width)){
        xVel = -xVel; // reverse movement.
        x = bounds.width -  width; // Set location to screen edge.
      }
      if (y > (bounds.height - height)){
        yVel = -yVel; // reverse movement.
        y = bounds.height - height;
      }
      if (x <= 0) { xVel = -xVel; x = 0; }
      if (y <= 0) { yVel = -yVel; y = 0; }
    }
  } // end of class VGBall

// Now the instance methods:
  public void paintComponent(Graphics g){
    // Get the drawing area bounds for game logic.
    bounds = g.getClipBounds();
    // Clear the drawing area, then draw the ball.
    g.clearRect(screen.x, screen.y, screen.width, screen.height);
    g.fillRect(ball.x, ball.y, ball.width, ball.height);
  }

  public static void main(String arg[]){

    java.util.Timer vgTimer = new java.util.Timer();  // Create a Timer object
    VGKernel panel = new VGKernel(); 
    
    panel.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    panel.frame.setSize(panel.screen.width, panel.screen.height);

    panel.frame.setContentPane(panel); 
    panel.frame.setVisible(true);

    // Set up a timer to do the vgTask regularly.
    vgTimer.schedule(panel.vgTask, 0, 33);
  }
}
Now the ball not only is its own class, it has a more sophisticated means of keeping track of its direction of movement (xVel and yVel, tracking velocity as a positive or negative value, as opposed to the simple right and down booleans in the original.) This means that logic in the game could vary the velocity of the ball easily, as well as change its direction of movement.

Other objects on the playfield should be defined in their own classes, outside VGKernel. This will keep VGKernel from becoming too long and from making the program too monolithic and difficult to maintain.

Simple exercises:
Since the ball has access to VGKernel's members, including the drawing screen, the ball can be made to draw itself. By giving the ball its own draw() method, we can make it easier to change the appearance of the ball at will. Give it a try.
StumbleUpon

Wednesday, August 4, 2010

A Simple Java Video Game Kernel

Most video games run continuously, rather than waiting for user input before they do something. The heart of a video game of this sort is called the kernel. The kernel is running in the background, collecting user input and updating the display. It uses logic to determine if the game has been won or lost or otherwise control the state of the game.


A bouncing ball in the simple Java video game kernel program.
This simple kernel sends a ball bouncing around on the screen. Turn it into your own Pong, Breakout, or Tank clone.

To run this way, Threads are usually used to allow more than one thing to be going on at a time in a Java program. We've looked at a simple way of using threads before, the Timer class.

Here's a really, really simple video game kernel. It has all the basic elements of a video game.
/* A simple video game style kernel
   by Mark Graybill, August 2010
   Uses the Timer Class to move a ball on a playfield.
*/

// Import Timer and other useful stuff:
import java.util.*;
// Import the basic graphics classes.
import java.awt.*;
import javax.swing.*;

public class VGKernel extends JPanel{

// Set up the objects and variables we'll want.
public Rectangle screen, ball; // The screen area and ball location/size.
public Rectangle bounds;  // The boundaries of the drawing area.
public JFrame frame; // A JFrame to put the graphics into.
public VGTimerTask vgTask; // The TimerTask that runs the game.
public boolean down, right; // Direction of ball's travel.

// Create a constructor method that initializes things:
  public VGKernel(){
    super();
    screen = new Rectangle(0, 0, 600, 400);
    ball   = new Rectangle(0, 0, 20, 20);
    bounds = new Rectangle(0, 0, 600, 400); // Give some starter values.
    frame = new JFrame("VGKernel");
    vgTask = new VGTimerTask();
}
  // Create an inner TimerTask class that has access to the
  // members of the VGKernel.
  class VGTimerTask extends TimerTask{
    public void run(){
      moveBall();
      frame.repaint();
    }
  }

// Now the instance methods:
  public void paintComponent(Graphics g){
    // Get the drawing area bounds for game logic.
    bounds = g.getClipBounds();
    // Clear the drawing area, then draw the ball.
    g.clearRect(screen.x, screen.y, screen.width, screen.height);
    g.fillRect(ball.x, ball.y, ball.width, ball.height);
  }

  public void moveBall(){
  // Ball should really be its own class with this as a method.
    if (right) ball.x+=ball.width; // If right is true, move ball right,
    else ball.x-=ball.width;       // otherwise move left.
    if (down)  ball.y+=ball.height; // Same for up/down.
    else ball.y-=ball.width;
    if (ball.x > (bounds.width - ball.width)) // Detect edges and bounce.
      { right = false; ball.x = bounds.width -  ball.width; }
    if (ball.y > (bounds.height - ball.height))
      { down  = false; ball.y = bounds.height - ball.height;}
    if (ball.x <= 0) { right = true; ball.x = 0; }
    if (ball.y <= 0) { down  = true; ball.y = 0; }
  }

  public static void main(String arg[]){
    java.util.Timer vgTimer = new java.util.Timer();  // Create a Timer.
    VGKernel panel = new VGKernel(); // Create and instance of our kernel.
    
    // Set the intial ball movement direction.
    panel.down = true;
    panel.right = true;

    // Set up our JFRame
    panel.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    panel.frame.setSize(panel.screen.width, panel.screen.height);
    panel.frame.setContentPane(panel); 
    panel.frame.setVisible(true);

    // Set up a timer to do the vgTask regularly.
    vgTimer.schedule(panel.vgTask, 0, 100);
  }
}

This example can be expanded with methods to get control inputs, additional players on the playfield (like paddles), and logic to determine when someone scores.

The code here is far from perfect, but I've made some compromises to make things as simple as I could while still showing a full working example. Not that any code that runs and does what is supposed to is really bad, but there are other, better ways of doing this. But this works and is fairly easy to understand.

What the program does is create a JPanel that has an inner class (a class defined within itself) of VGTimerTask. The VGTimerTask is a kind of TimerTask, which can be scheduled to occur on a regular basis by a Timer. Since VGTimerTask is an inner class of VGPanel, it has access to all the members of VGPanel. This is critical. Without that, it wouldn't be able to access the ball and redraw the screen easily (it can still be done, but in a more complex way.)

Timer is a decent way of running a simple game, but more complex games should use some other timing mechanism. java.util.Timer is affected by a number of outside events, so to get smoother, more reliable timing you a timer like the one in the Java3D package would work better.

A Simple Improvement

There are many ways of improving on this basic example. One way that is very simple is to smooth the animation. The movement of the ball is pretty jerky. This is caused by both the distance that the ball moves each "turn", and by the time between screen updates. We can smooth out the animation by addressing both of these.

First, let's change moveBall() to shift the ball a smaller distance each time:
public void moveBall(){
  // Ball should really be its own class with this as a method.
    if (right) ball.x+=ball.width/4; // If right is true, move ball right,
    else ball.x-=ball.width/4;       // otherwise move left.
    if (down)  ball.y+=ball.height/4; // Same for up/down.
    else ball.y-=ball.width/4;
    if (ball.x > (bounds.width - ball.width)) // Detect edges and bounce.
      { right = false; ball.x = bounds.width -  ball.width; }
    if (ball.y > (bounds.height - ball.height))
      { down  = false; ball.y = bounds.height - ball.height;}
    if (ball.x <= 0) { right = true; ball.x = 0; }
    if (ball.y <= 0) { down  = true; ball.y = 0; }
  }
Now the ball is being moved only one quarter of its size each turn.

Next, change the Timer schedule to draw the screen every 20 milliseconds instead of every 100 milliseconds:
// Set up a timer to do the vgTask regularly.
    vgTimer.schedule(panel.vgTask, 0, 20);

Now you have a ball that moves a lot smoother.

I'll be expanding on this basic kernel and improving it in future articles, starting with Java Video game Programming: Game Logic
StumbleUpon

Thursday, July 29, 2010

Repetition in Java: the Timer Class

One of the things computers are best at is doing the same thing over and over again. They can do things over again so fast that it looks like they're doing it all the time. For example, in animating a video game they are reading controls and redrawing the screen so often that it looks like they're doing it constantly.

One tool for making Java do something over and over again is the Timer class.

A Timer can make your program do something on a regular basis, like redraw the screen thirty times a second, or sound a klaxon every two seconds until you go mad.

Here's a simple example of using Timer to print a message to the console once every second:

import java.util.*;

public class TimerTest {
    public static void main(String[] arg){
        Timer tickTock = new Timer();  // Create a Timer object
        TimerTask tickTockTask = new TimerTask(){
           // This is what we want the Timer to do once a second.
            public void run(){
             System.out.println("Tick");
             System.out.println("Tock");
            }
        };

        tickTock.schedule(tickTockTask, 1000, 1000);
    }
}
I've used a shortcut here to override the run() method of the TimerTask. In TimerTask the run() method is abstract, so you create a definition for it for your instance of a TimerTask. Or for a class that extends TimerTask.

In the schedule() method, we set an initial delay time of 1000 milliseconds (one second) and a repeat time of 1000 milliseconds. When run, the program will do what we told it to do in the TimerTask's run() method once every second.

If you use timer in a simple video game, replace the System.out.println() statements in run() with your game loop commands. Then set the schedule() method's repeat rate to whatever you want, for example, use a repeat rate of 33 for about 30 frames per second.

The Timer is not necessarily the best way to do this for all applications, but it's adequate if your demands aren't too great. The Timer makes use of "threads", which is a way of letting a program do more than one thing at a time. For more intensive applications that need an ability to run in a loop, the Thread class and Runnable interface can do more than a simple Timer and TimerTask.
StumbleUpon

Friday, April 16, 2010

Lists in Java: Sample Code

Here are some simple code examples of using some basic List abilities as described in The List in Java.

Comments about what the code is up to are included below.

This code is written to simply demonstrate a few things, as a reference. I chose to write it a bit "dirty" for the sake of keeping what it does demonstrate as clear as possible. For example it makes some assumptions about the nature of the data it is working with. In a real program, this may not be the right thing to do.

The code will generate a warning you can ignore: Note: Lister.java uses unchecked or unsafe operations.

This is a result of not doing complete checking to make sure that the Object types passed to System.out.println() are compatible, i.e., have a toString() method. It's one of the things I'm not worrying about for the sake of this short demo.

/* Playing around with Lists, in basic ways.
  We use the ArrayList class as an implementation of List,
  since at this point we're just using a List's features,
  rather than learning about building our own List-based
  class.

  -Mark Graybill, Apr. 2010
*/


import java.util.*; // include the package with List in it.

public class Lister{
  public static void main(String arg[]){

  // Create some Lists to play with.
    ArrayList lister = new ArrayList();
    ArrayList dave = new ArrayList();
    ArrayList kryten = new ArrayList();

  // Put some things in the lister List, manually.
    lister.add("The End");
    lister.add("Future Echoes");
    lister.add("Confidence and Paranoia");
    lister.add("Thanks for the Memories");

  // Print the current lister list.
    System.out.print(lister);
    System.out.println();

  /* Get a sublist from lister.
    This will get items at indices 1 and 2. Stops
    short of item 3. I.e., gets sublist from element
    1 up to, but not including, 3. */

    dave.addAll(lister.subList(1,3));

    System.out.print("Sublist elements 1 and 2: ");
    System.out.print(dave);
    System.out.println();

  // Put something in the kryten list.
    kryten.add("The Rimmer Experience");
    kryten.add("Ace");

  // See if kryten is in the lister list.
    if (lister.containsAll(kryten)){
      System.out.println("All of kryten is in lister.");
    }
    else {
      System.out.println("Items in kryten aren't in lister.");
    }

  // Do the same thing with the dave list.
    if (lister.containsAll(dave)){
      System.out.println("Items in dave are all in lister.");
    }
    else {
      System.out.println("Items in dave aren't in lister.");
    }

  // Step through the list with a for-each
    System.out.println(); // Get a blank line.
    System.out.println("Items in Lister:"); // Title the list.
    for (Object epname: lister){ // Print the list.
      System.out.println(epname);
    }

  /* Note: the above code is a little bit "dirty", in that we're counting on
    the objects we get from lister to be printable. Since we've had tight
    control over what goes in, we can get away with this. If you make a List
    that lets anything in, make sure they've all got toString() methods, or
    otherwise take care of object types. Generics are a partial solution to
    this problem (though they're less than perfect.)
  */


  // Get an iterator and use it.
    ListIterator iter = lister.listIterator();

  // Iterator starts out with the first element in List as its "next()"
    System.out.println();
    System.out.println(iter.next());

  // Doing next() has advaned our iterator in the list,
  // so if we do it again:

    System.out.println(iter.next());
  // We see we have advanced. And we advance again.

  // We can it to go through the list, use hasNext() to watch for the end.
    System.out.println("\nGoing forward:");
    while (iter.hasNext()){
      System.out.println(iter.next());
  }

  // And we can go backward:
    System.out.println("\nGoing backward:");
    while (iter.hasPrevious()){
      System.out.println(iter.previous());
    }

  // Print the element in front of "Thanks for the Memories".
    System.out.println("\nItem before \"Thanks for the Memories\" is:");
    while (iter.hasNext()){
      if ( iter.next().toString().contentEquals("Thanks for the Memories") ){
        iter.previous(); //we found it, now move back to it.
        System.out.println(iter.previous());       // Two steps to get back.
        break; // We've done it, now get out of the loop.
      }
    }

  } // end of main()
} // end of Lister


Since I'm not using generics in this code, some of the information about what's stored in the list gets lost--everything becomes an "Object". Not using generics limits the usability of a Collection quite a lot, so it's usually best to use generics as it beats writing all the code to work around the lack of known class types for data.

For example, using Java's Generics, I can declare a type for items in the list that Java will enforce:
ArrayList<String> lister = new ArrayList<String>();

In this way, I can now treat items that come out of lister as a String, too:
if (iter.next().contentEquals("Thanks for the Memories")){ ...

Watch for more about Generics in another article.
StumbleUpon

Tuesday, April 13, 2010

The List in Java

A Java List is a way for keeping track of things in the order you put them in. They are part of the Collections framework in Java, in other words, they are a kind on Collection. Collections all share some abilities, and can easily be converted from one kind of Collection to another.

List is an Interface, which means that it is not a Class, but a standard that you can make a class adhere to. By making a class a List, and implementing at least the required methods of a List, you have the abilities of a List, as if it were a class.
Make sure you have the right List when you look it up.
This is the one you want. The List class from the java.awt package is something different.


Lists are used to keep a list of objects. This seems obvious, but there are lots of ways of collecting up a number of objects in Java, including sets, arrays, different types of lists like linked lists, and maps. Each has its own characteristics. A List is good for sets of objects where you don't know how many objects there might be, where you want the objects kept in the order you put them in, and where you want to be able add objects to the list or remove them. Objects can be added to or removed from Lists en masse. Lists can also be tested against other collections to see if they include all the objects in that list, or none of them.
  • Lists start at zero and go up to the number of objects in them, minus one.

  • You can determine if a List is empty (true or false) using isEmpty()

  • You can get the size of a List using size()

  • You can access an item in a List by its index using get().

  • Items can be added to the end of a List with add(), or

  • You can insert an object into a particular place in a List, moving the rest "down" with add(index, element).

  • You can put one object repeatedly in a List (unlike a Set).

  • You can find the first instance of an object in a List (getting its index) with indexOf(), or

  • You can get the last instance of an object (getting its index) with lastIndexOf()

  • You can delete an object from a List with remove().

  • You can append all the members of some other Collection to a List at once with addAll().

  • You can delete all members of some other Collection from a List all at once with removeAll().

  • You can delete all members that are not in another Collection with retainAll()

  • You can see if all members of a Collection are present in a List with containsAll().

  • You can clear the list out with clear()

  • or keep a section of it with subList().

Some things you can do with a List.

See Lists in Java: Sample Code for examples of using a List.

Many programmers first encounter the List when they run into a method for something they're working with that returns a List. If you're not used to using Collections, this will seem to add an extra layer of complexity. However, it lets the method deal with giving you a group of objects as its return value, without it having to know how many things it might be returning in advance, or what the classes of those objects will be.

For example, the Greenfoot framework for Java makes copious use of the List. If you have a World in Greenfoot that contains a bunch of Robot objects, like this:
A World That Contains a Bunch of Robots

You can do something to all the Robots by calling a World method that returns a List of the Robots.

Using the List


Once you've got the List, you can then do something to all the Robots by iterating through the list and calling the appropriate method for each Robot. To do this, we use the List's ability to provide us with an iterator to move between its elements one by one once we get the List. In this case, it's done automatically by Java's for-each loop:
List<robot> robots = getWorld().getObjects(Robot.class); // get a List of Robots

for (Robot thisRobot : robots) {
thisRobot.turnLeft();
}

This goes through and calls the turnLeft() method of each robot returned in the list.

To explicitly get an iterator from a List, we can use the listIterator() method of the List:
ListIterator robotIterator = robots.listIterator();

This gives us a list iterator that starts at zero and progresses through the list as we call the iterator's next() method, after checking to see that there is a next item using hasNext(), of course. See ListIterator to see what you can do with the iterator.

We can also get an iterator that starts at a particular position in the list. For example, let's say we want to skip our way past the first 100 elements:
ListIterator robotIterator = robots.listIterator(100);


The normal use of a List is as a simple list of objects to iterate through, as shown. The use of the additional features of the List make it a far more powerful construct, however. In general, it's very useful to learn as much about Collections in Java as possible, as they are the most generally useful data structures for dealing with groups of objects.

See Lists in Java: Sample Code for examples of using a List.
StumbleUpon

Tuesday, February 16, 2010

A Brief Guide to the Site

I've added a couple of article lists (visible at upper right on this page) to make it easier to find some of the more significant articles in the archives.

The first is basic articles on Java and programming in Java. The second covers graphics articles and user interaction like keyboard and mouse input.

I hope this makes it easier to find what you're looking for, or find other articles of interest.
StumbleUpon