-
-
Save anonymous/a55e9ab57b7f231ae93c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package snake; | |
import java.awt.Point; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.awt.event.KeyEvent; | |
import java.awt.event.KeyListener; | |
import java.util.ArrayList; | |
import java.util.Random; | |
import java.awt.Color; | |
import java.awt.Graphics; | |
import java.awt.Point; | |
import javax.swing.JFrame; | |
import javax.swing.Timer; | |
import javax.swing.JPanel; | |
public class Snake implements ActionListener, KeyListener { | |
public static int width = 500; | |
public static int height = width / 16 * 12; | |
public JFrame frame; | |
public RenderPanel renderPanel; | |
public static Snake snake; | |
public Timer timer = new Timer(20, this); // infinite loop & listener; | |
public Point head, apple; | |
public ArrayList<Point> snakeParts = new ArrayList<Point>(); | |
public Random random; | |
public static final int SPEED = 1, SCALE = 10, LEFT = 0, UP = 1, RIGHT = 2, DOWN = 3; | |
public int tick, direction = DOWN; | |
public static int tailLength = 0; // or 1; | |
public int XBOUND, YBOUND; | |
public boolean over, pause, keyPressed; | |
public static void main(String[] args) { | |
snake = new Snake(); | |
} | |
/*CONSTRUCTOR*/ | |
public Snake() { | |
frame = new JFrame("Snake"); | |
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
frame.setSize(width, height); | |
frame.setVisible(true); | |
frame.setResizable(false); | |
frame.setLocationRelativeTo(null); // centering the screen; | |
frame.getContentPane().add(renderPanel = new RenderPanel()); | |
frame.addKeyListener(this); | |
startGame(); | |
} | |
public void startGame() { | |
XBOUND = frame.getWidth() / SCALE - 1; // set a boundary; | |
YBOUND = frame.getHeight() / SCALE - 3; | |
random = new Random(); | |
over = false; | |
pause = false; | |
tick = 0; | |
apple = new Point (random.nextInt(XBOUND), random.nextInt(YBOUND)); | |
snakeParts.clear(); | |
head = new Point(0, 0); | |
snakeParts.add(new Point(head.x, head.y)); | |
timer.start(); // infinite loop of actionPerformed() method; | |
} | |
@Override | |
public void actionPerformed(ActionEvent event) { | |
renderPanel.repaint(); | |
tick++; | |
if (tick % SPEED == 0 && !over && !pause) { | |
/************************ | |
POINT | |
*************************/ | |
keyPressed = false; | |
if (snakeParts.size() >= tailLength && !over) { // over just for display, so that last tail won't be deleted if game over; | |
snakeParts.remove(0); | |
} | |
snakeParts.add(new Point(head.x, head.y)); | |
switch (direction) { | |
case DOWN : | |
if (head.y + 1 < YBOUND && noTailInFront(head.x, head.y + 1)) { // if there is tail == death; | |
head = new Point(head.x, head.y + 1); | |
} else { | |
over = true; | |
} | |
break; | |
case RIGHT : | |
if (head.x + 1 < XBOUND && noTailInFront(head.x + 1, head.y)) { | |
head = new Point(head.x + 1, head.y); | |
} else { | |
over = true; | |
} | |
break; | |
case UP : | |
if (head.y - 1 >= 0 && noTailInFront(head.x, head.y - 1)) { | |
head = new Point(head.x, head.y - 1); | |
} else { | |
over = true; | |
} | |
break; | |
case LEFT : | |
if (head.x - 1 >= 0 && noTailInFront(head.x - 1, head.y)) { | |
head = new Point(head.x - 1, head.y); | |
} else { | |
over = true; | |
} | |
break; | |
} // switch direction | |
if (head.equals(apple)) { | |
snakeParts.add(head); | |
tailLength++; | |
apple = new Point (random.nextInt(XBOUND), random.nextInt(YBOUND)); | |
} | |
} // end of tick | |
} // actionPerformed | |
public boolean noTailInFront (int x, int y) { | |
for (Point point : snakeParts) { | |
if (point.equals(new Point(x, y) ) ) { | |
return false; | |
} | |
} | |
return true; | |
} | |
@Override | |
public void keyPressed (KeyEvent key) { | |
int i = key.getKeyCode(); | |
/************************ | |
POINT | |
*************************/ | |
if (keyPressed) { // key can be pressed only once per loop; | |
return; // by returning immediately after key is pressed; | |
} | |
if (i == KeyEvent.VK_RIGHT && direction != LEFT) { | |
direction = RIGHT; | |
keyPressed = true; | |
} | |
if (i == KeyEvent.VK_LEFT && direction != RIGHT) { | |
direction = LEFT; | |
keyPressed = true; | |
} | |
if (i == KeyEvent.VK_UP && direction != DOWN) { | |
direction = UP; | |
keyPressed = true; | |
} | |
if (i == KeyEvent.VK_DOWN && direction != UP) { | |
direction = DOWN; | |
keyPressed = true; | |
} | |
if (i == KeyEvent.VK_SPACE) { | |
if (!over) { | |
pause = !pause; | |
} else { | |
startGame(); | |
} | |
} | |
} // keyPressed | |
@Override | |
public void keyReleased (KeyEvent key) { } | |
@Override | |
public void keyTyped (KeyEvent key) { } | |
} | |
/************************** | |
RENDER CLASS | |
***************************/ | |
public class RenderPanel extends JPanel { | |
public void paintComponent(Graphics g) { | |
Snake snake = Snake.snake; // ref to same object (snake) of class Snake; (if we create new obj, it will cause infinite loop) | |
int length = snake.snakeParts.size(); | |
g.setColor(Color.BLUE); | |
g.fillRect(0, 0, this.getWidth(), this.getHeight()); // as panel (class RenderPanel) size; | |
for (Point point : snake.snakeParts) { | |
if (point == snake.snakeParts.get(length - 1)) { // set head color distinctly from body; | |
g.setColor(Color.YELLOW); | |
g.fillRect(point.x * Snake.SCALE, point.y * Snake.SCALE, Snake.SCALE, Snake.SCALE); | |
} else { | |
g.setColor(Color.BLACK); | |
g.fillRect(point.x * Snake.SCALE, point.y * Snake.SCALE, Snake.SCALE, Snake.SCALE); | |
} | |
} | |
g.setColor(Color.RED); | |
g.fillOval(snake.apple.x * Snake.SCALE, snake.apple.y * Snake.SCALE, Snake.SCALE, Snake.SCALE); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment