• Welcome to Valhalla Legends Archive.
 

Recreating "Snake" - Drawing on a JFrame

Started by Joe[x86], March 06, 2006, 08:54 PM

Previous topic - Next topic

Joe[x86]

I'm sure pretty much everyone, even us programmers, have played the cell-phone game Snake, and pretty much know how it works. Anyhow, I'm writing it in Java in my spare time. So far I've set up a class that extends JFrame implements keyListener, and will capture the WSAD movement keys (for directing the snake), and tell you when you use a bad key. I've set up a timer to move the snake, which is just outputting a console message on firing right now. That's all just fine.

The hard part, though, is how I'm supposed to draw the snake (and hold the coordinates of his tail, but that shouldn't be nearly as hard) on an imaginary "grid" on top of the JFrame. Anyone have experience doing something like this?
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

iago

Well, if you need inspiration or ideas, you can check out ZSnake.  It's an open-source snake-style game written in Java. 
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


MyndFyre

I don't know if this is available in Java, but save yourself some headaches early on and look into double buffering to avoid flicker.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Joe[x86]

Quote from: iago on March 06, 2006, 10:16 PM
Well, if you need inspiration or ideas, you can check out ZSnake.  It's an open-source snake-style game written in Java. 

Although playing it was extremely fun (lol), it's commented in German. =(
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

iago

I thought the website was in French?

In any case, MyndFyre is right.  Java has a pretty extensive 2d (and 3d, if you're into that) graphics library, you could probably find out a lot about it on Java's site.  I'm sure I've seen a 2d tutorial.  But if you're going to do that, make sure you're on Java 1.5, because it's way faster than 1.4.*.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Joe[x86]

#5
EDIT -
Now playable and fun! All that's not coded yet is the growing of the tail, which I think will be a royal pain. Original post below:




Hdx linked me to Graphics2D last night. I don't see the difference between that and Graphics, but oh well. I'm using Graphics.fillRect(int, int, int, int) right now. I've managed to make the dot drag across the screen and be controlled with the WSAD keys. It won't go up or left (I probably did something really stupid..), and it won't clear it's path once it's gone, but I've made a ton of progress. =)

EDIT -
// Key listener
import java.awt.event.*;

// Window
import javax.swing.*;
import java.awt.*;

// Timer
import java.util.Timer;
import java.util.TimerTask;

public class Snake extends JFrame implements KeyListener
{
private static final int DIR_NULL  = 0; // Direction's for the snake to move
private static final int DIR_UP    = 1;
private static final int DIR_DOWN  = 2;
private static final int DIR_LEFT  = 3;
private static final int DIR_RIGHT = 4;

private static final int SIZE = 15; // Size of the snake

private Container c; // Container, marking the JFrame background
private Timer snakeMoveTimer = new Timer(); // Timer used to fire snake moving events

private int xPos = SIZE; // X coordinate of snake
private int yPos = SIZE; // Y coordinate of snake

private int direction = DIR_NULL; // direction snake is moving

private int xPosFood = 0; // X coordinate of food
private int yPosFood = 0; // Y coordinate of food

private int score = 0; // Score!


/**
* Program entry-point
* @param args Commandline arguments
*/
public static void main(String args[])
{
new Snake();
// calls class constructor
}

/**
* Class constructor
* Creates a new instance of Snake
*/
public Snake()
{
// Set up JFrame
super("Snake!");
this.setSize(800, 500);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
c = getContentPane();
c.setBackground(Color.yellow);
this.setVisible(true);

// Add a key listener
this.addKeyListener(this);

// Create the task to move the snake with
snakeMoveTimer.schedule(new SnakeMoveTask(), 1000, 100);
}

/**
* Fired by keyListener when a key is pressed then released
* Used to tell the snake which direction to move
* WSAD directions (up down left right)
* @param e KeyEvent struct, telling us what happened in this event
*/
    public void keyTyped(KeyEvent e) {
switch (e.getKeyChar())
{
case 'w': // up
this.direction = DIR_UP;
break;
case 's': // down
this.direction = DIR_DOWN;
break;
case 'a': // left
this.direction = DIR_LEFT;
break;
case 'd': // right
this.direction = DIR_RIGHT;
break;
default:
System.out.println("Unrecognized keystroke: 0x" + Integer.toHexString((int)e.getKeyChar()));
break;
}
    }

/**
* Fired when run of SnakeMoveTask calls repaint
* Resonsible for moving the snake
*/
    public void paint(Graphics g)
    {
if((xPosFood == 0) || (yPosFood == 0))
{
// Draw food
g.setColor(Color.pink);
xPosFood = (int)(Math.random() * 800 / SIZE) * SIZE;
yPosFood = (int)(Math.random() * 500 / SIZE) * SIZE;
g.fillRect(xPosFood, yPosFood, SIZE, SIZE);
}
int old_x = xPos, old_y = yPos;
switch (direction)
{
case DIR_UP:
yPos -= SIZE;
break;
case DIR_DOWN:
yPos += SIZE;
break;
case DIR_LEFT:
xPos -= SIZE;
break;
case DIR_RIGHT:
xPos += SIZE;
break;
}
if ((xPos == xPosFood) && (yPos == yPosFood))
{
g.setColor(Color.pink);
g.clearRect(xPosFood, yPosFood, SIZE, SIZE);
xPosFood = (int)(Math.random() * 800 / SIZE) * SIZE;
yPosFood = (int)(Math.random() * 500 / SIZE) * SIZE;
g.fillRect(xPosFood, yPosFood, SIZE, SIZE);
score += 10;
}
g.setColor(Color.yellow);
g.clearRect(old_x, old_y, SIZE, SIZE);
g.fillRect(xPos, yPos, SIZE, SIZE);

// Border check
if ((xPos < 0) || (xPos > 800) || (yPos < 0) || (yPos > 500))
{
// Game over
xPos = SIZE;
yPos = SIZE;
xPosFood = 0;
yPosFood = 0;
direction = DIR_NULL;
g.clearRect(0, 0, 800, 500);
JOptionPane.showMessageDialog(null, "Game over!\n Your score: " + score + ".");
score = 0;
}
}

/**
* Fired by keyListener - stub function
* @param e KeyEvent struct, telling us what happened in this event
*/
    public void keyPressed(KeyEvent e) {
    }
/**
* Fired by keyListener - stub function
* @param e KeyEvent struct, telling us what happened in this event
*/
public void keyReleased(KeyEvent e) {
    }

class SnakeMoveTask extends TimerTask
{
/**
* Called by snakeMoveTimer when it fires
* Responsible for calling repaint, to fire paint of Snake
*/
public void run()
{
repaint();
}
}

}


EDIT -
VB moment! I forgot to break in my direction switch. Oops!
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

SecretShop

#6
Consider the following:
1) A snake has a set length that increases over time
2) Each part of the snake exists until the tail surpasses it
3) The only part that moves are the head and the tail

Just after a first look, it seems like you could use a Queue that stores points on a matrix.  When the length of the Queue reaches the size of the snake just remove the tail item and push the new point of the head onto the Queue.  If you're following the motif of the cellphone game, probably just create a matrix to store the game board, possibly of integers.  0 for empty, 1 for head, 2 for body, 3 for tail.  Seems pretty simple with this design, tell me what you think.

Edit: Also I would use the directional keys only to dictate what vector the snake should move in and have it move automaticly on a timer.

Joe[x86]

I was following the cellphone game, but this was really a "case study" of sorts to learn more about Swing and ActionListener.
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

Grok

Snake (by any name) is one of those classic assignments you give to people in about 3rd year CS to help them think about algorithms.  Better algorithms are needed to improve look-ahead abilities the snake has to avoid collisions.

Joe[x86]

Yeah, this never turned out to be the old cell-phone game, snake. It was a dot moving around the screen bumping into other dots and gaining 10 points.
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.