【问题标题】:Implementing Realtime in a Text-Adventure?在文本冒险中实现实时?
【发布时间】:2013-02-25 04:32:20
【问题描述】:

我正在制作基于文本的 RPG,我真的很想模仿时间。
我可以在玩家每次输入内容之间留出一些时间,但如果可能的话,我希望它比这更好。我想知道多线程是否是一个很好的方法。

我在想可能只是在后台有第二个非常简单的线程,它只有一个循环,每 1000 毫秒循环一次。每通过一次循环,世界时间将增加 1 秒,玩家将恢复一点生命值和法力值。

这是多线程可以做的事情,还是有一些我不知道的东西会使它不起作用? (如果它不能帮助我完成这个项目,我宁愿不要花很多时间努力学习它。)

【问题讨论】:

  • cplusplus.com/reference/ctime 有什么问题?
  • 它可以完成这项工作。但是,如果您采用这种方法,那么熟悉互斥锁会为您省去一些麻烦。
  • 为什么有这样的线程比替代方案更好?
  • 感谢您的确认和提示。现在我知道它会帮助有经验的人提供的任何提示将不胜感激。
  • 在不了解您的软件设计的情况下,这很难回答。如果没有理由启动其他线程,您可能不应该启动其他线程。如果它是文本 RPG,您可能会在循环中运行 select() 或 poll(),在收到输入时做出响应。您还可以在这些功能中设置超时,以便您可以执行“时间已过”的任务,而不管用户输入如何。但是没有你的设计,我不知道这是否是一个合适的建议。

标签: c++ multithreading time game-engine adventure


【解决方案1】:

是的,多线程当然可以做到这一点,但要担心线程通常比替代方案更复杂(这将是主线程轮询各种更新事件作为其主循环的一部分,它应该至少每 100 毫秒运行一次无论如何)。

在你的情况下,如果时钟线程遵循非常严格的规则,你可能会“没问题”。

  1. 时钟线程是唯一允许设置/修改时间变量的线程。
  2. main/ui线程只允许读取时间。
  3. 您仍必须使用系统时间函数,因为无法信任线程休眠函数的准确性(根据系统活动,线程的更新循环可能要等到您请求运行几毫秒后才会运行)。

如果你这样实现它,那么你甚至不需要熟悉互斥锁就可以让线程安全运行,而且你的时间会很准确。

但是!这里有一些值得深思的地方:如果您想在一天中的特定时间绑定游戏内触发器怎么办?例如,将发布给用户的消息“太阳下山了” 或类似内容。无论如何,所需的代码都需要在主线程上运行(除非你想实现跨线程消息通信队列!),并且可能看起来很像基本的周期性检查和更新时钟代码.所以到那时你最好还是保持一个简单的统一线程模型。

【讨论】:

  • 不确定我最后的评论是否通过了 o.O.无论如何,如果它没有:我对编码还很陌生(只学习了几门关于 java、C++ 和汇编的课程),所以我需要一些时间来理解你的意思。感谢您的快速回答:)
  • 在您的回答中,您说时钟线程是唯一能够操纵时间的线程。但我需要我的球员能够休息。有没有办法让我的主线程发信号通知我的时钟线程向前推进几个小时?
  • 为此,您可以:1. 进行全面的互斥体排除设计,2. 暂停时钟线程,3. 将时钟重置请求传递给时钟线程的消息队列。我按照我认为它们代表的难度顺序(1 最简单)列出了它们。还要记住,对于每 1000 毫秒只“做事”的线程,最有可能出现错误的实现仍然可以在 99% 的时间内正常工作。因此,您可能永远不会真正知道自己是否做对了。
【解决方案2】:

我通常使用一个名为 Simulation 的类来推进时间。我在 C++ 中没有它,但我已经在 J​​ava 中完成了线程,它可以向前推进时间并根据计划(或计划时间的随机事件)激活事件。你可以把它翻译成 C++ 或使用来看看面向对象的实现是怎样的。

package adventure;

public class Simulation extends Thread {

    private PriorityQueue prioQueue;

    Simulation() {
        prioQueue = new PriorityQueue();
        start();
    }

    public void wakeMeAfter(Wakeable SleepingObject, double time) {
        prioQueue.enqueue(SleepingObject, System.currentTimeMillis() + time);
    }

    public void run() {
        while (true) {
            try {
                sleep(5); 

                if (prioQueue.getFirstTime() <= System.currentTimeMillis()) {
                    ((Wakeable) prioQueue.getFirst()).wakeup();
                    prioQueue.dequeue();
                }

            } catch (InterruptedException e) {

            }

        }
    }

}

要使用它,你只需实例化它并添加你的对象:

 `      Simulation sim = new Simulation();

        // Load images to be used as appearance-parameter for persons
        Image studAppearance = loadPicture("Person.gif");

        // --- Add new persons here ---
        new WalkingPerson(sim, this, "Peter", studAppearance);

【讨论】:

    【解决方案3】:

    我将假设您的程序目前大部分时间都在等待用户输入 - 这会不规则地阻塞您的主线程并且会在相对较长的时间内阻塞,从而阻止您进行短时间相关的更新。并且您希望避免复杂的解决方案(线程)。

    如果你想在主线程中访问时间,accessing it without a separate thread is relatively easy(看例子)。

    如果您在等待用户输入时不需要在后台执行任何操作,您就不能编写一个函数来根据等待时经过的时间计算新值吗?你可以有一些变量LastSystemTimeObserved,每次你需要使用你的时间相关变量之一时都会更新 - 调用一些函数,根据自上次调用以来经过的时间来计算变量的更改值,而不是重新计算每秒的值。

    如果您确实创建了一个单独的线程,请确保您 properly protect 两个线程都访问的任何变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-13
      • 1970-01-01
      • 1970-01-01
      • 2016-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多