「ゲーム」カテゴリーアーカイブ

電子の動きを制御するゲームの作成 (その1)

知人の提案で「電子を電場や磁場を配置してゴールに移動させるゲーム」を作っていました。 そのゲームがある程度は動作するようになったので、紹介と今後の予定を書き出します。

とりあえず、Android 版の apk は以下にあります。 (正式リリースまでは配布します)
https://dl.dropboxusercontent.com/u/90960441/electric_playfield-debug.apk

ゲームの概要

  • オレンジ色のブロックから電子が発射されるので、それを青色のゴールに導くのがゲームの目的です。
  • 画面下にあるボタンからドラッグして電極を配置すると、電場が変化します。 電子は電場から力を受けるので、電子の移動軌跡が変化します。
    • 電極は正、負の2つの種類が配置できます。

2015-02-17 14.45.01

  • 電場と同じように、範囲が円で示される磁場を配置することができます。 電子は磁場の範囲内ではフレミング左手の法則に基づいて力を受け、円弧軌跡を描きます。
    • 磁場には手前向き、奥向きの2つの種類が配置できます。

2015-02-17 14.46.23

  • ここまでに説明してきたステージは、ステージ選択の画面から遷移します。

2015-02-17 14.43.17

リリースするためにやること

最低限の動作は実装したので、Google Play へのリリースを目標に「やるべきこと」を以下に書き出してみます。

  • ステージをクリアできるか評価するボタンが表示されたときに、それを押したくなるようなエフェクトを追加する。
    • ボタンの外枠の色が明滅するとか。
  • ステージのクリア条件(電子のゴール率)を満たした時に、エフェクトを表示して結果を通知する。
    • 「電子が 100 % ゴール! スター3つ獲得!」というメッセージ表示と、「ゲームに戻る」「次のステージに進む」というボタンの表示など。
  • 電子を青いブロックに突入させたらステージクリアです、という情報を明示する。
  • 電極、磁場の効果を説明する方法を提供する。
    • ヒントボタンを押すと説明画像が表示されるとか。
  • ステージ選択画面で、既にクリアしたステージがわかるようにする。
    • ステージに取得したスターを表示するとか。
    • クリア時の電子の移動軌跡を描画するとか。
  • 配置できる電極、磁場の個数をステージ毎に制限できるようにする。
  • 電子が滞在し続ける電極配置だと、存在する電子が増え続けてしまうのに対処する。
    • ある数以上の電子が既に存在する場合、新規に電子を射出しないようにする。
  • 評価時に Android で処理落ちする理由を調べて修正する。
  • 音楽、効果音を付ける。
  • ボタンなどの画像を作りなおす。
  • エフェクト画像、エフェクトを作りなおす。
  • ステージの切り替わりにフェード効果を適用する。
  • ステージエディタを作成する。
  • ステージを追加する。
  • 複数の電場の射出ができるようにする。
  • iOS 版をビルドして動作確認する。

くらいでしょうか。

今後の予定

書きだした Todo をに優先順位を付けて、どこまで実装したらリリースするかを決める予定です。

moaicli の config について

moaicli を使うと config/config.yml に Moai SDK で設定できるオプションが列挙されます。
その中の modules が何かを調べたので、メモとして記しておく。

モジュール

  • Box2D … 2D の物理演算ライブラリ。
  • Chipmunk … 2D の物理演算ライブラリ。
  • curl … データを転送するライブラリ。 HTTP アクセスとかに使う。
  • crypto … 暗号ライブラリ。
  • Expat … XLM パーサーライブラリ。
  • FreeType … フォントエンジンを実装したライブラリ。
  • HttpClient … HTTP アクセスに使う。
  • JSON
  • JPEG
  • LuaExt … わからない。
  • Mongoose … MongoDB アクセス用のライブラリ。
  • Ogg
  • OpenSSL
  • SQLite3
  • TinyXml
  • PNG
  • SFMT … 擬似乱数ライブラリ。
  • Vorbis … Ogg の圧縮部分のライブラリ。
  • Untz … 音楽再生ライブラリ。’
  • LuaJit … Jit コンパイラ。

拡張

ほとんどが広告とか課金用の何か。

  • miscellaneous
  • adcolony … 動画広告の配信用。
  • billing
  • chartboost
  • crittercism
  • facebook
  • push
  • tapjoy
  • twitter
  • tstorewall
  • tstoregamecenter

作ったボードゲームで遊んでみての反省

  • モンスターとの戦闘のたびにダイスを振るのが面倒。
  • 戦闘でダイスを振った時に、負けたらくやしい。
  • 成長要素が線形な伸びだったので、後半の逆転とかなくてつまらない。

とかだった。
で、参考にと 3DS 版のカルドセプトを勧められたので遊んでみた。 さすがに面白かった。
ただ、カルドセプトで遊んで気になった点は「勝つためのデッキ見直しの方法がよくわからない」ということかな。 あとは、1プレイに 30 分くらいかかるのもちょっと…。

とりあえず、面白いものを作るにはちゃんと考える必要があるのがわかった。

ボードゲームのネット対戦用に Tabletop Simulator を買って使ってみた

ここではボードゲーム用のシミュレータ Tabletop Simulator を使ってみた感想とか、その過程でやったプログラミングを紹介します。

注意、Tabletop Simulator は売りもので Steam で 1,480 円です。
(改めて書き出してみると、けっこう高いな! この記事を書くモチベーションが…。
Steam のページ: http://store.steampowered.com/app/286160/?l=japanese
開発元のページ: http://www.berserk-games.com/ts/

Tabletop Simulator がどういうソフトウェアかを簡単に紹介すると「ボードゲームやカードゲームをネットワーク越しにできる」「自分が作ったカードデータも取り込める」というソフトウェアです。 というか詳しい紹介については http://tukedai.minibird.jp/blog/?p=168 のページが大変よくまとまっています。

この記事では、Tabletop Simulator 用に

  • カードデータを yaml で定義して作成するスクリプトを作成した。
  • カードを配置するボードも同様に作成した。
  • ボードの大きさを save データを修正して変更した。

という項目を記述します。

 

カードデータを yaml で定義して作成するスクリプトを作成した

Tabletop Simulator ではカードを作るためには、カードの裏の画像と表の画像を取り込む必要があります。 最終的には、このような画像を作成します。

item_card_back
カード裏の画像
item_cards
カード表の画像

カード表の画像が縮小されてて少しわかりにくいですが、カードの画像を作り、それを必要な枚数だけ並べています。? この画像を作る手順を簡単に記述すると

  1. ダミー文字を配置したテンプレートを svg ファイルで作成する。
  2. svg ファイルの文字列を置換した svg ファイルを作って inkscape で png 画像を作る。
  3. 作った png 画像を ImageMagic で指定した位置にコピーしていく。

となります。

用意したテンプレートを svg で作ったのは、フォーマットが文字列なので置換しやすそうだったからです。

用意したテンプレートファイル
https://bitbucket.org/satofumi/dungeon_sugoroku/src/default/item_card/item_template.svg

後はアイテム情報を列挙した yaml ファイルをスクリプトで読み込み、テンプレートファイルに個別に流しこんで svg ファイルを作れば、それを inkscape コマンドで png 画像が作成できます。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys, subprocess, yaml, codecs, copy


def print_help(program_name):
    print "usage:\n python " + program_name + " <yaml file> <template svg>"

if len(sys.argv) < 3:
    print_help(sys.argv[0])
    sys.exit(1)

yaml_file = sys.argv[1]
template_svg_file = sys.argv[2]


# 文字列を置換した SVG ファイルから png 画像を生成する
template_svg = open(template_svg_file).read().decode('utf-8')

for data in yaml.load_all(open(yaml_file)):
    for item in data:
        dest = copy.deepcopy(template_svg)
        name = item['name']
        output_file = name + '.png'

        # 各パラメータの置換
        dest = dest.replace('#name', name)
        dest = dest.replace('#type', item['type'] or '')
        dest = dest.replace('#cost', str(item.get('cost')))
        dest = dest.replace('#text1', item['text1'] or '')
        dest = dest.replace('#text2', item['text2'] or '')
        #dest = dest.replace('#flavor', item['flavor'])
        #dest = dest.replace('#image', item['image'])

        dest = dest.replace('#hp', str(item.get('hp') or ''))
        dest = dest.replace('#atk', str(item.get('atk') or ''))
        dest = dest.replace('#items', str(item.get('items') or ''))
        dest = dest.replace('#exp', str(item.get('exp') or ''))
        dest = dest.replace('#score', str(item.get('score') or 0))

        # ファイルを出力して画像を生成する
        f = codecs.open('out.svg', 'w', 'utf-8')
        f.write(dest)
        f.close()
        cmd = 'inkscape -z -e ' + output_file + ' -w 406 -h 584 ' + 'out.svg'
        subprocess.call(cmd, shell=True)


cmd = 'rm out.svg'
subprocess.call(cmd, shell=True)
?

(改めて見ると小汚いコードだな…。 いずれ直そう。

で、このスクリプトを実行すると yaml で定義したぶんの画像ができるので、次に別のスクリプトで Tabletop Simulator が読み込める画像を作ります。 そのスクリプトはこんな感じです。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys, subprocess, yaml


def print_help(program_name):
    print "usage:\n python " + program_name + " <yaml file> <output file>"

if len(sys.argv) < 3:
    print_help(sys.argv[0])
    sys.exit(1)

yaml_file = sys.argv[1]
cards_template_file = sys.argv[2]


def card_position(index):
    x = index % 10
    y = index / 10
    return (406 + 3) * x, (584 + 3) * y

def add_card_image(dest_image_file, card_image_file, x, y):
    cmd = 'convert ' + dest_image_file + ' ' + card_image_file + ' -gravity northwest -geometry ' + '+' + str(x) + '+' + str(y) + ' -composite out.jpg'
    subprocess.call(cmd, shell=True)

    cmd = 'mv out.jpg ' + dest_image_file
    subprocess.call(cmd, shell=True)

# yaml ファイルから名前と枚数を読み込み、順に配置する
total_index = 0
for data in yaml.load_all(open(yaml_file)):
    for item in data:
        card_image_file = item['name'] + '.png'
        print 'add ' + card_image_file
        number = item.get('number') or 1
        for i in range(0, number):
            x, y = card_position(total_index)
            total_index += 1
            add_card_image(cards_template_file, card_image_file, x, y)

 

(なんだろな、この「とりあえず作りました」的なコードは…。 いや、とりあえずで作ったんだけど。

カードを配置するボードも同様に作成した

ゲームのキャラクター毎に個別のカード置き場を作る必要があったので、同様にボード用の svg テンプレートファイルを定義して文字列を置換しました。

ボードの大きさを save データを修正して変更した

で、ここまでやって実際に Tabletop Simulator に画像を取り込んでみたのですが、ボードは大きすぎたので、保存データの JSON ファイル中の Scale を 1.0 から 0.5 に変更してサイズを小さくしました。 保存データは My Document / My Games / Tabletop Simulator / Saves 以下にあります。

2014-12-29_00002
変更前のスナップショット

ボードはこんなに大きくなくていい…。

2014-12-29_00001
変更後のスナップショット

(使わないパネルは、DEL キーで削除してもオッケーです。

あと、追記

◇取り込んだ画像はキャッシュされるので、「なんでリンク先の画像を変更したのに表示内容が変わらないんじゃい!」って思ったら My Document / My Games / Tabletop Simulator / Mods / Images 以下のファイルを削除してみましょう。

◇Tabletop Simulator は自作ゲームをネットワーク越しに遊んで評価するために購入したけど、結局まだネットワーク越しではゲームしてないです。 あと、ぶっちゃけるとマウス越しのコマとかの操作は面倒です。

◇自作ゲームを自分で何度かプレイしてみたけど、あんまり面白くなかった…。

自作ゲームのプロジェクト: https://bitbucket.org/satofumi/dungeon_sugoroku/wiki/Home
(Tabletop Simulator 用の保存データがダウンロードできます。

 

Moai SDK でタップゲーを作る (スワイプ用のコンポーネントが変…

自分で作ったスワイプを実現する仕組みが、ちゃんと動いてないのがわかった。
修正中…。

で、少し見なおしたら修正できたので、次はアイテムのアイコン(のつもりの画像)や、アイテム名を表示するあたりを実装しようと思う。
そこまで実装したら、アイテムがリスト表示された要素をスワイプ操作できるようになるはず。

Moai SDK で作るタップゲー (画面内の表示を切り替えるタブメニューの配置

アイテム閲覧の画面構成をノートに書きだしたので、実装を開始した。

  • どの種類のアイテムを閲覧するのかを選ぶタブメニュー
  • アイテムがリスト表示されたスワイプできる領域
  • アイテムをタップしたときの詳細表示

から構成される予定。
これらの動作は、状態遷移で表現せずにボタンが押された時のコールバックで処理してしまおうと思っている。

とりあえず、タブメニューまでが実装できた。
↓ソースコード
https://bitbucket.org/satofumi/dwarf_weapon_shop/src/e1c0225cad59e28bfa8f87fb6399bbf6a2e308db/src/items.lua?at=default

dwarf_items_2014_1008

タブメニューの個々の要素はボタンで構成されているので、下記コードをボタンが押された時のコールバックとして登録することで、メニューの排他まわりを実現している。

-- 押下時のコールバックを登録する
local function decided_callback(button_self)
   -- 押下を排他にする
   for _, button in pairs(button_) do
      if button_self ~= button then
         button:set_normal()
      end
   end

   -- スクロールエリアを切り替える
   -- !!!
end

実装に思っていたよりも時間がかかってしまうのは、ぶっちゃけ辛いけど頑張ろうと思う。

 

Moai SDK で作るタップゲー (ゲーム情報の配置

シーンを切り替えるボタンの配置が終わったので、ゲームの情報を表示させてみた。

dwarf_2014_1006_2

装飾が全然ないけど、とりあえずはこれで良いことにする。
次は、アイテムなんかの内部のデータ表現をどうするか、とかを決めてしまいたい。
そうしたら、アイテムを閲覧するシーンの実装ができるようになる。

Moai SDK で作るタップゲー (ボタンの作成と画面の切り替え

とりあえずシーンを遷移するためのボタン(白色の画素とも言う)を配置て、ボタンを押したらそのシーンへの遷移も行われるようにした。

dwarf_2014_1006

ソースコード
https://bitbucket.org/satofumi/dwarf_weapon_shop/src/47f005ad6caf3b477855629de1fc1ceade7dbbe4/src/workshop.lua?at=default

さて、ゲームっぽいあたりの実装は、これからだ!

Moai SDK で作るタップゲー (文字を明滅させるあたり

Moai SDK でアニメーションをどうにかする方法の説明は、下記フォーラムの記事にまとめてあった。

http://getmoai.com/wiki/index.php?title=Moai_SDK_Basics_Part_Two

私にとって直感的だったのは、コルーチン内でアニメーションの指示と待機を繰り返す、という方法だったので、そういうコードで文字を明滅させるようにした。

-- tap_message の明滅を指示する
local function blink_text()
   while true do
      tap_message:set_color(Colors.white, C.blink_second)
      Gui:wait(tap_message)

      tap_message:set_color(Colors.black, C.blink_second)
      Gui:wait(tap_message)
   end
end
blink_message_task_ = MOAICoroutine:new()
blink_message_task_:run(blink_text)

依存関係があるようなアニメーションだと混乱しそうだけど、とりあえずはこれで良いことにしたい。