I'm trying to make my first game in java but have stumbled over a problem. When I first wrote my game loop and FPS counter I tried to do it on my own, but it did not work well, so I used this code that I found online:
public void run(){
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1){
tick();
delta--;
}
if(running){
render();
}
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
stop();
}
It works great, but when I add the render() function, the window just sort of freezing. I can still close the window, but some times the whole computer need to be restarted. Here is the render function.
private void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.green);
g.fillRect(0, 0, WIDTH, HEIGHT);
handler.render(g);
g.dispose();
bs.show();
}
If I comment out everything in the render function, I get a white screen show up witch I can move around and a "constant" FPS on around 16200000. But when the code in the render function is active, the FPS looks like this:
FPS: 8644
FPS: 1
FPS: 5977
FPS: 3189
FPS: 3930
FPS: 8120
FPS: 1
FPS: 8024
FPS: 1
No stability or consistency, do anybody know what I have done wrong? My operating system is Ubuntu Mate and I use openjdk version 1.8.0_91 if it is of any importance. Thank you in advance.
Complete Code:
package com.tutorial.main;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1550691097823471818L;
public static final int WIDTH = 640, HEIGHT = WIDTH / 12 * 9;
private Thread thread;
private boolean running = false;
private Handler handler;
public Game(){
new Window(WIDTH, HEIGHT, "Lets Build!", this);
handler = new Handler();
handler.addObject(new Player(100, 100, ID.Player));
}
public synchronized void start(){
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop(){
try{
thread.join();
running = false;
}catch(Exception e){
e.printStackTrace();
}
}
public void run(){
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1){
tick();
delta--;
}
if(running){
render();
}
frames++;
if(System.currentTimeMillis() - timer > 1000){
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
stop();
}
private void tick(){
handler.tick();
}
private void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, WIDTH, HEIGHT);
handler.render(g);
g.dispose();
bs.show();
}
public static void main(String args[]){
new Game();
}
}
The problem was my operating system. When I switched over to Windows with JDK 8 installed everything worked great. Maybe becaus I have OpenJDK installed on my Linux machine there was some trobble, I honestly do not know. Will look in to it and see if I find it. Will update if so.
Related
I'm making games in Java. I'm using this game loop:
public void run() {
this.requestFocus();
double firstTime = 0;
double lastTime = System.nanoTime() / 1000000000.0;
double unprocessedTime = 0;
double passedTime = 0;
boolean render = false;
double frameTime = 0;
int frames = 0;
int fps = 0;
while (running) {
render = false;
firstTime = System.nanoTime() / 1000000000.0;
passedTime = firstTime - lastTime;
lastTime = firstTime;
unprocessedTime += passedTime;
frameTime += passedTime;
while (unprocessedTime >= UPDATE_CAP) {
unprocessedTime -= UPDATE_CAP;
render = true;
// TODO: update game
if (frameTime >= 1.0) {
fps = frames;
frameTime = 0;
frames = 0;
System.out.println("FPS: " + fps);
}
}
if (render) {
frames++;
tick();
render();
} else {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
stop();
}
I have a problem - FPS are dropping very low, even when there's only menu opened and pretty much nothing is happening.
FPS: 60
FPS: 61
FPS: 61
FPS: 61
FPS: 61
FPS: 48
FPS: 25
FPS: 8
FPS: 3
FPS: 4
FPS: 61
I have no idea why this is happening. If you want I can share more game code.
..................................
I know what happened: I was creating a lot of Font objects every tick:
public void render(Graphics g) {
Font f1 = new Font("SansSherif", Font.BOLD, 20);
Font f2 = new Font("SansSherif", Font.BOLD, 50);
Font f3 = new Font("SansSherif", Font.BOLD, 135);
}
Now, I'm creating them only when game starts.
I'm making a small asteroids game, and I'm having some trouble controlling the animation speed.
For example, let's say I have 20 asteroids in my game, when I destroy an asteroid, the amount of asteroids goes down (obviously). Because there are fewer objects in the game, the fps goes up and the animation speed of the asteroids is getting faster and faster.
I fixed it by adjusting the animation speed according to the amount of asteroids I have in the game, but I'm also facing another problem with the explosions when I destroy an asteroid. I could do the same thing I did with the asteroids I suppose, but I just think it's not a very wise way to "solve" it and just seems like bad practice to me.
I thought of capping the fps, but I'm not really sure how to do it. I'd like to get some advices and what's the best way to deal with such situations.
I'll post here my main game class including the game loop, and an example of the explosion class so you'll get the general idea of the code.
Game class and loop:
import com.asteroids.view.*;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = -8921419424614180143L;
public static final int WIDTH = 1152, HEIGHT = WIDTH / 8 * 5;
private Thread thread;
private boolean isRunning;
private LoadImages loadImages = new LoadImages();
private Player player = new Player();
private AllObjects objects;
private KeyInput keyInput;
private long delay = 80;
private long currentTime = System.currentTimeMillis();
private long expectedTime = currentTime + delay;
public static BufferedImage test;
public Game() {
new Window(WIDTH, HEIGHT, "Asteroids!", this);
objects = new AllObjects();
objects.addObject(player);
for (int i = 0; i < 20; i++) {
objects.addObject(new Rock((int) (Math.random() * (Game.WIDTH - 64) + 1),
(int) (Math.random() * (Game.HEIGHT - 64) + 1)));
}
keyInput = new KeyInput(player);
this.addKeyListener(keyInput);
}
public void run() {
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
// main game loop.
while (isRunning) {
adjustAsteroidsSpeed();
destroyAsteroids();
collisionLoop();
// used to set delay between every bullet(milliseconds)
currentTime = System.currentTimeMillis();
if (KeyInput.shoot && currentTime >= expectedTime) {
// calculates the accurate position of the x,y on the "circumference" of the
// player
float matchedX = player.getX() + 1 + (float) ((player.getRadius() + 32) * Math.cos(player.getRadian()));
float matchedY = player.getY() - 7 + (float) ((player.getRadius() + 32) * Math.sin(player.getRadian()));
objects.addObject(new Bullet(matchedX, matchedY, player));
expectedTime = currentTime + delay;
}
destroyBullets();
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick();
delta--;
}
if (isRunning)
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
render();
stop();
System.exit(1);
}
private void stop() {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.exit(1);
}
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.drawImage(LoadImages.getbackground(), 0, 0, getWidth(), getHeight(), this);
objects.render(g);
player.render(g);
g.dispose();
bs.show();
}
private void tick() {
player.tick();
objects.tick();
}
// starting thread and game loop.
public void start() {
thread = new Thread(this);
thread.start();
isRunning = true;
}
// minimum and maximum possible position for object.
public static float Bounds(float value, float min, float max) {
if (value >= max) {
return value = max;
}
if (value <= min) {
return value = min;
} else {
return value;
}
}
// detects collision between two objects
public boolean collision(GameObject a, GameObject b) {
return (b.getX() - a.getX() + 10) * (b.getX() - a.getX() + 10)
+ (b.getY() - a.getY() + 10) * (b.getY() - a.getY() + 10) < (a.getRadius() + b.getRadius())
* (a.getRadius() + b.getRadius());
}
// destroys bullets once they go out of the screen
public void destroyBullets() {
for (int i = 0; i < objects.getSize(); i++) {
if (objects.get(i).getId() == ID.BULLET) {
GameObject bullet = objects.get(i);
if (bullet.getX() > Game.WIDTH || bullet.getX() < 0 || bullet.getY() > Game.HEIGHT
|| bullet.getY() < 0) {
objects.removeObject(bullet);
}
}
}
}
// whenever a collision between an asteroid and a bullet occurs, the asteroid and the bullets are destroyed
public void destroyAsteroids() {
GameObject bullet = null;
GameObject bigRock = null;
for (int i = 0; i < objects.getSize(); i++) {
if (objects.get(i).getId() == ID.BULLET) {
bullet = (Bullet) objects.get(i);
for (int q = 0; q < objects.getSize(); q++) {
if (objects.get(q).getId() == ID.BIGROCK) {
bigRock = objects.get(q);
if (bullet != null && bigRock != null) {
if (collision(bigRock, bullet)) {
objects.addObject(new Explosion(bigRock.getX(), bigRock.getY(), objects));
objects.removeObject(bigRock);
objects.removeObject(bullet);
}
}
}
}
}
}
}
// calculates the amount of asteroids in the game and adjust the asteroids speed
public void adjustAsteroidsSpeed() {
int rocksCount = 0;
Rock rock;
for (GameObject object : objects.link()) {
if (object.getId() == ID.BIGROCK) {
rocksCount++;
}
}
for (GameObject object : objects.link()) {
if (object.getId() == ID.BIGROCK) {
rock = (Rock) object;
rock.setAnimSpeed(rocksCount * 0.002f);
}
}
}
Explosion class:
package com.asteroids.model;
import java.awt.Graphics;
import java.awt.Image;
import com.asteroids.controller.*;
import com.asteroids.view.LoadImages;
public class Explosion extends GameObject {
private AllObjects objects;
private Image explosion;
private float frame = 0;
private float animSpeed = 0.09f;
private int frameCount = 48;
public Explosion(float x, float y, AllObjects objects) {
super(x, y, ID.EXPLOSION, 1);
this.objects = objects;
}
public void render(Graphics g) {
explosion(g);
}
public void explosion(Graphics g) {
frame += animSpeed;
if (frame > frameCount) {
frame -= frameCount;
}
explosion = LoadImages.getExplosion().getSubimage((int) frame * 256, 0, 256, 256);
g.drawImage(explosion, (int) x, (int) y, 110, 110, null);
if (frame >= 47.8f) {
objects.removeObject(this);
}
}
public void tick() {
}
public void setAnimSpeed(float animSpeed) {
this.animSpeed = animSpeed;
}
}
Your main loop is generating uneven updates. If I do nothing, I get anywhere between 7799913 and 8284754 fps, however, if I throw in a 8 millisecond delay (to simulate some work), it drops to around 115-120 fps.
Your intention is to try and get the frame rate to be as even as possible, this will ensure that the animation speed remains the same
Personally, I don't like the "free-wheeling" style of game loop, it means that the loop is been allowed to consume CPU cycles without actually doing anything, where those cycles could be been used to do more important work, like update the UI.
In most cases, I just use a Swing Timer set to something like 5 millisecond intervals and then make use of the date/time API to calculate the difference between now and the last update and make choices about what to do, but, this assumes you're using a Swing based painting path. If you're doing a direct painting path (ie BufferStrategy), you could use a similar idea with a "loop" instead...
public void run() throws InterruptedException {
int frames = 0;
Duration threashold = Duration.ofMillis(1000 / 59);
Duration cycle = Duration.ofSeconds(1);
Instant cycleStart = Instant.now();
// main game loop.
while (isRunning) {
Instant start = Instant.now();
// Some update function...
Thread.sleep(rnd.nextInt(32));
Duration processTime = Duration.between(start, Instant.now());
Duration remainingTime = threashold.minusMillis(processTime.toMillis());
long delay = remainingTime.toMillis();
if (delay > 0) {
Thread.sleep(delay);
} else {
System.out.println("Dropped frame");
}
frames++;
// Render the output
Duration cycleTime = Duration.between(cycleStart, Instant.now());
if (cycleTime.compareTo(cycle) >= 0) {
cycleStart = Instant.now();
System.out.println(frames);
frames = 0;
}
}
}
In this example, your update and paint scheduling code simply have 16 milliseconds to get there job done, otherwise it will drop frames. If the work takes less then 16 milliseconds, the loop will "wait" the remaining time in order to provide some breathing room for the CPU to give time to other threads (and not take update unnecessary time on the CPU)
In the example above, I generate a "random" delay of up to 32 milliseconds for testing. Set it back to 16 and you should get (roughly) 60fps.
Now, I know people are extraordinarily passionate about these things, so if using Thread.sleep and Duration make your skin crawl, you "could" use a "free wheeling" loop, something like the one presented in Java Main Game Loop
Below is a sample implementation, I've set the number of updates and frames per second to 60, but you can change those values to suit your needs...
public void run() throws InterruptedException {
double ups = 60;
double fps = 60;
long initialTime = System.nanoTime();
final double timeU = 1000000000 / ups;
final double timeF = 1000000000 / fps;
double deltaU = 0, deltaF = 0;
int frames = 0, ticks = 0;
long timer = System.currentTimeMillis();
while (isRunning) {
long currentTime = System.nanoTime();
deltaU += (currentTime - initialTime) / timeU;
deltaF += (currentTime - initialTime) / timeF;
initialTime = currentTime;
if (deltaU >= 1) {
Thread.sleep(rnd.nextInt(32));
//getInput();
//update();
ticks++;
deltaU--;
}
if (deltaF >= 1) {
Thread.sleep(rnd.nextInt(32));
//render();
frames++;
deltaF--;
}
if (System.currentTimeMillis() - timer > 1000) {
System.out.println(String.format("UPS: %s, FPS: %s", ticks, frames));
frames = 0;
ticks = 0;
timer += 1000;
}
}
}
Again, the Thread.sleep here is just to inject a random amount of "work". Because it allows for more then 16ms of delay, you will also find it "drops" frames. Your job would be to get you work down to under 16ms per pass
Assuming I use this game loop and want to maintain 60 FPS, what would be the appropriate UPS (updates per second)? Should it be 60 as well? Thanks for any help
#Override
public void run() {
long initialTime = System.nanoTime();
final double timeU = 1000000000 / UPS;
final double timeF = 1000000000 / FPS;
double deltaU = 0, deltaF = 0;
int frames = 0, ticks = 0;
long timer = System.currentTimeMillis();
while (running) {
long currentTime = System.nanoTime();
deltaU += (currentTime - initialTime) / timeU;
deltaF += (currentTime - initialTime) / timeF;
initialTime = currentTime;
if (deltaU >= 1) {
getInput();
update();
ticks++;
deltaU--;
}
if (deltaF >= 1) {
render();
frames++;
deltaF--;
}
if (System.currentTimeMillis() - timer > 1000) {
if (RENDER_TIME) {
System.out.println(String.format("UPS: %s, FPS: %s", ticks, frames));
}
frames = 0;
ticks = 0;
timer += 1000;
}
}
}
Update should be fixed
double previous = getCurrentTime();
double lag = 0.0;
while (true) {
double current = getCurrentTime();
double elapsed = current - previous;
previous = current;
lag += elapsed;
processInput();
while (lag >= MS_PER_UPDATE) {
update();
lag -= MS_PER_UPDATE;
}
render();
}
If the difference between the real time and the game time is higher than wanted time between two updates you have to update.
If lag is lower it means you dont have to update yet but you can render anyway.
Better explanation here: http://gameprogrammingpatterns.com/game-loop.html
So, I'm writing a small game. I have a JPanel inside of a JFrame and the JFrame repaints in the game engine class every frame, but the player sprite will not react to keypress events.
Any help?
Oh, I'm not entirely sure what code to post because I can't seem to find the source of the problem in any way so just tell me what code you wish to see.
Run method in the engine:
#Override
public void run() {
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D / 60D;
int ticks = 0;
int frames = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
init();
while (engineRunning) {
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
boolean shouldRender = true;
while (delta >= 1) {
ticks++;
tick();
delta -= 1;
shouldRender = true;
}
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (shouldRender) {
frames++;
render();
}
if (System.currentTimeMillis() - lastTimer >= 1000) {
lastTimer += 1000;
frames = 0;
ticks = 0;
}
}
}
Tick & render in engine class:
public void tick() {
for (BaseEntity e : worldEntities) {
e.tick();
}
}
public void render() {
frame.repaint();
}
Player tick:
public void tick() {
Position.X += Position.velX;
Position.Y += Position.velY;
if (Position.velX > Max_Speed)
Position.velX = Max_Speed;
if (Position.velY > Max_Speed)
Position.velY = Max_Speed;
}
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I'm developing game using Java Swing framework. Does anyone know good framework based on Swing? Mostly I care about performance of redrawing.
Swing is fine for simple games, but if you really care about performance of redrawing, you should probably take a look at one of the frameworks based on OpenGL. Examples:
http://www.lwjgl.org/ - quite a low level library but very fast. basically raw OpenGL.
http://www.slick2d.org/ - a popular and fairly easy to use 2D game library.
http://jmonkeyengine.com/ - a good choice if you want a full 3D engine.
In particular, if you want to do more complex effects (lots of colours, shading, transparency effects for example) then you will probably need OpenGL.
This simple Fixed Time Step game loop (I adapted from reference credit to the author) has never let me down.
It will allow drawing at exactly 60 fps (or whatever you make it) the hertz can be changed too, it enables anti-aliasing via Graphics2D and a few other effects as well.
The original authors example included interpolation checking but I found it giving me a few problems in my games like pictures flickering in and out of their positions so I have kept that included but if you experience problems at least you will know what is causing it):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GameLoopTest implements ActionListener {
private GamePanel gamePanel;
private JButton startButton;
private JButton quitButton;
private JButton pauseButton;
private boolean running = false;
private boolean paused = false;
public GameLoopTest() {
JFrame frame = new JFrame("Fixed Timestep Game Loop Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gamePanel = new GamePanel(500, 500);
startButton = new JButton("Start");
quitButton = new JButton("Quit");
pauseButton = new JButton("Pause");
pauseButton.setEnabled(false);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 2));
startButton.addActionListener(this);
quitButton.addActionListener(this);
pauseButton.addActionListener(this);
buttonPanel.add(startButton);
buttonPanel.add(pauseButton);
buttonPanel.add(quitButton);
frame.add(gamePanel);
frame.add(buttonPanel, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new GameLoopTest();
}
});
}
#Override
public void actionPerformed(ActionEvent e) {
Object s = e.getSource();
if (s == startButton) {
running = !running;
if (running) {
startButton.setText("Stop");
pauseButton.setEnabled(true);
runGameLoop();
} else {
startButton.setText("Start");
pauseButton.setEnabled(false);
}
} else if (s == pauseButton) {
paused = !paused;
if (paused) {
pauseButton.setText("Unpause");
} else {
pauseButton.setText("Pause");
}
} else if (s == quitButton) {
System.exit(0);
}
}
//Starts a new thread and runs the game loop in it.
public void runGameLoop() {
Thread loop = new Thread(new Runnable() {
#Override
public void run() {
gameLoop();
}
});
loop.start();
}
//Only run this in another Thread!
private void gameLoop() {
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;
//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime / 1000000000);
while (running) {
double now = System.nanoTime();
int updateCount = 0;
if (!paused) {
//Do as many game updates as we need to, potentially playing catchup.
while (now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER) {
updateGame();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if (now - lastUpdateTime > TIME_BETWEEN_UPDATES) {
lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}
//Render. To do so, we need to calculate interpolation for a smooth render.
float interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime) / TIME_BETWEEN_UPDATES));
drawGame(interpolation);
lastRenderTime = now;
//Update the frames we got.
int thisSecond = (int) (lastUpdateTime / 1000000000);
int frameCount = gamePanel.getFrameCount();
if (thisSecond > lastSecondTime) {
System.out.println("NEW SECOND " + thisSecond + " " + frameCount);
gamePanel.setFps(frameCount);
frameCount = 0;
lastSecondTime = thisSecond;
}
//Yield until it has been at least the target time between renders. This saves the CPU from hogging.
while (now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES) {
//allow the threading system to play threads that are waiting to run.
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
//On my OS it does not unpuase the game if i take this away
try {
Thread.sleep(1);
} catch (Exception e) {
}
now = System.nanoTime();
}
}
}
}
private void updateGame() {
gamePanel.update();
}
private void drawGame(float interpolation) {
gamePanel.setInterpolation(interpolation);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
gamePanel.repaint();
}
});
}
}
class GamePanel extends JPanel {
float interpolation;
float ballX, ballY, lastBallX, lastBallY;
int ballWidth, ballHeight;
float ballXVel, ballYVel;
float ballSpeed;
int lastDrawX, lastDrawY;
private int frameCount = 0;
private int fps = 0;
int width, height;
public GamePanel(int width, int height) {
super(true);
ballX = lastBallX = 100;
ballY = lastBallY = 100;
ballWidth = 25;
ballHeight = 25;
ballSpeed = 25;
ballXVel = (float) Math.random() * ballSpeed * 2 - ballSpeed;
ballYVel = (float) Math.random() * ballSpeed * 2 - ballSpeed;
this.width = width;
this.height = height;
}
public void setInterpolation(float interp) {
interpolation = interp;
}
public void update() {
lastBallX = ballX;
lastBallY = ballY;
ballX += ballXVel;
ballY += ballYVel;
if (ballX + ballWidth / 2 >= getWidth()) {
ballXVel *= -1;
ballX = getWidth() - ballWidth / 2;
ballYVel = (float) Math.random() * ballSpeed * 2 - ballSpeed;
} else if (ballX - ballWidth / 2 <= 0) {
ballXVel *= -1;
ballX = ballWidth / 2;
}
if (ballY + ballHeight / 2 >= getHeight()) {
ballYVel *= -1;
ballY = getHeight() - ballHeight / 2;
ballXVel = (float) Math.random() * ballSpeed * 2 - ballSpeed;
} else if (ballY - ballHeight / 2 <= 0) {
ballYVel *= -1;
ballY = ballHeight / 2;
}
}
public int getFrameCount() {
return frameCount;
}
public void setFrameCount(int frameCount) {
this.frameCount = frameCount;
}
void setFps(int fps) {
this.fps = fps;
}
private final static RenderingHints textRenderHints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
private final static RenderingHints imageRenderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
private final static RenderingHints colorRenderHints = new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
private final static RenderingHints interpolationRenderHints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
private final static RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
public void applyRenderHints(Graphics2D g2d) {
g2d.setRenderingHints(textRenderHints);
g2d.setRenderingHints(imageRenderHints);
g2d.setRenderingHints(colorRenderHints);
g2d.setRenderingHints(interpolationRenderHints);
g2d.setRenderingHints(renderHints);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//applys effects like anti alising for images and tetx, as well as sets the renderinf value to quality etc
applyRenderHints(g2d);
g2d.setColor(Color.RED);
int drawX = (int) ((ballX - lastBallX) + lastBallX - ballWidth / 2);
int drawY = (int) ((ballY - lastBallY) + lastBallY - ballHeight / 2);
g2d.fillOval(drawX, drawY, ballWidth, ballHeight);
lastDrawX = drawX;
lastDrawY = drawY;
g2d.setColor(Color.BLACK);
g2d.drawString("FPS: " + fps, 5, 10);
frameCount++;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
}
UPDATE:
I've started my own Swing Game Library which someone might find useful if not to use then simply to borrow some concepts from it.
Reference:
http://www.java-gaming.org/index.php/topic,24220.0