Anscaから出ているモバイル端末向けアプリケーションの開発プラットフォームであるCoronaSDKのサンプルコードを自分用に解説、メモしていこうと思う。 まぁ、CoronaSDKってのは要はAndroidとかiPhone向けのアプリを作れるやつ(超適当)。 とりあえずこれを使ってアプリ開発しちゃおうってこと。 今回はその前段階 CoronaSDKのサンプルページのPhysicsにあるMulti-Puckというサンプルをもとに解説を行っていきます。 サンプルコードはつづきで
解説に入る前にMulti-Puckの説明に入ります。
ざっくり説明するとエアホッケーです。壁がないけど、、、
まず、画面をタップするとホッケーで使うようなパックが生成されます。これは複数生成できます。
そのパックを指でなぞって投げるようにすると、エアホッケーのような感じでパックが動き、他のパックとぶつかればお互いに弾き合ったりします。
display.setStatusBar( display.HiddenStatusBar )
local physics = require("physics")
local gameUI = require("gameUI")
local easingx = require("easingx")
physics.start()
physics.setGravity( 0, 0 ) -- no gravity in any direction
popSound = audio.loadSound ("pop2_wav.wav")
labelFont = gameUI.newFontXP{ ios="Zapfino", android=native.systemFont }
system.activate( "multitouch" )
local bkg = display.newImage( "paper_bkg.png", true )
bkg.x = display.contentWidth/2
bkg.y = display.contentHeight/2
local myLabel = display.newText( "Touch screen to create pucks", 0, 0, labelFont, 34 )
myLabel:setTextColor( 255, 255, 255, 180 )
myLabel.x = display.contentWidth/2
myLabel.y = 200
local diskGfx = { "puck_yellow.png", "puck_green.png", "puck_red.png" }
local allDisks = {} -- empty table for storing objects
-- Automatic culling of offscreen objects
local function removeOffscreenItems()
for i = 1, #allDisks do
local oneDisk = allDisks[i]
if (oneDisk and oneDisk.x) then
if oneDisk.x < -100 or oneDisk.x > display.contentWidth + 100 or oneDisk.y < -100 or oneDisk.y > display.contentHeight + 100 then
oneDisk:removeSelf()
table.remove( allDisks, i )
end
end
end
end
local function dragBody( event )
return gameUI.dragBody( event )
-- Substitute one of these lines for the line above to see what happens!
--gameUI.dragBody( event, { maxForce=400, frequency=5, dampingRatio=0.2 } ) -- slow, elastic dragging
--gameUI.dragBody( event, { maxForce=20000, frequency=1000, dampingRatio=1.0, center=true } ) -- very tight dragging, snaps to object center
end
local function spawnDisk( event )
local phase = event.phase
if "ended" == phase then
audio.play( popSound )
myLabel.isVisible = false
randImage = diskGfx[ math.random( 1, 3 ) ]
allDisks[#allDisks + 1] = display.newImage( randImage )
local disk = allDisks[#allDisks]
disk.x = event.x; disk.y = event.y
disk.rotation = math.random( 1, 360 )
disk.xScale = 0.8; disk.yScale = 0.8
transition.to(disk, { time = 500, xScale = 1.0, yScale = 1.0, transition = easingx.easeOutElastic }) -- "pop" animation
physics.addBody( disk, { density=0.3, friction=0.6, radius=66.0 } )
disk.linearDamping = 0.4
disk.angularDamping = 0.6
disk:addEventListener( "touch", dragBody ) -- make object draggable
end
return true
end
bkg:addEventListener( "touch", spawnDisk ) -- touch the screen to create disks
Runtime:addEventListener( "enterFrame", removeOffscreenItems ) -- clean up offscreen disks
解説には本家のAPI Rferenceを参考にして行っています。
1行目
display.setStatusBar()ですが
iPad, iPhone, iPod touch, and Android 2.x デバイスでのステータスバーの表示を隠したり変更できたりするらしいです。
引数は4つあり
display.HiddenStatusBar
display.DefaultStatusBar
display.TranslucentStatusBar
display.DarkStatusBar
が指定できます。
3~5行目
単に同じフォルダ内のluaファイルをインクルードしてるだけかと思います。
クラスっぽい感じで使えそうです。
luaファイルの中身がクラスの中身で
local class_inst = require("classA")
という記述でclass_intにclassAの実体を持たせるんだと思います。
まぁ、physics.luaってのはないのでこれはCoronaSDKが用意してくれた物理エンジン的な何かだということにします。
7行目
物理法則の始まり的な感じ。
8行目
重力の働く方向を指定しています。1番目の引数はx方向、2番目の引数はy方向。
数値の大小にて重力(引力?)の大きさを変更できる模様で、マイナス値も与えられます。
プラスを与えた場合は、x方向なら右方向、y方向なら下方向になります。(端末を普通に縦に持った場合)
10行目
パック生成時のポップ音を指定してます。
11行目
iOSとAndroidで別々に使用するフォントを指定してます。
12行目
引数でマルチタッチ等を指定できるらしいですが、今のところは"multitouch"のみのサポートらしいです。
15~17行目
bkgは読んで字の如く、背景の指定をしてますね。
ファイル名とtrueという引数が与えられてます。
tureはどうやら画面に合わせて自動的に大きさを合わせてくれる(最大2048x2048pixelまで)という優れもの。
だと思ってたんですが、違いました。動きを見てみたんですが、よう解りませんでした。
ただし、デフォルトではfalseになってます。
xとyの指定ではdisplay.contentWidthってのは、つまり画面の横幅って事になるので、画像の中心を指しているんではないかと思います。
左上じゃないことに注意ですね。
ただ、こうすることで、タッチした座標をそのまま使えるという利点もあり結構便利なんじゃないかと思ってます。
ただ、リファレンスだとdisplay.contentWidthってのはデフォルトではスクリーンサイズですが、config.luaで指定も出来るようです。
因みにこのx、yに関してはdisplay.*となるものはどれも持っているみたいですね。
display.new~で作ったオブジェクトは持っていないです。
あとdisplay.contentWidthですが、config.luaで指定することで解像度の違う端末の場合でも、それらのスクリーンを指定した解像度のように扱えるというものです。
19~22行目
ラベルの設定です。テキストエディットですかね?
24行目
diskGfxの意味というか、何の略称なのかちょっとわからんのですが、まぁ内容から察するに各パックのファイル名ですね。
後々説明すると思いますが、パックの色を乱数で設定しているのでそのためのオブジェクトでしょう。
25行目
空のテーブル?を用意してます。
オブジェクト(ここではパックのこと)を格納するためのテーブルです。
C/C++ではこんなことはありえないので(できないわけではないんだけど、、、)ちょっと見慣れないですね。
28~38行目
ここから関数に入ってますね。オブジェクトが画面から消えたら消去するという関数です。
29行目
オブジェクトの数の分だけループさせてます。
ここで、配列が1から始まってるってのが解りますね。
30~36行目
oneDiskに各パックを入れていき、その各パックのオブジェクトに対して画面外に出ているかの判定をします。
if文ではandやorをそのまま使うみたいですね。
31行目の条件式ではパックが存在していて、かつx座標が0以外の場合は通ります。
32行目での条件式でパックが画面内に残っているか完全に見えなくなっているかの判断をしています。
完全に見えなくなっていれば、パックを消去し、table.remove( allDisks, i )によりテーブルのi番目を削除しています。
40~46行目
ここでは、パックがドラッグされた時の処理をgameUI内のdragBodyに任せています。
41行目ではパラメータを与えずに処理を任せています。
44行目は、ドラッグすると輪ゴムで引っ張っているような感じになります。
45行目は、その真逆できっちりとドラッグについてきます。
またドラッグすると強制的にパックの中心を押さえるようになります。
48~72行目
簡単に説明するとパックを生成する関数です。
49行目のevent.phaseでは、タッチイベントなどの状態を表しています。
状態というのは、51行目を見てもらえればわかります。
"ended"というのが状態で、これは指が離された時の状態ということです。
他の状態は"began" "moved" "canceled"等があり、
"began"は画面がタッチさた時の状態になります。一回の動作で一度だけ呼び出されます。
"moved"は画面をスライドさせてる間の状態になります。一回の動作で何度も呼び出されます。
"canceled"はキャンセルされたときの状態?多分電話とかが掛かってきた時に、画面のタッチが強制的にキャンセルされた時の状態かな?
53行目のmyLabel.isVisible = falseではラベルを非表示にしてますね。
55~57行目で乱数によって色違いのパックの生成をしてますね。#allDisksってのはテーブルallDisksの要素数です。
58行目でタッチした座標をパックの座標としています。
59行目で乱数で回転、60行目でディスクの大きさをもとの0.8倍にしている。