Skip to content

Commit eb9cd2f

Browse files
committed
Ultra performance fixes
1 parent dedac55 commit eb9cd2f

File tree

15 files changed

+545
-929
lines changed

15 files changed

+545
-929
lines changed

SnakeGame/Snake.pde

Lines changed: 71 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,34 @@ import java.util.ArrayList;
99

1010
public class Snake {
1111

12-
public Snake() {
13-
}
14-
15-
private static final int FOOD_COLISION_TOLERANCE = 10, BODY_COLISION_TOLERANCE = 1;
16-
private List<SnakeBody> snakeBody = new ArrayList<>();
12+
private static final byte FOOD_COLISION_TOLERANCE = 10, BODY_COLISION_TOLERANCE = 1;
13+
private short[] bodyX, bodyY;
14+
private short arrIndex;
15+
private SnakeMove[] movements;
1716

18-
public List<SnakeBody> getSnakeBody() {
19-
return snakeBody;
17+
public Snake() {
18+
init();
2019
}
2120

22-
public void setSnakeBody(List<SnakeBody> snakeBody) {
23-
this.snakeBody = snakeBody;
21+
private void init() {
22+
arrIndex = 0;
23+
var pieces = piecesPerScreen();
24+
bodyX = new short[pieces];
25+
bodyY = new short[pieces];
26+
movements = new SnakeMove[pieces];
2427
}
2528

26-
/**
27-
* Get the size of the snake body
28-
* @return int the size of the snake body
29-
*/
30-
public int bodySize() {
31-
return snakeBody.size();
29+
public int piecesPerScreen() {
30+
return (SnakeGame.W * SnakeGame.H) / (SnakeGame.SNAKE_SIZE_W * SnakeGame.SNAKE_SIZE_H);
3231
}
3332

3433
/**
3534
* Get the snake body at the specified index
3635
* @param index the index of the snake body
3736
* @return SnakeBody the snake body at the specified index
3837
*/
39-
public SnakeBody getBody(int index) {
40-
return snakeBody.get(index);
38+
public short[] getPosition(int index) {
39+
return new short[]{bodyX[index], bodyY[index]};
4140
}
4241

4342
/**
@@ -46,30 +45,22 @@ public class Snake {
4645
* @return SnakeBody the snake body at the specified index
4746
*/
4847
public void updatePosition(SnakeMove movement) {
49-
getSnakeHead().setMovement(movement);
50-
}
51-
52-
/**
53-
* Adds a new SnakeBody to the snake.
54-
* @param body The SnakeBody to be added.
55-
*/
56-
public void addSnakeBody(SnakeBody body) {
57-
snakeBody.add(body);
48+
movements[0] = movement;
5849
}
5950

6051
/**
6152
* Gets the first position of the snake.
6253
* @return Position The first position of the snake.
6354
*/
64-
public int[] getFirstPosition() {
65-
return getSnakeHead().getPosition();
55+
public short[] getFirstPosition() {
56+
return new short[]{bodyX[0], bodyY[0]};
6657
}
6758

6859
/**
6960
* Destroys the snake by clearing its body and positions.
7061
*/
7162
public void destroySnake() {
72-
snakeBody.clear();
63+
init();
7364
}
7465

7566
/**
@@ -78,30 +69,32 @@ public class Snake {
7869
* The new body is positioned one movement offset away from the last body.
7970
*/
8071
public void newBody() {
81-
var lastBody = snakeBody.get(snakeBody.size()-1);
82-
var positions = lastBody.getPosition();
83-
var movement = lastBody.getMovement();
72+
short[] lastPosition = {bodyX[arrIndex], bodyY[arrIndex]};
73+
var movement = movements[arrIndex];
8474
var offset = movement.getOffset();
85-
var body = new SnakeBody(movement, positions);
86-
body.setX(body.getX() + offset[0]);
87-
body.setY(body.getY() +offset[1]);
88-
addSnakeBody(body);
75+
arrIndex++;
76+
bodyX[arrIndex] = (short)(lastPosition[0] + offset[0]);
77+
bodyY[arrIndex] = (short)(lastPosition[1] + offset[1]);
78+
movements[arrIndex] = movement;
79+
}
80+
81+
public short getSize() {
82+
return (short) (arrIndex + 1);
8983
}
9084

85+
9186
/**
9287
* Updates the movement of the snake and checks for collisions with food, borders and body.
9388
* If the snake collides with food, a new food is created and the score is updated.
9489
* If the snake collides with borders or body, the game is over.
9590
*/
9691
public void updateMovement() {
97-
if (snakeBody.size() > 1) {
98-
for (int index = snakeBody.size() - 1; index > 0; index--) {
99-
var currentBody = snakeBody.get(index);
100-
var previousBody = snakeBody.get(index - 1);
101-
currentBody.setX(previousBody.getX());
102-
currentBody.setY(previousBody.getY());
103-
currentBody.setMovement(previousBody.getMovement());
104-
}
92+
if (getSize() > 1) {
93+
for (int index = arrIndex; index > 0; index--) {
94+
bodyX[index] = bodyX[index - 1];
95+
bodyY[index] = bodyY[index - 1];
96+
movements[index] = movements[index-1];
97+
}
10598
}
10699
updateHeadPosition();
107100
if (checkCollisionWithFood()) {
@@ -118,15 +111,17 @@ public class Snake {
118111
* Starts the snake at the specified position.
119112
* @param position The position to start the snake.
120113
*/
121-
public void startSnake(int[] position) {
122-
addSnakeBody(new SnakeBody(SnakeMove.UP, position));
114+
public void startSnake(short[] position) {
115+
bodyX[0] = position[0];
116+
bodyY[0] = position[1];
117+
movements[0] = SnakeMove.UP;
123118
}
124119

125120
/**
126121
* Updates the position of all snake pieces of body.
127122
*/
128123
private void updateHeadPosition() {
129-
getSnakeHead().doMovement(SnakeGame.VELOCITY);
124+
doMovement(movements[0], SnakeGame.VELOCITY);
130125
}
131126

132127

@@ -135,44 +130,54 @@ public class Snake {
135130
* @return true if there is a collision, false otherwise.
136131
*/
137132
private boolean checkCollisionWithBody() {
138-
var firstBody = getSnakeHead();
139133
var result = false;
140-
for (int index = 1; index < snakeBody.size(); index++) {
141-
var body = snakeBody.get(index);
142-
if (Math.abs(body.getX() - firstBody.getX()) <= BODY_COLISION_TOLERANCE &&
143-
Math.abs(body.getY() - firstBody.getY()) <= BODY_COLISION_TOLERANCE) {
134+
for (int index = 1; index < getSize(); index++) {
135+
short[] body = {bodyX[index], bodyY[index]};
136+
if (Math.abs(body[0] - bodyX[0]) <= BODY_COLISION_TOLERANCE &&
137+
Math.abs(body[1] - bodyY[0]) <= BODY_COLISION_TOLERANCE) {
144138
result = true;
145139
break;
146140
}
147141
}
148142
return result;
149143
}
150144

151-
/**
152-
* Gets the snake's head.
153-
* @return SnakeBody The snake's head.
154-
*/
155-
public SnakeBody getSnakeHead() {
156-
return snakeBody.get(0);
157-
}
158-
159145
/**
160146
* Checks if the snake collides with the food.
161147
* @return true if the snake collides with the food, false otherwise.
162148
*/
163149
private boolean checkCollisionWithFood() {
164-
var bodyPos = getSnakeHead();
165-
return (Math.abs(SnakeGame.FOOD_X - bodyPos.getX()) <= FOOD_COLISION_TOLERANCE &&
166-
Math.abs(SnakeGame.FOOD_Y - bodyPos.getY()) <= FOOD_COLISION_TOLERANCE);
150+
return (Math.abs(SnakeGame.FOOD_X - bodyX[0]) <= FOOD_COLISION_TOLERANCE &&
151+
Math.abs(SnakeGame.FOOD_Y - bodyY[0]) <= FOOD_COLISION_TOLERANCE);
167152
}
168153

169154
/**
170155
* Checks if the snake has collided with the game borders.
171156
* @return true if the snake has collided with the borders, false otherwise.
172157
*/
173158
private boolean checkCollisionWithBorders() {
174-
var body = getSnakeHead();
175-
return (body.getX() < SnakeGame.BORDER || body.getX() > SnakeGame.W - SnakeGame.BORDER - SnakeGame.SNAKE_SIZE_W ||
176-
body.getY() < SnakeGame.BORDER || body.getY() > SnakeGame.H - SnakeGame.BORDER - SnakeGame.SNAKE_SIZE_H);
159+
return (bodyX[0] < SnakeGame.BORDER || bodyX[0] > SnakeGame.W - SnakeGame.BORDER - SnakeGame.SNAKE_SIZE_W ||
160+
bodyY[0] < SnakeGame.BORDER || bodyY[0] > SnakeGame.H - SnakeGame.BORDER - SnakeGame.SNAKE_SIZE_H);
161+
}
162+
163+
/**
164+
* Do a movement in the snake body with a velocity value
165+
* @param velocity short value of velocity
166+
*/
167+
public void doMovement(SnakeMove movement, short velocity) {
168+
switch(movement) {
169+
case UP:
170+
bodyY[0] -= velocity;
171+
break;
172+
case DOWN:
173+
bodyY[0] += velocity;
174+
break;
175+
case LEFT:
176+
bodyX[0] -= velocity;
177+
break;
178+
case RIGHT:
179+
bodyX[0] += velocity;
180+
break;
181+
}
177182
}
178183
}

SnakeGame/SnakeBody.pde

Lines changed: 0 additions & 52 deletions
This file was deleted.

SnakeGame/SnakeGame.pde

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55

66
import java.util.Random;
77

8-
public static final int[] BG_COLOR = {50, 230, 50};
8+
public static final short[] BG_COLOR = {50, 256, 50};
99
private static Snake snake;
10-
public static final int W = 600, H = 400;
11-
public static final int SNAKE_SIZE_W = 10, SNAKE_SIZE_H = 10, BORDER = 20, GRID_SIZE = 10, VELOCITY = 10;
12-
public static int MOVE_INTERVAL = 100;
10+
public static final short W = 600, H = 400;
11+
public static final byte SNAKE_SIZE_W = 10, SNAKE_SIZE_H = 10, BORDER = 20, GRID_SIZE = 10, VELOCITY = 10;
12+
public static byte MOVE_INTERVAL = 100;
1313
private static int score;
1414
private static SnakeMove lastMove = null;
1515
public static boolean isRunning;
1616
private static long currentTime = 0l, lastMoveTime;
17-
private static SnakeBody body = null;
18-
private static int FOOD_X, FOOD_Y;
19-
private static int[] FOOD_COLOR;
17+
private static short[] bodyPos;
18+
private static short FOOD_X, FOOD_Y;
19+
private static short[] FOOD_COLOR;
2020
private static Random random;
21-
21+
private static PFont FONT_SCORE, FONT_GAME;
2222

2323
/**
2424
* Setup configuration of the game
@@ -30,8 +30,10 @@ void setup() {
3030
isRunning = true;
3131
lastMoveTime = System.currentTimeMillis();
3232
frameRate(60);
33+
FONT_SCORE = createFont("Impact", 18);
34+
FONT_GAME = createFont("Impact", 32);
3335
snake = new Snake();
34-
snake.startSnake(new int[]{(int)W/2, (int)H/2});
36+
snake.startSnake(new short[]{W/2, H/2});
3537
random = new Random();
3638
newFood();
3739
}
@@ -68,7 +70,7 @@ void draw() {
6870
*/
6971
void drawGameOver() {
7072
fill(255, 255, 255);
71-
textFont(createFont("Impact", 32));
73+
textFont(FONT_GAME);
7274
text("Game Over", (W/2)-65, H/2);
7375
text("Press 'R' to restart", (W/2)-120, (H/2)+40);
7476
}
@@ -77,15 +79,15 @@ void drawGameOver() {
7779
* Draw the snake body and head in the screen
7880
*/
7981
void drawSnake() {
80-
body = snake.getBody(0);
82+
bodyPos = snake.getPosition(0);
8183
stroke(0, 30, 255);
8284
fill(150, 60, 200);
83-
rect(body.getX(), body.getY(), SNAKE_SIZE_W, SNAKE_SIZE_H);
84-
for (int index = 1; index < snake.bodySize(); index++) {
85-
body = snake.getBody(index);
85+
rect(bodyPos[0], bodyPos[1], SNAKE_SIZE_W, SNAKE_SIZE_H);
86+
for (int index = 1; index < snake.getSize(); index++) {
87+
bodyPos = snake.getPosition(index);
8688
stroke(0, 30, 255);
8789
fill(50, 100, 200);
88-
rect(body.getX(), body.getY(), SNAKE_SIZE_W, SNAKE_SIZE_H);
90+
rect(bodyPos[0], bodyPos[1], SNAKE_SIZE_W, SNAKE_SIZE_H);
8991
}
9092
}
9193

@@ -94,8 +96,8 @@ void drawSnake() {
9496
*/
9597
void drawScore() {
9698
fill(255, 255, 255);
97-
textFont(createFont("Impact", 18));
98-
text("Leon Snake Game: "+score, (W/2) - 70, H - 3);
99+
textFont(FONT_SCORE);
100+
text("Leon Snake Game: "+ score, (W/2) - 70, H - 3);
99101
}
100102

101103
/**
@@ -135,7 +137,7 @@ public static void gameOver() {
135137
* Restart the game (reset snake, food, score and move interval)
136138
*/
137139
void restartGame() {
138-
snake.startSnake(new int[]{(int)W/2, (int)H/2});
140+
snake.startSnake(new short[]{W/2, H/2});
139141
lastMove = null;
140142
isRunning = true;
141143
MOVE_INTERVAL = 100;
@@ -155,9 +157,9 @@ public static void updateScore() {
155157
* For each spawn increase the snake speed (decrease the move interval)
156158
*/
157159
public static void newFood() {
158-
FOOD_X = random.ints(0 + GRID_SIZE + BORDER, W - GRID_SIZE - BORDER).findFirst().getAsInt();
159-
FOOD_Y = random.ints(0 + GRID_SIZE + BORDER, H - GRID_SIZE - BORDER).findFirst().getAsInt();
160-
FOOD_COLOR = new int[]{random.nextInt(255), random.nextInt(255), random.nextInt(255)};
160+
FOOD_X = (short) random.ints(0 + GRID_SIZE + BORDER, W - GRID_SIZE - BORDER).findFirst().getAsInt();
161+
FOOD_Y = (short) random.ints(0 + GRID_SIZE + BORDER, H - GRID_SIZE - BORDER).findFirst().getAsInt();
162+
FOOD_COLOR = new short[]{(short)random.nextInt(255), (short)random.nextInt(255), (short)random.nextInt(255)};
161163
if (MOVE_INTERVAL > 50)
162164
MOVE_INTERVAL -= 1;
163165
}

0 commit comments

Comments
 (0)