Python Action Roguelite - Prototype
横向きにしてください
この画面は横向きで操作します。
戦闘は停止しているので、回転すると続きから再開します。
自機の射撃行動(decide(snapshot))をPythonで記述します。
何が読めて何を返すのかは、下の「書き方リファレンス」に全部あります。
snapshotsnapshot["time"] 経過秒数
snapshot["player"]["x"] 自機のX座標
snapshot["player"]["y"] 自機のY座標
snapshot["player"]["hp"] 今のHP
snapshot["player"]["maxHp"] 最大HP
snapshot["player"]["level"] 今のレベル
snapshot["player"]["weapons"] 装備中の武器 例: ["shoot", "blast"]
snapshot["player"]["nearbyBullets"] 近くにある敵弾の数
snapshot["player"]["stats"]["attackRange"] 射程
(他に attackPower / attackInterval / bulletSpeed /
bulletCount / moveSpeedMultiplier / maxHp)
snapshot["enemies"] 敵のリスト(0体のこともある)
enemy["id"] 敵の番号。shoot / blast で狙う相手に使う
enemy["x"] 敵のX座標
enemy["y"] 敵のY座標
enemy["hp"] 敵の残りHP
enemy["maxHp"] 敵の最大HP
enemy["radius"] 敵の大きさ
enemy["type"] "chaser" / "swarm" / "shooter" / "boss"
[{"type": "idle"}] 何もしない
[{"type": "shoot", "targetEnemyId": id, "angle": a}] 単体射撃(いつでも使える)
[{"type": "blast", "targetEnemyId": id}] 範囲爆発(装備が必要)
[{"type": "laser", "angle": a}] 貫通ビーム(装備が必要)
[{"type": "intercept"}] 自動迎撃(装備が必要)
[{"type": "snipe", "targetEnemyId": id, "angle": a}] 長距離狙撃(装備が必要)
射程が無く必ず当たる。硬い1体を安全な距離から削る
[{"type": "chain", "targetEnemyId": id}] 連鎖放電(装備が必要)
起点から近い敵へ最大5回飛び移る。1回ごとに威力が下がる
[{"type": "gravity", "x": px, "y": py}] 引力場(装備が必要)
その点へ敵を引き寄せる。ダメージはほぼ無く、集めてから撃つための武器
[{"type": "shield"}] 防御膜(装備が必要)
2秒間、触れた敵弾を消す。intercept は1発ずつ、shield は面で防ぐ
angle(向き・ラジアン) 右 0.0 / 下 1.5708 / 左 3.14159 / 上 -1.5708
リストなので、要素を増やせば1回の判断で同時に撃てる。
未装備の武器を返してもその行動は起きない(shoot で戦う)。
今どれを装備しているかは snapshot["player"]["weapons"] で分かる。
安全のため、このゲームのPythonは入門文法だけに絞ってあります。 「使えない」ものは文法として間違っているわけではなく、ここでは受け付けないというだけです。
+ - * / // % の計算if / elif / else と比較 < > == <= >= !=and / or / not / infor / while / break / continuedef による自作関数(decide 以外も定義できる。下の「5. 自作関数」)[]、辞書 {}、[0] や ["キー"] での取り出しlen abs max ほか。下の「4. 使える関数」に意味と例)print() → 実行された行は左の行番号が青くなります.append() などのメソッド → actions = actions + [新しい要素]import / math.sqrt → 距離は dx * dx + dy * dy のまま比べるdx ** 2(べき乗) → dx * dx[x for x in ...] → for 文f"..."、lambda、class、try / exceptsnapshot.get("enemies") → snapshot["enemies"]
decide(snapshot) は必ず1つ定義し、必ずリストを返します。
敵が0体のときも [{"type": "idle"}] のように何かを返す必要があります。
関数(値) と書くと、その関数が計算した結果の値が返ってきます。
x = len(enemies) のように変数へ入れて使います。
len(リスト)len(enemies) は敵の数。0 と比べれば「敵がいない」の判定になる。abs(数)abs(-3) は 3。左右どちらにずれていても「ずれの大きさ」を比べられる。min(a, b) / max(a, b)min(リスト) でその中の最小・最大になる。sum(リスト)sum(リスト) / len(リスト) で平均が出せる。round(数)round(1.6) は 2、round(1.4) は 1。int(数) / float(数)int は小数点以下を切り捨てて整数に(int(1.9) は 1)。float は小数にする。range(n)for i in range(3): は i が 0, 1, 2 と変わりながら3回繰り返す。enumerate(リスト)for i, enemy in enumerate(enemies): と書くと、i に 0, 1, 2… が、enemy に敵が入る。
bool(値)def)
同じ計算を何度も書く代わりに、def で名前を付けて切り出せます。
decide 自身も def で作った関数で、違いは呼ぶのがゲーム側だという点だけです。
def get_angle(dx, dy): # 名前と、受け取る値(引数)を決める
if abs(dx) >= abs(dy): # 中身は字下げして書く
return 0.0 if dx >= 0 else 3.14159
return 1.5708 if dy >= 0 else -1.5708
def decide(snapshot):
...
angle = get_angle(dx, dy) # 呼ぶと return した値が返ってくる
return [{"type": "shoot", "targetEnemyId": target["id"], "angle": angle}]
return に届かないまま関数が終わると、値は返らず None になります。decide より前に定義しておくと、読む順番とコードの順番が揃って分かりやすくなります。💡 左の行番号をクリック(またはコードにカーソルを置く)と、その行が何をしているかを説明します。
■ 直前の1回で実行された行 ■ エラーが出た行 (書き換えると実行の印は消えます)
改行で自動字下げ / [Tab] インデント / [Shift+Tab] 逆インデント / [Esc] エディタから離脱
Pythonで自機の戦闘ロジックを書き換えて生き延びる
Python: 初期化中...
移動: [W][A][S][D] / 回避: [SPACE] / コード編集: [E]
強化する能力を選択してください(キー [1] [2] [3] または クリック)
BOSS: GLITCH CORE を撃破し、システムを完全復旧しました!