TEXT ファイルを使う



MapEdit の出力ファイルで背景を描画します。

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

プログラムの作成

  1. メモ帳などでタイプして rpgbg.java の名前で保存して下さい。
    Applet はサーバーにアップロードすることが前提なので、ファイル名やクラス名を小文字で統一しています。
    //★ MapEdit の出力ファイルで BG を描画    前田 稔
    //   appletviewer rpgbg.htm
    import java.applet.*;
    import java.awt.*;
    import java.io.*;
    import java.net.URL;
    import javax.imageio.ImageIO;
    
    public class rpgbg extends Applet
    {   bg      obj;
    
        // Initialize
        public void init()
        {   obj = new bg(getCodeBase().toString(),"test.txt");
            obj.SetRect(0,0,240,160);
        }
    
        // Paint Method
        public void paint(Graphics g)
        {   obj.MapView(g);
        }
    }
    
    //★ BG Object Class
    class bg extends Applet
    {   String      Imgfile;        // image file
        Image       Img;            // Image Object
        Dimension   size= new Dimension(32,32); // Sprite Size
        Dimension   num= new Dimension(1,1);    // Sprite 並び数
        int         TT[][];         // MAP Table
        int         AT[];           // Chip 属性
        Dimension   Tn= new Dimension(1,1);     // TT[H][W] Size
        int         Tnum;           // H*W
        Rectangle   win= new Rectangle(0,0,320,320);
        Point       center= new Point(128,128);
        Point       scrollMax= new Point();
    
        //※ Work Area
        BufferedReader br;          // Reader
        String      str;            // Input Buffer
        int         len;            // Buffer Length
        int         idx;            // Buffer Index
    
        // Constructor
        bg(String url, String file)
        {   int     i,p,q,j,wk;
    
            try
            {   // Text File をオープン
                InputStream is = new URL(url+file).openStream();
                InputStreamReader myin = new InputStreamReader(is);
                br = new BufferedReader(myin);
    
                // Check File ID
                LineRead();
                if (str.substring(0,5).compareToIgnoreCase("//Map")!=0)
                {   System.out.println("Map File Error");
                    return;
                }
    
                // Set Image file
                LineRead();
                Imgfile= str.substring(2);
    
                // Set Xn,Yn,Width,Height
                LineRead();
                idx= 2;
                Tn.width= Val();
                Tn.height= Val();
                size.width= Val();
                size.height= Val();
    
                //画像ロード
                loadImage(url, Imgfile);
                num.width= Img.getWidth(null)/size.width;
                num.height= Img.getHeight(null)/size.height;
                if (num.width<1 || num.height<1)
                {   System.out.println("Image File Error" + Imgfile);
                    return;
                }
    
                //TT[][] に MapData を格納
                TT= new int[Tn.height][Tn.width];
                Tnum= Tn.height*Tn.width;
                NextRead();
                idx= 0;
                for(i=0; i<Tnum; i++)
                {   wk= Val();
                    TT[i/Tn.width][i%Tn.width]= wk;
                    if (wk==-1) break;
                }
                br.close();
            }
            catch(FileNotFoundException e)
            {   System.out.println(e);  }
            catch(IOException e)
            {   System.out.println(e);  }
        }
    
        // 一次元配列 AT[] にデータをロード
        public void LoadAT(String url, String fname)
        {   int ATnum,i,wk;
    
            // Text File をオープン
            try
            {   InputStream is = new URL(url+fname).openStream();
                InputStreamReader myin = new InputStreamReader(is);
                br = new BufferedReader(myin);
                //AT[] に 属性 Data を格納
                ATnum= num.height*num.width;
                AT= new int[ATnum];
                NextRead();
                idx= 0;
                for(i=0; i<ATnum; i++)
                {   wk= Val();
                    AT[i]= wk;
                    if (wk==-1) break;
                }
                br.close();
            }
            catch(FileNotFoundException e)
            {   System.out.println(e);  }
            catch(IOException e)
            {   System.out.println(e);  }
        }
    
        // View
        public void View(Graphics g, int dx, int dy)
        {   if (Img==null)  return;
            g.drawImage(Img,dx,dy,this);
        }
    
        // n 番目の Mapchip を描画
        private void View(Graphics g, int n, int dx, int dy)
        {   int sx, sy;
            if (n >= Tnum)
            {   System.out.println("Sprite Number Error" + n);
                return;
            }
            sx = (n%num.width) * size.width;
            sy = (n/num.width) * size.height;
            if (Img != null)
            {   g.drawImage(Img,dx,dy,dx+size.width,dy+size.height,
                            sx,sy,sx+size.width,sy+size.height,this);
            }
        }
        // Mapchip のオフセットを指定
        private void View(Graphics g, int n, int dx, int dy, int w, int h, int xoff, int yoff)
        {   int sx, sy;
            if (n >= Tnum)
            {   System.out.println("Sprite Number Error" + n);
                return;
            }
            sx = (n%num.width) * size.width;
            sy = (n/num.width) * size.height;
            if (Img != null)
            {   g.drawImage(Img,dx,dy,dx+w,dy+h,sx+xoff,sy+yoff,sx+xoff+w,sy+yoff+h,this);
            }
        }
    
        // TT[][] の MAP を矩形(win)に描画
        public void MapView(Graphics g)
        {   int x,y,xn,yn;
            if (Img==null)  return;
            xn= (win.width)/size.width;     //幅のループ回数
            yn= (win.height)/size.height;   //高さループ回数
            for(y=0; y<yn; y++)
            {   for(x=0; x<xn; x++)
                {   View(g,TT[y][x],x*size.width+win.x,y*size.height+win.y);  }
            }
        }
    
        // TT[][] を矩形(win)に描画(DOT Scroll)
        public void MapView(Graphics g, int xoff, int yoff)
        {
            int i,yn,yi,yp,yl;
            if (Img==null)  return;
            yn= (win.height)/size.height;   //高さループ回数
            yi= yoff/size.height;           //TT[Y][] 開始IDX
            yp= win.y;                      //Y座標
            yl= size.height-(yoff%size.height);   //開始セルのドット長
            MapLine(g,1,xoff,yi,yp,yl);     //先頭行
            yp+= yl;
            yl= size.height;
            for(i=1; i<yn; i++)
            {   MapLine(g,0,xoff,yi+i,yp,yl);
                yp+= yl;
                yl= size.height;
            }
            yl= yoff%size.height;
            if (yl!=0)  MapLine(g,0,xoff,yi+yn,yp,yl);
        }
        public void MapView(Graphics g, Point off)
        {   MapView(g,off.x, off.y);
        }
    
        // Map の One Line を描画
        // flg:1=First, 0=First以外, xoff:Xoffset, TT[y][], yp:座標, yl:長
        private void MapLine(Graphics g, int flg, int xoff, int y, int yp, int yl)
        {   int i,xn,xi,xp,xl;
            xn= (win.width)/size.width; //幅のループ回数
            xi= xoff/size.width;        //TT[y+yi][x+xi]開始IDX
            xp= win.x;                  //X座標
            xl= size.width-(xoff%size.width); //開始セルのドット長
            // xl(yl): 左(上)端では セルの offset になる
            if (flg==0)     View(g,TT[y][xi],xp,yp,xl,yl,size.width-xl,0);
            else            View(g,TT[y][xi],xp,yp,xl,yl,size.width-xl,size.height-yl);
            xp+= xl;
            xl= size.width;
            for(i=1; i<xn; i++)
            {   switch(flg)
                {   case 0: //First以外
                        View(g,TT[y][xi+i],xp,yp,xl,yl,0,0);
                        break;
                    case 1: //First Line
                        View(g,TT[y][xi+i],xp,yp,xl,yl,size.width-xl,size.height-yl);
                        break;
                }
                xp+= xl;
                xl= size.width;
            }
            xl= xoff%size.width;
            //右端セルは左端セルの残り分
            if (xl!=0)
            {   if (flg==0) View(g,TT[y][xi+xn],xp,yp,xl,yl,0,0);
                else        View(g,TT[y][xi+xn],xp,yp,xl,yl,0,size.height-yl);
            }
        }
    
        // Window Rect の設定
        public void SetRect(int x, int y, int w, int h)
        {   int wk;
            win.setBounds(x,y,w,h);
            // 中央座標の計算
            center.x= ((w/2)/size.width)*size.width;
            center.y= ((h/2)/size.height)*size.height;
            // Scroll の最大値の計算
            wk= (Tn.width*size.width)-w;
            //scrollMax.x= (wk/size.width)*size.width;
            scrollMax.x= wk;
            //scrollMax.x= (wk/size.width)*size.width+size.width-1;
            wk= (Tn.height*size.height)-h;
            //scrollMax.y= (wk/size.height)*size.height;
            scrollMax.y= wk;
            //scrollMax.y= (wk/size.height)*size.height+size.height-1;
        }
        public void SetRect(Rectangle rect)
        {   SetRect(rect.x, rect.y, rect.width, rect.height);
        }
    
        // TT[Y][X] の X-Index を取得
        public int GetX(int pt, int xoff)
        {   int wk;
            wk= (pt-win.x+xoff)/size.width;
            if (wk<0 || wk>=Tn.width) wk= -1;
            return wk;
        }
    
        // TT[Tn.height][Tn.width] の Y-Index を取得
        public int GetY(int pt, int yoff)
        {   int wk;
            wk= (pt-win.y+yoff)/size.height;
            if (wk<0 || wk>=Tn.height) wk= -1;
            return wk;
        }
    
        // Mapchip の属性を取得
        public int GetAtt(int xp, int yp, int xoff, int yoff)
        {   int wx,wy;
            wx= GetX(xp,xoff);
            wy= GetY(yp,yoff);
            if (wx<0 || wy<0)
            {   System.out.println("GetAtt 座標エラー");
                return -1;
            }
            return AT[TT[wy][wx]];
        }
    
        // 方向 dir の Mapchip の属性を取得
        public int GetAtt(int dir, int xp, int yp, int xoff, int yoff)
        {   int wx,wy;
            wx= GetX(xp,xoff);
            wy= GetY(yp,yoff);
            if (wx<0 || wy<0)   System.out.println("GetAtt 座標エラー");
            switch(dir)
            {   case 0: wy--;  break;
                case 1: wx++;  break;
                case 2: wy++;  break;
                case 3: wx--;  break;
            }
            if (wx<0 || wx>=Tn.width)  return -1;
            if (wy<0 || wy>=Tn.height) return -1;
            return AT[TT[wy][wx]];
        }
        public int GetAtt(Point pos, Point off)
        {   return GetAtt(pos.x, pos.y, off.x, off.y);
        }
        public int GetAtt(int dir, Point pos, Point off)
        {   return GetAtt(dir, pos.x, pos.y, off.x, off.y);
        }
    
        // Read Line(次の行)
        private boolean LineRead()
        {
            try
            {   str = br.readLine();  }
            catch(IOException e)
            {   System.out.println(e);  }
            if (str == null)
            {   System.out.println("End of file");
                return false;
            }
            len= str.length()-1;
            return true;
        }
    
        // Read Next Line(/をスキップ)
        private boolean NextRead()
        {
            while(LineRead())
            {   if (str.charAt(0)!='/')
                {   str = str + ",,";
                    len= str.length()-1;
                    return true;
                }
            }
            return false;
        }
    
        // Next Val(idx から次の値を取得)
        private int Val()
        {   int     p;
            while(true)
            {   for(p=idx; p<len && (str.charAt(p)<'0' || str.charAt(p)>'9'); p++);
                for(idx=p; idx<len && str.charAt(idx)>='0' && str.charAt(idx)<='9'; idx++);
                if (idx<len)   return  Integer.parseInt(str.substring(p,idx));
                if (NextRead()==false)  return -1;
                idx= 0;
            }
        }
    
        // Load Image
        private Image loadImage(String path, String file)
        {   Img = null;
            try
            {   URL u = new URL(path+file);
                Img = ImageIO.read(u);
            }
            catch (IOException e)
            {   System.out.println("Image Load Error");
            }
            return Img;
        }
    }
    
  2. Java Applet を起動する HTML ファイルです。
    <html>
      <body>
        <h3>MapEdit の出力ファイルで BG を描画</h3>
        <applet code="rpgbg.class" width="300" height="200">
        </applet>
      </body>
    </html>
    
  3. MapEditor で作成した TEXT 形式のファイル(test.txt)です。
    chip.gif が画像ファイルの名前です。
    15, 10 が背景を構成する二次元配列の大きさです。Mapchip のサイズを掛けると背景画面サイズになります。
    16, 16 が Mapchip 一枚の幅と高さです。
    次の行から MapChip の並び情報(Index)がタイプされています。
    //Map  Ver 3.2  前田 稔
    //chip.gif
    //  15,   10,   16,   16,  Map の幅と高さ, Mapchip の幅と高さ
    56, 57, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 76, 77,
    76, 77, 49, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 50, 51,
    48, 68, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 71,
    48, 35, 2, 2, 2, 2, 2, 2, 2, 2, 54, 55, 2, 2, 12,
    48, 15, 2, 2, 54, 55, 2, 2, 2, 2, 74, 75, 2, 2, 32,
    48, 35, 2, 2, 74, 75, 2, 2, 2, 2, 2, 2, 2, 2, 12,
    48, 35, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 
    48, 15, 2, 2, 2, 2, 2, 2, 2, 52, 53, 2, 2, 2, 32, 
    57, 44, 45, 2, 2, 2, 2, 2, 2, 72, 73, 2, 46, 46, 47, 
    77, 64, 65, 9, 8, 9, 8, 9, 8, 9, 8, 9, 66, 66, 67, 
    
  4. プロジェクトのフォルダーに TEXT 形式のファイル(test.txt)と MapChip の画像ファイル(chip.gif)を格納して下さい。
    chip.gif は 32*32 の Sprite が2段10列に並んだ画像ですが、今回は 16*16 のサイズに設定して4段20列で処理します。
    インターネットブラウザを起動して HTML ファイルから実行して下さい。
    Sprite(Mapchip)を組み合わせた背景画像が描画されたら完成です。

