Sophie

Sophie

distrib > Mageia > 7 > armv7hl > media > core-updates > by-pkgid > d5e62c01ae8d1e579463c6a871dd44bf > files > 4803

qtbase5-doc-5.12.6-2.mga7.noarch.rpm

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- rogue.qdoc -->
  <title>Rogue Example | Qt Widgets 5.12.6</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td >Qt 5.12</td><td ><a href="qtwidgets-index.html">Qt Widgets</a></td><td >Rogue Example</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right"><a href="qtwidgets-index.html">Qt 5.12.6 Reference Documentation</a></td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
<div class="sidebar">
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level1"><a href="#window-class-definition">Window Class Definition</a></li>
<li class="level1"><a href="#window-class-implementation">Window Class Implementation</a></li>
<li class="level1"><a href="#the-movementtransition-class">The MovementTransition Class</a></li>
<li class="level1"><a href="#the-roguelike-tradition">The Roguelike Tradition</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Rogue Example</h1>
<span class="subtitle"></span>
<!-- $$$statemachine/rogue-brief -->
<p>The Rogue example shows how to use the Qt state machine for event handling.</p>
<!-- @@@statemachine/rogue -->
<!-- $$$statemachine/rogue-description -->
<div class="descr"> <a name="details"></a>
<p class="centerAlign"><img src="images/rogue-example.png" alt="" /></p><p>This example implements a simple text based game. Do you see the <code>@</code> in the screenshot? That's you, the rogue. The <code>#</code> characters are walls, and the dots represent floor. In a real game, other ASCII characters would represent all kinds of objects and creatures, for instance, ancient dragons (<code>D</code>s) or food rations (<code>%</code>s). But let's not get carried away. In this game, the rogue is simply running around in an empty room.</p>
<p>The rogue is moved with the keypad (2, 4, 8, 6). That aside, we have implemented a <code>quit</code> command that triggers if the player types <code>q</code>. The player is then asked if he/she really wants to quit.</p>
<p>Most games have commands that need more than one key press (we think of consecutive presses, i.e&#x2e;, not of several keys being pressed at the same time). In this game, only the <code>quit</code> command falls under this category, but for the sake of argument, let's imagine a fully-fledged game with a rich set of commands. If we were to implement these by catching key events in <a href="qwidget.html#keyPressEvent">keyPressEvent()</a>, we would have to keep a lot of class member variables to track the sequence of keys already typed (or find some other way of deducing the current state of a command). This can easily lead to spaghetti, which is--as we all well know, I'm sure--unpleasant. With a state machine, on the other hand, separate states can wait for a single key press, and that makes our lives a lot simpler.</p>
<p>The example consists of two classes:</p>
<ul>
<li><code>Window</code> draws the text display of the game and sets up the state machine. The window also has a status bar above the area in which the rouge moves.</li>
<li><code>MovementTransition</code> is a transition that carries out a single move of the rogue.</li>
</ul>
<p>Before we embark on a code walkthrough, it is necessary to take a closer look at the design of the machine. Here is a state chart that shows what we want to achieve:</p>
<p class="centerAlign"><img src="images/rogue-statechart.png" alt="" /></p><p>The input state waits for a key press to start a new command. When receiving a key it recognizes, it transitions to one of the two commands of the game; though, as we will see, movement is handled by the transition itself. The quit state waits for the player to answer yes or no (by typing <code>y</code> or <code>n</code>) when asked whether he/she really wants to quit the game.</p>
<p>The chart demonstrates how we use one state to wait for a single key press. The press received may trigger one of the transitions connected to the state.</p>
<a name="window-class-definition"></a>
<h2 id="window-class-definition">Window Class Definition</h2>
<p>The <code>Window</code> class is a widget that draws the text display of the game. It also sets up the state machine, i.e&#x2e;, creates and connects the states in the machine. It is the key events from this widget that are used by the machine.</p>
<pre class="cpp">

  <span class="keyword">class</span> Window : <span class="keyword">public</span> <span class="type"><a href="qwidget.html">QWidget</a></span>
  {
      Q_OBJECT
      Q_PROPERTY(<span class="type"><a href="../qtcore/qstring.html">QString</a></span> status READ status WRITE setStatus)

  <span class="keyword">public</span>:
      <span class="keyword">enum</span> Direction { Up<span class="operator">,</span> Down<span class="operator">,</span> Left<span class="operator">,</span> Right };

      Window();

      <span class="type">void</span> movePlayer(Direction direction);
      <span class="type">void</span> setStatus(<span class="keyword">const</span> <span class="type"><a href="../qtcore/qstring.html">QString</a></span> <span class="operator">&amp;</span>status);
      <span class="type"><a href="../qtcore/qstring.html">QString</a></span> status() <span class="keyword">const</span>;

      <span class="type"><a href="../qtcore/qsize.html">QSize</a></span> sizeHint() <span class="keyword">const</span> override;

  <span class="keyword">protected</span>:
      <span class="type">void</span> paintEvent(<span class="type"><a href="../qtgui/qpaintevent.html">QPaintEvent</a></span> <span class="operator">*</span>event) override;

</pre>
<p><code>Direction</code> specifies the direction in which the rogue is to move. We use this in <code>movePlayer()</code>, which moves the rogue and repaints the window. The game has a status line above the area in which the rogue moves. The <code>status</code> property contains the text of this line. We use a property because the <a href="../qtcore/qstate.html">QState</a> class allows setting any Qt <a href="../qtcore/properties.html">property</a> when entered. More on this later.</p>
<pre class="cpp">

  <span class="keyword">private</span>:
      <span class="type">void</span> buildMachine();
      <span class="type">void</span> setupMap();

      <span class="type"><a href="../qtcore/qchar.html">QChar</a></span> map<span class="operator">[</span>WIDTH<span class="operator">]</span><span class="operator">[</span>HEIGHT<span class="operator">]</span>;
      <span class="type">int</span> pX<span class="operator">,</span> pY;

      <span class="type"><a href="../qtcore/qstatemachine.html">QStateMachine</a></span> <span class="operator">*</span>machine;
      <span class="type"><a href="../qtcore/qstring.html">QString</a></span> myStatus;
  };

</pre>
<p>The <code>map</code> is an array with the characters that are currently displayed. We set up the array in <code>setupMap()</code>, and update it when the rogue is moved. <code>pX</code> and <code>pY</code> is the current position of the rogue. <code>WIDTH</code> and <code>HEIGHT</code> are macros specifying the dimensions of the map.</p>
<p>The <code>paintEvent()</code> function is left out of this walkthrough. We also do not discuss other code that does not concern the state machine (the <code>setupMap()</code>, <code>status()</code>, <code>setStatus()</code>, <code>movePlayer()</code>, and <code>sizeHint()</code> functions). If you wish to take a look at the code, click on the link for the <code>window.cpp</code> file at the top of this page.</p>
<a name="window-class-implementation"></a>
<h2 id="window-class-implementation">Window Class Implementation</h2>
<p>Here is the constructor of <code>Window</code>:</p>
<pre class="cpp">

  Window<span class="operator">::</span>Window()
  {
      pX <span class="operator">=</span> <span class="number">5</span>;
      pY <span class="operator">=</span> <span class="number">5</span>;
      ...
      setupMap();
      buildMachine();
  }

</pre>
<p>The player starts off at position (5, 5). We then set up the map and statemachine. Let's proceed with the <code>buildMachine()</code> function:</p>
<pre class="cpp">

  <span class="type">void</span> Window<span class="operator">::</span>buildMachine()
  {
      machine <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qstatemachine.html">QStateMachine</a></span>;

      <span class="type"><a href="../qtcore/qstate.html">QState</a></span> <span class="operator">*</span>inputState <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qstate.html">QState</a></span>(machine);
      inputState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(<span class="keyword">this</span><span class="operator">,</span> <span class="string">&quot;status&quot;</span><span class="operator">,</span> <span class="string">&quot;Move the rogue with 2, 4, 6, and 8&quot;</span>);

      MovementTransition <span class="operator">*</span>transition <span class="operator">=</span> <span class="keyword">new</span> MovementTransition(<span class="keyword">this</span>);
      inputState<span class="operator">-</span><span class="operator">&gt;</span>addTransition(transition);

</pre>
<p>We enter <code>inputState</code> when the machine is started and from the <code>quitState</code> if the user wants to continue playing. We then set the status to a helpful reminder of how to play the game.</p>
<p>First, the <code>Movement</code> transition is added to the input state. This will enable the rogue to be moved with the keypad. Notice that we don't set a target state for the movement transition. This will cause the transition to be triggered (and the <a href="../qtcore/qabstracttransition.html#onTransition">onTransition()</a> function to be invoked), but the machine will not leave the <code>inputState</code>. If we had set <code>inputState</code> as the target state, we would first have left and then entered the <code>inputState</code> again.</p>
<pre class="cpp">

      <span class="type"><a href="../qtcore/qstate.html">QState</a></span> <span class="operator">*</span>quitState <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="../qtcore/qstate.html">QState</a></span>(machine);
      quitState<span class="operator">-</span><span class="operator">&gt;</span>assignProperty(<span class="keyword">this</span><span class="operator">,</span> <span class="string">&quot;status&quot;</span><span class="operator">,</span> <span class="string">&quot;Really quit(y/n)?&quot;</span>);

      <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>yesTransition <span class="operator">=</span> <span class="keyword">new</span>
          <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Y);
      yesTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(<span class="keyword">new</span> <span class="type"><a href="../qtcore/qfinalstate.html">QFinalState</a></span>(machine));
      quitState<span class="operator">-</span><span class="operator">&gt;</span>addTransition(yesTransition);

      <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>noTransition <span class="operator">=</span>
          <span class="keyword">new</span> <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_N);
      noTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(inputState);
      quitState<span class="operator">-</span><span class="operator">&gt;</span>addTransition(noTransition);

</pre>
<p>When we enter <code>quitState</code>, we update the status bar of the window.</p>
<p><code>QKeyEventTransition</code> is a utility class that removes the hassle of implementing transitions for <a href="../qtgui/qkeyevent.html">QKeyEvent</a>s. We simply need to specify the key on which the transition should trigger and the target state of the transition.</p>
<pre class="cpp">

      <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span> <span class="operator">*</span>quitTransition <span class="operator">=</span>
          <span class="keyword">new</span> <span class="type"><a href="qkeyeventtransition.html">QKeyEventTransition</a></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress<span class="operator">,</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Q);
      quitTransition<span class="operator">-</span><span class="operator">&gt;</span>setTargetState(quitState);
      inputState<span class="operator">-</span><span class="operator">&gt;</span>addTransition(quitTransition);

</pre>
<p>The transition from <code>inputState</code> allows triggering the quit state when the player types <code>q</code>.</p>
<pre class="cpp">

      machine<span class="operator">-</span><span class="operator">&gt;</span>setInitialState(inputState);

      connect(machine<span class="operator">,</span> SIGNAL(finished())<span class="operator">,</span> <a href="qapplication.html#qApp">qApp</a><span class="operator">,</span> SLOT(quit()));

      machine<span class="operator">-</span><span class="operator">&gt;</span>start();
  }

