satofumi のすべての投稿

Moai SDK で作るタップゲー (プロローグ画面の作成)

要は、タップしたら次のシーンに進むあたりを実装します。 実装したいことは

  • プロローグのメッセージと “Tap to Start” っていう文字列の表示。 “Tap to Start” の方は明滅させたい。
  • スクリーンがタップされたら次の状態に進ませる。

だけです。
そして、これを実装したコードが、以下のようになります。

--! \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

dwarf_prologue_2014_1003

どこに何を配置する、という画像リソースの場所などの状態は constants.lua に記述してあるので、このコードでは主にロジック的なあたりを表現しています。

「文字列を明滅させるあたりは、どう記述するのが Moai SDK っぽいのか?」は、現在模索中です。 (いずれ実装します。

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 のアプリを作ってリリースしてみる

いろいろと思い立って、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]

とりあえず、タッチした場所に割れたようなガラスの画像が表示されます。

touch_wareru_screenshot

さて、次は 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 への登録までができました。
やればできるのが、わかった。

 

Mac の Homebrew を使った実行ファイルのリリーステスト

まず、Homebrew で作った app ファイルをリリースしようとしたときに、自分の Mac では動作するのに、渡した人の Mac では動作しない、という問題に遭遇しました。
これは OpenCV を使っていて、libopencv_highgui.2.4.8.dylib が libopencv_core.2.4.dylib を利用していて、そのあたりの依存関係を install_name_tool で変更してなかった! というのが原因でした。

最初は

$ brew unlink opencv

で opencv を無効にしていたのですが、これだとリリース用のフォルダにある libopencv_highgui.2.4.8.dylib が直接 /usr/local/Cellar/opencv/2.4.8.2/lib/libopencv_core.2.4.dylib に依存していたのを、自分の Mac では検出できません。
(unlink は Cellar と /usr/local/ とのシンボリックリンクを削除)

それで、思いついたのが以下の方法です!

$ cd /usr/local/
$ mv Cellar Cellar_orig

我ながら「強引だな!」と思います。
で、この方法でリリース用フォルダのプログラムが実行できることを確認したら、忘れずに以下のコマンドで Cellar を元に戻します。

$ mv Cellar_orig Cellar