Main プログラムの説明

  1. このプログラムは Mapchip の境界に沿って動かす の続きです。
    マップチップを組み合わせた背景画像は、一般的には MapEditor などと呼ばれる専用のツールで作成します。
    私が開発した MapEditor で作成した TEXT 形式のファイル "test.txt" を読んで背景を描画してみましょう。
    MapEditor は「超初心者のプログラム入門/Game Program & 各種 Tool/Map Editor」から提供しています。
  2. init() はアプレットの初期化を行うメソッドです。
    obj = new bg() で bg Object Class をインスタンス化します。
    test.txt には、画像ファイルの名前やセルのサイズやインデックス情報など背景を描画するのに必要な情報が記録されています。
    obj.SetRect(0,0,240,160); で BG を描画する矩形領域を設定します。
        public class rpgbg extends Applet
        {   bg      obj;
    
            // Initialize
            public void init()
            {   obj = new bg(getCodeBase().toString(),"test.txt");
                obj.SetRect(0,0,240,160);
            }
        
  3. 後は paint() メソッドから map.MapView(g) で背景を描画するだけです。
            // Paint Method
            public void paint(Graphics g)
            {   obj.MapView(g);
            }
        

bg Object Class の説明

  1. MapEditor で作成した TEXT 形式のファイルには、画像ファイルの名前やセルのサイズやインデックス情報など背景を描画するのに必要な情報が記録されています。
    bg Class は、このファイルを入力して BG(Back Ground)を描画する専用のクラスです。
    BG Object Class の詳細は Java2 の解説ページを参照して下さい。
  2. ここではプログラムに関係する部分を、かいつまんで説明します。
    Imgfile は MapChip の画像ファイルの名前で Img が画像の領域です。
    size は MapChip 一枚分の幅と高さです。
    num は縦方向と横方向に並んでいる MapChip(Sprite)の枚数です。
    TT[][] は MapChip の並び情報(Index)を格納する二次元配列で、Tn がその大きさです。
    AT[] は MapChip の属性データを入力する配列です。
    Tnum には二次元配列の要素の総数(TT のサイズ)を格納します。
    win は Game Window の矩形領域です。
    center は Game Window の中央座標ですが、MapChip に合わせて端数を切り捨てるので、やや左上になります。
    scrollMax はスクロールの最大値で、この値を超えると配列の範囲外を参照する危険性があります。
    str は BgMap.txt の一行分の入力バッファで、len がそのサイズです。
    idx は現在処理している str の位置です。
        class bg extends Applet
        {   String      Imgfile;        // image file
            Image       Img;            // Image Object
            Dimension   size= new Dimension(32,32); // Sprite Size
            Dimension   num= new Dimension(1,1);    // Sprite 並び数
            int         TT[][];         // MAP Table
            int         AT[];           // Chip 属性
            Dimension   Tn= new Dimension(1,1);     // TT[H][W] Size
            int         Tnum;           // H*W
            Rectangle   win= new Rectangle(0,0,320,320);
            Point       center= new Point(128,128);
            Point       scrollMax= new Point();
    
            //※ Work Area
            BufferedReader br;          // Reader
            String      str;            // Input Buffer
            int         len;            // Buffer Length
            int         idx;            // Buffer Index
        
  3. Constructor でパラメータで渡された TEXT ファイルを解析して BG の情報を設定します。
    画像ファイル名を取得して Image をロードします。
    MapChip の並び情報(Index)を TT[][] に格納します。
  4. View() は画像を描画するメソッドです。
  5. MapView() は TT[][] の並び情報に従って BG を描画するメソッドです。
  6. SetRect() は Game Window の矩形領域を設定するメソッドです。
  7. GetAtt() は Mapchip の属性を取得するメソッドです。

Java Game Program