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

ゴースト [hsp3]

前回の操作やベストスコア時の操作を再現し、ゴーストカーとして表示します。
リプレイもゴーストと同じ理屈で作成可能です。

記憶するのは車の座標や速度ではなく、プレイヤーによって入力されたキーです。
キーを記録しておくだけならデータ量が1フレームあたり数ビットだけで済む*1ので、ファイルサイズも小さくなります。

なおゲーム中に乱数を使う処理やアイテムなどを実装している場合は、乱数の種も別途記録するなど複雑にする必要があるかもしれません。

[point]
フレームごとにファイルからデータを読み出すと、記録媒体(だいたいはハードディスク)への負担がかかってしまうため、 良いプログラムとは言えません。
変数にたくさんロードしておき、それをpeek命令などでちょっとずつ取り出す方が良いでしょう。
とは言えたくさんロードしすぎるとメモリに負担がかかってしまうのでほどほどに。

今回のスクリプトでは1KBずつロードしています。
await 16 で 1024 ループに一回 *loadNextGhost? 呼び出すので、約16秒に1回ディスクにアクセスする計算です。
(16*1024/1000 = 16.384 = 約16秒)

サンプルスクリプト

注意!起動時のカレントディレクトリにゴーストデータ記録用のファイル"Race_Ghost.sav"を保存します。
起動2回目以降はこのファイルを利用し、ゴーストを表示します。

必要最低限の機能のみを持たせたスクリプト

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
 
 
 
 
 
 
-
|
|
|
!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-
|
|
-
|
|
|
!
 
 
 
 
 
 
 
 
 
 
-
|
-
|
!
 
 
 
 
 
 
-
|
|
!
-
|
|
!
 
 
 
 
 
 
 
 
#define GHOST_FILE_NAME "Race_Ghost.sav"
#const PAGE_SIZE 1024
 
    exist GHOST_FILE_NAME
    existGhost = strsize                                // ゴーストが存在するか?
    sdim nextGhostData, PAGE_SIZE                       // キー入力を記憶する領域 これが次回起動時のゴーストになる
    if existGhost >= 0 {
        ghostPage = -1                                  // 読み込んだゴーストのページ数
        sdim ghostData, PAGE_SIZE                       // ファイルから読みだすための変数
        gosub *loadNextGhost
    }
    onexit goto *endFlag
 
*main
    gosub *getInput
    gosub *draw
 
    ghostIndex++
    if ghostIndex == PAGE_SIZE : gosub *loadNextGhost
    await 16
    goto *main
 
// 入力処理
*getInput
    stick key, 15
    if (ghostPage * PAGE_SIZE + ghostIndex) <= existGhost {
        // ゴーストデータがある
        ghostkey = peek(ghostData, ghostIndex)      // キー入力をファイルから読み出す
    } else {
        // ゴーストデータがない
        existGhost = -1                             // ゴーストの描画をストップ
        ghostkey = -1
    }
    poke nextGhostData, ghostIndex, key
 
// 描画処理
*draw
    redraw 0
    color 255, 255, 255 : boxf
 
    color : pos 0, 0
    mes "キー入力:" + key
 
    if ghostKey < 0 {
        mes "ゴーストのデータはありません"
    } else {
        mes "ゴースト:" + ghostKey
    }
    redraw 1
    return
 
// ゴーストデータを1KBずつ処理(読み込み・保存)する
*loadNextGhost
    ghostPage++     // 対象ページ番号を1増加
    if existGhost >= 0 {
        // ゴーストが存在する場合はキー入力が格納されたファイルを1KBずつghostData変数にロード
        bload GHOST_FILE_NAME, ghostData, limit(existGhost - ghostPage * PAGE_SIZE, 0, PAGE_SIZE), PAGE_SIZE * ghostPage
    }
    if ghostPage > 0 {
        // すでに読み終えたページがある場合、今のキー入力をそのページに上書き
        bsave GHOST_FILE_NAME, nextGhostData, PAGE_SIZE, PAGE_SIZE * (ghostPage - 1)
    }
    memset nextGhostData, 0, PAGE_SIZE
    ghostIndex = 0
    return
 
*endFlag
    // 保存していないキー入力を保存
    bsave GHOST_FILE_NAME, nextGhostData, ghostIndex, PAGE_SIZE * (ghostPage - 1)
    end

レースゲームとして動作するスクリプト

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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-
|
|
|
|
|
|
!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-
|
|
-
|
|
!
 
 
 
 
 
 
 
 
-
|
|
|
|
!
 
 
 
 
 
-
|
|
|
|
!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-
|
|
!
-
|
|
!
 
 
 
 
 
 
 
 
/* 操作方法
    [Up]          : 加速
    [Left][Right] : 旋回
*/
 
#include "d3m.hsp"
 
#const PI 3.14159
 
