2007年8月24日金曜日

リアルタイムシミュレーションっぽい動き

リアルタイムシミュレーションのように各キャラクタに対して移動指示を出し、移動させるサンプル。
配列を利用すれば、移動目標を複数保持してジグザグに移動させることも可能でしょう。JavaのVectorのような可変長配列が使えれば実装は楽そうですが……。

【操作方法】
キャラクタをクリックしてから他の地点をクリックすると、その地点めがけてキャラクタが移動を開始します。
他のキャラクタをクリックするまでキャラクタの選択状態は変更されません。
#define fillbox%1%2%3 ) boxf %1 - %3 / 2%2 - %3 / 2%1 + %3 / 2%2 + %3 / 2
#define drawbox%1%2%3 ) line %1 - %3 / 2%2 + %3 / 2%1 - %3 / 2%2 - %3 / 2 %line %1 + %3 / 2%2 + %3 / 2 %line %1 + %3 / 2%2 - %3 / 2 %line %1 - %3 / 2%2 - %3 / 2
#const CHARACTER_SIZE 32        // キャラクタの大きさ
#const CHARACTER_NUM   5        // キャラクタの個数
#const CHARACTER_SPEED 5        // キャラクタの速さ
    ddim character_x, CHARACTER_NUM     // キャラクタの位置
    ddim character_y, CHARACTER_NUM     // キャラクタの位置
    ddim target_x,    CHARACTER_NUM     // 移動先地点
    ddim target_y,    CHARACTER_NUM     // 移動先地点
    repeat CHARACTER_NUM
        character_x( cnt ) = doublerndginfo_winx - CHARACTER_SIZE ) )
        character_y( cnt ) = doublerndginfo_winy - CHARACTER_SIZE ) )
        target_x( cnt ) = character_x( cnt )
        target_y( cnt ) = character_y( cnt )
    loop
    command_num = -1            // 指令を出す対象のキャラクタナンバー
    onclick gosub *label_onclick

*main
    gosub *move
    gosub *draw
    wait 5
    goto *main

*move
    repeat CHARACTER_NUM
        theta = atan( character_y( cnt ) - target_y( cnt ), target_x( cnt ) - character_x( cnt ) )

        if absf( target_x( cnt ) - character_x( cnt ) ) > cos( theta ) * CHARACTER_SPEED {
            character_x( cnt ) += cos( theta ) * CHARACTER_SPEED
        } else {
            character_x( cnt ) = target_x( cnt )
        }

        if absf( target_y( cnt ) - character_y( cnt ) ) > sin( theta ) * CHARACTER_SPEED {
            character_y( cnt ) -= sin( theta ) * CHARACTER_SPEED
        } else {
            character_y( cnt ) = target_y( cnt )
        }
    loop
    return

*draw
    redraw 0
    color 255255255 : boxf
    gosub *draw_arrow
    gosub *draw_character
    gosub *draw_frame
    redraw 1
    return

*draw_character
    repeat CHARACTER_NUM
        hsvcolor cnt * 191 / CHARACTER_NUM255255
        fillbox character_x( cnt ), character_y( cnt ), CHARACTER_SIZE
    loop
    return

*draw_arrow
    repeat CHARACTER_NUM
        if ( target_x( cnt ) != character_x( cnt ) ) | ( target_y( cnt ) != character_y( cnt ) ) {
            hsvcolor cnt * 191 / CHARACTER_NUM255255
            line target_x( cnt ), target_y( cnt ), character_x( cnt ), character_y( cnt )
        }
    loop
    return

*draw_frame
    if command_num >= 0 {
        color
        drawbox character_x( command_num ), character_y( command_num ), CHARACTER_SIZE
    }
    return

*label_onclick
    // クリックしたキャラクタを探す
    tmp = -1
    repeat CHARACTER_NUM
        dx = absmousex - character_x( cnt ) )
        dy = absmousey - character_y( cnt ) )
        if ( 0 <= dx ) & ( dx <= CHARACTER_SIZE / 2 ) & ( 0 <= dy ) & ( dy <= CHARACTER_SIZE / 2 ) {
            tmp = cnt
            break
        }
    loop
    if tmp >= 0 : command_num = tmp : return

    // キャラクタ以外をクリックした場合
    if command_num >= 0 {
        target_x( command_num ) = doublemousex )
        target_y( command_num ) = doublemousey )
    }
    return

0 件のコメント: