Currently I'm studying Computer Science and my teacher want me to make a snake game with array.
I have this code that is exactly same as my friend's but it only grow one body length and won't grow longer and after it eats the food it starts to slow down the speed of moving snake. I'm not sure where I went wrong please help. Thank you.
Here's the code:
public class Main extends JPanel implements KeyListener, ActionListener {
private static final long serialVersionUID = 1L;
static int dir;
static int i;
static int x[] = new int[200]; // Decleare Array of snake on x coordinate
static int y[] = new int[200]; // Decleare Array of snake on y coordinate
static int taillength = 1;
static int sxinc = 20, syinc = 20; // Speed of moving snake
static int fx = 100, fy = 100; // Declare the position of where food at
static int f2x = 300, f2y = 300; // Declare the position of where food2 at
static int fmx = 300, fmy = 100; // Declare the position of where food3 at
static int score = 0; // Create Score Counter
static int width = 745, height = 489; // Declare the size of JPanel
static int nsx, nsy; // The new value of the snake movement
static int csx = 20, csy = 20; // The value to add/minus on the number to
static BufferedImage background = null;
static JFrame f;
static JFrame g;
public Main() {
addKeyListener(this);
}
public void addNotify() {
super.addNotify();
requestFocus();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, width, height, this);
g.setColor(Color.GREEN);
g.fillRect(fx, fy, 20, 20);
g.setFont(new Font("Times New Roman", Font.BOLD, 15));
g.setColor(Color.GREEN);
g.drawString("GREEN - Add 1 body length, add 1 score", 0, 429);
g.setColor(Color.BLUE);
g.fillRect(f2x, f2y, 20, 20);
g.setFont(new Font("Times New Roman", Font.BOLD, 15));
g.setColor(Color.BLUE);
g.drawString("BLUE - Add 2 body length, add 2 score", 0, 444);
g.setColor(Color.CYAN);
g.fillRect(fmx, fmy, 20, 20);
g.setFont(new Font("Times New Roman", Font.BOLD, 15));
g.setColor(Color.CYAN);
g.drawString("CYAN - Minus 1 body length, add 1 score", 0, 459);
g.setColor(Color.RED);
for (int j = 0; j < x.length && j < taillength; j++) {
g.fillRect(x[j], y[j], 20, 20);
g.setColor(Color.ORANGE);
}
g.fillRect(x[0], y[0], 20, 20);
g.setColor(Color.RED);
g.setFont(new Font("Times New Roman", Font.BOLD, 25));
g.setColor(Color.WHITE);
g.drawString("Score : " + score, 305, 459);
}
public void snakenew() {
for (int i = 0; i < x.length; i++) {
x[i] = 0;
y[i] = 0;
}
}
public static void main(String a[]) {
x[0] = 300;
y[0] = 220;
try { // Import Background
background = ImageIO.read(new File("H:/shutterstock_12730534.jpg"));
} catch (IOException e) {
}
Main p = new Main();
g = new JFrame();
g.add(p);
g.setSize(200, 300);
g.setVisible(true);
g.setResizable(false);
f = new JFrame();
f.add(p);
f.setSize(width, height);
f.setVisible(true);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Timer t = new Timer(60, p);
t.start();
}
public void actionPerformed(ActionEvent e) {
if ((x[0] + 20 > width) || (x[0] < 0) || (y[0] + 40 > height)
|| (y[0] < 0)) { // Game over when hit the wall
JOptionPane.showMessageDialog(null, "You hit the wall!", "Game",
JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
if ((taillength > 1) && (x[i] != x[0]) && (y[i] != y[0])) { // Game over
// when
// touch you
// snake
// body
if ((x[0] == x[i]) & (y[0] == y[i])) {
JOptionPane.showMessageDialog(null, "You ran into yourself!",
"Game", JOptionPane.INFORMATION_MESSAGE);
}
}
if (dir == KeyEvent.VK_UP) {
if (y[0] == y[taillength]) {
y[0] = y[0] - syinc;
}
}
else if (dir == KeyEvent.VK_DOWN) {
if (y[0] == y[taillength]) {
y[0] = y[0] + syinc;
}
}
else if (dir == KeyEvent.VK_LEFT) {
if (x[0] == x[taillength]) {
x[0] = x[0] - sxinc;
}
}
else if (dir == KeyEvent.VK_RIGHT) {
if (x[0] == x[taillength]) {
x[0] = x[0] + sxinc;
}
}
if (dir == KeyEvent.VK_K) {
if ((score > 6) && (taillength > 5)) {
taillength = taillength - 5;
score = score - 7;
}
}
if ((x[0] == fx) && (y[0] == fy)) { // Food Score and random food
fx = (int) (Math.random() * 37) * 20;
fy = (int) (Math.random() * 25) * 20;
taillength++;
score++;
}
if ((x[0] == f2x) && (y[0] == f2y)) {
f2x = (int) (Math.random() * 37) * 20;
f2y = (int) (Math.random() * 25) * 20;
taillength = taillength + 2;
score = score + 2;
}
if ((x[0] == fmx) && (y[0] == fmy)) {
if (taillength > 0) {
fmx = (int) (Math.random() * 37) * 20;
fy = (int) (Math.random() * 25) * 20;
taillength--;
score++;
}
}
for (i = taillength; i > 0; i--) {
x[i] = x[(i - 1)];
y[i] = y[(i - 1)];
}
f.repaint();
}
public void keyPressed(KeyEvent ke) {
dir = ke.getKeyCode();
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent arg0) {
}
}
A few things:
You are using a timer, but the item you are putting in the timer has no run() method... That's not how a timer works (please reference the last point as to why).
You are redrawing the whole screen every single time you tick. Not only is that ridiculous, it is most likely the cause of your aforementioned lag when you grow the body. Fixing this will ensure that you experience little to now lag between growth (although, you will still need to compensate at later growths by changing the speed of the snake; this, will also make the game more difficult as you go on, just like real Snake). This usage of the paint() method, can be attributed to the same reasoning as the last point.
You took someone elses code. Don't use code that doesn't belong to you--it might work, and you're fine, or you might have the same bug as the other guy, and now you've got a great time explaining why you have the copied code of some other student.
In conclusion: if you want to borrow code, never borrow code from someone who is in the same course as you. Finally, look up some examples of Snake games in Java. I'm sure you'll find some people who have experienced similar problems, from whom you might learn. I hope this helps you, and best of luck!
Related
This is my first question and I apologize if it's not posed as it should be in advance.
So, I'm trying to make the fruits (I also call them apples in code) spawn on a position that is different from the snake body just like the title says. The problem is that I don't know how to check if the coordinates of the new fruit is not equal to each of the body parts of the snake.
public void newApple() {
tempX = random.nextInt(width/unitSize)*unitSize;
tempY = random.nextInt(height/unitSize)*unitSize;
for (int i = 0; i < bodyParts; i++) {
if (tempX != x[i] && tempY != y[i]){
appleX = tempX;
appleY = tempY;
}
else {
newApple();
}
}
}
This is what I've figured so far: I'm using 2 temp variables that will correspond to a random position in the frame and then I want to check if those are not equal to each position of the snake. The if condition inside the for loop just checks for x[0] and y[0] which are the coordinates of the head of my snake though.
This is what's inside the paintComponent() method to draw the apple.
//drawing apple
if (appleX != null && appleY != null) {
g.setColor(Color.red);
g.fillOval(appleX, appleY, unitSize, unitSize);
}
Down below is my entire 2 classes of the project if you may need it.
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createGame();
}
});
}
public static void createGame() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(new MyPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
public class MyPanel extends JPanel implements ActionListener {
final int width = 600;
final int height = 600;
final int unitSize = 25;
final int maxNumberOfUnits = (width*height)/(unitSize*unitSize);
int[] x = new int[maxNumberOfUnits];
int[] y = new int[maxNumberOfUnits];
int bodyParts = 2;
Integer appleX, appleY, tempX, tempY;
int score = 0;
char direction = 'R';
boolean running;
int delay = 175;
Timer timer = new Timer(delay, this);
Random random = new Random();
Font font1 = new Font("Ink Free", Font.BOLD, 40);
Font font2 = new Font("Ink Free", Font.BOLD, 75);
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
MyPanel() {
setBackground(new Color(16, 16, 16));
setFocusable(true);
timer.start();
running = true;
newApple();
x[0] = 10*unitSize;
y[0] = 10*unitSize;
x[1] = 9*unitSize;
y[1] = 10*unitSize;
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case 37:
if (direction !='R') {
direction = 'L';
}
break;
case 38:
if (direction !='D') {
direction = 'U';
}
break;
case 39:
if (direction !='L') {
direction = 'R';
}
break;
case 40:
if (direction !='U') {
direction = 'D';
}
break;
}
}
});
}
public void moveSnake() {
for (int i = bodyParts; i > 0; i--) {
x[i] = x[i-1];
y[i] = y[i-1];
}
switch (direction) {
case 'U':
y[0] -= unitSize;
break;
case 'D':
y[0] += unitSize;
break;
case 'L':
x[0] -= unitSize;
break;
case 'R':
x[0] += unitSize;
break;
}
}
public void newApple() {
tempX = random.nextInt(width/unitSize)*unitSize;
tempY = random.nextInt(height/unitSize)*unitSize;
for (int i = 0; i < bodyParts; i++) {
if (tempX != x[i] && tempY != y[i]){
appleX = tempX;
appleY = tempY;
}
else {
newApple();
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (running) {
/*
//drawing a matrix
for (int i = 1; i < height/unitSize; i++) {
g.drawLine(0, i*unitSize, width, i*unitSize);
}
for (int i = 1; i < width/unitSize; i++) {
g.drawLine(i*unitSize, 0, i*unitSize, height);
}
*/
//drawing apple
if (appleX != null && appleY != null) {
g.setColor(Color.red);
g.fillOval(appleX, appleY, unitSize, unitSize);
}
//drawing snake
g.setColor(Color.green);
for (int i = 0; i < bodyParts; i++) {
g.fillRect(x[i], y[i], unitSize, unitSize);
}
//drawing score
g.setColor(Color.red);
g.setFont(font1);
FontMetrics metrics1 = getFontMetrics(g.getFont());
g.drawString("Score: " + score, (width-metrics1.stringWidth("Score: " + score))/2, g.getFont().getSize());
}
else {
g.setColor(Color.red);
g.setFont(font1);
FontMetrics metrics1 = getFontMetrics(g.getFont());
g.drawString("Score: " + score, (width-metrics1.stringWidth("Score: " + score))/2, g.getFont().getSize());
g.setColor(Color.white);
g.setFont(font2);
FontMetrics metrics2 = getFontMetrics(g.getFont());
g.drawString("Game Over", (width-metrics2.stringWidth("Game Over"))/2, height/2);
}
}
public void checkApple() {
if (x[0]==appleX && y[0]==appleY) {
score++;
bodyParts++;
newApple();
}
}
public void checkCollisions() {
//body
for (int i = bodyParts; i > 0; i--) {
if (x[0] == x[i] && y[0] == y[i]) {
running = false;
}
}
if (x[0] < 0) {
running = false;
}
if (x[0] > width) {
running = false;
}
if (y[0] < 0) {
running = false;
}
if (y[0] > height) {
running = false;
}
if (!running) {
timer.stop();
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (running) {
checkApple();
moveSnake();
checkCollisions();
}
repaint();
}
}
You don't need a recursive call. Method newApple() should not call itself. You need a loop.
Generate values for tempX and tempY.
For each part of the snake check whether tempX equals the snake body part x[i] and also tempY equals y[i].
If at least one part of the snake body equals the coordinates tempX and tempY, go back to step 1, above.
If none of the snake body parts equals the coordinates, assign the generated coordinates to the "apple".
This is method newApple()
public void newApple() {
boolean ok = false;
while (!ok) {
ok = true;
tempX = random.nextInt(width/unitSize)*unitSize;
tempY = random.nextInt(height/unitSize)*unitSize;
for (int i = 0; i < bodyParts; i++) {
if (tempX == x[i] && tempY == y[i]) {
ok = false;
break;
}
}
if (ok) {
appleX = tempX;
appleY = tempY;
}
}
}
I think you should have an array of all the location of body parts of snakes as any body part could do collision (As if the snake collide then it's game over).
You can use the same Array for fruit respawn just ensuring that it is not in the array.
You should verify whether tempX and tempY match the values in the x and y arrays and call newApple() if they do and break out of the loop.
This means, that if you reach the end of the loop, no matches were found. You can then safely set the apple's x and y coordinates:
public void newApple() {
tempX = random.nextInt(width/unitSize)*unitSize;
tempY = random.nextInt(height/unitSize)*unitSize;
for (int i = 0; i < bodyParts; i++) {
if (tempX == x[i] && tempY == y[i]){
newApple();
break;
}
if ( i == bodyParts - 1 ) {
appleX = tempX;
appleY = tempY;
}
}
}
If I were in your shoes, I would try to avoid recursion and create a separate function to calculate if a coordinate collides with the snake's body.
A basic idea would be like this:
newApple()
- randomize a new coordinate x,y
- while overlapsWithSnake(x,y)
- randomize a new coordinate x,y
overlapsWithSnake(x,y)
- iterate through all snake coordinates
- if coordinate is the same, return true
- return false
Now, I need to point out that the algorithm does not consider when there is no more free space in the screen (the end of the game).
Additionally, this algorithm takes more and more time to find an available coordinate as the snake's body grows. What you could do to improve that is the following:
newApple()
- assign the result of getAvailableSpaces() to a list
- if the list is empty, then is game over
- else, randomize a number between 0 and list size - 1 as p
- select the coordinate at position p of the list
getAvailableSpaces()
- create logic to return a list of all free coordinates
The problem is that you only check if the apple is in the first body parts index.
You need to complete the for loop before checking if the apple can be placed.
boolean applePlacementOk = true;
while(true){
applePlacementOk = true;
tempX = random.nextInt(width/unitSize)*unitSize;
tempY = random.nextInt(height/unitSize)*unitSize;
for (int i = 0; i < bodyParts; i++) {
if (tempX == x[i] && tempY == y[i]){
applePlacementOk = false;
break;
}
}
if(applePlacementOk){
break;
}
}
appleX = tempX;
appleY = tempY;
Edit: Sorry about SO. This should work better
Edit2: I notice it's essentially the same answer as Abra, now.
I have made a very basic 2D game where you have to shoot down your enemies which are coming from 5 different tracks. I created a 2D array (track) to store the locations of the enemies, projectiles. The array is 790 wide because the track is 790 pixels long. I am using a game loop to update and render which is working just fine.
But because the loop is influenced by the performance of the computer I am using the ScheduledExecutorService class to execute the movement and spawning of enemies but for some reason it isn't working, the enemies don't move or sometimes don't even spawn and the projectiles don't move. The program doesn't give an error it just doesn't work. I checked and there are no syntax errors and I couldn't find any logical problems in it either at least of my knowledge.
Please give a short and not too complicated answer because I'm still a beginner.
The code: (controls are S,D / up, down for movement and space to shoot)
package com.bacskai.peashooter;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable, KeyListener {
private static final long serialVersionUID = -4227990863874935837L;
JFrame frame;
static Dimension d;
Thread thread;
public static int width = 300;
public static int height = width / 16 * 9;
int scale = 3;
boolean running;
boolean alive = true;
int[][] track = new int[5][790]; // the array
int trackY = 2; // the track which the player is on
private int playerPos = 250;
private int playerPos1 = 220; // the 3 starting points for the triangle
private int playerPos2 = 280;
int health = 3;
int score = 0;
long delay = 100;
long delay2 = 5000;
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
ScheduledExecutorService executor2 = Executors.newScheduledThreadPool(1);
Runnable task = new Runnable() {
public void run() {
move();
}
};
Runnable task2 = new Runnable() {
public void run() {
spawnEnemy();
}
};
public Game() {
d = new Dimension(width * scale, height * scale);
setPreferredSize(d);
frame = new JFrame();
}
private void start() {
thread = new Thread(this, "thread");
running = true;
thread.start();
for (int i = 0; i == 5; i++) {
for (int j = 0; j == 790; j++) { // initializing the array
track[i][j] = 0;
}
}
executor.scheduleAtFixedRate(task, delay, delay,
TimeUnit.MILLISECONDS); // moveing
executor2.scheduleAtFixedRate(task2, delay2, delay2,
TimeUnit.MILLISECONDS); // spawning new enemies
System.out.println("Game started, window width: " + getWidth() + ",
height: " +
getHeight());
}
public void run() {
while (running) { // game loop
update();
if (alive) {
render();
}
}
}
private void stop() {
try {
frame.dispose();
thread.join();
executor.shutdownNow();
executor2.shutdownNow();
} catch (Exception e) {
System.out.println("Error while closing: " + e);
}
System.out.println("Program closed, processes halted");
}
public void update() {
if (health == 0) {
alive = false;
executor.shutdownNow();
executor2.shutdownNow();
System.out.println("Game over");
}
}
private void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {createBufferStrategy(3); return;}
Graphics g = bs.getDrawGraphics();
// Map
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.cyan);
g.fillRect(100, 0, 10, 490);
g.fillRect(0, 98, 900, 10);
g.fillRect(0, 196, 900, 10);
g.fillRect(0, 294, 900, 10);
g.fillRect(0, 392, 900, 10);
// Score / health
Font font = new Font("Default", Font.PLAIN, 30);
g.setFont(font);
g.setColor(Color.red);
g.drawString("Score: " + score, 740, 30);
g.setColor(Color.yellow);
g.drawString("Health: " + health, 600, 30);
// Player
g.setColor(Color.green);
int[] xPoints = {10, 10, 60};
int[] yPoints = {playerPos1, playerPos2, playerPos};
g.fillPolygon(xPoints, yPoints, 3);
// Enemies
g.setColor(Color.red);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 790; j++) {
if (track[i][j] == 1) {
g.fillRect(100 + j, i * 97 + 44, 30, 30);
}
}
}
// Projectiles
g.setColor(Color.green);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 790; j++) {
if (track[i][j] == 2) {
g.fillOval(110 + j, i * 97 + 44, 27, 27);
}
}
}
bs.show();
g.dispose();
} // End of render
public int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + 1;
return randomNum;
}
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
stop();
}
if(e.getKeyCode() == KeyEvent.VK_UP && trackY > 0) {
trackY--;
playerPos -= 98;
playerPos1 -= 98;
playerPos2 -= 98;
System.out.println("Key pressed: up");
}
if(e.getKeyCode() == KeyEvent.VK_DOWN && trackY < 4) {
trackY++;
playerPos += 98;
playerPos1 += 98;
playerPos2 += 98;
System.out.println("Key pressed: down");
}
if(e.getKeyCode() == KeyEvent.VK_SPACE) {
shoot();
}
}
public void keyReleased(KeyEvent e) {}
public void shoot() {
System.out.println("Player shot projectile from: " + (trackY + 1));
track[trackY][0] = 2;
}
public void move() {
System.out.print("asd");
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 790; j++) {
if (track[i][j] == 2 && track[i][j + 2] == 1) {
track[i][j] = 0;
track[i][j + 2] = 0;
break;
}
switch (track[i][j]) {
case 0: // 0 ==> empty position
break;
case 1: // 1 ==> enemy
if (j != 0) {
track[i][j - 1] = 1;
track[i][j] = 0;
} else {
track[i][j] = 0;
enemyArrived();
}
System.out.print("");
break;
case 2: // 2 ==> projectile
if (j == 789) {
track[i][j] = 0;
break;
}
track[i][j + 1] = 2;
track[i][j] = 0;
System.out.print("");
break;
default:
System.out.println("Unable to identify object type at: track[" + i + "][" + j + "]");
break;
}
}
}
}
public void spawnEnemy() {
int trakk = randInt(1, 5);
track[trakk][789] = 1;
System.out.println("New enemy at: " + trakk);
}
public void enemyArrived() {
health--;
System.out.println("Player lost a health point, current health: " + health);
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Peasooter");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.frame.addKeyListener(game);
game.start();
}
}
Also I would be very happy if somebody could tell me if there is a way of optimizing this game to not consume 25% - 30% of the cpu.
I've managed to make your app sort of run with some changes and bug fixing. It's not a finished solution but something to help you move forward.
From the top
I changed the delays values, this made the game playable since it seems 100 is way to short time. You probably won't like my values for playability but with my values the game can be tested at least.
long delay = 1000;
long delay2 = 3000;
No point in having two ScheduledExecutorService objects so delete the second one.
I have no idea why you want to spawn a thread run your code from there so I removed it.
//thread = new Thread(this, "thread");
running = true;
//thread.start();
And manually called the run() method at the end of start() so with that and the single executor the second half of start()is
executor.scheduleAtFixedRate(task, delay, delay,
TimeUnit.MILLISECONDS); // moveing
executor.scheduleAtFixedRate(task2, delay2, delay2,
TimeUnit.MILLISECONDS); // spawning new enemies
System.out.println("Game started, window width: " + getWidth() + ", height: " + getHeight());
run();
}
You are all over the place with your for loops, at one place you have i < 6 for the limit, and at another you have i == 5 (which always will be false). Go through all loops and make sure they are defined as
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 790; j++) {
Also call randInt properly to fit you array size
int trakk = randInt(0, 4);
The game still behaves very odd but most of the time I get some red enemies and I can shoot them down.
Update
I played some more with it and made two more changes.
Your random generator method creates a new Random object each time it's called which is unnecessary and I didn't see the point of having the randInt method so I delete the method and declare a new member at the top
Random rand = new Random();
and then used it where the call to randInt used to be
int trakk = rand.nextInt(NUMBER_OF_ROWS);
To see if I could improve the performance I introduced 3 constants and then used them for the array and the for loops (replacing all occurrences of 5 and 790 with them)
private static final int NUMBER_OF_ROWS = 5;
private static final int NUMBER_OF_PIXELS = 790;
private static final int LAST_PIXEL = NUMBER_OF_PIXELS - 1;
Then I made the array much smaller by changing the two first to 3 and 100, this again made the game much more playable (although it messed up the graphics some) making it easier to test and fix bugs.
I am currently making an applet that simulates a Tortoise vs. Hare Race. They each have individual moves, picked at random. My applet works, but it only displays the end of the race in which the Tortoise Wins. I would like it to display the individual moves that the tortoise/hare make, almost like a gif.
heres my code:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Color;
import java.awt.Font;
public class Project2 extends Applet
{
Image tortoise, hare;
int tortoiseXPos = 180, hareXPos = 180;
final int tortoiseYPos = 50, hareYPos = 400, SQUARE = 20;
int move;
public void init()
{
tortoise = getImage(getDocumentBase(), "tortoise.gif");
hare = getImage(getDocumentBase(), "hare.gif");
}
public void gameControl()
{
//1200 is finish line
while((tortoiseXPos < 1200) || (hareXPos < 1200))
{
move = (int)(Math.random() * 10);
tortoiseMoves(move);
hareMoves(move);
for(int i = 0; i < 10; i++)
{
delay();
}
}
}
public void paint(Graphics field)
{
drawField(field);
drawMove(field);
//Display winner when they get to the finish line
if(tortoiseXPos >= 1200)
{
field.setFont(new Font("Times New Roman", Font.ITALIC, 72));
field.drawString("Tortoise Wins", 650, 240);
}
else if(hareXPos >= 1200)
{
field.setFont(new Font("Times New Roman", Font.ITALIC, 72));
field.drawString("Tortoise Wins!!", 650, 240);
}
}
public void drawField(Graphics field)
{
setBackground(Color.green);
Font f = new Font("Times New Roman", Font.BOLD, 48);
field.setFont(f);
field.drawString("Tortoise", 0, 75);
field.drawString("Hare", 0, 425);
//fill alternating black and white rectangles
field.setColor(Color.black);
int x = 180;
for(int i = 0; i < 25; i++)
{
field.fillRect(x, 50, SQUARE, 50);
field.fillRect(x, 400, SQUARE, 50);
x += (SQUARE * 2);
}
field.setColor(Color.white);
x = 200;
for(int i = 0; i < 25; i++)
{
field.fillRect(x, 50, SQUARE, 50);
field.fillRect(x, 400, SQUARE, 50);
x += (SQUARE * 2);
}
}
public void clearMove(Graphics s)
{
}
public void drawMove(Graphics s)
{
gameControl();
s.drawImage(tortoise, tortoiseXPos, 50, this);
s.drawImage(hare, hareXPos, 400, this);
}
public void tortoiseMoves(int move)
{
//Moves for Tortoise
if(move <= 5)
{
tortoiseXPos += (3 * SQUARE);
}
else if(move <= 8)
{
tortoiseXPos += SQUARE;
}
else if(move <= 10)
{
tortoiseXPos -= (6 * SQUARE);
}
if(tortoiseXPos < 0)
{
tortoiseXPos = 0;
}
if(tortoiseXPos > 1200)
{
tortoiseXPos = 1200;
}
}
public void hareMoves(int move)
{
//Moves for Hare
if(move <= 2)
{
hareXPos += (9 * SQUARE);
}
if(move <= 5)
{
hareXPos += (SQUARE);
}
if(move <= 6)
{
hareXPos -= (SQUARE);
}
if(move <= 8)
{
hareXPos -= (2 * SQUARE);
}
if(move <= 10)
{
hareXPos = hareXPos;
}
if(hareXPos < 0)
{
hareXPos = 0;
}
if(hareXPos > 1200)
{
hareXPos = 1200;
}
}
public void delay()
{
//To see individual moves
for(int i = 0; i <= 90000000; i++)
{}
}
}
If you guys could give me some pointers on what method to use or how I should go about doing this, I'd appreciate it. Thanks
Add two arrays to your class and store each move for each racer. Then, "paint" the points for each racer on the screen as the race is progressing.
So I'm trying to get this square to bounce off of the wall. I'm fairly new to coding, but I can't understand why this is happening. It seems to be bouncing very badly, as in it completely reverses the direction in which it hits, so it does not bounce logically.
The most frustrating problem though, is that it only bounces once. It bounces once off of the side and then when it encounters a second wall, it just goes off into the abyss.
Here is a snippet of code used to write it:
void moveTheBox() {
while (inside == true) {
if ((bigBoxX <= 0) || (bigBoxY <= 0) ||
(bigBoxX >= 600 - bigBoxSize) ||
(bigBoxY >= 600 - bigBoxSize)) {
bigBoxDeltaX = bigBoxDeltaX * -1;
bigBoxDeltaY = bigBoxDeltaY * -1;
while ((bigBoxX >= 0) || (bigBoxY >= 0) ||
(bigBoxX <= 600 - bigBoxSize) ||
(bigBoxY <= 600 - bigBoxSize)) {
bigBoxX = bigBoxX + bigBoxDeltaX;
bigBoxY = bigBoxY + bigBoxDeltaY;
repaint();
pause();
}
} else {
bigBoxX = bigBoxX + bigBoxDeltaX;
bigBoxY = bigBoxY + bigBoxDeltaY;
repaint();
pause();
}
}
}
Edit: I figured out 4 minutes after you posted that. I fixed the awkward bouncing and the 1 bounce issue.
Here is the final product:
void moveTheBox() {
int i = 0;
while(i == 0){
if ((bigBoxX <= 0) || (bigBoxX >= 600-bigBoxSize)){
bigBoxDeltaX = bigBoxDeltaX * -1;
while((bigBoxX >= 0) || (bigBoxY >=0) || (bigBoxX <= 600-bigBoxSize) || (bigBoxY <= 600 - bigBoxSize)){
bigBoxX = bigBoxX + bigBoxDeltaX;
bigBoxY = bigBoxY + bigBoxDeltaY;
repaint();
pause();
break;
}
}else if ((bigBoxY <= 0) || (bigBoxY >= 600-bigBoxSize)){
bigBoxDeltaY = bigBoxDeltaY * -1;
while((bigBoxX >= 0) || (bigBoxY >=0) || (bigBoxX <= 600-bigBoxSize) || (bigBoxY <= 600 - bigBoxSize)){
bigBoxX = bigBoxX + bigBoxDeltaX;
bigBoxY = bigBoxY + bigBoxDeltaY;
repaint();
pause();
break;
}
}else{
bigBoxX = bigBoxX + bigBoxDeltaX;
bigBoxY = bigBoxY + bigBoxDeltaY;
repaint();
pause();
}
}
}
import java.awt.*;
import java.util.Formatter;
import javax.swing.*;
/**
* One ball bouncing inside a rectangular box.
* All codes in one file. Poor design!
*/
// Extends JPanel, so as to override the paintComponent() for custom rendering codes.
public class BouncingBallSimple extends JPanel {
// Container box's width and height
private static final int BOX_WIDTH = 640;
private static final int BOX_HEIGHT = 480;
// Ball's properties
private float ballRadius = 200; // Ball's radius
private float ballX = ballRadius + 50; // Ball's center (x, y)
private float ballY = ballRadius + 20;
private float ballSpeedX = 3; // Ball's speed for x and y
private float ballSpeedY = 2;
private static final int UPDATE_RATE = 30; // Number of refresh per second
/** Constructor to create the UI components and init game objects. */
public BouncingBallSimple() {
this.setPreferredSize(new Dimension(BOX_WIDTH, BOX_HEIGHT));
// Start the ball bouncing (in its own thread)
Thread gameThread = new Thread() {
public void run() {
while (true) { // Execute one update step
// Calculate the ball's new position
ballX += ballSpeedX;
ballY += ballSpeedY;
// Check if the ball moves over the bounds
// If so, adjust the position and speed.
if (ballX - ballRadius < 0) {
ballSpeedX = -ballSpeedX; // Reflect along normal
ballX = ballRadius; // Re-position the ball at the edge
} else if (ballX + ballRadius > BOX_WIDTH) {
ballSpeedX = -ballSpeedX;
ballX = BOX_WIDTH - ballRadius;
}
// May cross both x and y bounds
if (ballY - ballRadius < 0) {
ballSpeedY = -ballSpeedY;
ballY = ballRadius;
} else if (ballY + ballRadius > BOX_HEIGHT) {
ballSpeedY = -ballSpeedY;
ballY = BOX_HEIGHT - ballRadius;
}
// Refresh the display
repaint(); // Callback paintComponent()
// Delay for timing control and give other threads a chance
try {
Thread.sleep(1000 / UPDATE_RATE); // milliseconds
} catch (InterruptedException ex) { }
}
}
};
gameThread.start(); // Callback run()
}
/** Custom rendering codes for drawing the JPanel */
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // Paint background
// Draw the box
g.setColor(Color.BLACK);
g.fillRect(0, 0, BOX_WIDTH, BOX_HEIGHT);
// Draw the ball
g.setColor(Color.BLUE);
g.fillOval((int) (ballX - ballRadius), (int) (ballY - ballRadius),
(int)(2 * ballRadius), (int)(2 * ballRadius));
// Display the ball's information
g.setColor(Color.WHITE);
g.setFont(new Font("Courier New", Font.PLAIN, 12));
StringBuilder sb = new StringBuilder();
Formatter formatter = new Formatter(sb);
formatter.format("Ball #(%3.0f,%3.0f) Speed=(%2.0f,%2.0f)", ballX, ballY,
ballSpeedX, ballSpeedY);
g.drawString(sb.toString(), 20, 30);
}
/** main program (entry point) */
public static void main(String[] args) {
// Run GUI in the Event Dispatcher Thread (EDT) instead of main thread.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Set up main window (using Swing's Jframe)
JFrame frame = new JFrame("A Bouncing Ball");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new BouncingBallSimple());
frame.pack();
frame.setVisible(true);
}
});
}
}
Refer the tutorial
Arrays are not my strong point and I usually have to go through a lot of errors, IndexOutOfBoundsException usually, before I get it right. this time the error I'm getting is this over and over again.
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.get(ArrayList.java:322)
at FinalSnake$DrawPanel.paintComponent(FinalSnake.java:272)
at javax.swing.JComponent.paint(JComponent.java:1037)
at javax.swing.JComponent._paintImmediately(JComponent.java:5106)
at javax.swing.JComponent.paintImmediately(JComponent.java:4890)
at javax.swing.RepaintManager$3.run(RepaintManager.java:814)
at javax.swing.RepaintManager$3.run(RepaintManager.java:802)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:802)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:745)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:725)
at javax.swing.RepaintManager.access$1000(RepaintManager.java:46)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1680)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:715)
at java.awt.EventQueue.access$400(EventQueue.java:82)
at java.awt.EventQueue$2.run(EventQueue.java:676)
at java.awt.EventQueue$2.run(EventQueue.java:674)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:685)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
When I use this code in my program, which is used to paint the body of the snake.
/* Sprite: Snake Body */
if (length > 0) {
for (int i = 0; i <= length; i++) {
g.setColor(Color.darkGray);
g.fillRect(bodyX.get(i), bodyY.get(i), width, height);
}
}
I never can understand what the program is trying to tell me whenever I get these errors XD
Here's the rest of the code
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
import java.util.ArrayList;
public class FinalSnake extends JFrame {
String direction = "right";
//String duration =
int time = 100;
int start = 0;
/* Sprite: snake head co-ordinates */
int x = 400;
int y = 450;
int width = 10;
int height = 10;
/* Sprite: snake body */
int length = 0;
ArrayList<Integer> bodyX = new ArrayList<Integer>();
ArrayList<Integer> bodyY = new ArrayList<Integer>();
/* Score */
int point = 0;
String p = String.valueOf(point);
/* Sprite: mouse co-ordinates */
Random rand = new Random();
int addx = (rand.nextInt(10)) * 10;
int addy = (rand.nextInt(10)) * 10;
int mx = ((rand.nextInt(5) + 1) * 100) + addx;
int my = ((rand.nextInt(6) + 2) * 100) + addy;
DrawPanel drawPanel = new DrawPanel();
Timer timer;
public FinalSnake() {
addMouseListener(new MouseListenerfinal());
timer = new Timer(time, new TimerListener()); ////////////// <<<<<<<<<<<<<<<<<< TIMER
timer.start();
/* move snake up */
Action upAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
direction = "up"; ////////////// <<<<<<<<<<<<<<<<<< direction only change
}
};
/* move snake down */
Action downAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
direction = "down";
}
};
/* move snake left */
Action leftAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
direction = "left";
}
};
/* move snake right */
Action rightAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
direction = "right";
}
};
InputMap inputMap = drawPanel
.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = drawPanel.getActionMap();
inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "rightAction");
actionMap.put("rightAction", rightAction);
inputMap.put(KeyStroke.getKeyStroke("LEFT"), "leftAction");
actionMap.put("leftAction", leftAction);
inputMap.put(KeyStroke.getKeyStroke("DOWN"), "downAction");
actionMap.put("downAction", downAction);
inputMap.put(KeyStroke.getKeyStroke("UP"), "upAction");
actionMap.put("upAction", upAction);
add(drawPanel);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}// FinalSnake()
private class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) { /////////////////// <<<<<<<<<<<<<< All logic here
if ("right".equals(direction)) {
x += 10;
if (x >= mx && x <= mx + 9 && y >= my && y <= my + 9) {
addx = (rand.nextInt(10)) * 10;
addy = (rand.nextInt(10)) * 10;
mx = ((rand.nextInt(5) + 1) * 100) + addx;
my = ((rand.nextInt(6) + 1) * 100) + addy;
point += 100;
p = String.valueOf(point);
length++;
time--;
bodyY.add(0, y);
bodyX.add(0, x);
//System.out.println(bodyX + ":" + bodyY);
}
if (x > 699) {
new GameOver();
dispose();
}
} else if ("left".equals(direction)) {
x -= 10;
if (x >= mx && x <= mx + 9 && y >= my && y <= my + 9) {
addx = (rand.nextInt(10)) * 10;
addy = (rand.nextInt(10)) * 10;
mx = ((rand.nextInt(5) + 1) * 100) + addx;
my = ((rand.nextInt(6) + 1) * 100) + addy;
point += 100;
p = String.valueOf(point);
length++;
time--;
bodyY.add(0, y);
bodyX.add(0, x);
}
if (x < 99) {
new GameOver();
dispose();
}
} else if ("up".equals(direction)) {
y -= 10;
if (y >= my && y <= my + 9 && x >= mx && x <= mx + 9) {
addx = (rand.nextInt(10)) * 10;
addy = (rand.nextInt(10)) * 10;
mx = ((rand.nextInt(5) + 1) * 100) + addx;
my = ((rand.nextInt(6) + 1) * 100) + addy;
point += 100;
p = String.valueOf(point);
length++;
time--;
bodyY.add(0, y);
bodyX.add(0, x);
}
if (y < 99) {
new GameOver();
dispose();
}
} else if ("down".equals(direction)) {
y += 10;
if (y >= my && y <= my + 9 && x >= mx && x <= mx + 9) {
addx = (rand.nextInt(10)) * 10;
addy = (rand.nextInt(10)) * 10;
mx = ((rand.nextInt(5) + 1) * 100) + addx;
my = ((rand.nextInt(6) + 1) * 100) + addy;
point += 100;
p = String.valueOf(point);
length++;
time--;
bodyY.add(0, y);
bodyX.add(0, x);
}
if (y > 799) {
new GameOver();
dispose();
}
}
drawPanel.repaint();
}
}
private class GameOver extends JFrame implements ActionListener {
JLabel answer = new JLabel("");
JPanel pane = new JPanel(); // create pane object
JButton pressme = new JButton("Quit");
JButton replay = new JButton("Replay?");
GameOver() // the constructor
{
super("Game Over");
timer.stop(); ////////////////////// <<<<<<<<<< Stop TIMER
setBounds(100, 100, 300, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container con = this.getContentPane(); // inherit main frame
con.add(pane);
pressme.setMnemonic('Q'); // associate hotkey
pressme.addActionListener(this); // register button listener
replay.addActionListener(this);
pane.add(answer);
pane.add(pressme);
pane.add(replay);
pressme.requestFocus();
answer.setText("You Lose");
setVisible(true); // make frame visible
}// GameOver()
// here is the basic event handler
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == pressme)
System.exit(0);
if (source == replay) {
dispose();
EventQueue.invokeLater(new Runnable() {
public void run() {
new FinalSnake();
}
});
}
}// actionPreformed
}// GameOver
private class DrawPanel extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (start == 1){
g.setColor(Color.white);
}
Font ith = new Font("Ithornît", Font.BOLD, 78);
/* Background: Snake */
g.setColor(Color.darkGray);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.gray);
g.fillRect(100, 100, 600, 700);
g.setColor(Color.white);
g.drawRect(99, 99, 601, 701);
g.drawString("Quit", 102, 86);
g.drawRect(100, 70, 30, 20);
//g.drawString("Pause", 152, 86);
//g.drawRect(150, 70, 40, 20);
g.drawString("Score: ", 602, 86);
g.drawString(p, 640, 86);
g.setFont(ith);
g.drawString("SNAKE", 350, 60);
/* Sprite: Mouse */
g.setColor(Color.black);
g.fillRect(mx, my, width, height);
/* Sprite: Snake Body */
if (length > 0) {
for (int i = 0; i < length; i++) {
g.setColor(Color.darkGray);
g.fillRect(bodyX.get(i), bodyY.get(i), width, height);
}
}
/* Sprite: Snake head */
g.setColor(Color.white);
g.fillRect(x, y, width, height);
}// Paint Component
public Dimension getPreferredSize() {
return new Dimension(800, 850);
}// Dimension
}// DrawPanel
public static void main(String[] args) {
//new StartScreen();
EventQueue.invokeLater(new Runnable() {
public void run() {
new FinalSnake();
}
});
}// main
}// Snake Class
/* Tracks where mouse is clicked */
class MouseListenerfinal extends MouseAdapter {
public void mouseReleased(MouseEvent me) {
if (me.getX() >= 101 && me.getX() <= 131 && me.getY() >= 94
&& me.getY() <= 115) {
System.exit(0);
}
if (me.getX() >= 151 && me.getX() <= 181 && me.getY() >= 94
&& me.getY() <= 115) {
}
String str = "Mouse Released at " + me.getX() + "," + me.getY();
System.out.println(str);
}
}// MouseAdapter
Change for (int i = 0; i <= length; i++) { to for (int i = 0; i < length; i++) {, since ArrayLists start at index 0 and end at size()-1.
Ok so weird thing happened! I decided to switch the > into a < in the for loop and now it works!! I'm laughing at myself because the only problems were the less than/greater than signs.
for (int i = 0; i < length; i++) {
I found out why I got the error in the for loop
for (int i = 0; i < length; i++) {
the i < length really should be i > length. I assumed it was right and didn't look it over
after fixing that it still did not output the body and i have yet to make it work because when I run it I get a similar error, but it still runs the program (not the way it should tho)
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 64, Size: 64
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.get(ArrayList.java:322)
at FinalSnake$DrawPanel.paintComponent(FinalSnake.java:277)
at javax.swing.JComponent.paint(JComponent.java:1037)
at javax.swing.JComponent._paintImmediately(JComponent.java:5106)
at javax.swing.JComponent.paintImmediately(JComponent.java:4890)
at javax.swing.RepaintManager$3.run(RepaintManager.java:814)
at javax.swing.RepaintManager$3.run(RepaintManager.java:802)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:802)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:745)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:725)
at javax.swing.RepaintManager.access$1000(RepaintManager.java:46)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1680)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:715)
at java.awt.EventQueue.access$400(EventQueue.java:82)
at java.awt.EventQueue$2.run(EventQueue.java:676)
at java.awt.EventQueue$2.run(EventQueue.java:674)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:685)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)