はじめに
最近、友人とAmongUsで遊ぶことが多い。
プレイヤーの証言を突き合わせ犯人を割り出す本ゲームでは、他のメンバーに見つからないような状況で殺人行為を行う必要があり、かつ、行為に関与していないというアリバイ作りも必要となる。
むずかしい。。どういう行動が最適なのか。。
ということで、本取り組みでは、インポスター(犯人)としてAmangUsで勝つための最適パターンを見つけるため、エージェントモデルの行動シミュレーションを実施してみる。
AmongUsとは
アクションと人狼の要素を組み合わせたオンラインマルチプレイヤーゲーム
ちなみにタイトルの「カフェテリア」とは2枚目の画像のことで、同じ位置に集結した全プレイヤーがゲーム開始と同時に別の場所に移動する。
アプローチ
AmongUsのシミュレーションを行うために以下のことを実施した。
- 画像解析よりプレイマップのエッジの画像を作成
- エッジだけとなったプレイマップの中にエージェントを投入
- 決まった規則のもとエージェントを行動させる
- 行動規則
- 壁にぶつかっていない状態では等速直線運動
- 壁にぶつかったら、ランダムの方向に跳ね返る
- 行動規則
プレイマップ
img_org = cv2.imread('../data/the_skeld.PNG')
# 画像内にエージェント(〇)を描写する
def move_agent(x, y, img, agent_size=30):
radius = int(agent_size/2)
img_move_agent = cv2.circle(img, (x,y), radius, (255,255,255), thickness=-1)
return img_move_agent
# 行動開始地点の選択
def choice_start_position(xrange=(1000, 1250), yrange=(500, 600)):
x = np.random.choice(np.arange(xrange[0], xrange[1],1))
y = np.random.choice(np.arange(yrange[0], yrange[1],1))
return x, y
# 進行方向の選択
def choice_direction(directions=[1,2,3,4,6,7,8,9]):
return np.random.choice(directions)
# エージェントの座標を動かす
def move(x, y, direction, step=1):
if direction == 1:
x += -step
y += step
elif direction == 2:
x += 0
y += step
elif direction == 3:
x += step
y += step
elif direction == 4:
x += -step
y += 0
elif direction == 6:
x += step
y += 0
elif direction == 7:
x += -step
y += -step
elif direction == 8:
x += 0
y += -step
elif direction == 9:
x += step
y += -step
return x, y
# 壁にぶつかった際に進行できる方向を探る
def free_space_search(x, y, img):
free_direction = list()
xkernel = [x-1, x, x+1, x-1, x+1, x-1, x, x+1]
ykernel = [y+1, y+1, y+1, y, y, y-1, y-1, y-1]
kernel = [(xk, yk) for (xk,yk) in zip(xkernel, ykernel)]
direction_code = dict(zip(kernel,[1,2,3,4,6,7,8,9]))
for (xk, yk) in zip(xkernel, ykernel):
pixel = img[yk,xk]
if pixel == 0:
free_direction.append(direction_code[(xk, yk)])
return np.random.choice(free_direction)
img_path = '../data/the_skeld.PNG'
if __name__ == '__main__':
loop_n = 5000
write_path = '../data/move_agent1/'
x, y = choice_start_position()
direction = choice_direction()
for i in range(loop_n):
img_org = cv2.imread(img_path,0)
threshold = 200
ret, img_thresh = cv2.threshold(img_org, threshold, 255, cv2.THRESH_BINARY)
kernel = np.ones((10, 10), np.uint8)
closing = cv2.morphologyEx(img_thresh, cv2.MORPH_CLOSE, kernel)
img = closing.copy()
x_next, y_next = move(x, y, direction)
x, y = x_next, y_next
img_move_agent = move_agent(x, y, img)
#if np.max(img_org[y-10:y+10, x-10:x+10]) == 255:
if img_org[y, x] == 255:
direction = free_space_search(x, y, img_org)
i_str = '{0:04}'.format(i)
img_move = move_agent(x, y, img)
cv2.imwrite(write_path + 'move%s.png'%i_str, img_move)
画像を連結しmp4として保存
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
video = cv2.VideoWriter('video.mp4',fourcc, 20.0,(320,240))
filenames = glob.glob('../data/move_agent1/*')
for filename in filenames:
img = cv2.imread(filename)
img_text = img.copy()
img_text = cv2.resize(img_text, (320,240))
if img is None:
print("can't read")
break
video.write(img_text)
video.release()
結果
直進するだけでは、何の検証にもならない。。。ゲームがはじまらない(カフェテリアからでない)
次のステップは、エージェントにカフェテリアの出口を認識させて、そこに向かわせることですかね。
まとめ
- AmongUsでのエージェントモデルの行動シミュレーションを試してみた。
- 直進運動をするエージェントは、カフェテリアから出ず、ゲームが開始しなかった。
- が、なんとかこのエージェント君に出口を認識させたいという、新たな目標ができた。
深層学習を用いたエージェント学習など、勉強の幅が広がりそうな予感!
以上です。