BG に沿ってキャラクタを動かす

BG(背景画像)に沿ってキャラクタを動かします。

前田稔の超初心者のプログラム入門

プログラムの作成

  1. CARD.java をコンパイルして CARD.class を作成して下さい。
    CARD.class の説明は 矢印キーでキャラクタを操作 を参照して下さい。
    BG(背景画像)に沿ってキャラクタを動かすプログラムです。
    Rpg_02.java の名前で CARD.class と同じフォルダーに格納して下さい。
    //★ BG に沿ってキャラクタを動かす    前田 稔
    import java.awt.*;
    import javax.swing.*;
    import java.awt.event.*;
    
    public class Rpg_02 extends JFrame implements KeyListener
    {   CARD        card;
        Image       bg;
        int         key_t[] = { 0,0,0,0 };      //UP, RIGHT, DOWN, LEFT
        Point       pos= new Point(96,96);      //キャラクタの座標(32 bit境界)
        int         dir= 0, num= 0;
        Dimension   size;
        Image       back;
        Graphics    buffer;
    
        // Main
        public static void main(String args[])
        {   new Rpg_02();
        }
    
        // Constructor
        Rpg_02()
        {   super("Character");
            bg = getToolkit().getImage("c:\\data\\test\\MapBack.gif");
            card = new CARD("c:\\data\\test\\Chr47.gif",32,32);
            addKeyListener(this);
            ThreadClass threadcls = new ThreadClass();
            Thread thread = new Thread(threadcls);
            thread.start();
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setBackground(Color.gray);
            setSize(800,600);
            setVisible(true);
            size = getSize();
            back= createImage(size.width, size.height);
            if (back==null) System.out.print("createImage Error");
        }
    
        //  Runnable Class
        class ThreadClass implements Runnable
        {
            public void run()
            {   long    nowTime,drawTime;
                nowTime= System.currentTimeMillis();
                drawTime= nowTime+30;
                while(true)
                {   nowTime= System.currentTimeMillis();
                    if (drawTime<nowTime)
                    {   drawTime= nowTime+30;
                        if (action())   repaint();
                    }
                }
            }
        }
    
        // キャラクタの移動
        public boolean action()
        {   int     i;
            num^= 1;
            // キーが押されているか
            for(i=0; i<4; i++)
            {   if (key_t[i]==1)    {  dir= i;  break;  }
            }
            // MAP の境界まで動く
            if (i>=4)
            {   if (pos.x%32!=0 || pos.y%32!=0) i= dir;  }
            if (i>=4)   return false;
            dir= i;
            switch(i)
            {   case 0:     // UP
                    pos.y-= 4;  break;
                case 1:     // RIGHT
                    pos.x+= 4;  break;
                case 2:     // DOWN
                    pos.y+= 4;  break;
                case 3:     // LEFT
                    pos.x-= 4;  break;
            }
            return true;
        }
    
        // Paint
        public void paint(Graphics g)
        {   if (back==null)     return;
            buffer= back.getGraphics();
            if (buffer==null)   return;
            buffer.drawImage(bg,0,40,800,600,this);
            card.View(buffer,dir*2+num,pos);
            g.drawImage(back,0,0,this);
        }
    
        // KeyEvent Listener
        public void keyPressed(KeyEvent e)
        {   switch(e.getKeyCode( ))
            {   case KeyEvent.VK_ESCAPE: System.exit(0); break;
                case KeyEvent.VK_UP :   key_t[0]= 1;  break;
                case KeyEvent.VK_RIGHT: key_t[1]= 1;  break;
                case KeyEvent.VK_DOWN : key_t[2]= 1;  break;
                case KeyEvent.VK_LEFT : key_t[3]= 1;  break;
            }
        }
        public void keyReleased(KeyEvent e)
        {   switch(e.getKeyCode( ))
            {   case KeyEvent.VK_UP :   key_t[0]= 0;  break;
                case KeyEvent.VK_RIGHT: key_t[1]= 0;  break;
                case KeyEvent.VK_DOWN : key_t[2]= 0;  break;
                case KeyEvent.VK_LEFT : key_t[3]= 0;  break;
            }
        }
        public void keyTyped(KeyEvent e) { }
    }
    
  2. 画像ファイル(MapBack.gif と Chr47.gif)をパスで指定したフォルダーに格納して下さい。
    上下左右の矢印キーを押すとキャラクタの画像がアニメーションしながら動きます。
    キーを離すと背景画像の32(16)ドット境界の位置まで移動して止まります。

