Hi,
I'm making a snake game and I got a timer to check everything and repaint the component.
How can I achieve a 60 fps without affecting the movement of the snake.
I need help to come up with an equation for the speed of the snake.
Need to change the delay in SnakeBoard class and the speed in Snake class
If there is better implementation let me know.
Thanks in advance.
Here is the main logic:
package prototype;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class SnakeBoard extends JPanel implements ActionListener
{
private Image head, body, appleI;
private int width, height;
private JLabel statusBar;
private Snake snake;
private Apple apple;
private Random posGenerator;
private boolean inGame = true;
private Timer timer;
private int delay = 1000/60; // if I change it to 100 the game works just fine
private int lastDot =0;
public SnakeBoard(JLabel status,int width, int height)
{
statusBar = status;
setPreferredSize(new Dimension(width,height));
posGenerator = new Random();
setFocusable(true);
addKeyListener(new KAdapter());
setBackground(Color.BLACK);
setDoubleBuffered(true);
this.width = width;
this.height = height;
snake = new Snake(50,50,5,width,height);
apple = new Apple(250,250);
body = snake.getBody();
appleI = apple.getImg();
timer = new Timer(delay, this);
timer.start();
}
@Override
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
if(inGame)
{
g2.drawImage(appleI, apple.getX(),apple.getY(),this);
int x[] = snake.getX();
int y[] = snake.getY();
int size = snake.getDots();
g2.drawImage(snake.getHead(), x[0], y[0], this);
for(int i=1; i< size;i++)
g2.drawImage(snake.getBody(),x[i],y[i],null);
statusBar.setText("dots: "+size+" apple: "+apple.getX()+" "+apple.getY()+" delay: "+delay);
}
else
{
statusBar.setText("Game Over");
timer.stop();
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
private class KAdapter extends KeyAdapter
{
@Override
public void keyPressed(KeyEvent e)
{
snake.KeyPressed(e);
}
}
private void checkCollision()
{
int x[] = snake.getX();
int y[] = snake.getY();
for(int i= x.length-1; i >0; i--)
{
if(x.length >4 && (x[0] == x[i]) && (y[0] == y[i]) )
inGame = false;
}
System.out.println(x[0]+" "+y[0]);
if(x[0] < 0 || x[0] > width)
inGame = false;
if(y[0] < 0 || y[0] > height)
inGame = false;
}
public void locateApple()
{
int x=(int)( posGenerator.nextDouble()*28) *10;
int y =(int) (posGenerator.nextDouble() *28) *10;
apple.moveTo(x, y);
}
@Override
public void actionPerformed(ActionEvent e)
{
if(inGame)
{
checkApple();
checkCollision();
increaseDifficulty();
snake.move();
}
repaint();
}
public void increaseDifficulty()
{
if(snake.getDots()%2 ==0 && (snake.getDots() != lastDot))
{
lastDot = snake.getDots();
//delay -= 10;
timer.setDelay(delay);
}
}
public void checkApple()
{
int x = snake.getHeadX();
int y = snake.getHeadY();
if(x == apple.getX() && y == apple.getY())
{ snake.addDots(1);
locateApple();
}
}
}
Snake:
package prototype;
import java.awt.Image;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
public class Snake
{
private boolean up,down,left, right =true;
private final int ALL_DOTS;
private int x[];
private int y[];
private Image head, headL, headR,headU, headD, body;
private final int HEIGHT = 300;
private int dots;
private final int DOT_SIZE;
public Snake(int initialX, int initialY,int initialDots, int spaceW, int spaceH)
{
ImageIcon ii = new ImageIcon(this.getClass().getResource("headU.png"));
headU = ii.getImage();
ii = new ImageIcon(this.getClass().getResource("headD.png"));
headD = ii.getImage();
ii = new ImageIcon(this.getClass().getResource("headL.png"));
headL = ii.getImage();
ii = new ImageIcon(this.getClass().getResource("headR.png"));
headR = ii.getImage();
head = headR;
ii = new ImageIcon(this.getClass().getResource("body2.png"));
body = ii.getImage();
DOT_SIZE = head.getWidth(null);
ALL_DOTS = (spaceW/ DOT_SIZE) *(spaceH/DOT_SIZE);
x= new int[ALL_DOTS];
y= new int[ALL_DOTS];
dots = initialDots;
for(int i=0; i< dots;i++)
{
x[i] = initialX -i*DOT_SIZE;
y[i] = initialY;
}
}
public void KeyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if(key == KeyEvent.VK_LEFT && !right)
{
left = true;
right = false;
up = false;
down = false;
return;
}
if(key == KeyEvent.VK_RIGHT && !left)
{
left = false;
right = true;
up = false;
down = false;
return;
}
if(key == KeyEvent.VK_UP && !down)
{
left = false;
right = false;
up = true;
down = false;
return;
}
if(key == KeyEvent.VK_DOWN && !up)
{
left = false;
right = false;
up = false;
down = true;
return;
}
}
public void move()
{
for(int i =dots-1; i >0;i--)
{
x[i] = x[i-1]-10;
y[i] = y[i-1];
}
/*
* If I change the delay to 100ms this equation works fine but I want 60fps
*
*/
int speed = DOT_SIZE; //Trying to reduce the movement in each frame this is the equation that I need.
if(left)
{
x[0] -= speed;
head = headL;
}
if(right)
{
x[0] += speed;
head = headR;
}
if(up)
{
y[0] -= speed;
head = headU;
}
if(down)
{
y[0] += speed;
head = headD;
}
}
public int[] getX()
{
return x;
}
public int[] getY()
{
return y;
}
public void addDots(int number)
{
dots+= number;
}
public void removeDots(int number)
{
dots -= number;
}
public int getDots()
{
return dots;
}
public Image getHead()
{
return head;
}
public Image getBody()
{
return body;
}
public int getHeadX()
{
return x[0];
}
public int getHeadY()
{
return y[0];
}
}
Apple:
package prototype;
import java.awt.Image;
import javax.swing.ImageIcon;
public class Apple
{
public int x,y;
public Image apple;
public Apple(int x, int y)
{
this.x = x;
this.y = y;
ImageIcon ii = new ImageIcon(this.getClass().getResource("apple2.png"));
apple = ii.getImage();
}
public void moveTo(int x, int y)
{
this.x = x;
this.y = y;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public Image getImg()
{
return apple;
}
}