Reputation: 161
In my "SpcaeShip" game i have a loop game that updates and drawing all of my objects. Now i want to add an array list of asteroids to the game and to draw them, but the problem is that if i drawing the array of asteroids in the loop game, the game im moving very slow. My solution was to draw the asteroids on a timer thread and the game speed is perfect. The only problem i have is that my astreoids are flickering all the time. I need to use a bufferStrategy or something similier?
This is my draw method in the game loop (in this loop i call to the game state draw method):
private void tick()
{
//update all objects
}
private void render()
{
//how many buffers(hold the same data as our screen) the canvas would use
bs = display.getCanvas().getBufferStrategy();
if(bs == null)
{
display.getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
g.clearRect(0, 0, width, height);
if(State.getState() != null)
{
State.getState().render(g);
}
bs.show();
g.dispose();
}
public void run()
{
init();
int fps = 60;
double timePerTick = 1000000000/ fps;
double delta = 0;
long now;
long lastTime =System.nanoTime();
long timer = 0;
//game loop
while(running)
{
now = System.nanoTime();
delta += (now - lastTime) / timePerTick;
timer += now - lastTime;
lastTime = now;
if(delta >= 1)
{
tick();
render();
}
}
stop();
}
This is my game state methods:
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.Timer;
public class GameState extends State
{
private SpaceShip spaceShip;
private BgHandler bgHandler;
private ArrayList<Meteor> meteors;
public GameState(Handler handler)
{
super(handler);
bgHandler = new BgHandler(handler.getWidth(), handler.getHeight());
spaceShip = new SpaceShip(handler, handler.getWidth() / 2 - Things.DEFAULT_OBJECT_WIDTH / 2,
handler.getHeight() - Things.DEFAULT_OBJECT_HEIGHT - 100);
meteors = new ArrayList<Meteor>();
for(int i = 0; i < 5; i++)
{
Meteor m = new Meteor(handler,(int) (Math.random() * (handler.getWidth() - Things.DEFAULT_OBJECT_WIDTH ))
, -Things.DEFAULT_OBJECT_WIDTH,
Things.DEFAULT_OBJECT_WIDTH,
Things.DEFAULT_OBJECT_HEIGHT);
meteors.add(m);
}
timer.start();
}
Timer timer = new Timer (50, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
tickMeteor();
renderMeteor();
}
});
public void tickMeteor()
{
for(int i = 0; i < meteors.size(); i++)
{
Meteor m = meteors.get(i);
if(m.getVisible())
{
m.tick();
}
else
{
meteors.remove(i);
}
}
}
public void renderMeteor()
{
for(Meteor m: meteors)
{
Meteor m1 = (Meteor) m;
if(m1.getVisible())
{
m1.render(handler.getGame().getGraphics());
}
}
}
@Override
public void tick()
{
spaceShip.tick();
for(int i = 0; i < meteors.size(); i++)
{
Meteor m = meteors.get(i);
if(m.getVisible())
{
m.tick();
}
else
{
meteors.remove(i);
}
}
}
}
@Override
public void render(Graphics g)
{
bgHandler.render(g);
spaceShip.render(g);
}
}
Upvotes: 0
Views: 552
Reputation: 347194
This m1.render(handler.getGame().getGraphics())
is massively wrong.
The rendering of the meteors should be done in the render
method and use the same Graphics
context as the other elements, so they are all rendered in the same pass
getGraphics
should never be used, as it provides a reference to the Graphics
context outside of the normal painting cycle, which means anything painted to it will be removed on the next paint cycle
To be honest, I have no idea what your "run" method is trying to achieve but basically, it's free-wheeling, which could be consuming CPU cycles unnecessarily, stealing away cycles from other parts of your program.
At no point in the run loop does it sleep
to allow time to be given to other threads (or processes).
The following is an example which tries to maintain a constant speed update cycle of 60 ticks a second, based on the amount of time that the actual work took to complete.
public void run() {
int fps = 60;
long nanosInSecond = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
long timePerTick = (long)(nanosInSecond / (double)fps);
//game loop
while (true) {
long now = System.nanoTime();
try {
// This is simulating the update and rendering process
Thread.sleep(5);
} catch (InterruptedException ex) {
}
long delta = System.nanoTime() - now;
long timer = timePerTick - delta;
timer = TimeUnit.MILLISECONDS.convert(timer, TimeUnit.NANOSECONDS);
if (timer > 0) {
try {
System.out.println("sleep for " + timer + " milliseconds");
Thread.sleep(timer);
} catch (InterruptedException ex) {
}
}
}
}
Upvotes: 1