#const AREA_X 320       // 走行エリアの広さ(横)
#const AREA_Y 320       // 走行エリアの広さ(縦)
#const GRID_DISTANCE 32 // グリッドの間隔
#const GRID_NUM_X 11    // グリッドの本数 (= AREA_X / GRID_DISTANCE + 1)
#const GRID_NUM_Y 11    // グリッドの本数 (= AREA_Y / GRID_DISTANCE + 1)
#const CAR_SIZE 12      // 車の長さ
#const CAM_DISTANCE 15.0// カメラと車の距離
#const GHOST_SAVE_SPAN 1024 // ゴーストデータを読み書きする単位(バイト)
#define GHOST_FILE_NAME "Race_Ghost.sav"
 
*init
    buffer 1, AREA_X, AREA_Y
    screen 0, AREA_X, AREA_Y * 2, 0
    gmode 0, AREA_X, AREA_Y
    title "ゴーストの記憶・表示 - 平面レースゲームの場合"
 
    carX = 10.0 : carY = 10.0 : carZ = 0.0              // 車の座標
    carT = PI / 4                                       // 車の向き
    carSpeed = 0.0                                      // 車のスピード
 
    camX = 0.0 : camY = 0.0 : camZ = 20.0               // カメラの座標
    camT = carT                                         // カメラの向き
    needToDraw = 1                                      // 描画し直す必要性がある場合は1
 
    exist GHOST_FILE_NAME
    existGhost = strsize                                // ゴーストが存在するか?
    sdim nextGhostData, GHOST_SAVE_SPAN                            // キー入力を記憶する領域 これが次回起動時のゴーストになる
    if existGhost >= 0 {
        ghostX = carX : ghostY = carY : ghostZ = carZ   // ゴーストの座標
        ghostT = carT                                   // ゴーストの向き
        ghostSpeed = carSpeed                           // ゴーストのスピード
        ghostPage = -1                                  // 読み込んだゴーストのページ数
        sdim ghostData, GHOST_SAVE_SPAN                            // ファイルから読みだすための変数
        gosub *loadNextGhost
    }
    onexit goto *endFlag
 
*main
    gosub *move     // 車とカメラの移動
    gosub *draw     // 車とグリッド、全体マップの描画
 
    // ゴーストデータの保存
    ghostIndex++
    if ghostIndex == GHOST_SAVE_SPAN : gosub *loadNextGhost
 
    await 16
    goto *main
 
*move
    stick key, 15
    if (ghostPage * GHOST_SAVE_SPAN + ghostIndex) <= existGhost {
        // ゴーストデータがある
        ghostkey = peek(ghostData, ghostIndex)      // キー入力をファイルから読み出す
    } else {
        // ゴーストデータがない
        existGhost = -1                             // ゴーストの描画をストップ
    }
    poke nextGhostData, ghostIndex, key
    gosub *moveCar  // 車の移動
    gosub *moveGhost// ゴーストの移動
    gosub *moveCam  // カメラの移動
    return
 
*moveCar
    carSpeed = limitf(carSpeed + 0.1*((key & 2) - 1), 0.0, 3.0) // ↑を押せば加速、押さなければ減速
    if carSpeed > 0.0 {
        carT += 0.1*((key & 1) - (key >> 2 & 1))
        carX = limitf(carX + carSpeed * cos(carT), 0, AREA_X)
        carY = limitf(carY + carSpeed * sin(carT), 0, AREA_Y)
        needToDraw = 1  // 車が移動したので画面を描画し直す必要がある
    }
    return
 
*moveGhost
    if existGhost < 0 : return
    ghostSpeed = limitf(ghostSpeed + 0.1*((ghostKey & 2) - 1), 0.0, 3.0)
    if GhostSpeed > 0.0 {
        ghostT += 0.1*((ghostKey & 1) - (ghostKey >> 2 & 1))
        ghostX = limitf(ghostX + ghostSpeed * cos(ghostT), 0, AREA_X)
        ghostY = limitf(ghostY + ghostSpeed * sin(ghostT), 0, AREA_Y)
        needToDraw = 1
    }
    return
 
*moveCam
    camT = atan(camY - carY, camX - carX)
    camX = carX + cos(camT) * CAM_DISTANCE
    camY = carY + sin(camT) * CAM_DISTANCE
    gsel 1
    d3setcam camX, camY, camZ, carX, carY, carZ, 2
    return
 
*draw
    if needToDraw == 0 : return
    gsel 1
    gosub *drawBuf
    gsel 0
    gosub *drawScr
    if carSpeed == 0.0 : needToDraw = 0
    return
 
*drawBuf
    color : boxf
    gosub *drawBufGrid  // バッファにグリッドを描画
    gosub *drawBufGhost // バッファにゴーストを描画
    gosub *drawBufCar   // バッファに車を描画
    return
 
*drawBufGrid
    color 0, 0, 255
    repeat 9, int(carY / GRID_DISTANCE) - 4
        if (cnt < 0)|(GRID_NUM_X <= cnt) : continue
        y = cnt * GRID_DISTANCE
        repeat 9, int(carX / GRID_DISTANCE) - 4
            if (cnt < 0)|(GRID_NUM_Y <= cnt) : continue
            x = cnt * GRID_DISTANCE
            d3line x, 0, 0, x, AREA_Y, 0
            d3line 0, y, 0, AREA_X, y, 0
        loop
    loop
    return
 
