<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
      xmlns:thr="http://purl.org/syndication/thread/1.0">
  <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html" />
  <link rel="self" type="application/atom+xml" href="http://www.insideria.com/atom.xml" />
  <id>tag:www.insideria.com,2009://34/tag:www.insideria.com,2009://34.36111-</id>
  <updated>2009-11-16T15:00:18Z</updated>
  <title>Comments for Writing the Pac-Man Game in JavaFX - Part 2 (http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html)</title>
  <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>
  <entry>
    <id>tag:www.insideria.com,2009://34.36111</id>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blogs.oreilly.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=34/entry_id=36111" title="Writing the Pac-Man Game in JavaFX - Part 2" />
    <published>2009-05-21T13:00:00Z</published>
    <updated>2009-06-08T15:27:18Z</updated>
    <title>Writing the Pac-Man Game in JavaFX - Part 2</title>
    <summary>In last article, we designed a data model and drew a maze with dots spread into the maze. Now we are ready
to create the Pac-Man character. The Pac-Man character is controlled by the game player to move 
around the maze. While he is moving, he keeps gobbling dots along the path. To implement the
Pac-Man character, we divide the coding into a few tasks so that we can create it bit by bit:</summary>
    <author>
      <name>Haining Henry Zhang</name>
      
    </author>
    
    <category term="Features" />
    
    <content type="html" xml:lang="en" xml:base="http://www.insideria.com/">
      <![CDATA[<p><b>Haining Henry Zhang with <a href="http://learnjavafx.typepad.com" target="_blank">James L. Weaver</a></b></p>

<p>In the <a href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja.html">last article</a>, we designed a data model and drew a maze with dots spread into the maze. Now we are ready
to create the Pac-Man character. The Pac-Man character is controlled by the game player to move 
around the maze. While he is moving, he keeps gobbling dots along the path. To implement the
Pac-Man character, we divide the coding into a few tasks so that we can create it bit by bit:

<ol>
<li>Basic animation: the Pac-Man character continually open and close mouth, but he does not move</li>
<li>Moving animation: the Pac-Man character moves inside the maze</li>
<li>Player Controlling: the player controls the moving direction of the Pac-Man character</li>
<li>Gobbling dots: the Pac-Man gobbles dots</li>
</ol>


<p><b>Basic Animation</b></P>

<p>Let's start from the simplest thing first. We create the basic animation of the Pac-Man character. 
The Pac-Man character at this phase does not move but can keep opening 
and closing his mouth. The <b><tt>javafx.animation</tt></b> package, part of the JavaFX API, provides 
the easy-to-use functionality for animation. We are going to use the <b><tt>Timeline</tt></b> class to
implement the animation. During an animation, properties such as speed, shape, color and location 
are constantly changing to achieve the desired behavior. 
The <b><tt>Timeline</tt></b> class allows us
to update the values of animation properties along the progression of time. The <b><tt>Timeline.Keyframes</tt></b>
attribute can be used to define the order of frames.
We create four pictures shown below for Pac-Man's animation:</p>

<p><img src="http://www.insideria.com/upload/2009/05/fourframes.png"> </p>

<p>
When we keep switching the above pictures(frames) of the Pac-Man character, it generates the animation effect of
opening and closing the mouth. We are going to write two classes: 
<b>MovingObject.fx</b> and <b>PacMan.fx</b>. The <b><tt>MovingObject</tt></b> class abstracts some common attributes
that we could later use to implement the <b><tt>Ghost</tt></b> class. The <b><tt>PacMan</tt></b> class extends
<b><tt>MovingObject</tt></b> to display the Pac-Man character. Here is the code: 
</p>
<P><b>MovingObject.fx:</b>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
<span class="blockcomment">/*
 * MovingObject.fx
 *
 * Created on 2009-1-1, 11:40:49
 */</span>

package pacman;

<span class="category1">import</span> javafx.animation.KeyFrame;
<span class="category1">import</span> javafx.animation.Timeline;
<span class="category1">import</span> pacman.Maze;
<span class="category1">import</span> pacman.MazeData;

<span class="blockcomment">/**
 * @author Henry Zhang
 */</span>

<span class="category1">public</span> abstract <span class="category1">class</span> MovingObject {
 
   <span class="linecomment">// animation frames total and movement distance</span>
   <span class="category1">public</span> def ANIMATION_STEP=4;
   <span class="category1">public</span> def MOVE_SPEED = MazeData.GRID_GAP / ANIMATION_STEP;
 
   <span class="category1">public</span> def MOVING = 1;
   <span class="category1">public</span> def STOP =0;
   
   <span class="category1">public</span> def MOVE_LEFT=0;
   <span class="category1">public</span> def MOVE_UP=1;
   <span class="category1">public</span> def MOVE_RIGHT=2;
   <span class="category1">public</span> def MOVE_DOWN=3;
 
   <span class="category1">public</span> <span class="category1">var</span> maze: Maze;
   <span class="category1">public</span> <span class="category1">var</span> state : Integer;
 
   <span class="category1">public</span> <span class="category1">var</span> currentImage=0;
   <span class="category1">public</span> <span class="category1">var</span> moveCounter: Integer=0;
 
   <span class="linecomment">// grid coordinates</span>
   <span class="category1">public</span> <span class="category1">var</span> <span class="category2">x</span>: <span class="category2">Number</span>;
   <span class="category1">public</span> <span class="category1">var</span> <span class="category2">y</span>: <span class="category2">Number</span>;
 
   <span class="linecomment">// graphical coordinates</span>
   <span class="category1">public</span> <span class="category1">var</span> imageX: <span class="category2">Number</span> ;
   <span class="category1">public</span> <span class="category1">var</span> imageY: <span class="category2">Number</span> ;
 
   <span class="category1">public</span> <span class="category1">var</span> xDirection: <span class="category2">Number</span> = 0;
   <span class="category1">public</span> <span class="category1">var</span> yDirection: <span class="category2">Number</span> = 0;
 
   <span class="category1">public</span> <span class="category1">var</span> timeline: Timeline =  createTimeline();
 
   <span class="category1">public</span> <span class="category1">function</span> <span class="category2">stop</span>() {
      timeline.<span class="category2">stop</span>();
    }
 
   <span class="category1">public</span> <span class="category1">function</span> <span class="category2">pause</span>() {
      timeline.<span class="category2">pause</span>();
    }
 
   <span class="category1">public</span> <span class="category1">function</span> <span class="category2">start</span>() {
      timeline.<span class="category2">play</span>();
    }
 
   <span class="linecomment">// animation time line, moving the pacman</span>
   <span class="category1">public</span> <span class="category1">function</span> createTimeline(): Timeline {
      Timeline {
         repeatCount: Timeline.INDEFINITE
         keyFrames: [
           KeyFrame {
              <span class="category2">time</span>: 250ms
              action: <span class="category1">function</span>() {
                 moveOneStep();
               }
            }
         ]
        }
    }
 
   <span class="category1">public</span> abstract <span class="category1">function</span> moveOneStep(): Void;
}</pre>
</code>

</div></div> 

<p><b>PacMan.fx:</b>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
<span class="blockcomment">/*
 * PacMan.fx
 *
 * Created on 2009-1-1, 11:50:58
 */</span>

package pacman;

<span class="category1">import</span> javafx.scene.CustomNode;
<span class="category1">import</span> javafx.scene.image.Image;
<span class="category1">import</span> javafx.scene.image.ImageView;
<span class="category1">import</span> javafx.scene.Node;
<span class="category1">import</span> pacman.MazeData;

<span class="blockcomment">/**
 * @author Henry Zhang
 */</span>

<span class="category1">public</span> <span class="category1">class</span> PacMan <span class="category1">extends</span> CustomNode, MovingObject {
 
   <span class="category1">public</span> <span class="category1">var</span> defaultImage: Image = Image {
      <span class="category2">url</span>: "<span class="quote">{__DIR__}images/left1.png</span>"
    };
 
   <span class="linecomment">// images for animation</span>
   def images = [
     defaultImage,
     Image {
        <span class="category2">url</span>: "<span class="quote">{__DIR__}images/left2.png</span>"
      },
     defaultImage,
     Image {
        <span class="category2">url</span>: "<span class="quote">{__DIR__}images/round.png</span>"
      }
   ];
 
   <span class="linecomment">// GUI image of the man</span>
   <span class="category1">var</span> pacmanImage : ImageView = ImageView {
      <span class="category2">x</span>: bind imageX  - 13
      <span class="category2">y</span>: bind imageY  - 13
      image: bind images[currentImage]
      }
 
   postinit {
      imageX = MazeData.calcGridX(<span class="category2">x</span>);
      imageY = MazeData.calcGridX(<span class="category2">y</span>);
      
      state = MOVING;
      <span class="category2">start</span>();
    }
 
 
   <span class="category1">public</span> override <span class="category1">function</span> create(): Node {
      <span class="category1">return</span> pacmanImage;
    }
 
   <span class="linecomment">// handle animation of one tick</span>
   <span class="category1">public</span> override <span class="category1">function</span> moveOneStep() {
  
      <span class="category1">if</span> ( state == MOVING) {
   
         <span class="linecomment">// switch to the image of the next frame</span>
         <span class="category1">if</span> ( currentImage &lt; ANIMATION_STEP - 1  )
           currentImage++
         <span class="category1">else</span> {
            currentImage=0;
          }
       }
    }
}</pre>
</code>

</div></div> 

<p>The <b><tt>MovingObject</tt></b> class defines an abstract function <b><tt>moveOneStep()</tt></b> which is
called every 200 millisecond. Subclasses should
implement this function to create frames of the animation. The <b><tt>PacMan</tt></b> class extends both the 
<b><tt>CustomNode</tt></b> and <b><tt>MovingObject</tt></b> classes. In Java, a class can implement a few
interfaces. In JavaFX's grammar, there is no interface, so multiple inheritance is used here. The attribute
<b><tt>images</tt></b> is a sequence containing four pictures of the animation frames. 
When the function <b><tt>moveOneStep()</tt></b> is invoked every 200ms, the value of the attribute <b><tt>pacmanImage</tt></b> 
is rotated to the next picture in the sequence. In this way, the animation of Pac-Man's opening and closing his 
mouth is accomplished. </p>

<p>Let's add in some code to the <b><tt>Maze</tt></b> class so that we can see the result of our animation. First, 
add a statement to create an instance of <b><tt>PacMan</tt></b>:
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
<span class="category1">public</span> <span class="category1">class</span> Maze <span class="category1">extends</span> CustomNode {
 
   <span class="linecomment">// Pac Man Character</span>
   <span class="category1">public</span> <span class="category1">var</span> pacMan : PacMan = PacMan{ maze:<span class="category1">this</span> <span class="category2">x</span>:23 <span class="category2">y</span>:5};
 
   . . . .</pre>
</code>

</div></div> 

Then in the postinit block, we put the <b><tt>PacMan</tt></b> instance into the maze:

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  postinit {
 
     . . . . . 
 
     &lt;b&gt;insert pacMan into group.content;&lt;/b&gt;
   }</pre>
</code>

</div></div> 

Now, let's run the program and you can see that the Pac-Man character keeps biting.
For illustration and testing purpose, we set an interval of 200ms between frames. This is a relatively large
interval and it is kind of slow for playing. We will reduce this interval a bit later as we move forward.
Click on the below image to view how the program runs so far: </P>
<p><a href="http://www.javafxgame.com/v3/pacman.jnlp">
<img src="http://www.insideria.com/upload/2009/05/maze4.png" border=0><br><br>
<img src="http://www.insideria.com/upload/2009/05/launch.gif" border=0></a>
</p>

<p><b>Animation of Pac-Man Moving</b></p>
<p>We now can make the Pac-Man character moving inside the maze. First, let me explain the purpose of a pair of variables in 
the <b><tt>MovingObject</tt></b> class: <b><tt>xDirection</tt></b> and <b><tt>yDirection</tt></b>. They are
used to store the horizontal and vertical direction of a character. See below table: </p>
<p>
<table border=1>
<tr>
<td width=200><b>Moving Direction</b></td><td width=100><b><tt>xDirection</tt></b></td>
<td width=100><b><tt>yDirection</tt></b></td>
</tr>
<tr>
<td>Left</td><td>-1</td><td>0</td>
</tr>
<tr>
<td>Right</td><td>1</td><td>0</td>
</tr>
<tr>
<td>Up</td><td>0</td><td>-1</td>
</tr>
<tr>
<td>Down</td><td>0</td><td>1</td>
</tr>
</table>
</p>
<p>
Since we have four frames for a cycle of animation, 
we can change the position (i.e. x or y coordinates) of the character when we update the picture of a frame.
So a constant variable <b><tt>MOVE_SPEED</tt></b>, the moving speed of a character is defined in the <b><tt>MovingObject</tt></b> class and is computed as:
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="category1">public</span> def ANIMATION_STEP=4;
  <span class="category1">public</span> def MOVE_SPEED = MazeData.GRID_GAP / ANIMATION_STEP;</pre>
</code>

</div></div> 
During every animation clock cycle, we update the x or y coordinates of a character by a delta of <b><tt>MOVE_SPEED</tt></b>.
After 4 clock cycles, the Pac-Man character moves to the next point of the grid either horizontally or vertically.
Based on this algorithm, we add two functions <b><tt>moveHorizontally()</tt></b> and <b><tt>moveVertically()</tt></b> into 
<b><tt>PacMan</tt></b> class.

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
<span class="category1">public</span> <span class="category1">class</span> PacMan <span class="category1">extends</span> CustomNode, MovingObject {
 
   . . . . . .
 
   <span class="linecomment">// moving horizontally</span>
   <span class="category1">public</span> <span class="category1">function</span> moveHorizontally() {
  
      moveCounter++;
  
      <span class="category1">if</span> ( moveCounter &lt; ANIMATION_STEP ) {
         imageX += xDirection * MOVE_SPEED;
       }
      <span class="category1">else</span> {
         moveCounter = 0;
         <span class="category2">x</span> += xDirection;
         
         imageX = MazeData.calcGridX(<span class="category2">x</span>);
   
         <span class="linecomment">// the X coordinate of the next point in the grid</span>
         <span class="category1">var</span> nextX = xDirection + <span class="category2">x</span>;
   
         <span class="linecomment">// check if the character hits a wall</span>
         <span class="category1">if</span> ( MazeData.<span class="category2">getData</span>(nextX, <span class="category2">y</span>) == MazeData.BLOCK ) {
            state = STOP;
          }
       }
    }
 
   <span class="linecomment">// moving vertically</span>
   <span class="category1">public</span> <span class="category1">function</span> moveVertically() {
        
      moveCounter++;
  
      <span class="category1">if</span> ( moveCounter &lt; ANIMATION_STEP ) {
         imageY += yDirection * MOVE_SPEED;
       }
      <span class="category1">else</span> {
         moveCounter = 0;
         <span class="category2">y</span> += yDirection;
         imageY = MazeData.calcGridX(<span class="category2">y</span>);
   
         <span class="linecomment">// the Y coordinate of the next point in the grid</span>
         <span class="category1">var</span> nextY = yDirection + <span class="category2">y</span>;
   
         <span class="linecomment">// check if the character hits a wall</span>
         <span class="category1">if</span> ( MazeData.<span class="category2">getData</span>(<span class="category2">x</span>, nextY) == MazeData.BLOCK ) {
            state = STOP;
          }
       }
    }
 
   . . . . . . 
}</pre>
</code>

</div></div> 
<p>
The two functions are similar to each other, so let's take a look at the function <b><tt>moveHorizontally()</tt></b>.
When the character's position is between two points of the grid, we use this statement to move it: </p>

<p>
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
imageX += xDirection * MOVE_SPEED;</pre>
</code>

</div></div> 
<p>
When the character reaches a point, we check whether it hits a wall of the maze. If it does, we make it stop:
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
<span class="linecomment">// check if the character hits a wall</span>
<span class="category1">if</span> ( MazeData.<span class="category2">getData</span>(nextX, <span class="category2">y</span>) == MazeData.BLOCK ) {
     state = STOP;
}</pre>
</code>

</div></div> 
</P>
<p>
Now, we can write some codes to test the moving of the Pac-man character. In <b><tt>PacMan</tt></b> class, 
we add in the moving code in the function <b><tt>moveOnetStep()</tt></b>:

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="linecomment">// handle animation of one tick</span>
  <span class="category1">public</span> override <span class="category1">function</span> moveOneStep() {
 
     <span class="category1">if</span> ( state == MOVING) {
  
        <span class="category1">if</span> ( xDirection != 0 )
          moveHorizontally();
  
        <span class="category1">if</span> ( yDirection != 0 )
          moveVertically();
  
        <span class="linecomment">// switch to the image of the next frame</span>
        <span class="category1">if</span> ( currentImage &lt; ANIMATION_STEP - 1  )
          currentImage++
        <span class="category1">else</span> {
           currentImage=0; 
         }
      }
   }</pre>
</code>

</div></div> 

In the <b><tt>postinit</tt></b> block, we set the initial direction of the pac-man character: 

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  postinit {
     imageX = MazeData.calcGridX(<span class="category2">x</span>);
     imageY = MazeData.calcGridX(<span class="category2">y</span>);
     
     xDirection = -1;
     yDirection = 0;
 
     state = MOVING;
     <span class="category2">start</span>();
   }</pre>
</code>

</div></div> 

<p>Run the program now and we can see the Pac-Man moving to the left and stop at the border of the maze. 
<p><a href="http://www.javafxgame.com/v4/pacman.jnlp">
<img src="http://www.insideria.com/upload/2009/05/maze5.png" border=0><br><br>
<img src="http://www.insideria.com/upload/2009/05/launch.gif" border=0></a>
</p>
<p>You can try other moving directions by changing the values of <b><tt>xDirection</tt></b> and <b><tt>yDirection</tt></b> 
in the <b><tt>postinit</tt></b> block. Refer to the table in previous section for possible combinations.
Since we have not yet handled the part to turn the Pac-man's mouth, he always faces to
 the left no matter which direction he moves in. 
</p>
<p>
One last thing is to deal with a special case in the Pac-man's passing through the tunnel. The Pac-man character
can walk into the tunnel to reach the other side of the maze. We put in some handling in function <b><tt>moveHorizontally()</tt></b> for this purpose.


<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="category1">public</span> <span class="category1">function</span> moveHorizontally() {
 
     moveCounter++;
 
     <span class="category1">if</span> ( moveCounter &lt; ANIMATION_STEP ) {
        imageX += xDirection * MOVE_SPEED;
      }
     <span class="category1">else</span> {
        moveCounter = 0;
        <span class="category2">x</span> += xDirection;
        
        imageX = MazeData.calcGridX(<span class="category2">x</span>);
  
        <span class="linecomment">// the X coordinate of the next point in the grid</span>
        <span class="category1">var</span> nextX = xDirection + <span class="category2">x</span>;
  
        <span class="category1">if</span> ( <span class="category2">y</span> == 14 <span class="category1">and</span> ( nextX &lt;= 1 <span class="category1">or</span> nextX &gt;= 28) ) {
           <span class="category1">if</span> ( nextX &lt; -1 <span class="category1">and</span> xDirection &lt; 0 ) {
              <span class="category2">x</span> = MazeData.GRID_SIZE;
              imageX = MazeData.calcGridX(<span class="category2">x</span>);
            }
           <span class="category1">else</span>
             <span class="category1">if</span> ( nextX &gt; 30 <span class="category1">and</span> xDirection &gt; 0) {
                <span class="category2">x</span> = 0;
                imageX = MazeData.calcGridX(<span class="category2">x</span>);
               }
         }
        <span class="category1">else</span> <span class="linecomment">// check if the character hits a wall</span>
          <span class="category1">if</span> ( MazeData.<span class="category2">getData</span>(nextX, <span class="category2">y</span>) == MazeData.BLOCK ) {
             state = STOP;
         }
      }
   }</pre>
</code>

</div></div> 

In <b>Maze.fx</b>, we add two <b><tt>WallBlackRectangle</tt></b> objects to create the clipping effect of
the Pac-man passing the tunnel.
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  postinit {
 
    . . . . . 
 
     insert pacMan into group.content;
     insert WallBlackRectangle{ x1:-3, y1:13, x2:0, y2:15} into group.content;
     insert WallBlackRectangle{ x1:29, y1:13, x2:31, y2:15} into group.content;
   }</pre>
</code>

</div></div> 

<p>Then we can test this code by placing the Pac-Man character at the position (5,14):

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="category1">public</span> <span class="category1">var</span> pacMan : PacMan = PacMan{ maze:<span class="category1">this</span> &lt;b&gt;<span class="category2">x</span>:5 <span class="category2">y</span>:14&lt;/b&gt; };</pre>
</code>

</div></div> 

So far, we completed the moving part of the Pac-man character. 

<p><b>Player's Controlling</b></p>
<p>Now, we start to work on the player's keyboard controlling. In <b><tt>PacMan</tt></b> class, we define two
attributes: 

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="linecomment">// buffer to keep the keyboard input</span>
  <span class="category1">var</span> keyboardBuffer: Integer = -1;

  <span class="linecomment">// current direction of Pacman</span>
  <span class="category1">var</span> currentDirection: Integer = MOVE_LEFT;</pre>
</code>

</div></div> 

<p>The <b><tt>keyboardBuffer</tt></b> attribute is used to store the keyboard input(keypress event). It will be consumed 
when the pac-man character's position is valid for the turn. Buffered keyboard input can be overwritten
by subsequent keypressed event. For this reason, an experienced player usually presses a key well before the Pac-man reaches a turning
point.</p>

<p>The <b><tt>currentDirection</tt></b> is an attribute to determine which direction the pac-man faces to.
</P>

<p>In <b>PacMan.fx</b>, we create a few functions as below. 
The function <b><tt>moveRight()</tt></b>, <b><tt>moveLeft()</tt></b>, <b><tt>moveUp()</tt></b> and <b><tt>moveDown()</tt></b>
are to change the direction of the Pac-Man character based on keyboard events. 
</p>
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="linecomment">// turn pac-man to the right</span>
  <span class="category1">public</span> <span class="category1">function</span> moveRight(): Void {
 
     <span class="category1">if</span> ( currentDirection == MOVE_RIGHT ) <span class="category1">return</span>;
 
     <span class="category1">var</span> nextX = <span class="category2">x</span> + 1;
 
     <span class="category1">if</span> ( nextX &gt;= MazeData.GRID_SIZE) <span class="category1">return</span>;
 
     <span class="category1">if</span> ( MazeData.<span class="category2">getData</span>(nextX, <span class="category2">y</span>) == MazeData.BLOCK ) <span class="category1">return</span>;
 
     xDirection = 1;
     yDirection = 0;
 
     keyboardBuffer = -1;
     currentDirection = MOVE_RIGHT;
 
     state = MOVING;
   }

  <span class="linecomment">// turn pac-man to the left</span>
  <span class="category1">public</span> <span class="category1">function</span> moveLeft(): Void {
 
     <span class="category1">if</span> ( currentDirection == MOVE_LEFT ) <span class="category1">return</span>;
 
     <span class="category1">var</span> nextX = <span class="category2">x</span> - 1;
 
     <span class="category1">if</span> ( nextX &lt;= 1) <span class="category1">return</span>;
 
     <span class="category1">if</span> ( MazeData.<span class="category2">getData</span>(nextX, <span class="category2">y</span>) == MazeData.BLOCK ) <span class="category1">return</span>;
 
     xDirection = -1;
     yDirection = 0;
 
     keyboardBuffer = -1;
     currentDirection = MOVE_LEFT;
 
     state = MOVING;
   }

  <span class="linecomment">// turn pac-man going up</span>
  <span class="category1">public</span> <span class="category1">function</span> moveUp(): Void {
 
     <span class="category1">if</span> ( currentDirection == MOVE_UP ) <span class="category1">return</span>;
 
     <span class="category1">var</span> nextY = <span class="category2">y</span> - 1;
 
     <span class="category1">if</span> ( nextY &lt;= 1) <span class="category1">return</span>;
 
     <span class="category1">if</span> ( MazeData.<span class="category2">getData</span>(<span class="category2">x</span>,nextY) == MazeData.BLOCK ) <span class="category1">return</span>;
 
     xDirection = 0;
     yDirection = -1;
 
     keyboardBuffer = -1;
     currentDirection = MOVE_UP;
 
     state = MOVING;
   }

  <span class="linecomment">// turn pac-man going down</span>
  <span class="category1">public</span> <span class="category1">function</span> moveDown(): Void {
 
     <span class="category1">if</span> ( currentDirection == MOVE_DOWN ) <span class="category1">return</span>;
 
     <span class="category1">var</span> nextY = <span class="category2">y</span> + 1;
 
     <span class="category1">if</span> ( nextY &gt;= MazeData.GRID_SIZE ) <span class="category1">return</span>;
 
     <span class="category1">if</span> ( MazeData.<span class="category2">getData</span>(<span class="category2">x</span>,nextY) == MazeData.BLOCK ) <span class="category1">return</span>;
 
     xDirection = 0;
     yDirection = 1;
 
     keyboardBuffer = -1;
     currentDirection = MOVE_DOWN;
 
     state = MOVING;
   }

  <span class="linecomment">// handle keyboard input</span>
  <span class="category1">public</span> <span class="category1">function</span> handleKeyboardInput(): Void {
     <span class="category1">if</span> ( keyboardBuffer &lt; 0) <span class="category1">return</span>;
 
     <span class="category1">if</span> ( keyboardBuffer == MOVE_LEFT )
       moveLeft()
     <span class="category1">else</span>
       <span class="category1">if</span> ( keyboardBuffer == MOVE_RIGHT )
         moveRight()
       <span class="category1">else</span>
         <span class="category1">if</span> ( keyboardBuffer == MOVE_UP )
           moveUp()
         <span class="category1">else</span>
           <span class="category1">if</span> ( keyboardBuffer == MOVE_DOWN )
             moveDown();
   }

  <span class="category1">public</span> <span class="category1">function</span> setKeyboardBuffer( k: Integer): Void {
     keyboardBuffer = k;
   }</pre>
</code>

</div></div> 

In <b><tt>moveOneSteop()</tt></b> function, add in two lines of code to handle keyboard events
during each tick of the animation:

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="category1">public</span> override <span class="category1">function</span> moveOneStep() {
 
     <span class="linecomment">// handle keyboard input only when pac-man is at a point of the grid</span>
     <span class="category1">if</span> ( currentImage==0 )
       handleKeyboardInput();
 
     . . . . . .
   }</pre>
</code>

</div></div> 
</P>

<p>As we mentioned previously, the Pac-Man always faces to the left in our code. Let's modify our codes
a bit to enable the Pac-Man to "turn" his mouth. A common approach is to use a separate set of pictures when 
the character is moving in a particular direction. However, we going to  utilize the transformation feature of 
JavaFX to achieve this goal. Instead of switching to another set of pictures, we just rotate the picture of
each frame to face to the correct direction. JavaFX makes it very simple to accomplish. Let's change some 
code in <b><tt>PacMan</tt></b>.
</p>
<p>
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
<span class="category1">public</span> <span class="category1">class</span> PacMan <span class="category1">extends</span> CustomNode, MovingObject {
 
   . . . . . 
 
   <span class="linecomment">// angles of rotating the images</span>
   def rotationDegree = [0, 90, 180, 270];
 
   <span class="linecomment">// GUI image of the man</span>
   <span class="category1">var</span> pacmanImage : ImageView = ImageView {
      <span class="category2">x</span>: bind imageX - 13
      <span class="category2">y</span>: bind imageY - 13
      image: bind images[currentImage]
      transforms: Rotate {
         angle: bind rotationDegree[currentDirection]
         pivotX: bind imageX
         pivotY: bind imageY
         }
     }
 
   . . . . . </pre>
</code>

</div></div> 

<p>The <b><tt>transforms</tt></b> attribute of the <b><tt>ImageView</tt></b> class allows us to apply the rotation
we need. An instance of <b><tt>Rotate</tt></b> defines the angle and the center of the rotation.
Binding is used again to automatically update the GUI of the character.
</p>

<p>To accept keyboard events, we override the <b><tt>onKeyPressed</tt></b> attribute of the <b><tt>Maze</tt></b> class: 

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="category1">public</span> override <span class="category1">var</span> onKeyPressed = <span class="category1">function</span> ( e: KeyEvent ) : Void {
 
     <span class="category1">if</span> ( e.code == KeyCode.VK_DOWN )
       pacMan.setKeyboardBuffer( pacMan.MOVE_DOWN )
     <span class="category1">else</span>
       <span class="category1">if</span> ( e.code == KeyCode.VK_UP )
         pacMan.setKeyboardBuffer( pacMan.MOVE_UP )
       <span class="category1">else</span>
         <span class="category1">if</span> ( e.code == KeyCode.VK_RIGHT )
           pacMan.setKeyboardBuffer( pacMan.MOVE_RIGHT )
         <span class="category1">else</span>
           <span class="category1">if</span> ( e.code == KeyCode.VK_LEFT )
             pacMan.setKeyboardBuffer( pacMan.MOVE_LEFT );
   }</pre>
</code>

</div></div> 

<p>To get better visual effect, we now reduce the interval of animation keyframes.
In function <b><tt>MovingObject.createTimeline()</tt></b>, we change the <b><tt>time</tt></b> attribute to 50ms.

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="category1">public</span> <span class="category1">function</span> createTimeline(): Timeline {
     Timeline {
        repeatCount: Timeline.INDEFINITE
        keyFrames: [
          KeyFrame {
             <span class="category2">time</span>: &lt;b&gt;50ms&lt;/b&gt;
             action: <span class="category1">function</span>() {
                moveOneStep();
              }
           }
        ]
       }
   }</pre>
</code>

</div></div> 

<p>Run the program and you can control the pac-man character's moving by arrow keys. Click the below button
to view it online:</p>
<p>
<a href="http://www.javafxgame.com/v5/pacman.jnlp">
<img src="http://www.insideria.com/upload/2009/05/maze6.png" alt="click to run" border=0><br><br>
<img src="http://www.insideria.com/upload/2009/05/launch.gif" border=0></a>
</p>

<p><b>Gobbling Dots</b></p>
<p>The last part of the Pac-man's animation is gobbling the dots. We first create two attributes in the 
<b><tt>PacMan</tt></b>
class: <b><tt>dotEatenCount</tt></b> and <b><tt>scores</tt></b>.

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="linecomment">// the number of dots eaten</span>
  <span class="category1">public</span> <span class="category1">var</span> dotEatenCount : Integer = 0;

  <span class="linecomment">// scores of the game</span>
  <span class="category1">public</span> <span class="category1">var</span> scores: Integer = 0;</pre>
</code>

</div></div> 

<p>Then we write a function <b><tt>updateScores()</tt></b> to check if a dot is gobbled by the
Pac-man character. The scores is updated accordingly. 
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="category1">public</span> <span class="category1">function</span> updateScores() : Void {
     <span class="category1">if</span> ( <span class="category2">y</span> != 14 <span class="category1">or</span> ( <span class="category2">x</span> &gt; 0 <span class="category1">and</span> <span class="category2">x</span> &lt; MazeData.GRID_SIZE ) ) {
        <span class="category1">var</span> dot : Dot = MazeData.getDot( <span class="category2">x</span>, <span class="category2">y</span> ) as Dot ;
  
        <span class="category1">if</span> ( dot != <span class="category1">null</span> <span class="category1">and</span> dot.<span class="category2">visible</span> ) {
           scores += 10;
           dot.<span class="category2">visible</span> = <span class="category1">false</span>;
           dotEatenCount ++;
         }
      }
   }</pre>
</code>

</div></div> 
</p>

<p>In function <b><tt>moveOneStep()</tt></b>, we invoke the <b><tt>updateScores()</tt></b> as below:
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
  <span class="category1">public</span> override <span class="category1">function</span> moveOneStep() {
 
       . . . . . .
 
       <span class="category1">if</span> ( currentImage &lt; ANIMATION_STEP - 1  )
         currentImage++
       <span class="category1">else</span> {
          currentImage=0;
          updateScores();
        }
       . . . . . .
 
   }</pre>
</code>

</div></div> 
</P>

<p>Finally, we add a <b><tt>Text</tt></b> instance as a scoreboard under the maze. It displays the scores as Pac-man eats the dots.
The content of the <b><tt>Text</tt></b> instance is bound to <b><tt>pacMan.scores</tt></b>.
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre> 
<span class="category1">public</span> <span class="category1">class</span> Maze <span class="category1">extends</span> CustomNode {
 
   . . . . . . 
 
   <span class="category1">var</span> group : Group =
   Group {
      content: [  
  
        . . . . . .
     
        Text {
           <span class="category2">font</span>: Font {
                  <span class="category2">size</span>: 20
                  }
           <span class="category2">x</span>: MazeData.calcGridX(0), 
           <span class="category2">y</span>: MazeData.calcGridY(MazeData.GRID_SIZE + 2)
           content: bind "<span class="quote">SCORES: {pacMan.scores} </span>"
           fill: <span class="category2">Color</span>.YELLOW
         }
       ]
     . . . . . .</pre>
</code>

</div></div> 

<p>By now, we completed the all the animation part of the Pac-man character. A player can control the
pac-man character by keyboard and score by gobbling the dots. Click on the below button to run and play it.
<p>
<a href="http://www.javafxgame.com/v6/pacman.jnlp">
<img src="http://www.insideria.com/upload/2009/05/maze7.png" alt="click to run" border=0><br><br>
<img src="http://www.insideria.com/upload/2009/05/launch.gif" border=0></a>
</p>

<p><a href="http://www.insideria.com/upload/2009/05/javafxsource2.zip">Download Source Code</a></p>

<p><strong>Related Features</strong></p>
<ul><li><a href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja.html">Writing the Pac-Man Game in JavaFX - Part 1</a></li>
<li><a href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-2.html">Writing the Pac-Man Gamin JavaFX - Part 3</a></li>
</ul>]]>
      
    </content>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.36111-comment:2066131</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.36111" type="text/html" href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html#comment-2066131" />
    <title>Comment from J sarath shyamson on 2009-06-12</title>
    <author>
        <name>J sarath shyamson</name>
        <uri>http://www.aficionadous.co.cc/</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.aficionadous.co.cc/">
        <![CDATA[<p>Great Work.... Hats off.<br />
But im not getting the pacman character even after adding MovingObject and PacMan fx files.I have also tries putting separate images for left1.jpg<br />
left2.jpg round.jpg.<br />
  But there is prob somewhere....What must have gone wrong?<br />
Pls Guide me at shyamjohnson@gmail.com</p>]]>
    </content>
    <published>2009-06-13T02:49:00Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.36111-comment:2066146</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.36111" type="text/html" href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html#comment-2066146" />
    <title>Comment from Haining Henry Zhang on 2009-06-13</title>
    <author>
        <name>Haining Henry Zhang</name>
        <uri>http://www.javafxgame.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.javafxgame.com">
        <![CDATA[<p>Hi Sarath,</p>

<p>I think you were probably running JavaFX 1.2. The code in this article was written for JavaFX 1.1. The latest code had been updated for JavaFX 1.2. Please check out the download page on <a href="http://www.javafxgame.com">http://www.javafxgame.com</a> </p>]]>
    </content>
    <published>2009-06-13T10:01:29Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.36111-comment:2066226</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.36111" type="text/html" href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html#comment-2066226" />
    <title>Comment from Haining Henry Zhang on 2009-06-15</title>
    <author>
        <name>Haining Henry Zhang</name>
        <uri>http://www.javafxgame.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.javafxgame.com">
        <![CDATA[<p>Sarath,</p>

<p>You can also follow instructions on <a href="/2009/06/writing-the-pac-man-game-in-ja-3.html"> to modify the code to work under JavaFX 1.2. </a></p>

<p>More info: <a href="http://www.javafxgame.com">http://www.javafxgame.com</a></p>]]>
    </content>
    <published>2009-06-15T15:00:36Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.36111-comment:2135119</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.36111" type="text/html" href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/05/writing-the-pac-man-game-in-ja-1.html#comment-2135119" />
    <title>Comment from Dinesh on 2009-10-10</title>
    <author>
        <name>Dinesh</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>The presentation was too good...!<br />
Amazing work and thanks for sharing.</p>]]>
    </content>
    <published>2009-10-10T19:44:38Z</published>
  </entry>

</feed
