2007年10月2日火曜日

俯瞰型RPGマップの描画

RPG関連のスクリプトを書こうと思い立ち、作成。普通のマップじゃつまらないので3Dにしてみました。
drawmodeが1の時の明るさの計算は、CodeZine: 3Dモデルを表示するJavaアプレットの作成を参考としています。
障害物のあるマップで視野を求めるで使った視野計算を合わせれば、よりそれっぽくなりそうです。

少々単純すぎるうえに用途が限られるので、開発wikiには投げずにここへ置いときます。
#include "d3m.hsp"
#const CELL_SIZE 100    // d3m上のマップチップサイズ
#const IMG_SIZE   64    // bmpのマップチップサイズ
#const CAM_X       0    // カメラ位置(45°手前から俯瞰)
#const CAM_Y    -400
#const CAM_Z     400
#define ctype pow(%1,%2expf(logf(%1)*(%2))    // x^y

    // マップチップのロード
    buffer 1 : picload dir_exe + "/sample/game/testchr.bmp"

    // カメラの設定
    gsel 0
    d3setcam CAM_XCAM_YCAM_Z000

    // 変数の初期化
    gz = 0000     // d3texture用の配列
    ch = CAM_Z          // CH = カメラの高さ

    // マップ作成
    dim map, 2020
    repeat length2( map )
        y = cnt
        repeat length( map )
            map( cnt, y ) = rnd3 )
        loop
    loop
    title "クリックで描画モード変更"
    onclick gosub *change_drawmode
    gosub *draw
    stop

*draw
    redraw 0
    color : boxf
    for x, -1010
        for y, -1010
            // マップチップの明るさを計算
            switch drawmode
                case 0  // 均等描画(どのマップチップも同じ明るさで描画)
                    c = 255
                    swbreak
                case 1  // 光の反射を考慮(45°手前から俯瞰するとして最適化済み)
                    // カメラの位置を点C、カメラの位置からXY平面におろした垂線の足を点H、
                    // マップチップの中心を点B、マップチップの中心からY軸におろした垂線の足を点A、
                    // XY平面上の原点を点Oとする。
                    // このとき、マップの中心が最も明るいという条件(すなわち光が45°奥から入射するという条件)を課すと、
                    // マップの明るさは cos( ∠COH - ∠CAH ) * cos( ∠BCA ) で決定される。
                    ah = y * CELL_SIZE - CAM_Y                  // AH
                    ab = x * CELL_SIZE                          // AB
                    cb = sqrt( ab * ab + ah * ah + ch * ch )    // CB
                    c = intdouble( ah + ch ) / ( sqrt2.0 ) * cb ) * 255 )   // = cos( ∠COH - ∠CAH ) * cos( ∠BCA ) * 255
                    swbreak
                case 2  // 距離に応じて変化(遠ければ遠いほど暗くなる)
                    c = int255.0 / pow( x * x + y * y + 10.2 ) )            // 距離に反比例させると暗すぎたので0.2乗で調整
                    swbreak
            swend
            gmode GMODE_ALPHA, , , c

            // d3texture用の配列を準備
            gx( 0 ) = x * CELL_SIZE - CELL_SIZE / 2, x * CELL_SIZE + CELL_SIZE / 2
            gx( 2 ) = gx( 1 ), gx( 0 )
            gy( 0 ) = y * CELL_SIZE + CELL_SIZE / 2 : gy( 1 ) = gy( 0 )
            gy( 2 ) = y * CELL_SIZE - CELL_SIZE / 2 : gy( 3 ) = gy( 2 )
            d3texture gx, gy, gz, 1IMG_SIZE * map( x + 10, y + 10 ), 0IMG_SIZEIMG_SIZE
        next
    next
    redraw 1
    return

*change_drawmode
    drawmode = ( drawmode + 1 ) \ 3
    switch drawmode
        case 0 : title "均等描画"         : swbreak
        case 1 : title "光の反射を考慮"   : swbreak
        case 2 : title "距離に応じて変化" : swbreak
    swend
    gosub *draw
    return

0 件のコメント: