2007年10月2日火曜日

俯瞰型RPGマップの描画 2

前回のスクリプトにカメラの移動とキャラクタの移動・ジャンプを追加しました。マップチップの明るさは距離に応じた変化に限定しています。
ここまでくるとRPGというよりはアクションに近いものがありますね。

カメラの位置に合わせてカーソルキーで移動する方向を変化させる処理や、ビルボードのようにキャラクタを常に手前を向ける処理など、三角関数を多用しているので、今回のスクリプトはさすがに読みづらいと思います。d3setlocal命令によって多少は読みやすくなっていますが……。興味のある方はぜひ式を解いてみてください。
// カーソルキーでキャラクタの移動
// Ctrl同時押しでカメラの移動(回転)
// Spaceでジャンプ
#include "d3m.hsp"
#include "hspmath.as"
#const CELL_SIZE 100    // d3m上のマップチップサイズ
#const IMG_SIZE   64    // bmpのマップチップサイズ
#const CAM_DIST  500
#const CHAR_SPEED 15
#const MAP_WIDTH  18
#const MAP_HEIGHT 15
    // マップチップのロード
    buffer 1 : picload dir_exe + "/sample/game/testchr.bmp"

    // 影用の画像を用意する
    color : boxf IMG_SIZE * 30IMG_SIZE * 4IMG_SIZE
    color 255,255,255 : circle IMG_SIZE * 30IMG_SIZE * 4IMG_SIZE1

    gsel 0

    // 変数の初期化
    cam_theta = M_PI * 2 / 5    // カメラの角度
    cam_phi = -M_PI / 2
    char_x  = 0.0               // キャラクタの位置
    char_y  = 0.0
    char_z  = 0.0
    char_vz = 0.0               // キャラクタの速度

    // マップ作成
    dim map, MAP_WIDTHMAP_HEIGHT
    repeat length2( map )
        y = cnt
        repeat length( map )
            map( cnt, y ) = rnd3 )
        loop
    loop
    gosub *draw

*main
    stick keys, 15 + 64
    gosub *move
    if ( is_jumping ) | ( ( keys & 15 ) > 0 ) : gosub *draw
    wait 3
    goto *main

*move
    if ( keys >> 4 & 1 ) & ( is_jumping == 0 ) {
        char_vz = 20.0  // ジャンプ開始
        is_jumping = 1  // ジャンプ中フラグをON
    }
    char_vz -= 2.0      // 重力による加速
    char_z += char_vz   // Z方向の移動
    if char_z < 0.0 {
        // 着地時の演算
        char_z = 0.0
        char_vz = 0.0
        is_jumping = 0
    }
    if keys & 64 {
        // ctrl同時押し…カメラの移動
        cam_theta = limitf( cam_theta + 0.05 * ((keys >> 3 & 1) - (keys >> 1 & 1)), 0.01, M_PI / 2 - 0.01 )
        cam_phi += 0.05 * ((keys >> 2 & 1) - (keys & 1))
    } else {
        // ctrlを押さない…キャラクタの移動
        keys_x = (keys >> 2 & 1) - (keys & 1)
        keys_y = (keys >> 3 & 1) - (keys >> 1 & 1)
        char_x = limitf( char_x - ( sin( cam_phi ) * keys_x - cos( cam_phi ) * keys_y ) * CHAR_SPEED, -MAP_WIDTH/2*CELL_SIZE, (MAP_WIDTH-1)/2*CELL_SIZE)
        char_y = limitf( char_y + ( cos( cam_phi ) * keys_x + sin( cam_phi ) * keys_y ) * CHAR_SPEED, -MAP_HEIGHT/2*CELL_SIZE, (MAP_HEIGHT-1)/2*CELL_SIZE)
    }
    return

*draw
    // カメラの設定
    d3setcam cos(cam_phi)*sin(cam_theta)*CAM_DIST + char_x, sin(cam_phi)*sin(cam_theta)*CAM_DIST + char_y, cos(cam_theta)*CAM_DIST, char_x, char_y, 0

    redraw 0
    color : boxf
    gz = 0000 // d3texture用の配列
    repeat MAP_WIDTH, -MAP_WIDTH/2 : x = cnt
        repeat MAP_HEIGHT, -MAP_HEIGHT/2 : y = cnt
            dx = ( x * CELL_SIZE - char_x ) / CELL_SIZE
            dy = ( y * CELL_SIZE - char_y ) / CELL_SIZE
            gmode GMODE_ALPHA, , , 255.0 / pow( dx * dx + dy * dy + 10.25 )
            // 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 + MAP_WIDTH/2, y + MAP_HEIGHT/2 ), 0IMG_SIZEIMG_SIZE
        loop
    loop

    d3setlocal char_x, char_y, 0sin(cam_phi),cos(cam_phi),0,-cos(cam_phi),sin(cam_phi),0,0,0,1
    // 影を描画
    gmode GMODE_SUB,,,32
    gx( 0 ) = -CELL_SIZE / 2CELL_SIZE / 2
    gx( 2 ) = gx( 1 ), gx( 0 )
    gy( 0 ) =  CELL_SIZE / 2 : gy( 1 ) = gy( 0 )
    gy( 2 ) = -CELL_SIZE / 2 : gy( 3 ) = gy( 2 )
    gz( 0 ) = 0000
    d3texture gx, gy, gz, 1IMG_SIZE * 30IMG_SIZEIMG_SIZE
    // キャラクターを描画
    gmode GMODE_RGB0
    gy( 0 ) = 0000
    gz( 0 ) = CELL_SIZE + char_z : gz( 1 ) = gz( 0 )
    gz( 2 ) = int( char_z ) : gz( 3 ) = gz( 2 )
    d3texture gx, gy, gz, 1IMG_SIZE * 1IMG_SIZEIMG_SIZEIMG_SIZE
    redraw 1
    return

0 件のコメント: