hinekure.net が http://hspdev-wiki.net/ から自動クローリングした結果を表示しています。画像やリソースなどのリンクが切れています。予めご了承ください。
追跡弾 - HSP開発wiki
トップ    編集凍結 差分バックアップ添付複製名前変更リロード   新規一覧単語検索最終更新   最終更新のRSS

追跡弾

シューティングなどでよく見られる追跡弾(ホーミングミサイルなど)のサンプルです。ターゲットに向かって弾が飛んでいきます。

パターン1(旋回角度限定版)

簡単に言えばターゲットのいる方向へ進むようにすれば良いのですが、それでは追跡の精度が高すぎて実際のゲームには向かないことがあります。 そのためこのサンプルでは最大旋回角度(定数TURN_MAX)を指定し、その角度以上の旋回はできないようにしてあります。eller作。

vector.png

スクリプト

定数

RADIUS
ミサイル及び標的の半径を表す整数。
PI
円周率を表す実数。
MISSILE_LIFE
ミサイルの寿命を表す整数。
MISSILE_SPEED
ミサイルの速度を表す整数。
MISSILE_MAX
ミサイルが存在できる最大弾数。
TURN_MAX
ミサイルの最大旋回角度を表わす実数。単位はラジアン。

ミサイルごとに保持する変数

MissileX, MissileY(整数型配列変数)
弾の座標。画面左上を(0, 0)とする。posと同等。
MissileLife?(整数型配列変数)
ミサイルの寿命。ミサイル生成時に定数MISSILE_LIFEを代入し、毎フレームごとにデクリメントする。これがゼロの場合、ミサイルは存在しないと考える(キャラクター管理の生存フラグを兼ねる)。
MissileSpeed?(整数型配列変数)
ミサイルの速度。このスクリプトでは一律で定数MISSILE_SPEEDを代入している。
MissileDirection?(実数型配列変数)
ミサイルの向いている角度。右方向をゼロとし、反時計まわりを正とする。

処理の流れ

HSP講座/基本的なスクリプトのパターンのアニメーション版に準拠しています。

  1. 初期設定
    乱数の初期化、配列変数の作成、onclickによるクリック割り込み実行の指定を行っています。
  2. メインループ
    メインループでは以下の処理を定期的に行っています。
    1. 画面の初期化
      画面を白で塗りつぶしています。
    2. ミサイルの移動
      ミサイルごとに移動すべき方向を計算し、その方向に移動させています。
    3. ターゲット(標的)の表示
      マウスカーソルを中心に青い円を描いています。
    4. ミサイルの表示
      ミサイルの位置にオレンジ色の円を描いています。
    5. ウェイト
      一定時間処理を停止しています。この間に画面がクリックされると、ミサイルを生成します。
filehoming.hsp
Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/*
	ターゲット追跡弾 サンプルスクリプト
*/
 
#module
/*  ターゲットとミサイルを描く  */
#deffunc plot int radius, int x, int y
    // radius : 円の半径
    // x : 中点のX座標
    // y : 中点のY座標
    circle x-radius, y-radius, x+radius, y+radius
    return
#global
 
/*  定数の設定  */
#const RADIUS 8                 // 点の半径
#const PI 3.1415926535897932384 // 円周率π
#const MISSILE_MAX 16           // 最大ミサイル数
#const TURN_MAX 0.1             // ミサイルの最大旋回角度(0.0〜π)
#const MISSILE_LIFE 300         // ミサイルの寿命
#const MISSILE_SPEED 4          // ミサイルの速度
 
    randomize
    title "homing missile - クリックでミサイル生成"
 
/*  配列変数の準備  */
    dim MissileX, MISSILE_MAX           // ミサイルのX座標
    dim MissileY, MISSILE_MAX           // ミサイルのY座標
    dim MissileLife, MISSILE_MAX        // ミサイルの寿命
    dim MissileSpeed, MISSILE_MAX       // ミサイルのスピード
    ddim MissileDirection, MISSILE_MAX  // ミサイルの進んでいる方向(ラジアン)
 
    onclick gosub *make_missile         // クリックするごとにミサイル生成
 
/*  メインループ  */
*main
    redraw 0
    gosub *clear                        // 画面を初期化する
    gosub *move_missile                 // 全てのミサイルを動かす
    gosub *plot_mouse                   // ターゲットを描画
    gosub *plot_missile                 // 全てのミサイルを描画
    redraw 1
    await 8
    goto *main
 
/*  画面を初期化  */
*clear
    color 255, 255, 255
    boxf
    return
 
/*  ミサイルを1発生成する  */
*make_missile
    repeat MISSILE_MAX
        if MissileLife(cnt)>0 : continue
        MissileX(cnt) = rnd(ginfo_winx)     // X座標をランダムに決定
        MissileY(cnt) = rnd(ginfo_winy)     // Y座標をランダムに決定
        MissileLife(cnt) = MISSILE_LIFE     // ミサイルの寿命を決定
        MissileSpeed(cnt) = MISSILE_SPEED   // ミサイルのスピードを決定
 
        // ミサイルの進む方向(ミサイルから見たターゲットの方向)を決定
        MissileDirection(cnt) = atan(mousey-MissileY(cnt), mousex-MissileX(cnt))
        break
    loop
    return
 
/*  全てのミサイルを動かす  */
*move_missile
    repeat MISSILE_MAX
        if MissileLife(cnt)==0 : continue       // 寿命が残っているミサイルのみを対象
 
        // ミサイルから見たターゲットの方向 と ミサイルの進んでいる方向 の角度差を求める
        turn = atan(mousey-MissileY(cnt), mousex-MissileX(cnt))-MissileDirection(cnt)
 
        // 角度差を-π〜πの間に収める
        if turn> PI : turn -= PI*2
        if turn<-PI : turn += PI*2
 
        // 角度差を旋廻可能角度(-TURN_MAX〜TURN_MAX)内に収め、
        // ミサイルの進んでいる方向 と足し合わせて ミサイルの進むべき角度 を求める 
        direction = limitf(turn, -TURN_MAX, TURN_MAX)+MissileDirection(cnt)
 
        // 角度を-π〜πの間に収める
        if direction> PI : direction -= PI*2
        if direction<-PI : direction += PI*2
 
        // ミサイルを移動させる
        MissileX(cnt) += cos(direction)*MissileSpeed(cnt)
        MissileY(cnt) += sin(direction)*MissileSpeed(cnt)
 
        MissileDirection(cnt) = direction       // ミサイルの進んだ方向を記録
        MissileLife(cnt)--                      // ミサイルの寿命を縮める
    loop
    return
 
/*  ターゲットを描画  */
*plot_mouse
    color 0, 0, 255
    plot RADIUS, mousex, mousey     // 半径RADIUSの円(塗りつぶし)を描画
    return
 
/*  全てのミサイルを描画  */
*plot_missile
    color 255,128,0
    repeat MISSILE_MAX
        if MissileLife(cnt)==0 : continue           // 寿命が残っているミサイルのみを対象
        plot RADIUS, MissileX(cnt), MissileY(cnt)   // 半径RADIUSの円(塗りつぶし)を描画
    loop
    return

パターン2(ロボットミサイル)

このスクリプトは、厳密には「標的を追いかける弾」を実現するものではありません。「標的の方向を向き続けようとする弾」を実現するものです。標的の方向を向き続ける結果、(弾は静止しないので)標的へ近づきます。
旋回角度が固定されているのもパターン1との大きな違いです。Shinya?作、eller編集。

スクリプト

まずはじめに、弾から見た標的の方向を調べます。弾はこの向きになるまで移動と回転を続け、その間は標的の向きを調べることがありません(よってプレイヤーは、弾に大きな方向転換を強いることで回避しやすくなります)。
先述の通り、旋回角度は定数値RoboAngSpeed?に固定されています。

filerobot_missile.hsp
Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-
|
|
|
!
 
-
|
|
!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-
|
|
|
|
!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/*
┌────────────┐
│ ロボットミサイルの表示 │
└────────────┘*/
 
; #####################################################################
 
; ====================
;  TYPE MACROS
; ====================
#const global PI   3.1415926535
#const global _2PI (PI * 2.0)
 
; ====================
;  DATA MACROS
; ====================
#const global RoboFig  8                // ミサイルの数
#const global RoboSize 32               // ミサイルの大きさ
#const global halfSize (RoboSize / 2)
#const global double RoboSpeed 1.8      // ミサイルの速度
#const global double RoboAngSpeed 0.08  // ミサイルの角速度
 
; #####################################################################
 
#module
#defcfunc chRobot array Rx, array Ry, int num
// ミサイルの衝突をチェック
;【parameter】
;  Rx  : ミサイルの座標X
;  Ry  : ミサイルの座標Y
;  num : length
;  Size: 当たり判断の大きさ
;【ret】
;  上位16bit, 下位16bitに分けて衝突しているミサイルのインデックスを返す。
;  衝突している場合はインデックスに+1をして返す。
;  衝突していなければ 0 を返す。
    lpoke ret   // ≒ ret = 0
    repeat num
        a = cnt + 1
        x = Rx(cnt) : y = Ry(cnt)
        repeat num - a, a
                b = cnt
                if int(x - Rx(b))/RoboSize == 0 & int(y - Ry(b))/RoboSize == 0 {
                    // 衝突時
                    ret++
                    break
                }
        loop
        if ret {
            ret = (a << 16) + b + 1
            break
        }
    loop
    return ret
#global
 
; #####################################################################
 
    randomize
    gosub *InitRobot
 
*Main
    gosub *MoveObjects
    redraw 0
    color 255, 255, 255 : boxf
    gosub *DrawObjects
    redraw 1
    await 10
    goto *Main
 
*MoveObjects
    // ミサイルを描画
    repeat RoboFig
        ang_mouse = atan(RoboY(cnt)- mousey, mousex - RoboX(cnt))          // ミサイルから見たマウスの角度
        if cAng(cnt) == 0  {
            ang_difference = ang_mouse - Ang(cnt)                          // 今の角度と目標(マウス)の角度の差分
            ang_difference += _2PI * ((ang_difference < -PI) - (PI < ang_difference))  // -PI〜+PIの間に収める
            sig(cnt) = (ang_difference > 0) - (ang_difference < 0)         // bの符号(+1 or -1)
            frames_move(cnt) = int( absf(ang_difference) / RoboAngSpeed )  // 回転量。このフレーム数だけ回転したら移動する方向を再度決定する。
        }
 
        // 移動
        RoboX(cnt) += RoboSpeed * cos(Ang(cnt))
        RoboY(cnt) -= RoboSpeed * sin(Ang(cnt))
        Ang(cnt)   += RoboAngSpeed * sig(cnt)
        cAng(cnt)++
 
        if cAng(cnt) == frames_move(cnt) : cAng(cnt) = 0
    loop
    return
 
; ======================================================================
*DrawObjects
; ======================================================================
    // ミサイルを描画
    repeat RoboFig
        color
        circle RoboX(cnt) - halfSize, RoboY(cnt) - halfSize, RoboX(cnt) + halfSize, RoboY(cnt) + halfSize // ミサイルを表す円
        color 255, 255, 255
        line RoboX(cnt), RoboY(cnt), RoboX(cnt) + cos(Ang(cnt)) * halfSize, RoboY(cnt) - sin(Ang(cnt)) * halfSize // 向きを表す線
    loop
    return
 
; ======================================================================
*InitRobot
; ======================================================================
    ; ====================
    ; ミサイルの座標
    ; ====================
    ddim RoboX, RoboFig
    ddim RoboY, RoboFig
 
    ; ====================
    ; ミサイルの角度関連
    ; ====================
    ddim Ang , RoboFig
    dim  frames_move, RoboFig
    dim  sig , RoboFig
    dim  cAng, RoboFig
 
    // ミサイルの座標をランダムに初期化
    // ミサイルが互いに衝突しないように配置する(本題とは関係のないおまけ)
    repeat RoboFig
        RoboX(cnt) = double(rnd(ginfo_winx))
        RoboY(cnt) = double(rnd(ginfo_winy))
        if chRobot(RoboX, RoboY, cnt+1) : continue cnt
    loop
    return
 
; #####################################################################

コメントログ

単独ページ時代のコメントログ。

+  コメントログ

パターン3(引力版)

パターン1やパターン2とは違い、速度が変化する追跡弾です。旋回角度に制限はありませんが、急激な方向変化には対応が遅くなります。
具体的には標的に向かって加速し続けるというもので、物理学の引力磁力に近いものです。イメージとしてはミサイルよりもエネルギー弾でしょうか?eller作。

スクリプト

filehoming2.hsp
Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/*
	ターゲット追跡弾 サンプルスクリプト 引力版
*/
 
#module
/*  ターゲットとミサイルを描く  */
#deffunc plot int radius, int x, int y
    // radius : 円の半径
    // x : 中点のX座標
    // y : 中点のY座標
    circle x - radius, y - radius, x + radius, y + radius
    return
#global
 
/*  定数の設定  */
#const RADIUS            8                      // 点の半径
#const PI                3.1415926535897932384  // 円周率π
#const MISSILE_MAX       16                     // 最大ミサイル数
#const MISSILE_LIFE      300                    // ミサイルの寿命
#const MISSILE_SPEED_MIN 0                      // ミサイルの最高速度(通常ゼロ)
#const MISSILE_SPEED_MAX 6                      // ミサイルの最高速度
#const MISSILE_ANGSPEED  0.2                    // ミサイルの加速度
 
#if MISSILE_SPEED_MIN > MISSILE_SPEED_MAX
    dialog "定数の指定が異常です", 1
    end
#endif
 
    randomize
    title "homing missile - クリックでミサイル生成"
 
/*  配列変数の準備  */
    dim MissileX, MISSILE_MAX           // ミサイルのX座標
    dim MissileY, MISSILE_MAX           // ミサイルのY座標
    dim MissileLife, MISSILE_MAX        // ミサイルの寿命
    ddim MissileSpeedX, MISSILE_MAX     // ミサイルのスピード
    ddim MissileSpeedY, MISSILE_MAX     // ミサイルのスピード
 
    onclick gosub *make_missile         // クリックするごとにミサイル生成
 
/*  メインループ  */
*main
    redraw 0
    gosub *clear                        // 画面を初期化する
    gosub *move_missile                 // 全てのミサイルを動かす
    gosub *plot_mouse                   // ターゲットを描画
    gosub *plot_missile                 // 全てのミサイルを描画
    redraw 1
    await 16
    goto *main
 
/*  画面を初期化  */
*clear
    color 255, 255, 255
    boxf
    return
 
/*  ミサイルを1発生成する  */
*make_missile
    repeat MISSILE_MAX
        if MissileLife(cnt) > 0 : continue
        // 座標を決定
        MissileX(cnt) = rnd(ginfo_winx)
        MissileY(cnt) = rnd(ginfo_winy)
        // 寿命を決定
        MissileLife(cnt) = MISSILE_LIFE
        // ミサイルのスピードを決定
        ang = atan(mousey-MissileY(cnt), mousex-MissileX(cnt))  // ミサイルから見たターゲットの方向
        MissileSpeedX(cnt) = cos(ang) * MISSILE_SPEED_MAX
        MissileSpeedY(cnt) = sin(ang) * MISSILE_SPEED_MAX
        break
    loop
    return
 
/*  全てのミサイルを動かす  */
*move_missile
    repeat MISSILE_MAX
        if MissileLife(cnt) == 0 : continue     // 寿命が残っているミサイルのみを対象
 
        // ミサイルから見たターゲットの方向を求める
        ang = atan( MissileY(cnt) - mousey, mousex - MissileX(cnt) )
        // ミサイルの加速
        MissileSpeedX(cnt) += cos(ang) * MISSILE_ANGSPEED
        MissileSpeedY(cnt) -= sin(ang) * MISSILE_ANGSPEED
        // 速度をMISSILE_SPEED_MIN〜MISSIKE_SPEED_MAXの間に収める
        ang = atan( -MissileSpeedY(cnt), MissileSpeedX(cnt) )
        speed = sqrt( MissileSpeedX(cnt) * MissileSpeedX(cnt) + MissileSpeedY(cnt) * MissileSpeedY(cnt) )
        MissileSpeedX(cnt) =  limitf( speed, MISSILE_SPEED_MIN, MISSILE_SPEED_MAX ) * cos( ang )
        MissileSpeedY(cnt) = -limitf( speed, MISSILE_SPEED_MIN, MISSILE_SPEED_MAX ) * sin( ang )
        // ミサイルを移動させる
        MissileX(cnt) += MissileSpeedX(cnt)
        MissileY(cnt) += MissileSpeedY(cnt)
        // ミサイルの寿命を縮める
        MissileLife(cnt)--
    loop
    return
 
/*  ターゲットを描画  */
*plot_mouse
    color 0, 0, 255
    plot RADIUS, mousex, mousey     // 半径RADIUSの円(塗りつぶし)を描画
    return
 
/*  全てのミサイルを描画  */
*plot_missile
    color 255,128,0
    repeat MISSILE_MAX
        if MissileLife(cnt)==0 : continue           // 寿命が残っているミサイルのみを対象
        plot RADIUS, MissileX(cnt), MissileY(cnt)   // 半径RADIUSの円(塗りつぶし)を描画
    loop
    return

コメント


URL B I U SIZE Black Maroon Green Olive Navy Purple Teal Gray Silver Red Lime Yellow Blue Fuchsia Aqua White

添付ファイル:
filehoming2.hsp
495件 [詳細]
filerobot_missile.hsp
530件 [詳細]
filevector.png
371件 [詳細]
filehoming.hsp
745件 [詳細]
トップ    編集凍結 差分バックアップ添付複製名前変更リロード   新規一覧単語検索最終更新   最終更新のRSS
Last-modified: 2007-09-23 (日) 08:30:32 (2268d)