*drawBufGhost
    if existGhost < 0 : return
    color 128, 128, 128
    d3initlineto
    d3lineto ghostX, ghostY, ghostZ
    d3lineto ghostX - cos(ghostT + 0.2) * CAR_SIZE, ghostY - sin(ghostT + 0.2) * CAR_SIZE, ghostZ
    d3lineto ghostX - cos(ghostT - 0.2) * CAR_SIZE, ghostY - sin(ghostT - 0.2) * CAR_SIZE, ghostZ
    d3lineto ghostX, ghostY, ghostZ
    return
 
*drawBufCar
    color 255
    d3initlineto
    d3lineto carX, carY, carZ
    d3lineto carX - cos(carT + 0.2) * CAR_SIZE, carY - sin(carT + 0.2) * CAR_SIZE, carZ
    d3lineto carX - cos(carT - 0.2) * CAR_SIZE, carY - sin(carT - 0.2) * CAR_SIZE, carZ
    d3lineto carX, carY, carZ
    return
 
*drawScr
    redraw 0
    gosub *drawScrMap
    pos 0, 320
    gcopy 1, 0, 0       // 3D表示をコピー
    redraw 1
    return
 
*drawScrMap
    color : boxf 0, 0, 320, 320
    gosub *drawScrMapGrid
    gosub *drawScrMapGhost
    gosub *drawScrMapCar
    gosub *drawScrMapCam
    return
 
// グリッドを描く
*drawScrMapGrid
    color 0, 0, 255
    repeat GRID_NUM_Y
        y = cnt * GRID_DISTANCE
        repeat GRID_NUM_X
            x = cnt * GRID_DISTANCE
            line x, 0, x, AREA_Y
            line 0, y, AREA_X, y
        loop
    loop
    return
 
// ゴーストの位置を表示
*drawScrMapghost
    if existGhost < 0 : return
    color 128, 128, 128
    pos ghostX, AREA_Y - ghostY
    line ghostX - cos(ghostT + 0.2) * CAR_SIZE, AREA_Y - (ghostY - sin(ghostT + 0.2) * CAR_SIZE)
    line ghostX - cos(ghostT - 0.2) * CAR_SIZE, AREA_Y - (ghostY - sin(ghostT - 0.2) * CAR_SIZE)
    line ghostX, AREA_Y - ghostY
    return
 
// 車の位置を表示
*drawScrMapCar
    color 255
    pos carX, AREA_Y - carY
    line carX - cos(carT + 0.2) * CAR_SIZE, AREA_Y - (carY - sin(carT + 0.2) * CAR_SIZE)
    line carX - cos(carT - 0.2) * CAR_SIZE, AREA_Y - (carY - sin(carT - 0.2) * CAR_SIZE)
    line carX, AREA_Y - carY
    return
 
// カメラの位置を表示
*drawScrMapCam
    color 0, 255
    circle camX - 2, - camY + 2 + AREA_Y, camX + 2, - camY - 2 + AREA_Y
    return
 
// ゴーストデータをGHOST_SAVE_SPANずつ処理(読み込み・保存)する
*loadNextGhost
    ghostPage++     // 対象ページ番号を1増加
    if existGhost >= 0 {
        // ゴーストが存在する場合はキー入力が格納されたファイルを1KBずつghostData変数にロード
        bload GHOST_FILE_NAME, ghostData, limit(existGhost - ghostPage * GHOST_SAVE_SPAN, 0, GHOST_SAVE_SPAN), GHOST_SAVE_SPAN * ghostPage
    }
    if ghostPage > 0 {
        // すでに読み終えたページがある場合、今の車の動きをそのページに上書き
        bsave GHOST_FILE_NAME, nextGhostData, GHOST_SAVE_SPAN, GHOST_SAVE_SPAN * (ghostPage - 1)
    }
    memset nextGhostData, 0, GHOST_SAVE_SPAN
    ghostIndex = 0
    return
 
*endFlag
    // 保存していないキー入力を保存
    bsave GHOST_FILE_NAME, nextGhostData, ghostIndex, GHOST_SAVE_SPAN * (ghostPage - 1)
    end

コメント

  • >await 16なので約16秒に1回ディスクにアクセスする計算です。>16/1000秒ですか? -- サンポーニャ? 2007-07-17 (火) 22:41:28
  • そうですね。awaitはミリ秒単位で指定するので、await 16は16ミリ秒待ちます。 -- eller 2007-07-27 (金) 15:26:46

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

*1 今回のスクリプトは本来←↑→の3ビットで済むのですが、読みやすくするために1バイトずつ保存しています
トップ    編集凍結 差分バックアップ添付複製名前変更リロード   新規一覧単語検索最終更新   最終更新のRSS
Last-modified: 2010-03-22 (月) 17:00:48 (1357d)