読者です 読者をやめる 読者になる 読者になる

人工知能に関する断創録

人工知能、認知科学、心理学、ロボティクス、生物学などに興味を持っています。このブログでは人工知能のさまざまな分野について調査したことをまとめています。最近は、機械学習、Deep Learning、Kerasに関する記事が多いです。



スクロール処理1

Javagame

今までのプログラムはなんかドラクエっぽくないですよね。私も作っててどこか違うと違和感を持ちました。

そんなわけでドラクエを取り出してプレイしてみたところあることに気がつきました。ドラクエでは移動しても勇者の位置は常に画面の中央なんですね。勇者は中央に鎮座してマップの方がスクロールしているわけです。さすが勇者ですね(笑)

この章ではドラクエと同じように勇者が移動するとマップがスクロールするように作り直します。大枠は同じなんですが移動関係の部分をかなり書き直しました。今までの中で一番複雑で説明するのはちょっと大変です。ドラクエタイプのスクロール処理は結構大変なのでスクロール処理2(2005/10/22)との2段階に分けて説明します。

rpg08.jar

スクロール処理

RPGのマップは通常画面に表示される部分よりずっと大きいためマップ全体は一度に表示しきれず見える部分のみ表示します。そして、勇者を移動させると見える部分が徐々に変わっていくというのがスクロールの仕組みです。今回は簡単のため全体マップが5×5マス、画面に表示される部分3×3マスと想定して説明します。

まず、勇者が上に移動した場合について考えてみます。勇者が座標(2,2)から上に1歩移動した前と後の状態を考えてみると下の図のようになります。周囲の3×3マスだけしか画面に表示されないことに注意してください。この図を見ると勇者の位置は常に見える範囲の中央であり、表示される部分(アニメーションでは赤で囲んだ部分)が上にずれたことがわかります。これがスクロールの本質です。

まとめますとスクロールするには画面上の見える部分を少しずつずらしていけばよいわけです。またRPGでは勇者の位置を常に見える部分の中央に表示します。

f:id:aidiary:20100327200913g:plain

上下左右のどの方向の移動でもずらす方向を変えるだけで上へのスクロールとまったく同じです。

スクロールの実装

実は横スクロールアクションのマップスクロール(2005/6/24)で解説した方法と同じです。下のようなイメージです。勇者の位置に応じてオフセットを求め、勇者が画面の中央に来るようにマップの一部分を表示します。表示する部分の左上の座標が(-offsetX, -offsetY)になります。詳しくは横スクロールアクションのマップスクロール(2005/6/24)の解説を見てください。

f:id:aidiary:20100327200912g:plain

実行してみると勇者の移動によって画面がちゃんとスクロールしていることがわかります。ただドラクエのスクロールとはまだ違いますよね。ドラクエの移動はもっと滑らかです。これは、ドラクエでは移動時にタイル単位の移動ではなくて、ピクセル単位の移動を行っているからです。スクロール処理2(2005/10/22)で実装します。

追記

オフセットの求め方は下のほうがわかりやすいかもしれないです。 offsetの正負が逆になってます。 CharaとMapのdraw()内のoffsetも-を+に+を-に変更してください。

        // オフセットを計算
        int offsetX = hero.getX() * CS - MainPanel.WIDTH / 2;
        // マップの端ではスクロールしないようにする
        if (offsetX < 0) {
            offsetX = 0;
        } else if (offsetX > Map.WIDTH - MainPanel.WIDTH) {
            offsetX = Map.WIDTH - MainPanel.WIDTH;
        }

        int offsetY = hero.getY() * CS - MainPanel.HEIGHT / 2;
        // マップの端ではスクロールしないようにする
        if (offsetY < 0) {
            offsetY = 0;
        } else if (offsetY > Map.HEIGHT - MainPanel.HEIGHT) {
            offsetY = Map.HEIGHT - MainPanel.HEIGHT;
        }

        map.draw(g, offsetX, offsetY);
        hero.draw(g, offsetX, offsetY);