import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
import java.util.ArrayList;
public class Snake extends JFrame implements ActionListener {
private static final long serialVersionUID = 123654L; // just to avoid compile warning
// number of squares in the grid, size of each of them
private static final int SIZE = 25, WIDTH = 20;
// the labels for displaying the snake and its foods
private SnakeLabel[][] label = new SnakeLabel[SIZE][SIZE];
// arrayList containing all of the snake position (Labels)
private SnakeList snakeList = new SnakeList();
// the label displaying if I am running or not and the size of the snake
private JLabel statusLabel = new JLabel("Initializing");
// random number generator to find a new spot for a new food when I eat one
private Random random = new Random();
// if I am in a pause state or not
boolean pause = false;
// the button to switch from pause to not pause
private JButton pauseResume = new JButton("Pause");
// which direction I am running and where is my head
private int directionX = 0, directionY = -1, headX, headY;
// the refresh rate
private int refreshRate;
// The Timer that moves the Snake
private Timer timer;
Snake() {
super("Snake Game");
// to hold all the labels with a gap of 1 pixel
JPanel panel = new JPanel(new GridLayout(SIZE, SIZE, 1, 1));
// the same color as the Snake so the back will show a continuos snake
panel.setBackground(Color.BLUE);
panel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
// create all the JLabels
initLabels(panel);
// add the 4 foods
initFood();
// init the snake the length of a quarter of our size
initSnake(SIZE / 4);
add(panel, BorderLayout.CENTER);
// label if I am running well and size of the snake
statusLabel.setHorizontalAlignment(SwingConstants.CENTER);
statusLabel.setOpaque(true);
statusLabel.setBackground(Color.YELLOW);
add(statusLabel, BorderLayout.NORTH);
// listener so the pause button will work
pauseResume.setForeground(Color.RED);
pauseResume.addActionListener(this);
add(pauseResume, BorderLayout.SOUTH);
// general JFrame stuff its size and visible
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(SIZE * WIDTH - 5, SIZE * WIDTH - 5);
setVisible(true);
// start the thread that move the snakes
refreshRate = 5000 / (snakeList.size() / 2);
timer = new Timer(refreshRate, this);
timer.start();
}
// to initialize the labels filling the grid
// this method is called only once
private void initLabels(JPanel p) {
for(int j = 0; j < SIZE; j++) {
for(int i = 0; i < SIZE; i++) {
label[i][j] = new SnakeLabel(i, j);
p.add(label[i][j]);
}
}
}
// to put the initial 4 food labels in 1/4 of the grid
// this method will be called only once
private void initFood() {
// north/west at 1/4 of the grid
int x = SIZE / 4;
int y = x;
label[x][y].setFood(true);
// north east so x is the same delta from the end
x = SIZE - x;
label[x][y].setFood(true);
// south/west
y = x;
x = SIZE / 4;
label[x][y].setFood(true);
// south east
x = y;
label[x][y].setFood(true);
}
// to position the snake at the beginning of game
private void initSnake(int length) {
// the snake in the middle of everything initial size of length
headX = SIZE / 2;
headY = (SIZE / 2) - (length / 2);
// declare these label as holding the snake
// registering them in the arrayList
for(int i = headY; i < headY + length; i++)
snakeList.addLabel(label[headX][i]);
// set the color for the first time
snakeList.updateColor();
}
// run
public void runSnake() {
// wait according to snake length... determine an empiric way
int oldRefreshRate = refreshRate;
refreshRate = 5000 / (snakeList.size() / 2);
// manage to have at least a minimum refresh rate
if(refreshRate < 10)
refreshRate = 10;
// if refresh rate changed, update Timer delay
if(oldRefreshRate != refreshRate)
timer.setDelay(refreshRate);
// if the "Pause" button was pushed go to next turn
if(pause)
return;
// update snake head position
headX += directionX;
headY += directionY;
// check if we are going out of bound
if(headX < 0 || headX >= SIZE || headY < 0 || headY >= SIZE) {
statusLabel.setText("Out of bound... length: " + snakeList.size());
timer.stop();
pauseResume.setEnabled(false);
return;
}
// check if we are eating ourself
if(label[headX][headY].isSnake) {
statusLabel.setText("You eat yourself... length: " + snakeList.size());
timer.stop();
pauseResume.setEnabled(false);
return;
}
// if we hit food
if(label[headX][headY].isFood) {
snakeList.updateHead(); // without updating tail
// found new place for food
for(;;) {
int x = random.nextInt(SIZE);
int y = random.nextInt(SIZE);
// start again if new random place is already in the snake or is already food
if(label[x][y].isFood)
continue;
if(label[x][y].isSnake)
continue;
// ok good dpot not used yet/// declare it as food
label[x][y].setFood(true);
break;
}
}
else {
snakeList.updateTail(); // first if I pass on my back
snakeList.updateHead();
}
statusLabel.setText("Running... snake length: " + snakeList.size()
+ " Refresh Rate: " + refreshRate + "/1000 sec");
}
// called when the pause/resume button is hit
public void actionPerformed(ActionEvent e) {
Object o = e.getSource();
if(o == pauseResume) {
// change the state
pause = !pause;
// update button text accordingly
if(pause) {
pauseResume.setText("Resume");
timer.stop();
}
else {
pauseResume.setText("Pause");
timer.restart();
}
return;
}
else { // it is the Timer if it is not the pauseResume button
runSnake();
}
}
// to run the whole damned thing
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Snake();
}
});
}
// array list that contains the position taken by the snake
private class SnakeList extends ArrayList<SnakeLabel> {
private static final long serialVersionUID = 654321L; // to avoid compile warning
// the 2 colours of the snake
private Color[] snakeColor = {new Color(0, 0, 255), new Color(75, 75, 255)};
// for initial build when we install the snake first positions
private boolean addLabel(SnakeLabel sl) {
// flag the SnakeLabel as being part of the Snake
sl.setSnake(true);
// call father's method to add an object into the arrayList
return add(sl);
}
// remove (make free) the tail of the snake
private void updateTail() {
SnakeLabel sl = remove(size() - 1);
sl.setSnake(false);
}
// to update the head to new position
private void updateHead() {
// declare it as part of the snake
label[headX][headY].setSnake(true);
// add it to the head of the snake
add(0, label[headX][headY]);
// switch colors
updateColor();
}
// to put 2 colours in the snake
private void updateColor() {
int len = size();
// the head in black
get(0).setBackground(Color.BLACK);
// variation of blue for the others
for(int i = 1; i < len; i++) {
get(i).setBackground(snakeColor[i % snakeColor.length]);
}
}
} // end of inner class SnakeList
// specialized JLabel to keep coordinate X and Y and have a mouseListener if cliked
private class SnakeLabel extends JLabel implements MouseListener{
private static final long serialVersionUID = 123456L; // to avoid compile warning
// my coordinates on the Grid so the mouseListener can know where I am situate
private int x, y;
// init not food and not snake
boolean isFood = false; // not a food case
boolean isSnake = false; // not part of the snake
// constructor
SnakeLabel(int x, int y) {
super("");
// save my coordinates
this.x = x; this.y = y;
// opaque because I use background to represent myself
setOpaque(true);
// so I will react if I am cleicked
addMouseListener(this);
// default color
setBackground(Color.WHITE);
}
// declares me as a food case or not
private void setFood(boolean state) {
isFood = state;
// change color accordingly
if(state)
setBackground(Color.RED); // food color
else
setBackground(Color.WHITE); // regular color
}
// declares me as part of the snake or not
private void setSnake(boolean state) {
isSnake = state;
// change my color accordingly
if(state) {
setFood(false); // make it available again as food slot
setBackground(Color.BLUE);
}
else {
setBackground(Color.WHITE);
}
}
// ok click on me I just chek for the Pressed event to react faster
// (important when the snake goes very fast)
public void mousePressed(MouseEvent e) {
// so am I going vertically or horitonaly
if(directionX == 0) {
// if clicked on my same X nothing to do
if(x == headX)
return;
directionY = 0; // stop updating Y
// if clicked to my left
if(x < headX) {
// update the way I am going
directionX = -1;
}
else { // so to my rioght
directionX = +1;
}
}
else { // OK I am moving horizontaly
if(y == headY)
return;
directionX = 0;
if(y < headY) { // to my left
directionY = -1;
}
else { // to my right
directionY = +1;
}
}
}
// do not react to those but as I implement MouseListener have have to implement these
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
public void mouseClicked(MouseEvent arg0) {}
public void mouseReleased(MouseEvent arg0) {}
} // end inner class SnakeLabel
}
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
import java.util.ArrayList;
public class Snake extends JFrame implements ActionListener {
private static final long serialVersionUID = 123654L; // just to avoid compile warning
// number of squares in the grid, size of each of them
private static final int SIZE = 25, WIDTH = 20;
// the labels for displaying the snake and its foods
private SnakeLabel[][] label = new SnakeLabel[SIZE][SIZE];
// arrayList containing all of the snake position (Labels)
private SnakeList snakeList = new SnakeList();
// the label displaying if I am running or not and the size of the snake
private JLabel statusLabel = new JLabel("Initializing");
// random number generator to find a new spot for a new food when I eat one
private Random random = new Random();
// if I am in a pause state or not
boolean pause = false;
// the button to switch from pause to not pause
private JButton pauseResume = new JButton("Pause");
// which direction I am running and where is my head
private int directionX = 0, directionY = -1, headX, headY;
// the refresh rate
private int refreshRate;
// The Timer that moves the Snake
private Timer timer;
Snake() {
super("Snake Game");
// to hold all the labels with a gap of 1 pixel
JPanel panel = new JPanel(new GridLayout(SIZE, SIZE, 1, 1));
// the same color as the Snake so the back will show a continuos snake
panel.setBackground(Color.BLUE);
panel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
// create all the JLabels
initLabels(panel);
// add the 4 foods
initFood();
// init the snake the length of a quarter of our size
initSnake(SIZE / 4);
add(panel, BorderLayout.CENTER);
// label if I am running well and size of the snake
statusLabel.setHorizontalAlignment(SwingConstants.CENTER);
statusLabel.setOpaque(true);
statusLabel.setBackground(Color.YELLOW);
add(statusLabel, BorderLayout.NORTH);
// listener so the pause button will work
pauseResume.setForeground(Color.RED);
pauseResume.addActionListener(this);
add(pauseResume, BorderLayout.SOUTH);
// general JFrame stuff its size and visible
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(SIZE * WIDTH - 5, SIZE * WIDTH - 5);
setVisible(true);
// start the thread that move the snakes
refreshRate = 5000 / (snakeList.size() / 2);
timer = new Timer(refreshRate, this);
timer.start();
}
// to initialize the labels filling the grid
// this method is called only once
private void initLabels(JPanel p) {
for(int j = 0; j < SIZE; j++) {
for(int i = 0; i < SIZE; i++) {
label[i][j] = new SnakeLabel(i, j);
p.add(label[i][j]);
}
}
}
// to put the initial 4 food labels in 1/4 of the grid
// this method will be called only once
private void initFood() {
// north/west at 1/4 of the grid
int x = SIZE / 4;
int y = x;
label[x][y].setFood(true);
// north east so x is the same delta from the end
x = SIZE - x;
label[x][y].setFood(true);
// south/west
y = x;
x = SIZE / 4;
label[x][y].setFood(true);
// south east
x = y;
label[x][y].setFood(true);
}
// to position the snake at the beginning of game
private void initSnake(int length) {
// the snake in the middle of everything initial size of length
headX = SIZE / 2;
headY = (SIZE / 2) - (length / 2);
// declare these label as holding the snake
// registering them in the arrayList
for(int i = headY; i < headY + length; i++)
snakeList.addLabel(label[headX][i]);
// set the color for the first time
snakeList.updateColor();
}
// run
public void runSnake() {
// wait according to snake length... determine an empiric way
int oldRefreshRate = refreshRate;
refreshRate = 5000 / (snakeList.size() / 2);
// manage to have at least a minimum refresh rate
if(refreshRate < 10)
refreshRate = 10;
// if refresh rate changed, update Timer delay
if(oldRefreshRate != refreshRate)
timer.setDelay(refreshRate);
// if the "Pause" button was pushed go to next turn
if(pause)
return;
// update snake head position
headX += directionX;
headY += directionY;
// check if we are going out of bound
if(headX < 0 || headX >= SIZE || headY < 0 || headY >= SIZE) {
statusLabel.setText("Out of bound... length: " + snakeList.size());
timer.stop();
pauseResume.setEnabled(false);
return;
}
// check if we are eating ourself
if(label[headX][headY].isSnake) {
statusLabel.setText("You eat yourself... length: " + snakeList.size());
timer.stop();
pauseResume.setEnabled(false);
return;
}
// if we hit food
if(label[headX][headY].isFood) {
snakeList.updateHead(); // without updating tail
// found new place for food
for(;;) {
int x = random.nextInt(SIZE);
int y = random.nextInt(SIZE);
// start again if new random place is already in the snake or is already food
if(label[x][y].isFood)
continue;
if(label[x][y].isSnake)
continue;
// ok good dpot not used yet/// declare it as food
label[x][y].setFood(true);
break;
}
}
else {
snakeList.updateTail(); // first if I pass on my back
snakeList.updateHead();
}
statusLabel.setText("Running... snake length: " + snakeList.size()
+ " Refresh Rate: " + refreshRate + "/1000 sec");
}
// called when the pause/resume button is hit
public void actionPerformed(ActionEvent e) {
Object o = e.getSource();
if(o == pauseResume) {
// change the state
pause = !pause;
// update button text accordingly
if(pause) {
pauseResume.setText("Resume");
timer.stop();
}
else {
pauseResume.setText("Pause");
timer.restart();
}
return;
}
else { // it is the Timer if it is not the pauseResume button
runSnake();
}
}
// to run the whole damned thing
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Snake();
}
});
}
// array list that contains the position taken by the snake
private class SnakeList extends ArrayList<SnakeLabel> {
private static final long serialVersionUID = 654321L; // to avoid compile warning
// the 2 colours of the snake
private Color[] snakeColor = {new Color(0, 0, 255), new Color(75, 75, 255)};
// for initial build when we install the snake first positions
private boolean addLabel(SnakeLabel sl) {
// flag the SnakeLabel as being part of the Snake
sl.setSnake(true);
// call father's method to add an object into the arrayList
return add(sl);
}
// remove (make free) the tail of the snake
private void updateTail() {
SnakeLabel sl = remove(size() - 1);
sl.setSnake(false);
}
// to update the head to new position
private void updateHead() {
// declare it as part of the snake
label[headX][headY].setSnake(true);
// add it to the head of the snake
add(0, label[headX][headY]);
// switch colors
updateColor();
}
// to put 2 colours in the snake
private void updateColor() {
int len = size();
// the head in black
get(0).setBackground(Color.BLACK);
// variation of blue for the others
for(int i = 1; i < len; i++) {
get(i).setBackground(snakeColor[i % snakeColor.length]);
}
}
} // end of inner class SnakeList
// specialized JLabel to keep coordinate X and Y and have a mouseListener if cliked
private class SnakeLabel extends JLabel implements MouseListener{
private static final long serialVersionUID = 123456L; // to avoid compile warning
// my coordinates on the Grid so the mouseListener can know where I am situate
private int x, y;
// init not food and not snake
boolean isFood = false; // not a food case
boolean isSnake = false; // not part of the snake
// constructor
SnakeLabel(int x, int y) {
super("");
// save my coordinates
this.x = x; this.y = y;
// opaque because I use background to represent myself
setOpaque(true);
// so I will react if I am cleicked
addMouseListener(this);
// default color
setBackground(Color.WHITE);
}
// declares me as a food case or not
private void setFood(boolean state) {
isFood = state;
// change color accordingly
if(state)
setBackground(Color.RED); // food color
else
setBackground(Color.WHITE); // regular color
}
// declares me as part of the snake or not
private void setSnake(boolean state) {
isSnake = state;
// change my color accordingly
if(state) {
setFood(false); // make it available again as food slot
setBackground(Color.BLUE);
}
else {
setBackground(Color.WHITE);
}
}
// ok click on me I just chek for the Pressed event to react faster
// (important when the snake goes very fast)
public void mousePressed(MouseEvent e) {
// so am I going vertically or horitonaly
if(directionX == 0) {
// if clicked on my same X nothing to do
if(x == headX)
return;
directionY = 0; // stop updating Y
// if clicked to my left
if(x < headX) {
// update the way I am going
directionX = -1;
}
else { // so to my rioght
directionX = +1;
}
}
else { // OK I am moving horizontaly
if(y == headY)
return;
directionX = 0;
if(y < headY) { // to my left
directionY = -1;
}
else { // to my right
directionY = +1;
}
}
}
// do not react to those but as I implement MouseListener have have to implement these
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
public void mouseClicked(MouseEvent arg0) {}
public void mouseReleased(MouseEvent arg0) {}
} // end inner class SnakeLabel
}
0 komentar:
Posting Komentar