【プチコン4講座】ゲームクリアの実装

プチコン4

プチコン4 レベルアップ

こんにちは。継続の錬金術士なおキーヌです。

ブログ毎日更新は200日目になります。

前回「【プチコン4講座】レベルアップシステムを作ってみる」でリザルト時にレベルアップを組み込みました。

プチコン4RPG作り方講座もいよいよラストです。

今回はゲームクリアのための仕組みを作っていきましょう。

そもそも何をもってクリアなのかを決めなければいけませんね。

とりあえずゴーストを倒して後ろの宝箱を開けたらクリアにしてみます。

それではプチコン4でRPG作りその31回目始めましょう。

  1. ゴーストを倒すためにはスケルトン討伐が必須
  2. せいすいというクリアフラグを用意する
  3. せいすいを持っているとゴーストを倒すことが出来る
  4. クリア宝箱を開いたらゲームクリア!

ゴーストを倒すためにはスケルトン討伐が必須

ステージボスの前に中ボスであるスケルトンを討伐しなければゴーストを倒せないようにしましょう。

正確にはスケルトンの後ろにある宝箱がクリアするためのフラグにしたいと思います。

まずは設定していない宝箱イベントを設定してしまいましょう。

@Event007
DATA 7,  10,95,400  3,1,268,  2,0,1  1,1,0,  10,12,0  1,2,0, 0,1,1
@Event007_1
DATA 2,  1,3,0,  0,0,0

@Event008
DATA 7,  10,95,400  3,1,268,  2,0,1  1,1,0,  10,12,0  1,2,0, 0,1,1
@Event008_1
DATA 2,  1,3,0,  0,0,0

@Event009
DATA 7,  10,95,400  3,1,268,  2,1,0  1,1,0,  10,113,0  1,2,0, 0,1,1
@Event009_1
DATA 2,  1,3,0,  0,0,0

@Event010
DATA 7,  10,95,400  3,1,268,  1,1,0,  10,113,0  1,2,0, 2,2,0, 0,1,1


DIM G_ItemName$[3] = ["ライフポーション", "せいすい", "サファイアのティアラ"]

7と8、つまりコウモリの下とラミアの後ろにある宝箱はライフポーション。

9はスケルトンの後ろで10はゴーストの後ろにある宝箱です。

7は元々作ってあったので、コピーして8を作りました。

そして9は中身を「せいすい」にして獲得音を少し豪華にしてみました。

10はゲームクリアにしたいので、アイテム入手イベントを最後の方に持ってきています。

というのも、取得したらシーンを即座にゲームクリアに切り替える為です。

そしてクリア用の「サファイアのティアラ」を追加しました。

そして10の宝箱を取るにはゴーストを倒さなければいけません。

ゴーストを倒すにはせいすいが必須です。

せいすいを取るためにはスケルトンを倒さなければいけません。

ということでスケルトン討伐はゲームにおいて必須事項となります。

せいすいというクリアフラグを用意する

先ほどの宝箱の設定でせいすいを入手することが出来るようになったので、
イベントキュー処理のところにせいすい取得イベントを追記しましょう。

ライフポーションのように所持するのではなく、フラグをONにする感じで行きましょう。

折角スプライト変数という便利なものがあるので、そこを利用します。

CLEAWR_FLAG

というスプライト変数を用意します。

スプライト初期化の時点で0にしておきましょう。

全スプライトに設定されてしまいますが、そんなに数が多くないので別に気にしなくても大丈夫です。

もしスプライトが膨大な数になっているゲームの場合はスプライト個別に割り当てるか、
グローバル変数として1つ作ってあげるかにするといいいでしょう。

' スプライト初期化
'──────────────────────────
def D_SpInitialize A_Id
  ' 戦闘用スプライト定義
  SPDEF "@BattleSP_DEF",2000,0,0

  SPSET A_Id, 500
  SPVAR A_Id, "X", G_EvId[G_SpEvStep * A_Id + 1] * #CSZ
  SPVAR A_Id, "Y", G_EvId[G_SpEvStep * A_Id + 2] * #CSZ
  SPVAR A_Id, "Direct", -1
  SPVAR A_Id, "MoveFlag", 0
  SPVAR A_Id, "EventPage", 0
  SPVAR A_Id, "CLEAR_FLAG", 0
  SPOFS A_Id, SPVAR(A_Id,"X"), SPVAR(A_Id,"Y")

  D_MapArrayReWrite A_Id, SPVAR(A_Id, "Direct"), 1, #LAYER_EV

  if G_EvId[G_SpEvStep * A_Id + 3] != -1 then
    SPANIM A_Id, "I",\
    20,spAnimNo[A_Id],\
    20,spAnimNo[A_Id]+1,\
    20,spAnimNo[A_Id]+2,\
    20,spAnimNo[A_Id]+3,\
    G_EvId[G_SpEvStep * A_Id + 3]
  endif
end


' イベントキュー処理
'──────────────────────────
def D_ShiftEvData
  var type = SHIFT(G_EvQueue)
  var event = SHIFT(G_EvQueue)
  var reserve = SHIFT(G_EvQueue)

  case type
    when 0
      ' メッセージウィンドウが開いている時に0イベントが来たらフラグをOFFにする
      if G_OpenMsgFlag == #TRUE then
        GCLS
        G_OpenMsgFlag = #FALSE
      endif

      ' イベントによって
      case event
        when 1
          SPVAR G_EvIdNow, "EvPage", reserve
      endcase
    when 1
      if G_OpenMsgFlag == #FALSE then
        D_WindowDraw G_WindowSize[0], G_WindowSize[1], G_WindowSize[2], G_WindowSize[3]
      endif
      D_MessageDraw event, reserve
      G_EvMsgStopFlag = #TRUE
    when 2
      case event
       when 0
        INC G_PlayerStatus[7], reserve
       when 1
        SPVAR 0, "CLEAR_FLAG", 1
      endcase
    when 3
    ~~~ 省略 ~~~

    when 10
      ' SEを鳴らす
      BEEP event, reserve
  endcase

  if LEN(G_EvQueue) <= 0 then
    G_SceneFlag = 0
  endif
end

これでせいすいを手に入れたらクリアフラグがONになるようになりました。

次はこのフラグを使った処理を作ります。

せいすいを持っているとゴーストを倒すことが出来る

せいすいを手に入れたらフラグがオンになったので、ようやくゴーストを倒すことが出来るようになります。

しかし今のままでは棒立ち状態のモンスターを斬りまくれば勝てる状態になっていますので、
ゴースト戦のときだけ特殊な処理を呼び出してみましょう。

' プレイヤーの攻撃の衝突判定
'──────────────────────────
def D_BattlePlayerAttackColCheck
  var spid = SPHITSP(200,101,199)
  if spid > 100 && spid < 200 then
    if spid != -1 && SPVAR("ALPHA") == 255 then
      if SPVAR(100,"AtkHit") == -1 then

        DIM ary = SPVAR(spid, "STATUS")
        var damage = 0
        var flag = SPVAR(0, "CLEAR_FLAG")

        SPVAR 100,"AtkHit", spid

        if G_EvIdNow != 10 then
          if flag == 1 then
            damage = 10
          endif
        else
          damage = 2
        endif

        if damage > 0 then
          SPCOLOR spid, RGB(255,0,0)
          BEEP 103
          DEC ary[0], damage
          SPVAR spid,"STATUS", ary
        else
          BEEP 98, 500
        endif

        PRINT SPVAR(spid,"STATUS")[0]

      endif
    endif
  endif
