JavaFX模拟卡诺引擎

时间:2014-02-04 20:58:52

标签: javafx simulation physics

我正在寻找一些关于使用JavaFX构建复杂动画的答案。 我正在尝试用活塞移动等构建一个简单的Carnot Engine动画。 与this one类似的东西。

我需要的是开始编写此类模拟的最佳方式。 目前我对FX中的3种模拟类型很熟悉,因此我认为在我的情况下,最佳选择是时间线模拟。

但我仍然不确定如何开始。我应该在窗格上放置不同的砖块,如矩形板,路径,圆圈,甚至没有触及模拟,并尝试将生命放入其中,或者这种方法是完全误解的?这是我期待获得一些答案或至少提示的问题。

2 个答案:

答案 0 :(得分:1)

我会从物理引擎类开始,只有文本输出。

获取绘图中每个关键点的坐标,如连接和枢轴,并使用真实物理,计算下一个1/60秒的位置。将这些位置与热变量等一起输出到控制台。确保它是正确的,然后填写真实的形状和动画。 Javafx使用60帧/秒的标准。

如果绘图是2d并且模拟是3d(真实世界)物理,则可能在两者之间进行转换时遇到一些问题。对于奖励积分,您可以进行3D模拟。

答案 1 :(得分:1)

嗯......我对Javafx的模拟器和游戏感兴趣

几个月前我创建了一个布料模拟器,虽然并不完美,但它是我的第一个打磨模拟器。

你可以期待的麻烦:

更新UI,必须在FXthread上更新所有节点 在不妨碍场景性能的情况下运行更新

AnimationTimer是一个好的解决方案。使用标准动画创建一堆代码。

我的解决方案是创建一个每16ms运行一次的LoopService(ScheduledService) (大约60fps)与AnimationTimer相比,这个数字几乎翻了一番。

关于LoopService的好处是你可以让代码在fxthread之外运行,onSucceeded更新UI而不需要额外的监听器等。

以下是youtube上最终结果的视频:https://www.youtube.com/watch?v=uRsCcpbsdsg (由于某些原因,vid已上传到旧帐户)

您可以在我的实际YouTube页面上查看进度:
https://www.youtube.com/channel/UCxCaGZeistOC2J_rBF8JbWQ

我的数学远非完美,它仍然需要进行大量改进,但我介绍了更新UI的难点。 在源代码中,我用不同的名称来调用服务,但基础是相同的。

Cloth的源代码在这里:https://github.com/Birdasaur/FXyz 在Tests文件夹中,您应该找到一个可运行的样本。

希望它有所帮助!

以下是该服务的更新版本:

/**
 * Simple Looping Service. Useful for games, Simulations, or other items that require a running "Loop".
 *
 * @author Jason Pollastrini aka jdub1581
 */
public abstract class AbstractLoopService extends ScheduledService<Void>{
    private final long ONE_NANO = 1_000_000_000L;
    private final double ONE_NANO_INV = 1f / 1_000_000_000L;

    private long startTime, previousTime;
    private double frameRate, deltaTime;

    private final LoopThreadFactory tf = new LoopThreadFactory();    
    private final ExecutorService cachedExecutor = Executors.newCachedThreadPool(tf);


    protected AbstractLoopService() {
        this.setPeriod(Duration.millis(16.667)); // eqiv to 60 fps
        this.setExecutor(cachedExecutor);
    }


    protected final double getTimeElapsed() {
        return getCurrentTime() * ONE_NANO_INV;
    }

    protected final long getCurrentTime() {
        return System.nanoTime() - startTime;
    }

    protected final double getFrameRate() {
        return frameRate;
    }

    protected final double getDeltaTime() {
        return deltaTime;
    }

    private void updateTimer() {
        deltaTime = (getCurrentTime() - previousTime) * (1.0f / ONE_NANO);
        frameRate = 1.0f / deltaTime;
        previousTime = getCurrentTime();

    }

    @Override
    public void start() {
        super.start();
        if (startTime <= 0) {
            startTime = System.nanoTime();
        }
    }

    @Override
    public void reset() {
        super.reset();
        startTime = System.nanoTime();
        previousTime = getCurrentTime();
    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                updateTimer();
                // perform needed background tasks here ..
                runInBackground();

                return null;
            }
        };
    }

    @Override
    protected void succeeded() {
        super.succeeded();
        // Setup to handle Actions for UI here     
        runOnFXThread();
    }

    @Override
    protected void failed() {
        getException().printStackTrace(System.err);

    }

    @Override
    public String toString() {
        return "ElapsedTime: " + getCurrentTime() + "\nTime in seconds: " + getTimeElapsed()
                + "\nFrame Rate: " + getFrameRate()
                + "\nDeltaTime: " + getDeltaTime();
    }

    /*==========================================================================
     *      Methods for access
     */

    protected abstract void runOnFXThread();
    protected abstract void runInBackground();

    /*==========================================================================

     */
    private final class LoopThreadFactory implements ThreadFactory {

        public LoopThreadFactory() {
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "NanoTimerThread");
            t.setPriority(Thread.NORM_PRIORITY + 1);
            t.setDaemon(true);
            return t;
        }

    }

}