Trying_To_Understand
Trying_To_Understand

Reputation: 161

Flickering image that running on a thread

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

Answers (1)

MadProgrammer
MadProgrammer

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

Related Questions