</pre>
<p>The machine is set up, so it's time to start it.</p>
<a name="the-movementtransition-class"></a>
<h2 id="the-movementtransition-class">The MovementTransition Class</h2>
<p><code>MovementTransition</code> is triggered when the player request the rogue to be moved (by typing 2, 4, 6, or 8) when the machine is in the <code>inputState</code>.</p>
<pre class="cpp">

  <span class="keyword">class</span> MovementTransition : <span class="keyword">public</span> <span class="type"><a href="../qtcore/qeventtransition.html">QEventTransition</a></span>
  {
      Q_OBJECT

  <span class="keyword">public</span>:
      MovementTransition(Window <span class="operator">*</span>window) :
          <span class="type"><a href="../qtcore/qeventtransition.html">QEventTransition</a></span>(window<span class="operator">,</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress) {
          <span class="keyword">this</span><span class="operator">-</span><span class="operator">&gt;</span>window <span class="operator">=</span> window;
      }

</pre>
<p>In the constructor, we tell <a href="../qtcore/qeventtransition.html">QEventTransition</a> to only send <a href="../qtcore/qevent.html#Type-enum">KeyPress</a> events to the <a href="../qtcore/qabstracttransition.html#eventTest">eventTest()</a> function:</p>
<pre class="cpp">

  <span class="keyword">protected</span>:
      bool eventTest(<span class="type"><a href="../qtcore/qevent.html">QEvent</a></span> <span class="operator">*</span>event) override {
          <span class="keyword">if</span> (event<span class="operator">-</span><span class="operator">&gt;</span>type() <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>StateMachineWrapped <span class="operator">&amp;</span><span class="operator">&amp;</span>
              <span class="keyword">static_cast</span><span class="operator">&lt;</span><span class="type"><a href="../qtcore/qstatemachine.html">QStateMachine</a></span><span class="operator">::</span>WrappedEvent <span class="operator">*</span><span class="operator">&gt;</span>(event)<span class="operator">-</span><span class="operator">&gt;</span>event()<span class="operator">-</span><span class="operator">&gt;</span>type() <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>KeyPress) {
              <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span> <span class="operator">*</span>wrappedEvent <span class="operator">=</span> <span class="keyword">static_cast</span><span class="operator">&lt;</span><span class="type"><a href="../qtcore/qstatemachine.html">QStateMachine</a></span><span class="operator">::</span>WrappedEvent <span class="operator">*</span><span class="operator">&gt;</span>(event)<span class="operator">-</span><span class="operator">&gt;</span>event();

              <span class="type"><a href="../qtgui/qkeyevent.html">QKeyEvent</a></span> <span class="operator">*</span>keyEvent <span class="operator">=</span> <span class="keyword">static_cast</span><span class="operator">&lt;</span><span class="type"><a href="../qtgui/qkeyevent.html">QKeyEvent</a></span> <span class="operator">*</span><span class="operator">&gt;</span>(wrappedEvent);
              <span class="type">int</span> key <span class="operator">=</span> keyEvent<span class="operator">-</span><span class="operator">&gt;</span>key();

              <span class="keyword">return</span> key <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_2 <span class="operator">|</span><span class="operator">|</span> key <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_8 <span class="operator">|</span><span class="operator">|</span> key <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_6 <span class="operator">|</span><span class="operator">|</span>
                     key <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_4 <span class="operator">|</span><span class="operator">|</span> key <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Down <span class="operator">|</span><span class="operator">|</span> key <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Up <span class="operator">|</span><span class="operator">|</span>
                     key <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Right <span class="operator">|</span><span class="operator">|</span> key <span class="operator">=</span><span class="operator">=</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Left;
          }
          <span class="keyword">return</span> <span class="keyword">false</span>;
      }

</pre>
<p>The KeyPress events come wrapped in <a href="../qtcore/qstatemachine-wrappedevent.html">QStateMachine::WrappedEvent</a>s. <code>event</code> must be confirmed to be a wrapped event because Qt uses other events internally. After that, it is simply a matter of checking which key has been pressed.</p>
<p>Let's move on to the <code>onTransition()</code> function:</p>
<pre class="cpp">

      <span class="type">void</span> onTransition(<span class="type"><a href="../qtcore/qevent.html">QEvent</a></span> <span class="operator">*</span>event) override {
          <span class="type"><a href="../qtgui/qkeyevent.html">QKeyEvent</a></span> <span class="operator">*</span>keyEvent <span class="operator">=</span> <span class="keyword">static_cast</span><span class="operator">&lt;</span><span class="type"><a href="../qtgui/qkeyevent.html">QKeyEvent</a></span> <span class="operator">*</span><span class="operator">&gt;</span>(
              <span class="keyword">static_cast</span><span class="operator">&lt;</span><span class="type"><a href="../qtcore/qstatemachine.html">QStateMachine</a></span><span class="operator">::</span>WrappedEvent <span class="operator">*</span><span class="operator">&gt;</span>(event)<span class="operator">-</span><span class="operator">&gt;</span>event());

          <span class="type">int</span> key <span class="operator">=</span> keyEvent<span class="operator">-</span><span class="operator">&gt;</span>key();
          <span class="keyword">switch</span> (key) {
              <span class="keyword">case</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Left:
              <span class="keyword">case</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_4:
                  window<span class="operator">-</span><span class="operator">&gt;</span>movePlayer(Window<span class="operator">::</span>Left);
                  <span class="keyword">break</span>;
              <span class="keyword">case</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Up:
              <span class="keyword">case</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_8:
                  window<span class="operator">-</span><span class="operator">&gt;</span>movePlayer(Window<span class="operator">::</span>Up);
                  <span class="keyword">break</span>;
              <span class="keyword">case</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Right:
              <span class="keyword">case</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_6:
                  window<span class="operator">-</span><span class="operator">&gt;</span>movePlayer(Window<span class="operator">::</span>Right);
                  <span class="keyword">break</span>;
              <span class="keyword">case</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_Down:
              <span class="keyword">case</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">::</span>Key_2:
                  window<span class="operator">-</span><span class="operator">&gt;</span>movePlayer(Window<span class="operator">::</span>Down);
                  <span class="keyword">break</span>;
              <span class="keyword">default</span>:
                  ;
          }
      }

</pre>
<p>When <code>onTransition()</code> is invoked, we know that we have a <a href="../qtcore/qevent.html#Type-enum">KeyPress</a> event with 2, 4, 6, or 8, and can ask <code>Window</code> to move the player.</p>
<a name="the-roguelike-tradition"></a>
<h2 id="the-roguelike-tradition">The Roguelike Tradition</h2>
<p>You might have been wondering why the game features a rogue. Well, these kinds of text based dungeon exploration games date back to a game called, yes, &quot;Rogue&quot;. Although outflanked by the technology of modern 3D computer games, roguelikes have a solid community of hard-core, devoted followers.</p>
<p>Playing these games can be surprisingly addictive (despite the lack of graphics). Angband, the perhaps most well-known rougelike, is found here: <a href="http://rephial.org/">http://rephial.org/</a>.</p>
<p>Files:</p>
<ul>
<li><a href="qtwidgets-statemachine-rogue-main-cpp.html">statemachine/rogue/main.cpp</a></li>
<li><a href="qtwidgets-statemachine-rogue-movementtransition-h.html">statemachine/rogue/movementtransition.h</a></li>
<li><a href="qtwidgets-statemachine-rogue-rogue-pro.html">statemachine/rogue/rogue.pro</a></li>
<li><a href="qtwidgets-statemachine-rogue-window-cpp.html">statemachine/rogue/window.cpp</a></li>
<li><a href="qtwidgets-statemachine-rogue-window-h.html">statemachine/rogue/window.h</a></li>
</ul>
</div>
<!-- @@@statemachine/rogue -->
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2019 The Qt Company Ltd.
   Documentation contributions included herein are the copyrights of
   their respective owners.<br/>    The documentation provided herein is licensed under the terms of the    <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation    License version 1.3</a> as published by the Free Software Foundation.<br/>    Qt and respective logos are trademarks of The Qt Company Ltd.     in Finland and/or other countries worldwide. All other trademarks are property
   of their respective owners. </p>
</div>
</body>
</html>