【拡張編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件のコメントがあります。

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

    このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください