Java渲染循环和逻辑循环 [英] Java rendering loop and logic loop

查看:64
本文介绍了Java渲染循环和逻辑循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究通用的2D瓷砖样式游戏.目前,在我的主线程中,我有一个循环,它会尽可能快地循环,并调用另一个处理游戏内容的类中的JPanel的repaint方法.看起来像这样:

public class Main {
    public static void main(String[] args) {
        Island test = new Island();
        while(true) {
            test.getCanvas().requestFocus();
            test.getCanvas().repaint();
        }
    }
}

getCanvas()仅返回JPanel.

当前,这已经完成了我想要的操作,现在我已经开始为播放器添加动作,并且显然我不想尽可能快地在屏幕上移动他.因此,我在Island班上有一个输入图和一个动作图,它可以检测按键的按下和释放,并告诉我的玩家班级哪些键被按住.然后,我使用一个每10毫秒调用一次的摆动计时器在播放器类内部移动播放器.所以我想这就像我的游戏滴答声,我的游戏将尽可能快地制作帧,然后游戏每秒完成其所有逻辑工作100次,当然,我将为游戏逻辑添加更多内容,而不仅仅是运动.

进行一些研究后,似乎摆动计时器并不是执行此操作的最佳方法,因为它是为执行小型任务和摆动任务而设计的.所以我想我的问题是,像我在主要方法中那样制作帧是否明智,又是什么使我的游戏每10ms可靠地滴答作响的好方法呢?我有一些想法,例如也许我应该创建一个新线程来处理游戏逻辑并使用System.getnanotime或它所调用的任何方法来测量执行一个滴答声然后执行一个小线程所需的时间.直到我们到达10ms然后重复.

如果您愿意的话,我很乐意发布更多代码,并在此先感谢.

解决方案

一个标准的实现方法是在线程中.这是一个标准的游戏准系统游戏线程

public class GameThread implements Runnable {
    private Thread runThread;
    private boolean running = false;
    private boolean paused = false;
    public GameThread() {
    }

    public void start() {
        running = true;
        paused = false;
        if(runThread == null || !runThread.isAlive())
            runThread = new Thread(this);
        else if(runThread.isAlive())
            throw new IllegalStateException("Thread already started.");
        runThread.start();
    }

    public void stop() {
        if(runThread == null)
            throw new IllegalStateException("Thread not started.");
        synchronized (runThread) {
            try {
                running = false;
                runThread.notify();
                runThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void pause() {
        if(runThread == null)
            throw new IllegalStateException("Thread not started.");
        synchronized (runThread) {
            paused = true;
        }
    }

    public void resume() {
        if(runThread == null)
            throw new IllegalStateException("Thread not started.");
        synchronized (runThread) {
            paused = false;
            runThread.notify();
        }
    }

    public void run() {
        long sleep = 0, before;
        while(running) {
            // get the time before we do our game logic
            before = System.currentTimeMillis();
            // move player and do all game logic
            try {
                // sleep for 100 - how long it took us to do our game logic
                sleep = 100-(System.currentTimeMillis()-before);
                Thread.sleep(sleep > 0 ? sleep : 0);
            } catch (InterruptedException ex) {
            }
            synchronized (runThread) {
                if(paused) {
                    try {
                        runThread.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        paused = false;
    }
}

请注意,您需要调用gameThead.start()才能开始游戏!

I've been working on a generic 2d tile style game. Currently In my main thread I have a loop that just goes as fast as it possibly can and calls the repaint method of a JPanel that is in another class which handles the game stuff. It looks like this:

public class Main {
    public static void main(String[] args) {
        Island test = new Island();
        while(true) {
            test.getCanvas().requestFocus();
            test.getCanvas().repaint();
        }
    }
}

getCanvas() just returns the JPanel.

Currently this has done what I've wanted, now that I've started adding movement for a player and obviously I don't want to move him across the screen as fast as I possibly can. So I have an input map and action map in my Island class and that detects the key presses and releases and tells my player class which keys are being held. I then move my player about inside the player class with a swing timer that calls every 10ms. So I guess this is like my game tick, my game will make frames as fast as it possibly can and then the game does all its logic stuff 100 times a second, I will be adding more to the gamelogic of course, not just movement.

After doing some research it would appear a swing timer isn't the best way of doing this as it is designed for doing small tasks and for swing tasks. So I guess my question is, is it sensible to make my frames the way I am in my main method, and what would be a good way of getting my game to tick reliably every 10ms or whatever? I've had a few ideas, like maybe I should make a new thread that handles the game logic and use the System.getnanotime or whatever its called to measure the time taken to do a tick and then do a wee thread.sleep for however long it is until we reach 10ms and then repeat.

I am happy to post more code if you want :), and thanks in advance.

解决方案

A standard way of doing this is in a Thread. Heres a standard game barebones game thread

public class GameThread implements Runnable {
    private Thread runThread;
    private boolean running = false;
    private boolean paused = false;
    public GameThread() {
    }

    public void start() {
        running = true;
        paused = false;
        if(runThread == null || !runThread.isAlive())
            runThread = new Thread(this);
        else if(runThread.isAlive())
            throw new IllegalStateException("Thread already started.");
        runThread.start();
    }

    public void stop() {
        if(runThread == null)
            throw new IllegalStateException("Thread not started.");
        synchronized (runThread) {
            try {
                running = false;
                runThread.notify();
                runThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void pause() {
        if(runThread == null)
            throw new IllegalStateException("Thread not started.");
        synchronized (runThread) {
            paused = true;
        }
    }

    public void resume() {
        if(runThread == null)
            throw new IllegalStateException("Thread not started.");
        synchronized (runThread) {
            paused = false;
            runThread.notify();
        }
    }

    public void run() {
        long sleep = 0, before;
        while(running) {
            // get the time before we do our game logic
            before = System.currentTimeMillis();
            // move player and do all game logic
            try {
                // sleep for 100 - how long it took us to do our game logic
                sleep = 100-(System.currentTimeMillis()-before);
                Thread.sleep(sleep > 0 ? sleep : 0);
            } catch (InterruptedException ex) {
            }
            synchronized (runThread) {
                if(paused) {
                    try {
                        runThread.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        paused = false;
    }
}

Note you will need to call gameThead.start() to start your game!

这篇关于Java渲染循环和逻辑循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