-
Notifications
You must be signed in to change notification settings - Fork 0
/
GamePanel.java
236 lines (208 loc) · 6.46 KB
/
GamePanel.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/**
* This is the classic Snake Game programmed in Java. The class extends JPanel and implements the ActionListener.
*
* I added a button to restart the game after losing.
* This class holds the whole game.
*
* @author Vivian Gleißner (I followed a Youtube Tutorial--> https://www.youtube.com/watch?v=bI6e6qjJ8JQ)
* @version 1.1
* @since 2023-10-02
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class GamePanel extends JPanel implements ActionListener{
static final int SCREEN_WIDTH = 600;
static final int SCREEN_HEIGHT = 600;
static final int UNIT_SIZE = 25; // size of the squares
static final int GAME_UNITS = (SCREEN_WIDTH * SCREEN_HEIGHT)/UNIT_SIZE;
static final int DELAY = 130; // the higher the number, the slower the game
final int x[] = new int[GAME_UNITS]; // holds all the x-coordinates of the snakes body
final int y[] = new int [GAME_UNITS]; // holds all the y-coordinates of the snakes body
int bodyParts = 6; // holds the amount of body parts of the snake (the length of the snake)
int applesEaten; // is zero in the beginning
int appleX; // random x-coordinates of the apples that can be eaten
int appleY; // random y-coordinates of the apples that can be eaten
char direction = 'R'; // Direction if the snake when game is started ('R' for right)
boolean running = false;
Timer timer;
Random random;
public GamePanel() {
random = new Random();
this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
this.setBackground(Color.black);
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
}
/**
* Method that starts the game
*/
public void startGame() {
newApple();
running = true;
timer = new Timer(DELAY, this);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
/**
* Method that draws the components on the Panel (Apples, Snake,...)
* It also displays the score
*
* @param g The graphical components
*/
public void draw(Graphics g) {
if(running) {
// going through the panel to draw a grid to make the units visible (draw lines across x-axis)
for(int i=0; i<SCREEN_HEIGHT/UNIT_SIZE;i++) {
g.setColor(Color.darkGray);
g.drawLine(i*UNIT_SIZE, 0, i*UNIT_SIZE, SCREEN_HEIGHT);
g.drawLine(0, i*UNIT_SIZE, SCREEN_WIDTH, i*UNIT_SIZE);
}
g.setColor(Color.red);
g.fillOval(appleX, appleY, UNIT_SIZE, UNIT_SIZE);
// drawing the snake
for(int i=0; i<bodyParts;i++) {
if(i==0) {
//then it is the head of the snake
g.setColor(Color.yellow);
g.fillOval(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
}
else {
g.setColor(Color.yellow);
g.fillOval(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
}
}
// Shows the current score
g.setColor(Color.white);
g.setFont(new Font("", Font.BOLD, 20));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString("Your score: " + applesEaten, (SCREEN_WIDTH - metrics.stringWidth("Your score: " + applesEaten))/2, g.getFont().getSize());
} else {
gameOver(g);
}
}
/**
* Creates random positions for the apples
*/
public void newApple() {
appleX = random.nextInt((int)(SCREEN_WIDTH/UNIT_SIZE))*UNIT_SIZE;
appleY = random.nextInt((int)(SCREEN_HEIGHT/UNIT_SIZE))*UNIT_SIZE;
}
/**
* Moves the snake around and shifts the body parts of the snake
*/
public void move() {
for(int i=bodyParts;i>0;i--) {
x[i] = x[i-1];
y[i] = y[i-1];
}
//switch changes the direction of the snake, depending on switch case
switch(direction) {
case 'U': y[0] = y[0] - UNIT_SIZE;
break;
case 'L': x[0] = x[0] - UNIT_SIZE;
break;
case 'D': y[0] = y[0] + UNIT_SIZE;
break;
case 'R': x[0] = x[0] + UNIT_SIZE;
break;
}
}
/**
* Check if the sneaks heads position is the same as the current apple
*/
public void checkApple() {
if((x[0] == appleX) && (y[0] == appleY)){
bodyParts++;
applesEaten++;
newApple();
}
}
/**
* Method that checks if the snakes head collides with another element
*
* Option 1: Collides with own body
* Option 2: Collides with border
*/
public void checkCollisions() {
// Checks if head collides with body
for(int i=bodyParts; i>0; i--) {
if((x[0] == x[i]) && (y[0] == y[i])) running = false;
}
// Checks if head collides with border
if(x[0]<0) running=false;
if(x[0]>SCREEN_WIDTH) running=false;
if(y[0]<0) running=false;
if(y[0]>SCREEN_HEIGHT) running=false;
if(!running) timer.stop();
}
/**
* Display text when game is over
*
* @param g The text that gets displayed on the Panel
*/
public void gameOver(Graphics g) {
// Game over text gets displayed
g.setColor(Color.yellow);
g.setFont(new Font("Ink Free", Font.BOLD, 75));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString("Game over!", (SCREEN_WIDTH - metrics.stringWidth("Game over!"))/2, SCREEN_HEIGHT/2);
// also display the score when game is over
g.setColor(Color.white);
g.setFont(new Font("Ink Free", Font.BOLD, 20));
FontMetrics metricsScrore = getFontMetrics(g.getFont());
g.drawString("Score: " + applesEaten, (SCREEN_WIDTH - metricsScrore.stringWidth("Score: " + applesEaten))/2, SCREEN_HEIGHT/3);
String buttonText = "Do you want to try again?";
JButton restartButton = new JButton(buttonText);
Font font = new Font("Ink Free", Font.PLAIN, 18);
restartButton.setFont(font);
restartButton.setBorderPainted(true);
restartButton.setBackground(Color.yellow);
restartButton.setForeground(Color.black);
restartButton.setBounds(150,350,300,50);
add(restartButton);
restartButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
SnakeGame.main(null);
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
if(running) {
move();
checkApple();
checkCollisions();
}
repaint();
}
/**
* Listing to the 4 keyboard actions (up, right, down, left)
*
* @author viviangleissner
*/
public class MyKeyAdapter extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if(direction != 'R') direction = 'L';
break;
case KeyEvent.VK_UP:
if(direction != 'D') direction = 'U';
break;
case KeyEvent.VK_DOWN:
if(direction != 'U') direction = 'D';
break;
case KeyEvent.VK_RIGHT:
if(direction != 'L') direction = 'R';
break;
}
}
}
}