【拡張編1】神経衰弱ゲーム:ブラウザで動くPython実装 Brython
前回、ブラウザ上で動作するPythonであるBrythonを使って、シンプルな神経衰弱ゲームを作成しました。
今回は前回のコードを基にして、もっとブラウザゲームらしくなるように視覚的な遊び効果を加えてみます。
ゲーム制作に際し、フリーアイコン素材サイトICOOON MONOさんの画像を使わせていただいております。
コード解説
今回もjQueryをjqとして使っています。2文字インデントで若干読みにくいかもしれませんが、ご容赦ください。
今回拡張する部分はいくつかあります。
まず、選んだ2つのアイテムが同じ種類だった場合、つまり正解の場合の視覚効果です。
オリジナル版では何もせず、アイテムがそのまま表示されていましたが、拡張版ではアイテムのサイズと透明度をアニメーションを使って変化させています。
アイテムに対するアニメーション効果を実現するため、次のような関数を導入しました。この関数はjQueryのanimateメソッドに受け渡すための可変数の引数群を取ります。
def animate(target, *list_of_args_for_animate):
if isinstance(target, int):
idx = target
q = jq(f'#item li:eq({idx}) img')
else:
q = target
for args in list_of_args_for_animate:
q.animate(*args)
この関数を使い、正解のアイテムに対しては、
animate(idx, ({'zoom':'105%'},50),({'zoom':'40%','opacity':0.3},500))
とします。これは、50ミリ秒かけてアイテム画像をズームアップし、その後500ミリ秒かけてズームダウンしながら透明度を高めていくという意味になります。
もう一つの拡張は、ゲーム開始とゲームクリア時に行われる、アイテムがはてなマークに切り替わる処理です。
前回作ったオリジナル版のゲームでは、アイテム画像とはてなマーク画像を交互に切り替えるという単純な演出でしたが、今回はランダムな順番ではてなマークが現れ、ゲーム盤面をくまなく埋め尽くします。
担当するのは次の関数です(正しくは、この関数の生成する関数fですが…)
def splash():
global ignore_select
ignore_select = True
cur = 0
ptn = list(range(N_ITEM))
shuffle(ptn)
def f():
nonlocal cur
global selected
if selected:
selected.pop()
if selected:
return
if cur < N_ITEM:
close(ptn[cur], ({'zoom':'100%','opacity':1}, 100, f))
cur += 1
else:
reset()
return f
ptnは、はてなマークの出現パタンです。このパタンはrandom.shuffleを使うことにより、毎回ランダムに決まります。
なお、はてなマークを100ミリ秒ずつ順番にズームアップするためには、アニメーション処理が終わってから次のアニメーション処理に移らなければなりません。このため、animateメソッドに適用するための引数を({'zoom':'100%','opacity':1}, 100, f)
とし、100ミリ秒後に自分自身である関数fを呼び出させています。
次回は、今回のコードを基にして、ゲームの内容を拡張してみたいと思います。
以下、今回拡張したコードの全容です。
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/brython-dev/brython/master/www/src/brython.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/brython-dev/brython/master/www/src/brython_stdlib.js"></script>
<script type="text/python">
from browser import window,bind,timer,alert
from random import shuffle
jq = window.jQuery
N_KIND = 8
N_ITEM = N_KIND*2
indexes = list(range(1,N_KIND+1))
indexes += indexes
selected, cleared = None,None
ignore_select = True
for i in range(N_ITEM):
jq('#item').append('<li><img src="/wp/wp-content/uploads/2019/03/icon-128px-hatena.jpeg"></li>');
def reset():
shuffle(indexes)
global cleared,selected,ignore_select
cleared,selected = [],[]
ignore_select = False
#for i in range(N_ITEM):
# close(i)
@bind(jq('#item li'), 'mousedown')
def onSelect(ev):
if ignore_select: return
idx = jq('#item li').index(ev.currentTarget)
if len(selected) < 2 and idx not in selected and idx not in cleared:
selected.append(idx)
open(idx)
if len(selected) == 2:
check()
def open(idx, *list_of_args_for_animate):
turn(True, idx, *list_of_args_for_animate)
def close(idx, *list_of_args_for_animate):
turn(False, idx, *list_of_args_for_animate)
def turn(front, idx, *list_of_args_for_animate):
if front:
img_num = indexes[idx]
img_path = f'/wp/wp-content/uploads/2019/03/icon-128px-{img_num}.jpeg'
else:
img_path = f'/wp/wp-content/uploads/2019/03/icon-128px-hatena.jpeg'
q=jq(f'#item li:eq({idx}) img')
q.attr('src', img_path)
if list_of_args_for_animate:
animate(q, *list_of_args_for_animate)
def animate(target, *list_of_args_for_animate):
if isinstance(target, int):
idx = target
q = jq(f'#item li:eq({idx}) img')
else:
q = target
for args in list_of_args_for_animate:
q.animate(*args)
def close_selected_items():
global selected,ignore_select
close(selected[0])
close(selected[1])
selected = []
ignore_select = False
def splash():
global ignore_select
ignore_select = True
cur = 0
ptn = list(range(N_ITEM))
shuffle(ptn)
def f():
nonlocal cur
global selected
if selected:
selected.pop()
if selected:
return
if cur < N_ITEM:
close(ptn[cur], ({'zoom':'100%','opacity':1}, 100, f))
cur += 1
else:
reset()
return f
def check():
global selected, cleared
if indexes[selected[0]] == indexes[selected[1]]:
complete = len(cleared) == N_ITEM-2
if not complete:
for idx in selected:
animate(idx, ({'zoom':'105%'},50),({'zoom':'40%','opacity':0.3},500))
cleared.extend(selected)
if complete:
args = ({'zoom':'40%','opacity':0.3}, 1000, splash())
for idx in selected: animate(idx, args)
else:
selected = []
else:
ignore_select = True
timer.set_timeout(close_selected_items, 350)
for idx in range(N_ITEM):
animate(idx, ({'zoom':'10%','opacity':0},1))
splash()()
</script>
“【拡張編1】神経衰弱ゲーム:ブラウザで動くPython実装 Brython” に対して1件のコメントがあります。