プログラムの説明

  1. 前回までの説明は 矢印キーでキャラクタを操作 を参照して下さい。
    KeyListener で直接キーを検出したのでは、タイムラグが生じます。
    詳しい説明は Timer でキーの状態を調べる または Runnable を使う を参照して下さい。
    ゲームでは FPS(frames per second) を一定にして描画します。
    FPS の説明は Thread で FPS を制御 または Runnable で FPS を制御 を参照して下さい。
    普通に描画したのでは画面の「チラツキ」が大きくてゲームになりません。
    チラツキを少なくする方法は Double Buffer を使う を参照して下さい。
  2. RPG(Role Playing Game)の背景画像は、マップチップと呼ばれるタイル状の画像を組み合わせて描画する方法が良く使われます。
    マップチップは32(16)ドットで構成されるので、キャラクタはこの境界に沿って移動するのが好都合です。
    矢印キーでキャラクタを32ドットの境界に沿って動かしてみましょう。
    CARD card は画像を切り分ける CARD Class の領域です。
    Image bg は背景の画像です。
    key_t[] はキャラクタを矢印キーで操作するための領域です。
    pos はキャラクタの座標です。
    dir は進む方向(後,右,前,左)で、num は二枚の画像を切り替えながらキャラクタをアニメーションする領域です。
    size, back, buffer は描画の「チラツキ」を抑えるための Back Buffer です。
        import java.awt.*;
        import javax.swing.*;
        import java.awt.event.*;
    
        public class Rpg_02 extends JFrame implements KeyListener
        {   CARD        card;
            Image       bg;
            int         key_t[] = { 0,0,0,0 };      //UP, RIGHT, DOWN, LEFT
            Point       pos= new Point(96,96);      //キャラクタの座標(32 bit境界)
            int         dir= 0, num= 0;
            Dimension   size;
            Image       back;
            Graphics    buffer;
        
  3. Constructor で背景画像を読み込みます。
    new CARD() で CARD Class をインスタンス化します。
    32,32 は Sprite 一枚分のサイズです。
    矢印キーを検出するために KeyListener を設定します。
    スレッドを設定して thread.start() で起動します。
    「チラツキ」を抑えるために Back Buffer を作成します。
        // Constructor
        Rpg_02()
        {   super("Character");
            bg = getToolkit().getImage("c:\\data\\test\\MapBack.gif");
            card = new CARD("c:\\data\\test\\Chr47.gif",32,32);
            addKeyListener(this);
            ThreadClass threadcls = new ThreadClass();
            Thread thread = new Thread(threadcls);
            thread.start();
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setBackground(Color.gray);
            setSize(800,600);
            setVisible(true);
            size = getSize();
            back= createImage(size.width, size.height);
            if (back==null) System.out.print("createImage Error");
        }
        
  4. Runnable から action() メソッドを呼び出して、座標が更新されていると repaint() で描画します。
    Runnable の説明は、これまで説明したページを参照して下さい。
        //  Runnable Class
        class ThreadClass implements Runnable
        {
            public void run()
            {   long    nowTime,drawTime;
                nowTime= System.currentTimeMillis();
                drawTime= nowTime+30;
                while(true)
                {   nowTime= System.currentTimeMillis();
                    if (drawTime<nowTime)
                    {   drawTime= nowTime+30;
                        if (action())   repaint();
                    }
                }
            }
        }
        
  5. キーを検出してキャラクタを操作する action() メソッドです。
    キーを離したあとも x%32!=0 または y%32!=0 で BG 境界になるまでキャラクタを進めます。
    action() メソッドの説明は、これまで説明したページを参照して下さい。
        // キャラクタの移動
        public boolean action()
        {   int     i;
            num^= 1;
            // キーが押されているか
            for(i=0; i<4; i++)
            {   if (key_t[i]==1)    {  dir= i;  break;  }
            }
            // MAP の境界まで動く
            if (i>=4)
            {   if (pos.x%32!=0 || pos.y%32!=0) i= dir;  }
            if (i>=4)   return false;
            dir= i;
            switch(i)
            {   case 0:     // UP
                    pos.y-= 4;  break;
                case 1:     // RIGHT
                    pos.x+= 4;  break;
                case 2:     // DOWN
                    pos.y+= 4;  break;
                case 3:     // LEFT
                    pos.x-= 4;  break;
            }
            return true;
        }
        
  6. paint() メソッドでは、BackBuffer の準備が整っていることを確認して描画します。
    BackBuffer にイメージを作成してから一挙に Front Buffer に転送します。
        // Paint
        public void paint(Graphics g)
        {   if (back==null)     return;
            buffer= back.getGraphics();
            if (buffer==null)   return;
            buffer.drawImage(bg,0,40,800,600,this);
            card.View(buffer,dir*2+num,pos);
            g.drawImage(back,0,0,this);
        }
        
  7. KeyEvent Listener の説明は、これまで説明したページを参照して下さい。

超初心者のプログラム入門(Java2)