コンテンツにスキップ

はね返りで撃つ

まっすぐには見えない敵に、壁ではね返らせて弾を届かせます。

上の壁をだと思います。敵を、鏡のむこうに映します。 映った敵(鏡像)をまっすぐ狙うと、弾は壁で折れ曲がって、本物の敵に届きます。

上の壁の面は y = 1.0 にあります。横の壁なら x を折り返します。

pmirror=(xenemy, 2wyenemy)(w=1.0)\mathbf{p}_{\text{mirror}} = (\,x_{\text{enemy}},\ 2w - y_{\text{enemy}}\,) \qquad (w = 1.0)

くわしい説明と図は跳弾のしくみにあります。

Python で書く(そのまま動く bot)

Section titled “Python で書く(そのまま動く bot)”
上の壁で、1 回はね返らせる
def update(state):
me = state.me
en = state.enemy
grid = state.map.grid
# まっすぐ見えるなら、ふつうに撃つ
if line_of_sight(grid, me.x, me.y, en.x, en.y):
want = angle_to(me.x, me.y, en.x, en.y)
合っている = abs(angle_diff(want, me.angle)) < 3
return {"drive": "stop", "steer": want, "fire": 合っている, "barrier": False}
# 見えないとき:上の壁(y = 1.0)を鏡にして、敵の鏡像をねらう
mx = en.x
my = 2 * 1.0 - en.y
# 自分 → 鏡像 の線が、壁 y = 1.0 と交わる点(はね返る場所)
t = (me.y - 1.0) / (me.y - my)
px = me.x + (mx - me.x) * t
py = 1.5 # 壁のすぐ手前(マスの中)で調べる
# 2 本の線が、どちらも通っているときだけ撃つ
通る = line_of_sight(grid, me.x, me.y, px, py) and line_of_sight(grid, px, py, en.x, en.y)
want = angle_to(me.x, me.y, mx, my)
合っている = abs(angle_diff(want, me.angle)) < 3
return {"drive": "stop", "steer": want, "fire": 通る and 合っている, "barrier": False}
  1. 見えるなら、ふつうに撃ちます。 はね返りは、まっすぐ届かないときの手段です
  2. 見えないときは、敵の鏡像 (mx, my) を計算します
  3. はね返る場所 (px, py) を出します
  4. 2 本の線(自分 → 反射点、反射点 → 敵)を line_of_sight で調べて、どちらも通るときだけ撃ちます

広場の真ん中に縦の鉄の壁(x = 9 の列、y = 313)を立てて、そのむこう(x = 15)にいる止まっている敵を撃たせました。

撃った弾結果
この bot(上の壁で 1 回はね返らせる)5 発3 発が敵に当たった(敵は倒れた)
敵のほうを向く(そのまま撃つ)4 発敵には 0 発。はね返った弾が自分に 3 発当たって、負けた
  • 下の壁(y = 14.0)や、横の壁(x = 1.0x = 19.0)でも、同じ考えかたで書けます。式の 2 * 1.0 の部分を、壁の位置に変えます
  • 「はね返りがうまくいく場面」を、試合画面を 1 コマずつ見て探してみましょう
  • 当たらない。 敵は動いています。鏡像も、先まわりした位置(predict_lead)にできるでしょうか
  • 自爆する。 壁に近すぎる位置から撃っていませんか