end

プチコン4表示結果その1

せいすいを取る前にゴーストと戦ってみるとダメージを与えられないようになっています。

現状では逃げるコマンドがないので詰んでしまいますね。

そのうち逃げるコマンドの実装もしましょうか。

プチコン4表示結果その2

その後、せいすいを取ってみます。

せいすいを持った状態で再びゴーストに挑むと

プチコン4表示結果その3

このようにダメージを与えられるようになっています!

クリア宝箱を開いたらゲームクリア!

いよいよゲームクリアの実装です。

頭の良い人は気付いたかもしれませんが、イベント10を調べるとエラーが出ます。

なぜかというと、イベント取り出しの関数をよく見てもらうとわかります。

文字列で直接@Event00+イベントIDとしているので、
10のイベントが来たときは@EV0010を参照しようとするのでエラーが出るのは当然ですね。

IDが1桁であろうが2桁であろうが3桁であろうが、常に3桁を維持しなければいけません。

条件式を書いて2桁以上の時は~とか1桁の時は~とか手動で書いてみるのもプログラミングの練習になります。

これをゼロパディングといって指定の桁数で0を埋めるという手法です。

データベースを扱っていると結構使ったりするので覚えておいて損はないです。

しかしプチコンにはなんとゼロパディングを簡単にしてくれる関数が用意されています。

それは「FORMAT$("%nD",変数)」という形にすると数値を文字列化した後、n桁になるように前に0を足した文字列を返します。

何と好都合な!これを使えば面倒くさい条件式を書かなくても済みます。

早速使ってみましょう。

' イベントデータ取り出してキューに格納
'──────────────────────────
def D_GetEvData A_Id
  var evCount = 0
  var evData = 0

  if SPVAR(A_Id, "EvPage") == 0 then
    RESTORE "@Event" + FORMAT$("%03D",A_Id)
  elseif SPVAR(A_Id, "EvPage") == 1 then
    RESTORE "@Event" + FORMAT$("%03D",A_Id) + "_1"
  endif
  READ evCount
  for G_I=1 to (evCount * 3)-1
    READ evData
    PUSH G_EvQueue, evData
  next

  if LEN(G_EvQueue) > 0 then
    G_EvIdNow = A_Id
    G_SceneFlag = 1
  endif
end

STR$(A_Id)だったところをFORMAT$()に置き換えてみました。

引数1つ目を「%03D」にしたので3桁に揃えてくれます。

FORMAT$は他にも色々便利な機能があるので、公式リファレンスをチェックしてみてください。

これでゲームクリアのための宝箱イベントを実行することが出来るようになりました。

ゲームクリアシーンを用意する

サファイアのティアラを手に入れたらゲームクリアシーンに強制チェンジするようにしたいので
シーンフェーズのところに付け加えてしまいましょう。

' シーン管理
'──────────────────────────
def D_GameSceneManager
  var direct = D_Controller()
  case G_SceneFlag
    when 0
      ' マップシーン
      D_SpriteGridMove 0, direct
      ' イベントキュー監視
      if LEN(G_EvQueue) > 0 then
        G_SceneFlag = 1
    when 1
      ' イベントシーン
      D_EventScene direct
    when 2
      ' ステータス画面
      D_StatusScene
    when 3
      ' バトル画面
      D_BattleScene direct
    when 4
      'クリア画面
      D_GameClear
  endcase
end

これでゲームクリアシーンを作りました。

イベントでサファイアのティアラを取ったらシーン4に移るようにしてみましょう。

' イベントキュー処理
'──────────────────────────
def D_ShiftEvData
  var type = SHIFT(G_EvQueue)
  var event = SHIFT(G_EvQueue)
  var reserve = SHIFT(G_EvQueue)

  case type
    when 0
    ~~~ 省略 ~~~


    when 2
      case event
        when 0
          INC G_PlayerStatus[7], reserve
        when 1
          SPVAR 0, "CLEAR_FLAG", 1
        when 2
          BEEP 71
          BGMPLAY 41
          G_SceneFlag = 4
      endcase
    when 3
    ~~~ 省略 ~~~

  endcase

  if LEN(G_EvQueue) <= 0 then
    G_SceneFlag = 0
  endif
end

完璧です!

後はゲームクリアシーンの関数中身を作っていくだけですね。

ゲームクリアシーンを作る

スタッフロールとかは作る気はないので、プチコンBIGの時と同じ感じで終わろうと思います。

そういえばゲームオーバー処理を作ってなかったなと思ったのですが、
そもそもモンスターAIを作らないと負けることがないですね。

ゲームオーバーはモンスターAIが完成してから講座のゲームオーバーという意味も込めて最後の最後にします。

' ゲームクリアシーン
'──────────────────────────
def D_GameClear
  GPUTCHR  72,100,"CONGRATULATIONS!",16,RGB(255,255,255),1
end

プチコン4表示結果その4

ゲームクリアです!

おめでとうございます!

これであなたもゲームクリエイターの仲間入りですね!

プチコンを買って起動してマップを自分で用意してから31回。

ついにRPGの基礎が詰まったゲームを作り上げることが出来ました!

モンスターAIや細かい雑な挙動なんかはオリジナルで組んだり修正してみるのも勉強になりますよ。

プチコン4でのRPG作り方講座はこれにて一旦閉幕とさせていただきます。

ブログも毎日更新200日目というキリのいいところなので個人的にも良い区切りかなと思いました。

そろそろ来年に向けてUnityでゲームを作らないとマジで間に合わなさそうというか
正直体験版レベルしか出せなさそうな状態なので、ゲーム作りを集中します。

プチコン4RPGのモンスターAIに関しては牛歩になりますが作っていきますので、
気が向いたら見に来ていただけると幸いです。

最後に完成版ソースコードを残しておきます。

それでは

'──────────────────────────
' ▼ 動作モード設定:変数宣言は必須
'──────────────────────────
OPTION STRICT
'──────────────────────────
' ▼ 画面のクリア
'──────────────────────────
ACLS
'──────────────────────────
' ▼ 定数・構造体の定義
'──────────────────────────
CONST #CSZ = 16
CONST #NORMAL_BATTLE_BGM = 30
ENUM #LAYER_MAP1=0,#LAYER_MAP2,#LAYER_EV

'──────────────────────────
' ▼ 変数・配列の定義
'──────────────────────────
' ┠─ 汎用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
var G_I = 0, G_J = 0, ¥
G_BGW = 0, G_BGH = 0
' ゲームループを制御するフラグ
var G_GameLoopFlag = #TRUE
'──────────────────────────
' ┠─ マップシーン用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' 空配列宣言
DIM G_MapData[]
'──────────────────────────
' ┠─ スプライト用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' アニメーション開始スプライト定義No配列
var G_SpEvStep = 4
DIM G_SpAnimNo[] = [500,1040,920,1000,980,1080,1020,269,269,269,269]
DIM G_BattleSpAnimNo[] = [500,1040,920,1000,980,1080,1020,269,269,269,269]

'──────────────────────────
' ┠─ ウィンドウ用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
var G_OpenStatusFlag = #FALSE
var G_OpenMsgFlag = #FALSE

'──────────────────────────
' ┠─ イベント用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
var G_EvMsgStopFlag = #FALSE
var G_EvNow = 0

' プレイヤー含むイベント初期設定
DIM G_EvId[] = [0,1,0,0,\
  1,5,5,0,\
  2,23,13,0,\
  3,4,11,0,\
  4,13,3,0,\
  5,20,9,0,\
  6,22,4,0,\
  7,6,7,-1,\
  8,21,9,-1,\
  9,3,11,-1,\
  10,22,2,-1\
  ]

' イベントキュー
DIM G_EvQueue[]

' 各イベントデータ(ラベル管理
'──────────────────────────
@Event000
DATA 1,  0,0,0

'───_1
@Event001
DATA 3,  4,1,0, 5,0,0, 0,1,1
@Event001_1
DATA 1,  0,0,0
@Troop001_1
DATA 1,1
@Troop001_2
DATA 2,1,1
@Troop001_0
DATA 2
'=================
'───_2
@Event002
DATA 3,  4,2,0, 5,0,0, 0,1,1
@Event002_1
DATA 1,  0,0,0
@Troop002_1
DATA 1,2
@Troop002_2
DATA 2,2,1
@Troop002_3
DATA 2,2,2
@Troop002_0
DATA 3
'=================
'───_3
@Event003
DATA 4,  6,29,0, 4,3,0, 5,0,0, 0,1,1
@Event003_1
DATA 1,  0,0,0
@Troop003_1
DATA 1,3
@Troop003_0
DATA 1
'=================
'───_4
@Event004
DATA 3,  4,4,0, 5,0,0, 0,1,1
@Event004_1
DATA 1,  0,0,0
@Troop004_1
DATA 1,4
@Troop004_2
DATA 2,4,2
@Troop004_3
DATA 2,4,5
@Troop004_0
DATA 3
'=================
'───_5
@Event005
DATA 3,  4,5,0, 5,0,0, 0,1,1
@Event005_1
DATA 1,  0,0,0
@Troop005_1
DATA 1,5
@Troop005_2
DATA 2,5,1
@Troop005_3
DATA 2,5,4
@Troop005_0
DATA 3
'=================
'───_6
@Event006
DATA 4,  6,25,0, 4,6,0, 5,0,0, 0,1,1
@Event006_1
DATA 1,  0,0,0
@Troop006_1
DATA 1,6
@Troop006_0
DATA 1




@Event007
DATA 7,  10,95,400  3,1,268,  2,0,1  1,1,0,  10,12,0  1,2,0, 0,1,1
@Event007_1
DATA 2,  1,3,0,  0,0,0

@Event008
DATA 7,  10,95,400  3,1,268,  2,0,1  1,1,0,  10,12,0  1,2,0, 0,1,1
@Event008_1
DATA 2,  1,3,0,  0,0,0

@Event009
DATA 7,  10,95,400  3,1,268,  2,1,0  1,1,0,  10,113,0  1,2,0, 0,1,1
@Event009_1
DATA 2,  1,3,0,  0,0,0

@Event010
DATA 7,  10,95,400  3,1,268,  1,1,0,  10,113,0  1,2,0, 2,2,0, 0,1,1


DIM G_ItemName$[3] = ["ライフポーション", "せいすい", "サファイアのティアラ"]

'──────────────────────────
' ┠─ バトル用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
var G_BattleSceneState = 0
var G_BattleBGM = #NORMAL_BATTLE_BGM
DIM G_BattleInfoDatas[]
DIM G_BattleEnemyTroop[]


'──────────────────────────
' ┠─ データベース
'━━━━━━━━━━━━━━━━━━━━━━━━━━
DIM G_PlayerStatus[8] = [1,20,20,3,2,3,0,1]

G_ExpTable[7] = [0,10,40,70,100,130,160]

DIM G_SystemWord$[7] = ["Lv", "HP", "こうげき", "ぼうぎょ", "すばやさ", "けいけんち", "ポーション"]

DIM G_ItemName$[3] = ["ライフポーション", "せいすい", "サファイアのティアラ"]

DIM G_EnemyName$[6] = ["リトルバット", "ゴブリン", "スケルトン", "ラミア", "マミー", "ゴースト"]

DIM G_Message$[6] = [" は たからばこを あけた", "たからばこ には ", " が はいっていた!","からっぽ!"]

DIM G_WindowSize[16] = [80,150,240,58,  10,10,112,77, 80,8,240,50, 100,58,200,20]

DIM G_BattleWalkAnimNo[] = [\
  2012,2004,2008,2000,\ ' プレイヤー
  2112,2104,2108,2100,\ ' コウモリ
  2032,2024,2028,2020,\ ' ゴブリン
  2072,2064,2068,2060,\ ' スケルトン
  2052,2044,2048,2040,\ ' ラミア
  2132,2124,2128,2120,\ ' マミー
  2092,2084,2088,2080,\ ' ゴースト
]

DIM G_BattleEnemyDatas[] = [\
  7,   5,3,3,10,\ ' コウモリ
  20, 13,2,3,20,\ ' ゴブリン
  45, 15,6,3,40,\ ' スケルトン
  35, 15,5,3,30,\ ' ラミア
  30,  7,5,3,30,\ ' マミー
  100,18,7,3,50\ ' ゴースト
]


@BattleSP_DEF
DATA 152
DATA 0,01312,32,32,16,31,0 '戦士_歩き_右0", "WarriorR0" '3556

~~~ 省略 ~~~
DATA 96,1568,32,32,16,31,4 ' "戦士_ダメージ_3", "WarriorDmg3" '3531
DATA 768,1792,16,32,8,31,0 ' "小さな剣0" , "Knife0" '3196
DATA 768,1792,16,32,8,31,1 ' "小さな剣1" , "Knife0" '3197
DATA 768,1792,16,32,8,31,2 ' "小さな剣2" , "Knife0" '3198
DATA 768,1792,16,32,8,31,3 ' "小さな剣3" , "Knife0" '3199



'──────────────────────────
' ┠─ コントローラー用配列
'━━━━━━━━━━━━━━━━━━━━━━━━━━
’ ボタンカウント配列
DIM G_BtnPressCount[4]

'──────────────────────────
' ▼ プログラム初期化処理
'──────────────────────────
D_GAME_INITIALIZE
'──────────────────────────
' ゲームループ開始
'──────────────────────────
loop
  'シーン管理呼び出し
  D_GameSceneManager
  ' ゲームループフラグ監視
  if !G_GameLoopFlag then BREAK
  ' フレームレート安定
  VSYNC 1
endloop

'──────────────────────────
' シーン管理
'──────────────────────────
def D_GameSceneManager
  var direct = D_Controller()
  case G_SceneFlag
    when 0
      ' マップシーン
      D_SpriteGridMove 0, direct
      ' イベントキュー監視
      if LEN(G_EvQueue) > 0 then
        G_SceneFlag = 1
    when 1
      ' イベントシーン
      D_EventScene direct
    when 2
      ' ステータス画面
      D_StatusScene
    when 3
      ' バトル画面
      D_BattleScene direct
    when 4
      'クリア画面
      D_GameClear
  endcase
end

'──────────────────────────
' ▼ 関数の定義
'──────────────────────────
' ┠─ ▼ 初期化関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
def D_GameInitialize
  ' マップデータのロード
  D_MapInitialize "MAP001.DAT"
  ' マップデータの描写
  'D_MapDraw
  ' スプライトの初期化
  for G_I=0 to LEN(G_EvId)-1 step G_SpEvStep
    D_SpInitialize G_EvId[G_I]
  next
  ' レイヤーのセッティング
  D_ScreenLayerSettings
end

' ▼ スクリーンレイヤー変更
'──────────────────────────
def D_ScreenLayerSettings
  TLAYER 0, 4
  for G_I = 0 to LEN(G_SpAnimNo)-1
    SPLAYER G_I, 3
  next
  GTARGET 0
end

'──────────────────────────
' ┗━┓ ▼ マップ関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
def D_MapInitialize A_FILENAME$
  ' マップデータファイル読み込み
  G_MAPDATA = LOADV(A_FILENAME$)

  ' マップデータ配列の先頭2つを取り出す
  G_BGW = SHIFT(G_MapData)
  G_BGH = SHIFT(G_MapData)
end
'──────────────────────────
'   ┗━┳━ ▼ マップデータ描写
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' マップデータの描写関数
def D_MapDraw
  ' マップチップ配列を描写
  for G_J = 0 to G_BGH-1
    for G_I = 0 to G_BGW-1
      ' ローカル変数CPに計算した値を入れる 
      var cp = G_I + ( G_J * G_BGW )
      ' CASE文でMAPDATA[CP]の内容に応じて処理を切り替える
      case G_MapDat[cp]
        ' 0のとき
        when 0:
          ' 地面を表示
          TPUT 0, G_I, G_J, CHR(&HE8C9)
        ' 1のとき
        when 1:
          ' 木を表示
          TPUT 0, G_I, G_J, CHR(&HE8CA)
      endcase
    next
  next
end

