スワイプ用のコンポーネントの実装が適切でないが…、とりあえずリスト表示まわりを実装した。
アイテムとかの表示ができるようになったので、次はタップして武器を作成できるようにするあたり。 スワイプ用コンポーネントの実装が変なのが気になるんだけど…。
自分で作ったスワイプを実現する仕組みが、ちゃんと動いてないのがわかった。
修正中…。
で、少し見なおしたら修正できたので、次はアイテムのアイコン(のつもりの画像)や、アイテム名を表示するあたりを実装しようと思う。
そこまで実装したら、アイテムがリスト表示された要素をスワイプ操作できるようになるはず。
アイテム閲覧の画面構成をノートに書きだしたので、実装を開始した。
から構成される予定。
これらの動作は、状態遷移で表現せずにボタンが押された時のコールバックで処理してしまおうと思っている。
とりあえず、タブメニューまでが実装できた。
↓ソースコード
https://bitbucket.org/satofumi/dwarf_weapon_shop/src/e1c0225cad59e28bfa8f87fb6399bbf6a2e308db/src/items.lua?at=default
タブメニューの個々の要素はボタンで構成されているので、下記コードをボタンが押された時のコールバックとして登録することで、メニューの排他まわりを実現している。
-- 押下時のコールバックを登録する 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 でアニメーションをどうにかする方法の説明は、下記フォーラムの記事にまとめてあった。
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)
依存関係があるようなアニメーションだと混乱しそうだけど、とりあえずはこれで良いことにしたい。
要は、タップしたら次のシーンに進むあたりを実装します。 実装したいことは
だけです。
そして、これを実装したコードが、以下のようになります。
--! \file --! \brief プロローグの表示 require("name_input") _G.prologue = {} local layer_ = nil local is_tapped_ = false local function update_components() Gui.layers:remove(layer_) layer_ = Layer:new() -- !!! 背景画像 local message = Gui.set_text_label(C.prologue.message) layer_:insert(message) local tap_message = Gui.set_text_label(C.prologue.tap_message) layer_:insert(tap_message) -- tap_message の明滅を指示する -- !!! Gui.layers:push_front(layer_) end prologue["Enter"] = function(state) update_components() is_tapped_ = false -- フェード・イン Gui.screen:fade_in(C.fade_second) end prologue["Execute"] = function(state) if Input:force_redraw() then update_components() end -- tap されたら次のシーンに遷移させる local x, y, up = Input:pointer() if up then Gui.screen:fade_out(C.fade_second) is_tapped_ = true end -- フェードアウトが完了したら次のシーンに遷移させる if is_tapped_ and not Gui.screen:is_fading() then state:change_to(name_input) end end prologue["Exit"] = function(state) Gui.layers:remove(layer_) layer_ = nil end
どこに何を配置する、という画像リソースの場所などの状態は constants.lua に記述してあるので、このコードでは主にロジック的なあたりを表現しています。
「文字列を明滅させるあたりは、どう記述するのが Moai SDK っぽいのか?」は、現在模索中です。 (いずれ実装します。
Moai SDK を利用して、タップゲーを作ろうと思います。
1ヶ月くらい前からメイドさんをテーマにした喫茶店のゲームを作成しているのですが、それの練習という立ち位置で作成していきます。 (この練習版で作ったコードは、そのままメイドさんの方に流用できるはず!
さて、タップゲーと言っても音ゲーとか色々ありますが、ここでは「Cookie Clicker」 風の何かを作りたいと思います。 で、ゲームは周回プレイを前提にしつつ、1周のゲーム時間は1時間くらいになるように調整しようと思います。
ソースコードの管理ページ: https://bitbucket.org/satofumi/dwarf_weapon_shopa
仕様などのドキュメント: http://hyakuren-soft.sakura.ne.jp/dwarf_weapon_shop
いろいろと思い立って、Android のアプリを作ることにしました。
今回の目標は「アプリを作って Google Play で配布すること」です。
まず何を作るかですが、タップした位置に「ガラスが割れたような画像」を配置するだけのアプリにします。
まず BitBucket にプロジェクトを作ります。 プロジェクト名は touch_wareru (タッチ割れる)にしました。 はい、大丈夫です。 センスがないのは自覚しています。
開発プロジェクトは下記アドレスで公開しています。
https://bitbucket.org/satofumi/touch_wareru
開発には Moai SDK を使うことにします。 (Moai SDK は Lua スクリプトでもって Android を含む各種環境で動作するゲームを記述できる SDK です)
で、なんやかんやで実装したのが、以下の Lua スクリプトです。
[lua] --! \file --! \brief タッチ割れる require("strict") require("input") math.randomseed(os.time()) local Screen_width = MOAIEnvironment.horizontalResolution or 640 local Screen_height = MOAIEnvironment.verticalResolution or 480 MOAISim.openWindow("touch wareru", Screen_width, Screen_height) local layer = MOAILayer2D.new() MOAISim.pushRenderPass(layer) local viewport = MOAIViewport.new() viewport:setSize(Screen_width, Screen_height) viewport:setScale(Screen_width, Screen_height) layer:setViewport(viewport) local crack_deck = MOAIGfxQuad2D.new() crack_deck:setTexture("glass.png") crack_deck:setRect(-64, -64, 64, 64) local Max_props = 100 local props = {} local props_size = 0 local function remove_front_prop(props) layer:removeProp(props[1]) table.remove(props, 1) props_size = props_size - 1 end local function push_back_prop(props, prop) layer:insertProp(prop) table.insert(props, prop) props_size = props_size + 1 end local function new_prop(x, y, degree) local prop = MOAIProp2D.new() prop:setDeck(crack_deck) prop:setLoc(layer:wndToWorld(x, y)) prop:setRot(degree, 0) return prop end local function update() while true do -- タップ位置を取得する local is_clicked, x, y = clicked_input() if is_clicked then if props_size >= Max_props then -- 最も古い画像を削除して、メモリ使用量が増え続けないようにする remove_front_prop(props) end -- タップされた位置に、画像を表示する local degree = math.random(0, 360) push_back_prop(props, new_prop(x, y, degree)) end coroutine.yield() end end local thread = MOAIThread.new() thread:run(update) [/lua]
とりあえず、タッチした場所に割れたようなガラスの画像が表示されます。
さて、次は Google Play への登録です。
Google Play の開発者になるには 2,500 円ほど要求されます。 支払ってしまえば問題なしです。
で、Google Play Developer Console の Web ページにログインして、うきうきしながら touch_wareru.apk をアップロードしようとすると signed パッケージにしろっていうエラーが出ましたが、下記サイトを参考になんとかしました。
http://sp.vitalify.jp/archives/?p=587
あとは Google Play にパッケージ情報を書き込んで登録ボタンを押すと、「Google Play に反映されるまで数時間かかるかもよ?」 っていうメッセージが表示されます。 私の場合は 12 時間くらい経過してから反映された気がします。
ともあれ、Moai SDK を使ったアプリ作成から Google Play への登録までができました。
やればできるのが、わかった。
前回の記事 にて Android の実機にウィンドウを表示させるあたりまで作成しました。今回はゲームの状態遷移まわりの実現方法について説明します。
ここでの状態遷移とは「最初のメニュー画面」「ステージ選択画面」といった、大きく切り替わる単位だとします。今回作っているゲームは、選択したステージをクリアできるようにするタイプで、状態遷移の図は下記のようになります。
このような状態と遷移を実現するにあたり、Lua で State_machine クラスと state モジュールを作成します。State_machine クラスと state モジュール、状態の一つである first_menu_state.lua を順に示します。
state_machine.lua
-- 状態遷移の処理 _G.State_machine = {} function State_machine:new () ?? local members = { ????? states_ = {}, ????? current_state_ = nil, ?? } ?? State_machine.__index = State_machine ?? setmetatable(members, State_machine) ?? return members end function State_machine:set_state (state) ?? self.current_state_ = nil ?? self:change_state(state) end function State_machine:change_state (state) ?? if self.current_state_ ~= nil then ????? self.current_state_["Exit"]() ?? end ?? self.current_state_ = state ?? self.current_state_["Enter"]() end function State_machine:execute () ?? if self.current_state_ ~= nil then ????? self.current_state_["Execute"]() ?? end end
state.lua
-- 状態遷移の初期化 module("state", package.seeall) require("state_machine") require("first_menu_state") require("stage_select_state") require("stage_play_state") require("option_state") require("credit_state") local state_machine_ = nil function initialize () ?? state_machine_ = State_machine.new() end function set_state (state) ?? state_machine_:set_state(state) end function start () ?? local thread = MOAIThread.new() ?? local function update_function () ????? while true do ???????? state_machine_:execute() ???????? coroutine.yield() ????? end ?? end ?? thread:run(update_function) end function change_state (state) ?? state_machine_:change_state(state) end
first_menu_state.lua
-- 最初のメニュー _G.First_menu_state = {} First_menu_state["Enter"] = ?? function () -- 画面の作成などのセットアップの処理 -- ... ?? end First_menu_state["Execute"] = ?? function () ????? -- !!! ボタンが押された時の処理とか ?? end First_menu_state["Exit"] = ?? function () -- システムのクリーンアップの処理 -- ... ?? end
このような仕組みについては O’Reilly から出版されている「ゲーム開発者の AI 入門」や「ゲーム AI プログラミング」に詳しく説明してあります。お勧めです。
簡単に説明すると、状態毎に Enter, Execute, Exit という名前に関数を登録しておき、その状態に入ったときに Enter の関数を実行し、状態から出るときに Exit の関数を実行します。また Execute の関数は、その状態にいる間に毎回呼び出されます。この関数を登録しているのが例えば first_menu_state.lua で、実際に状態遷移の処理をしているのが state_machine.lua です。state.lua では、first_menu_state.lua などを読み込む処理をしています。
ここまででゲームの全体的な状態を管理するコードが作成できたので、次回の記事では Moai SDK に慣れるのを兼ねてゲーム起動直後の画面を作成したいと思います。