まぁ、そもそもコマンドラインでビルドしてリリースするのが良くないんじゃないかな、とは思っています。(コマンドラインでなく XCode を使うとか?

悩ましいです…。

Qt で Windows のタスクバーにアプリ名を表示させないようにする

Qt でマスコット系のアプリを作っていると、タスクバーにアプリ名が表示されるのを抑制したいことがあります。(抑制すると Alt-Tab を押したときにも表示されなくなる) そういう場合、単に

#if defined(Q_OS_WIN)
    WId wid = winId();
    LONG style = GetWindowLong(wid, GWL_EXSTYLE);
    SetWindowLong(wid, GWL_EXSTYLE, style | WS_EX_TOOLWINDOW);
#endif

を追記してもよいのですが QWidget::setWindowFlags() が SetWindowLong() を呼び出しているせいか、設定がうまく反映されなかったりしました。

仕方がないので、タスクバーへのアプリ名表示を抑制する Widget クラスに(例えば Balloon_widget) の setWindowFlags() をオーバーライドして、以下のようにしました。

void Balloon_widget::setWindowFlags(Qt::WindowFlags flags)
{
    QWidget::setWindowFlags(flags);
#if defined(Q_OS_WIN)
    WId wid = winId();
    LONG style = GetWindowLong(wid, GWL_EXSTYLE);
    SetWindowLong(wid, GWL_EXSTYLE, style | WS_EX_TOOLWINDOW);
#endif
}

親クラスのメソッドを呼び出してから、setWindowLong() を呼び出すようにしただけですが、こんな感じでうまくいきます。

Moai SDK でゲームを作ろう (状態遷移の処理について)

前回の記事 にて Android の実機にウィンドウを表示させるあたりまで作成しました。今回はゲームの状態遷移まわりの実現方法について説明します。

ゲームの状態遷移

ここでの状態遷移とは「最初のメニュー画面」「ステージ選択画面」といった、大きく切り替わる単位だとします。今回作っているゲームは、選択したステージをクリアできるようにするタイプで、状態遷移の図は下記のようになります。

dot_inline_dotgraph_1

このような状態と遷移を実現するにあたり、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 に慣れるのを兼ねてゲーム起動直後の画面を作成したいと思います。

Moai SDK でゲームを作ろう(画面の作成まで)

それでは、画面の作成までの準備です。ここまでに Moai SDK で moai-dev/ant/untitled-host ディレクトリが作成されており、実行できるプロジェクトがあるとします。

バージョン管理の開始

まず、moai-dev から必要なファイルだけをコピーしましょう。Android で実行する場合、untitled-host/build/project フォルダがあれば動作できるので、このフォルダを別の場所にコピーしてバージョン管理の対象とします。project というディレクトリ名は自由に変更して問題ありません。また、作成中のプログラムをホスト環境で実行するために moai-dev/cmake/moai/moai バイナリを(例えば) $(HOME)/bin などにコピーします。
以降は、主に project/assets/lua/ 以下の Lua スクリプトを編集します。

アプリ名、アイコンの変更

Android で実行したときのアプリ名は project/res/values/strings.xml で管理されています。このファイルの app_name には、日本語も O.K. です。

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">ずん子と封印の城</string>
</resources>

次にアイコンですが、これは project/res/drawable-* の各ディレクトリに、それぞれの大きさの icon.png という名前の PNG 画像を作成して配置すれば変更できます。

  • drawable-ldpi … 36 x 36
  • drawable-mdpi … 48 x 48
  • drawable-hdpi … 72 x 72
  • drawable-xhdpi … 96 x 96

zunko_icon_2014_0105

resource/icon.png という 96×96 のファイルを用意し、それを ImageMagic を使って縮小しながら ref ディレクトリに配置する Makefile は、例えば以下のようになります。

image.png (96×96) を縮小しながらコピーする Makefile

RES_DIR = ../source/res

all : icons
clean :

icons : \
??? $(RES_DIR)/drawable-ldpi/icon.png \
??? $(RES_DIR)/drawable-mdpi/icon.png \
??? $(RES_DIR)/drawable-hdpi/icon.png \
??? $(RES_DIR)/drawable-xhdpi/icon.png \

$(RES_DIR)/drawable-ldpi/icon.png : icon.png
??? convert -geometry 36x36 icon.png $@

$(RES_DIR)/drawable-mdpi/icon.png : icon.png
??? convert -geometry 48x48 icon.png $@

$(RES_DIR)/drawable-hdpi/icon.png : icon.png
??? convert -geometry 72x72 icon.png $@

$(RES_DIR)/drawable-xhdpi/icon.png : icon.png
??? cp $< $@

ウィンドウの作成

画面のアスペクト比が異なる場合を考慮したコードにします。実機デバイスの画面の解像度は MOAIEnvironment.horizontalResolution と MOAIEnvironment.verticalResolution で取得しています。

画面解像度についての Moai フォーラム
http://getmoai.com/forums/get-screen-resolution-sdk-1-2-t894/

ウィンドウを作成するコード例

-- 画面の初期化
function initialize_screen ()
   local screen_width = MOAIEnvironment.horizontalResolution or World_width
   local screen_height = MOAIEnvironment.verticalResolution or World_height
   MOAISim.openWindow ( "Zunko Castle", screen_width, screen_height )

   -- アスペクト比が異なるデバイスへの対応
   local world_aspect = World_width / World_height
   local screen_aspect = screen_width / screen_height
   local view_width, view_height
   if screen_aspect > world_aspect then
      view_height = screen_height
      view_width = world_aspect * view_height
   else
      view_width = screen_width;
      view_height = view_width / world_aspect
   end
   local view_offset_x = 0
   if view_width < screen_width then
      view_offset_x = (screen_width - view_width) / 2
   end
   local view_offset_y = 0
   if view_height < screen_height then
      view_offset_y = (screen_height - view_height) / 2
   end

   -- ビューの作成
   local viewport = MOAIViewport.new ()
   viewport:setSize ( view_width, view_height )
   viewport:setOffset ( view_offset_x, view_offset_y )
   viewport:setScale ( World_width, -World_height )
   return viewport
end

このコード中の World_width, World_height は config.lua の中で定義したものを利用しています。

デバッグメッセージの確認

追記ですが、Eclipse を使ってコードを実機で実行する場合 Eclipse の LogCat に Lua コード中に記述した print() の内容が出力されるようになっています。簡単なデバッグメッセージの確認には LogCat が便利です。
(私は Eclipse はあまり使わないので、今まで知りませんでした)

まとめ

Android の実機において Moai SDK を使ってウィンドウを表示するまでをまとめてみました。何か疑問があれば遠慮なくコメントにてお知らせ下さい。

Moai SDK でゲームを作ろう (moai-dev/samples/[d-z] を見てみる)

前回の記事 からの続きです。
github にある moai-dev/samples にあるサンプルをみていきます。

deck

deck (画像リソース) の扱いについてのサンプル。
どのサンプルも最終的には画像を表示するのですが、各サンプルの違いはコードと API リファレンスを見ながらでないとわからないです。

  • gfxQuad2D
  • gfxQuad2D-grid
  • gfxQuadDeck2D
  • gfxQuadDeck2D-grid
  • gfxQuadListDeck2D
  • gfxQuadListDeck2D-grid
  • gridDeck2D
  • scriptDeck
  • stretchPatch-basic
  • stretchPatch-flipbook
  • stretchPatch-sub
  • tileDeck2D
  • tileDeck2D-grid
  • tilemap-animated
  • tilemap-expand-for-sort
  • tilemap-wrapping

extending

  • foo … よくわかりません。

flash

Flash を扱うサンプル、だと思うのですが不明です。

  • flash-flipbook
  • flash-spriteDeck
  • flash-tween
  • jsfl

font

フォントの利用サンプルです。サンプル名の種類のフォントを扱っています。

  • font-bitmap
  • font-bmfont-scaled
  • font-serialize
  • font-utf8
  • font-bmfont
  • font-colors
  • font-ttf

graphics

OpenGL を使ったサンプルです。シェーダーも利用しています。

  • gl-cube
  • gl-cube-debugLines
  • gl-frameBuffer
  • gl-shader-attributes
  • gl-shader-color
  • gl-vertexBuffer
  • scissor-rect

grid

正方形でないタイルを敷き詰めるサンプルです。

  • grid-diamond
  • grid-hex
  • grid-oblique
  • grid-quads

hello-moai

  • 画像を回転させつつ、文字を表示するサンプルです。

image

画像に対して行える操作のサンプルです。

  • image-compare
  • image-copyRect
  • image-fillRect
  • image-framebuffer-grab
  • image-texture

input

  • input-callbacks … 入力の扱い方のサンプルです。
  • input-picking … どの画像がクリックされたかのサンプルです。
  • input-picking3D … どの 3D オブジェクトがクリックされたかのサンプルです。

ios

iOS に関連するサンプルです。

  • app-dialog
  • app-gamecenter
  • app-keyboard
  • app-notifications
  • app-orientation
  • app-retina
  • app-screenSize
  • app-storekit
  • app-tapjoy
  • app-testpattern
  • app-video

iso

格子の実現についてのサンプル、か?

  • billboard
  • billboard-grid
  • bounds-override
  • iso-grid-brush
  • iso-walls-brushes
  • iso-walls-thick
  • iso-walls-tilemap
  • sort-iso
  • tilemap-iso

layer

layer についてのサンプルです。

  • layer-bridge … なんかブリッジしてるらしい。
  • layer-camera … layer と camera のサンプル。
  • layer-parallax … layer による多重スクロールのサンプル。
  • layer-sort … layer の prop の表示順についてのサンプル。

location

エラーで実行できなかった…。

log

  • custom-log-messages … ログフォーマットを上書きするサンプル。

particles

パーティクルとして、たくさんの画像を表示するサンプルです。

  • particles-compute-bounds
  • particles-distanceEmitter
  • particles-pex-plugin
  • particles-presets
  • particles-states

partition

  • debugLines-partition … デバッグ表示についてのサンプルです。

pathfinding

経路探索のサンプルです。

  • pathfinding
  • pathfinding-diamond
  • pathfinding-hex

physics

2D の物理演算のサンプルです。

  • physics-box2d
  • physics-chipmunk

prop

prop についてのサンプルです。

  • debugLines-prop
  • prop-color
  • prop-uvTransform

sim

Moai SDK の動作タイミングについてのサンプル、か?

  • moai-extend
  • sim-step-fixed
  • sim-step-multi

test

開発用のテストがたくさんあります。

textbox

テキスト表示についてのサンプルです。

  • textBox-alignment
  • textBox-curves
  • textBox-escapes
  • textBox-glyph-scale
  • textBox-highlight
  • textBox-nested-styles
  • textBox-newlines
  • textBox-paging
  • textBox-spool
  • textBox-traits
  • textBox-update-style
  • textBox-word-break

texture

texture についてのサンプルです。

  • multitexture
  • texture-default
  • texture-load-async
  • texture-mipmap
  • texture-pvr
  • texturepacker

thread

スレッドのサンプルです。

  • thread-blocking

transform

変形についてのサンプルです。

  • traits
  • transform-attrLinks
  • transform-attrLinks-box2D
  • transform-pivot

tutorials

ゲームの完成までが少しずつフォルダに分けて登録されています。

util

補助モジュール。Web 関連から圧縮関連までいろいろ。

  • util-base64
  • util-base64-stream
  • util-crash-report
  • util-deflate
  • util-deflate-stream
  • util-environment-listener
  • util-filestream
  • util-guid
  • util-hash
  • util-histogram
  • util-http-async
  • util-http-blocking
  • util-http-cookies
  • util-https
  • util-json
  • util-parser
  • util-serialize
  • util-serialize-to-header
  • util-xml

viewport

  • viewport-yDown … Y 軸の正負を入れ替えてるの、か?

とりあえず、各サンプルを実行してみました。
私から言えることは「自分でサンプルを実行してみよう!」でしょうか?

Moai SDK はドキュメントが少ないように思うので、サンプルの理解は重要に思います。今回、理解できなかったサンプルの方が多いので、Moai SDK を使いながら色々と調べていこうと思います。

Moai SDK でゲームを作ろう (moai-dev/samples/[a-c] を見てみる)

「Developing Mobile Games with Moai SDK」という書籍(Amazon で買えます)を読み終えたので、次は github にある moai-dev のサンプルやクラス API のドキュメントを読もうと思う。まずは moai-dev/samples 以下にあるサンプルから。

android

Android の機能についてのサンプル。

  • app-accelerometer … 加速度の値を表示する。
  • app-backbutton … ‘戻る’ のタップを扱う方法についてのサンプル。
  • app-billing … 支払いについて Google の機能を使ったサンプル。
  • app-dialog … ダイアログの動作サンプル。
  • app-notifications … (左上に表示される)通知を使うサンプル。
  • app-video … 動画再生のサンプル。

anim

アニメーションのサンプル。

  • anim-basic … 画像を1回転させるサンプル。
  • anim-curve … タイミングを指定して画像を1回転させるサンプル。
  • anim-curve-draw … さまざまな曲線を描画するサンプル。
  • anim-curve-modes … 複数タイマーと同期させたアニメーションのサンプル。
  • anim-drive … アニメーションの組み合わせサンプル。
  • anim-fat-curve … よくわからない。
  • anim-flipbook … セルを順番に表示するアニメーション。
  • anim-listener … アニメーションに同期した関数の呼び出しサンプル。
  • anim-span … 巻き戻すアニメーションのサンプル。
  • chase … 2つの prop のアニメーションサンプル。
  • chase-bridge … layer を用いたアニメーションのサンプル。

app

アプリ解析や広告などについてのサンプル。

  • app-apsalar … Apsalar サービス利用サンプル。
  • app-connectivity … WiFi 接続があるかの確認サンプル。
  • app-tapjoy … Tapjoy サービスの利用サンプル。

audio

  • audio-untz … 効果音の再生サンプル。

camera

  • camera-fitter … camera (視点) の動作サンプル。

chrome

  • app-basic … 画像表示サンプル。

color

  • device-clear-color … クリア色の登録サンプル。

compass

  • compass … コンパスの利用サンプル。

contrib

サンプルというか、モジュールがいくつかある。

  • moaigui … Moai 用の GUI がいろいろ。
  • particle-helper … だんだん消えるパーティクルのサンプル。

思っていたよりもサンプルは多かったので、とりあえずここまで。
できれば、もう少しサンプルコードにコメントが欲しかった…。

Moai SDK でゲームを作ろう(Android でサンプルを動作させる)

開発用の Linux 上でプログラムが動作したので、次は Android でプログラムを実行しようと思う。

で、調べながらやってみた結果、下記ページの説明通りにすることで、 Android でサンプルが動作した。
http://www.gamefromscratch.com/post/2012/08/28/Setting-up-a-Moai-Android-host-build-environment.aspx

Screenshot_2014-01-01-00-28-42

いい感じですな!
Android の実機で作ったプログラムが動作するのが確認できたので、簡単でよいのでゲームっぽいものを作ろうと思う。