'──────────────────────────
' ┠─ コントローラー関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' コントローラー関数
'──────────────────────────
def D_Controller()
  var B = BUTTON(0)
  var direct = -1

  ' バトルシーンでなおかつ移動可能な場合はボタン状態を得る
  if G_SceneFlag == 3 && G_BattleSceneState == 2 then
    direct = B
  else
    ' 十字キー監視
    direct = D_LeftButtonProcess(B, #B_LUP, direct)
    direct = D_LeftButtonProcess(B, #B_LDOWN, direct)
    direct = D_LeftButtonProcess(B, #B_LLEFT, direct)
    direct = D_LeftButtonProcess(B, #B_LRIGHT, direct)
  endif

  ' ABXY監視
  D_RightButtonProcess B, #B_RUP
  D_RightButtonProcess B, #B_RDOWN
  D_RightButtonProcess B, #B_RLEFT
  D_RightButtonProcess B, #B_RRIGHT

  return direct
end

' 十字キー処理
'──────────────────────────
def D_LeftButtonProcess(A_B, A_Type, A_NowDirect)

  if A_NowDirect > -1 then
   return A_NowDirect
  endif

  var BtnPush = 0
  var direct = -1

  ' 方向を保持
  case A_Type
    when #B_LUP
      BtnPush = 1 << #B_LUP
      direct = #B_RUP
    when #B_LDOWN
      BtnPush = 1 << #B_LDOWN
      direct = #B_RDOWN
    when #B_LLEFT
      BtnPush = 1 << #B_LLEFT
      direct = #B_RLEFT
    when #B_LRIGHT
      BtnPush = 1 << #B_LRIGHT
      direct = #B_RRIGHT
  endcase

  ' 押されていたら方向を返し押されていなければ-1を返す
  if (B and BtnPush) > O then
    return direct
  else
    direct = -1
    return direct
  endif
end

' ABXYボタン処理
'──────────────────────────
def D_RightButtonProcess A_B, A_Type
  var BtnPush = 0

  case A_Type
    when #B_RUP
      BtnPush = 1 << #B_RUP
    when #B_RDOWN
      BtnPush = 1 << #B_RDOWN
    when #B_RLEFT
      BtnPush = 1 << #B_RLEFT
    when #B_RRIGHT
      BtnPush = 1 << #B_RRIGHT
  endcase

  if (A_B AND BtnPush ) > O then
    D_BtnPressCount A_Type
    if G_BtnPressCount[A_Type] == 1 then
      case A_Type
        when #B_RUP
          case G_SceneFlag
            when 0
              G_SceneFlag = 2
          endcase
        when #B_RDOWN
        when #B_RLEFT
        when #B_RRIGHT
          D_EvCheck 0, SPVAR(0, "Direct")
      endcase
    endif
  else
    if G_BtnPressCount[A_Type] >= 1 then
       G_BtnPressCount[A_Type] = 0
    endif
  endif
end

' ボタンカウント関数
'──────────────────────────
def D_BtnPressCount A_Button
  if G_BtnPressCount[A_Button] < 256 then 
    INC G_BtnPressCount[A_Button]
  endif
end

'──────────────────────────
' ┠─ ▼ スプライト関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' スプライト初期化
'──────────────────────────
def D_SpInitialize A_Id
  ' 戦闘用スプライト定義
  SPDEF "@BattleSP_DEF",2000,0,0

  SPSET A_Id, 500
  SPVAR A_Id, "X", G_EvId[G_SpEvStep * A_Id + 1] * #CSZ
  SPVAR A_Id, "Y", G_EvId[G_SpEvStep * A_Id + 2] * #CSZ
  SPVAR A_Id, "Direct", -1
  SPVAR A_Id, "MoveFlag", 0
  SPVAR A_Id, "EventPage", 0
  SPVAR A_Id, "CLEAR_FLAG", 0
  SPOFS A_Id, SPVAR(A_Id,"X"), SPVAR(A_Id,"Y")

  D_MapArrayReWrite A_Id, SPVAR(A_Id, "Direct"), 1, #LAYER_EV

  if G_EvId[G_SpEvStep * A_Id + 3] != -1 then
    SPANIM A_Id, "I",\
    20,spAnimNo[A_Id],\
    20,spAnimNo[A_Id]+1,\
    20,spAnimNo[A_Id]+2,\
    20,spAnimNo[A_Id]+3,\
    G_EvId[G_SpEvStep * A_Id + 3]
  endif
end

' スプライトの移動
def D_SpriteGridMove A_Id, A_Direct

  if SPVAR(A_Id,"MoveFlag") == 1 then 
    case SPVAR(A_Id,"Direct")
    when #B_RUP
      SPVAR A_Id, "Y", SPVAR(A_Id, "Y") - 1
    when #B_RDOWN
      SPVAR A_Id, "Y", SPVAR(A_Id, "Y") + 1
    when #B_RLEFT
      SPVAR A_Id, "X", SPVAR(A_Id, "X") - 1
    when #B_RRIGHT
      SPVAR A_Id, "X", SPVAR(A_Id, "X") + 1
    endcase

    ' キャラクターの移動
    SPOFS A_Id, SPVAR(A_Id,"X"), SPVAR(A_Id,"Y")

    ' 割った余りが0になったら動きを止める
    if SPVAR(A_Id, "X") MOD #CSZ == 0 && SPVAR(A_Id, "Y") MOD #CSZ == 0 then
      SPVAR A_Id, "MoveFlag", 0
    endif
  else
    if A_Direct >= 0 then
      ' 現在のグリッド座標にアクセスするマップ配列添え字を取得
      var pos = D_GetMapPosition(SPVAR(A_Id, "X"), SPVAR(A_Id, "Y"), 0)
      ' 移動の可否関係なく向きは変更しておく
      SPVAR 0, "Direct", A_ Direct
      ' 向かう先が移動可能かどうかを調べる(MAPレイヤー&イベントレイヤー)
      if D_CheckCollision(pos, SPVAR(A_Id, "Direct")) == #TRUE then
        SPVAR A_Id, "MoveFlag", 1
      endif
    endif
  endif
end


'──────────────────────────
' ┠─ ▼ 衝突判定関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' ドット座標をグリッド座標に変換
def D_GetGridXY(A_XY)
  return A_XY / #CSZ
end

' グリッド座標とレイヤーを与えてマップ配列の値を取得する
def D_GetMapPosition(A_X, A_Y, A_LAYER)
  var gridX = D_GetGridXY(A_X)
  var gridX = D_GetGridXY(A_Y)

  VAR layerNo = (G_BGW * G_BGH) * A_LAYER

  IF A_Y <= 0 then
    return gridX + layerNo
  ELSE
    return gridX +  (GRIX_Y * G_BGW)) + layerNo
  ENDIF

END

' 進む先のグリッドが移動可能かどうかを調べる
DEF D_CheckCollision(A_Pos, A_Direct)
  var sumPos = 0
  var evPos = 0

  sumPos = D_GetMapArrayLayerNo(A_Pos, #LAYER_MAP1) + D_GetGridDirectPoint(A_Direct)
  evPos  = D_GetMapArrayLayerNo(A_Pos, #LAYER_EV) + D_GetGridDirectPoint(A_Direct)

  if G_MapData[sumPos] == 0 then
    if G_MapData[evPos] == 0 then
      return #TRUE
    endif
  endif
  return #FALSE 
END

' 方向定数から1歩前のグリッド座標を得るための値を得る
def D_GetGridDirectPoint(A_Direct)
  var direct = 0
  case A_Direct
    when #B_RUP
      direct = -G_BGW
    when #B_RDOWN
      direct = G_BGW
    when #B_RLEFT
      direct = -1
    when #B_RRIGHT
      direct = 1
  endcase
  return direct
end

' マップ配列添字生成
def D_GetMapArrayLayerNo(A_Pos,A_Layer)
  ' 与えられた位置に対してレイヤーを考慮した配列添字を返す
  return A_Pos + ((G_BGW * G_BGH) * A_Layer)
end

' マップ配列書き換え(レイヤー指定
def D_MapArrayReWrite A_Id, A_Direct, A_Flag, A_Layer
  var pos = D_GetMapPosition(SPVAR(A_Id,"X"), SPVAR(A_Id,"Y), A_Layer)

  if A_Flag == 99 then
      G_MapData[pos] = 0
  elseif A_Flag > 0 then
    if A_Direct >= 0 then
      var afterPos = pos + D_GetGridDirectPoint(A_Direct)
      G_MapData[afterPos] = A_Id
    else
      G_MapData[pos] = A_Id
    endif
  else
    var beforePos = pos - D_GetGridDirectPoint(A_Direct)
    G_MapData[beforePos] = 0
  endif
end

'──────────────────────────
' ┠─ ▼ イベント判定関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' 前方のイベントをチェックする
def D_EvCheck A_Id, A_Direct

  if G_SceneFlag == 0 then
    var pos = D_GetMapPosition(SPVAR(A_Id,"X"), SPVAR(A_Id,"Y"), #LAYER_EV)
    var afterPos = pos + D_GetGridDirectPoint(A_Direct)

    var evId = G_MapData[afterPos]

    D_GetEvData evId
  endif
end

'──────────────────────────
' ┠─ ▼ イベント処理関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
def D_EventScene A_Direct
  if G_EvMsgStopFlag == #FALSE then
    D_ShiftEvData
  else
    D_MsgStopCheck
  endif
end

' イベントキュー処理
'──────────────────────────
def D_ShiftEvData
  var type = SHIFT(G_EvQueue)
  var event = SHIFT(G_EvQueue)
  var reserve = SHIFT(G_EvQueue)

  case type
    when 0
      ' メッセージウィンドウが開いている時に0イベントが来たらフラグをOFFにする
      if G_OpenMsgFlag == #TRUE then
        GCLS
        G_OpenMsgFlag = #FALSE
      endif
    when 1
      if G_OpenMsgFlag == #FALSE then
        D_WindowDraw G_WindowSize[0], G_WindowSize[1], G_WindowSize[2], G_WindowSize[3]
      endif
      D_MessageDraw event, reserve
      G_EvMsgStopFlag = #TRUE
    when 2
      case event
        when 0
          INC G_PlayerStatus[7], reserve
        when 1
          SPVAR 0, "CLEAR_FLAG", 1
        when 2
          BEEP 71
          BGMPLAY 41
          G_SceneFlag = 4
      endcase
    when 3
      if event == 1 then
        SPCHR G_EvIdNow, reserve
      endif
    when 4
      ' バトルシーンに突入
      D_BattleSceneInitialize
      PUSH G_BattleInfoDatas, event
      PUSH G_BattleInfoDatas, reserve
      G_SceneFlag = 3
    when 5
      SPHIDE G_EvIdNow
      D_MapArrayReWrite G_EvIdNow, 0,99, #LAYER_EV
    when 6
      G_BattleBGM = event
    when 10
      ' SEを鳴らす
      BEEP event, reserve
  endcase

  if LEN(G_EvQueue) <= 0 then
    G_SceneFlag = 0
  endif
end

' メッセージ送り待ち
'──────────────────────────
def D_MsgStopCheck
  if G_BtnPressCount[3] == 1 then
    G_EvMsgStopFlag
  endif
endif

' イベントデータ取り出してキューに格納
'──────────────────────────
def D_GetEvData A_Id
  var evCount = 0
  var evData = 0

  if SPVAR(A_Id, "EvPage") == 0 then
    RESTORE "@Event" + FORMAT$("%03D",A_Id)
  elseif SPVAR(A_Id, "EvPage") == 1 then
    RESTORE "@Event" + FORMAT$("%03D",A_Id) + "_1"
  endif
  READ evCount
  for G_I=1 to (evCount * 3)-1
    READ evData
    PUSH G_EvQueue, evData
  next

  if LEN(G_EvQueue) > 0 then
    G_EvIdNow = A_Id
    G_SceneFlag = 1
  endif
end

'──────────────────────────
' ┠─ ▼ メッセージ処理関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' ウィンドウ生成
'──────────────────────────
def D_WindowDraw A_X, A_Y, A_W, A_H
  ' カラー配列を定義
  var WC_Back = RGB(0, 21, 151) ' 背景色
  var WC_Frame = RGB(128,126,129) ' フレーム色
  var WC_Highlight = RGB(255,255,255) ' ハイライト色

  ' 右下を計算
  var EX = A_W + A_X
  var EY = A_H + A_Y

  ' 背景描写(塗りつぶし有り矩形)
  GFILL A_X, A_Y, EX, EY, WC_Back

  ' 矩形フレーム描写(塗りつぶし無し矩形)
  GBOX A_X-1, A_Y-1, EX+1, EY+1, WC_Frame
  GBOX A_X-2, A_Y-2, EX+2, EY+2, WC_Frame
  GBOX A_X-3, A_Y-3, EX+3, EY+3, WC_Frame

  ' ハイライトの角の部分(点)
  GPSET A_X-2, A_Y-2, WC_Highlight
  GPSET A_X-2, EY+2, WC_Highlight
  GPSET EX+2, A_Y-2, WC_Highlight
  GPSET EX+2, EY+2, WC_Highlight

  ' ハイライトとフレームの直線部分
  GLINE A_X-3, A_Y-1, A_X-3, EY+1, WC_Highlight
  GLINE A_X-4, A_Y-1, A_X-4, EY+1, WC_Frame

  GLINE EX+3, A_Y-1, EX+3, EY+1, WC_Highlight
  GLINE EX+4, A_Y-1, EX+4, EY+1, WC_Frame

  GLINE A_X-1, A_Y-3, EX+1, A_Y-3, WC_Highlight
  GLINE A_X-1, A_Y-4, EX+1, A_Y-4, WC_Frame

  GLINE A_X-1, EY+3, EX+1, EY+3, WC_Highlight
  GLINE A_X-1, EY+4, EX+1, EY+4, WC_Frame

  G_OpenMsgFlag = #TRUE
end
' メッセージ描写
'──────────────────────────
def D_MessageDraw A_Ev, A_Re
  case A_Ev
    when 1
      GPUTCHR 85, 155, "プレイヤー"+ G_Message$[0],8,RGB(255,255,255),1
    when 2
      GPUTCHR 85, 165, G_Message$[1]+ G_ItemName$[A_Re] +G_Message$[2],8,RGB(255,255,255),1
    when 3
      GPUTCHR 85, 155, G_Message$[3],8,RGB(255,255,255),1
  endcase
end
'──────────────────────────
' ┠─ ▼ ステータス処理関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' ステータスシーン
def D_StatusScene
  if G_OpenStatusFlag == #FALSE then
    D_StatusWindowDraw
    G_OpenStatusFlag = #TRUE
  else
    if G_BtnPressCount[0] == 1 then
      GCLS
      G_OpenStatusFlag = #FALSE
      G_OpenMsgFlag = #FALSE
      G_SceneFlag = 0
    endif
  endif
end

' ステータスウィンドウ描写
'──────────────────────────
def D_StatusWindowDraw
 ' ウィンドウの描写
  D_WindowDraw G_WindowSize[4], G_WindowSize[5], G_WindowSize[6], G_WindowSize[7]

 ' 実際のステータスの描写
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5,    G_SystemWord$[0]+":"+ STR$(G_PlayerStatus[0]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+10, G_SystemWord$[1]+":"+ STR$(G_PlayerStatus[1])+"/"+STR$(G_PlayerStatus[2]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+20, G_SystemWord$[2]+":"+ STR$(G_PlayerStatus[3]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+30, G_SystemWord$[3]+":"+ STR$(G_PlayerStatus[4]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+40, G_SystemWord$[4]+":"+ STR$(G_PlayerStatus[5]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+50, G_SystemWord$[5]+":"+ STR$(G_PlayerStatus[6])+"/999",8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+60, G_SystemWord$[6]+":"+ STR$(G_PlayerStatus[7]),8,RGB(255,255,255),1
end
'──────────────────────────
' ┠─ ▼ バトル処理関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' バトルシーン
'──────────────────────────
def D_BattleScene
  case G_BattleSceneState
    when 0
      ' 暗転処理
      D_ScreenClear
      D_SceneSpriteHideSwitch
      FADE RGBF(255,0,0,0)
      INC G_BattleSceneState
    when 1
      if FADE() == INT(RGBF(255,0,0,0)) then
        ' バトル準備
        BGMPLAY G_BattleBGM
        D_SelectBattleTroop
        D_BattleBackGroundDraw
        D_BattleSpriteSettings
        D_BattleSpritePlayer
        FADD RGBF(0,0,0,0),120
      else
        if FADE() == 0 then
          INC G_BattleSceneState
        endif
      endif
    when 2
      ' バトル中
      D_BattleEnemeyHpCheck
      if SPVAR(100, "Attack") == -1 then
        D_SpriteDotMove 100, A_Direct
      endif
      D_BattlePlayerColCheck
      D_BattlePlayerAttack A_Direct
      D_BattlePlayerAttackColCheck
    when 3
      ' リザルト準備
      D_BattleRelustSettings
    when 4
      ' リザルト待機
      if G_BtnPressCount[3] == 1 then
        var lvupFlag = D_LvUpChecker()
        if lvupFlag == #TRUE then
          G_BattleSceneState = 5
        else
          G_BattleSceneState = 6
        endif
      endif
    when 5
      ' レベルアップ処理
      D_LvUp
      G_BattleSceneState = 6
    when 6
      if G_BtnPressCount[3] == 1 then
        G_BattleSceneState = 7
        FADE RGBF(255,0,0,0),120
      endif
    when 7
      ' 戦闘終了処理
      if FADE() == INT(RGBF(255,0,0,0)) then
        D_ScreenClear
        D_SceneSpriteHideSwitch
        SPCLR 100,200
        D_MapDraw
        BGMPLAY 0, 24, 50
        FADE RGBF(0,0,0,0),120
      elseif FADE() == 0 then
        G_BatteleBGM = #NORMAL_BATTLE_BGM
        G_SceneFlag = 1
      endif
  endcase
end

' バトルトループの選択
'──────────────────────────
def D_SelectBattleTroop
  var ev = SHIFT(G_BattleInfoDatas)
  var re = SHIFT(G_BattleInfoDatas)
  var enemyLoopCount = 0
  var troopData = 0

  ' reが0の時はトループの最大数を保持する
  if re == 0 then
    RESTORE "@Troop00" + STR$(ev) + "_" + STR$(re)
    var troopCount = 0
    READ troopCount
    re = RND(troopCount) + 1
  endif

  ' トループ情報を配列に書き込む
  RESTORE "@Troop00" + STR$(ev) + "_" + STR$(re)
  READ enemyLoopCount
  for G_I=0 to enemyLoopCount-1
    READ troopData
    PUSH G_BattleEnemyTroop, troopData
  next
end

' バトルスプライトセッティング
'──────────────────────────
def D_BattleSpriteSettings
  SPDEF "@BattleSP_DEF",2000,0,0
  var frame = 10

  for G_I=0 to LEN(G_BattleEnemyTroop)
    var spno = "10"+ STR(G_I+1)
    var spid = 0
    var eid = G_BattleEnemyTroop[G_I]
    spid = G_BattleWalkAnimNo[(eid*4) + 3]

    SPSET VAL(spno), spid, 1
    SPVAR VAL(spno), "STATUS", D_BattleEnemyStatusSetup(eid)
    SPVAR VAL(spno), "ALPHA", 255
    SPCOL VAL(spno)
    SPANIM VAL(spno), "I", frame, spid, frame, spid+1, frame, spid+2, frame, spid+3
    SPOFS VAL(spno), 30,30 + (30*G_I)
  next
end

' バトルエネミーステータス取り出し
'──────────────────────────
def D_BattleEnemyStatusSetup(A_No)
  var stLoop = 5
  DIM status[]
  var i = 0
  var point = A_No-1

  for i = 0 to stLoop-1
    PUSH status,G_BattleEnemyDatas[i + (point*stLoop)]
  next

  return status
end

' バトルシーン背景描写
'──────────────────────────
def D_BattleBackGroundDraw
  ' 所属レイヤー変更
  TLAYER 1,1
  TLAYER 1,2
  TLAYER 1,3

  ' 描写できる範囲を広げる
  TSCREEN 1,16,16,48,30
  TSCREEN 2,16,16,48,30

  ' 背景の描写
  TFILL 3,0,0,24,14, &HE8C9
  ' 背景の色味を変更
  TCOLOR 3, &HFFFF9900

  ' 手前の木の描写
  D_BgTreeDraw 0,0,1
  D_BgTreeDraw 3,0,1
  D_BgTreeDraw 6,0,1
  D_BgTreeDraw 9,0,1
  D_BgTreeDraw 12,0,1
  D_BgTreeDraw 15,0,1
  D_BgTreeDraw 18,0,1
  D_BgTreeDraw 21,0,1
  D_BgTreeDraw 24,0,1

  ' スクリーン1を指定位置ズラす
  SCROLL 1,1,3

  ' 奥の木の描写
  D_BgTreeDraw 0,0,2
  D_BgTreeDraw 4,0,2
  D_BgTreeDraw 6,0,2
  D_BgTreeDraw 9,0,2
  D_BgTreeDraw 13,0,2
  D_BgTreeDraw 15,0,2
  D_BgTreeDraw 18,0,2
  D_BgTreeDraw 22,0,2
  D_BgTreeDraw 24,0,2
  D_BgTreeDraw 26,0,2
  D_BgTreeDraw 28,0,2
  D_BgTreeDraw 32,0,2
  D_BgTreeDraw 34,0,2
  D_BgTreeDraw 36,0,2

  ' スクリーン2を指定位置ズラす
  SCROLL 1,1,3
  ' スクリーン2のスケールを縮小する
  TSCALE 2,0.65,0.65
  ' スクリーン2の明度を少し下げる
  TCOLOR 2, &HFFACACAC
end

' バトルシーン用木描写
'──────────────────────────
def D_BgTreeDraw A_X,A_Y,A_Screen

  TPUT A_Screen,A_X+1,A_Y+0,&HEC93
  TPUT A_Screen,A_X+2,A_Y+0,&HEC94

  TPUT A_Screen,A_X+0,A_Y+1,&HECD3
  TPUT A_Screen,A_X+1,A_Y+1,&HECD4
  TPUT A_Screen,A_X+2,A_Y+1,&HECD5

  TPUT A_Screen,A_X+0,A_Y+2,&HED13
  TPUT A_Screen,A_X+1,A_Y+2,&HED14
  TPUT A_Screen,A_X+2,A_Y+2,&HED15

  TPUT A_Screen,A_X+0,A_Y+3,&HED53
  TPUT A_Screen,A_X+1,A_Y+3,&HED54
  TPUT A_Screen,A_X+2,A_Y+3,&HED55

  TPUT A_Screen,A_X+0,A_Y+4,&HED93
  TPUT A_Screen,A_X+1,A_Y+4,&HED94
  TPUT A_Screen,A_X+2,A_Y+4,&HED95

  TPUT A_Screen,A_X+0,A_Y+5,&HEDD3
  TPUT A_Screen,A_X+1,A_Y+5,&HEDD4
  TPUT A_Screen,A_X+2,A_Y+5,&HEDD5

  TPUT A_Screen,A_X+0,A_Y+6,&HEE13
  TPUT A_Screen,A_X+1,A_Y+6,&HEE14
  TPUT A_Screen,A_X+2,A_Y+6,&HEE15
end

' バトル用プレイヤー定義
'──────────────────────────
def D_BattleSpritePlayer
  var frame = 20
  var x = 350
  var y = 210
  var d = 2

  var spid = G_BattleWalkAnimNo[d]

  SPSET 100, spid, 1
  SPCOL 100
  SPVAR 100, "X", x
  SPVAR 100, "X", y
  SPVAR 100, "Direct", d
  SPVAR 100, "Move", 0
  SPVAR 100, "Attack", -1
  SPVAR 100, "AtkHit", -1
  SPANIM 100, "I", frame, spid,0
  SPOFS 100, x, y

  SPSET 200, 2151, 0
  SPOFS 200, x-32, y

end

' スプライトのドット移動
'──────────────────────────
def D_SpriteDotMove A_Id, A_Direct

  dim b[4] = [\
    1<<#B_LUP,\
    1<<#B_LDOWN,\
    1<<#B_LLEFT,\
    1<<#B_LRIGTH\
  ]

  var dirct = -1
  var d_x = 0, d_y = 0
  var frame = 10
  var spid = G_BattleWalkAnimNo[2]

  ' キャラクターの移動設定
  if (A_Direct and b[0]) != 0 then
    SPVAR A_Id, "Y", SPVAR(A_Id,"Y")-2
    d_y = 1
  elseif (A_Direct and b[1]) != 0 then
    SPVAR A_Id, "Y", SPVAR(A_Id,"Y")+2
    d_y = 2
  endif
  if (A_Direct and b[2]) != 0 then
    SPVAR A_Id, "X", SPVAR(A_Id,"X")-2
    d_x = 4
  elseif (A_Direct and b[0]) != 0 then
    SPVAR A_Id, "X", SPVAR(A_Id,"X")+2
    d_x = 8
  endif

  ' キャラクターの方向決定
  if (d_x + d_y) AND &B1 then
    direct = 0
  endif
  if (d_x + d_y) AND &B10 then
    direct = 1
  endif
  if (d_x + d_y) AND &B100 then
    direct = 2
  endif
  if (d_x + d_y) AND &B1000 then
    direct = 3
  endif

  ' キャラクターの方向保持
  if direct > -1 then
    spid = G_BattleWalkAnimNo[direct]

    if SPVAR(A_Id, "Move") == 0 then
      ' キャラクターの向きアニメーションを変更
      SPANIM A_Id, "I", frame, spid, frame, spid+1, frame, spid+2, frame, spid+3, 0
      SPVAR A_Id, "Direct", direct
      SPVAR A_ID, "Move", 1
    endif
  elseif direct == -1 then
    SPANIM A_Id, "I", frame, G_BattleWalkAnimNo[SPVAR(A_Id, "Direct")], 0
    SPVAR A_Id, "Move", 0
  endif

  ' キャラクターの移動
  SPOFS A_Id, SPVAR(A_Id,"X"), SPVAR(A_Id,"Y")
end


' バトル用プレイヤー攻撃定義
'──────────────────────────
def D_BattlePlayerAttack A_Direct
  var frame = 30
  var anim = 2000
  var sword = 2151
  var swordOFS_X = 0
  var swordOFS_Y = -10
  var swordAway = 16

  ' 攻撃中じゃなければ
  if SPVAR(100, "Attack") == -1 then
    if G_BtnPressCount[3] == 1 then
      BEEP 100, 1200
      case SPVAR(100, "Direct")
        when 0
          SPVAR 100, "Attack", 0
          anim = 2143
          sword = 2148
          swordOFS_Y = -swordAway*1.5
        when 1
          SPVAR 100, "Attack", 1
          anim = 2141
          sword = 2150
          swordOFS_Y = 0
        when 2
          SPVAR 100, "Attack", 2
          anim = 2142
          sword = 2151
          swordOFS_X = -swordAway
        when 3
          SPVAR 100, "Attack", 3
          anim = 2140
          sword = 2149
          swordOFS_X = swordAway
      endcase
      SPANIM 100, "I", frame, anim, 1
      SPSET 200, sword, 1
      SPCOL 200
      SPVAR 200, "Rotate", 125
      SPROT 200, SPVAR(200, "Rotate")
      SPOFS 200, SPVAR(100,"X")+swordOFS_X,SPVAR(100,"Y")+swordOFS_Y
    endif
  else
    ' 攻撃中でアニメが終わったら
    if SPCHK(100) == 0 then
      SPVAR 100, "Attack", -1
      SPVAR 100, "Move", 0
      SPANIM 100, "I", frame, G_BattleWalkAnimNo[SPVAR(100, "Direct")], 0
      SPSET 200, sword, 0
      SPVAR 100,"AtkHit", -1
    else
      if SPVAR(200, "Rotate") > 0 then
        SPVAR 200, "Rotate", SPVAR(200, "Rotate")-30
        SPROT 200, SPVAR(200, "Rotate")
      endif
    endif
  endif
end

' プレイヤーの衝突判定
'──────────────────────────
def D_BattlePlayerColCheck
  SPHITSP(100,101,199)
end

' プレイヤーの攻撃の衝突判定
'──────────────────────────
def D_BattlePlayerAttackColCheck
  var spid = SPHITSP(200,101,199)
  if spid > 100 && spid < 200 then
    if spid != -1 && SPVAR("ALPHA") == 255 then
      if SPVAR(100,"AtkHit") == -1 then

        DIM ary = SPVAR(spid, "STATUS")
        var damage = 0
        var flag = SPVAR(0, "CLEAR_FLAG")

        SPVAR 100,"AtkHit", spid

        if G_EvIdNow != 10 then
          if flag == 1 then
            damage = 10
          endif
        else
          damage = 2
        endif

        if damage > 0 then
          SPCOLOR spid, RGB(255,0,0)
          BEEP 103
          DEC ary[0], damage
          SPVAR spid,"STATUS", ary
        else
          BEEP 98, 500
        endif

        PRINT SPVAR(spid,"STATUS")[0]

      endif
    endif
  endif
end

' エネミーのHP監視
'──────────────────────────
def D_BattleEnemeyHpCheck
  var lp = LEN(G_BattleEnemyTroop)-1
  var enemy = LEN(G_BattleEnemyTroop)-1
  var i = 0
  var e = 101
  for i=0 to lp
    if SPVAR(e+i,"STATUS")[0] <= 0 then
      D_BattleEnemyFadeOut e+i
      if SPVAR(e+1, "ALPHA") <= 0 then
        DEC enemy
      endif
    endif
  next

  if enemy <= 0 then
    BGMSTOP 0, 1
    if BGMCHK == 0 then
      G_BattleSceneState = 3
    endif
  endif
end

' エネミーのHP監視
'──────────────────────────
def D_BattleEnemyFadeOut A_Id
  if SPVAR(A_Id,"ALPHA") > 0 then
    var alpha = SPVAR(A_Id,"ALPHA")
    if alpha == 255 then
      BEEP 13, 80,127
    endif
    DEC alpha, 5
    SPVAR A_Id, "ALPHA", alpha
    SPCOLOR A_Id, RGB(SPVAR(A_Id,"ALPHA"),255,0,0)
  endif
end

' リザルト準備
'──────────────────────────
def D_BattleRelustSettings
  var lp = LEN(G_BattleEnemyTroop)-1
  var i = 0
  var eid = 101
  var exp = 0
  var expSum = 0

  BGMPLAY 5

  ' 経験値合算
  for i=0 to lp
     exp = SPVAR(eid+i, "STATUS")[4]
     INC expSum, exp
  next

  ' プレイヤー経験値反映
  INC G_PlayerStatus[6],expSum

  ' リザルトウィンドウ表示
  D_ResultWindowDraw expSum

  G_BattleSceneState = 4
end

' リザルトウィンドウ描写
'──────────────────────────
def D_ResultWindowDraw A_Exp
 ' ウィンドウの描写
  D_WindowDraw G_WindowSize[8],G_WindowSize[9],G_WindowSize[10],G_WindowSize[11]

  GPUTCHR  G_WindowSize[8]+20,  G_WindowSize[9]+10,    "BATTLE RESULT",16,RGB(255,255,150),1
  GPUTCHR  G_WindowSize[8]+30,  G_WindowSize[9]+5+30,  "かくとく けいけんち:",8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[8]+190, G_WindowSize[9]+5+30,  STR$(A_Exp),8,RGB(255,255,255),1
end

' 4以外の全スクリーンクリア
'──────────────────────────
def D_ScreenClear
  CLS 0
  CLS 1
  CLS 2
  CLS 3
end

'  スプライト表示切替
'──────────────────────────
def D_SceneSpriteHideSwitch
  for G_I=0 to LEN(G_EvId)-1 step G_SpEvStep
    if SPSHOW(G_EvId[G_I]) == 1 then
      SPHIDE(G_EvId[G_I])
    else
      SPSHOW(G_EvId[G_I])
    endif
  next

end

' レベルアップチェック 
'──────────────────────────
D_LvUpChecker()
  var lv = G_PlayerStatus[0]
  var exp = G_PlayerStatus[6]

  if exp >= G_ExpTable[lv] then
    return #TRUE
  else
    return #FALSE
  endif
end

' レベルアップ処理
'──────────────────────────
def D_LvUp
  BEEP 72
  D_PlayerLvUp
  D_WindowDraw G_WindowSize[12],G_WindowSize[13],G_WindowSize[14],G_WindowSize[15]
  GPUTCHR  G_WindowSize[8]+30, G_WindowSize[9]+5+52,  "プレイヤーは レベル "+ STR$(G_PlayerStatus[0])+ "に あがった!",8,RGB(255,255,255),1
end

' プレイヤーステータスアップ
'──────────────────────────
def D_PlayerLvUp
  INC G_PlayerStatus[0]
  INC G_PlayerStatus[2], RND(3) + 5
  INC G_PlayerStatus[3], RND(3) + 1
  INC G_PlayerStatus[4], RND(3) + 1
  INC G_PlayerStatus[5], RND(3) + 1 
end

' ゲームクリアシーン
'──────────────────────────
def D_GameClear
  GPUTCHR  72,100,"CONGRATULATIONS!",16,RGB(255,255,255),1
end