Corona で スマートフォン アプリ開発をしよう。開発編
海賊王をめざす男 マツです。こんにちは。
Corona で、タップするとその位置に画像が追加され、地面に落下するアプリをつくってみます。
local screenW, screenH = display.contentWidth, display.contentHeight
local physics = require("physics")
physics.start()
display.setStatusBar( display.HiddenStatusBar )
local ground = display.newImage( "ground.png" )
ground.x = 160; ground.y = 445
physics.addBody( ground, "static", { friction=0.5, bounce=0.3 } )
local scaleFactor = 1.0
local physicsData = (require "matsu").physicsData(scaleFactor)
local matsuShape = display.newImage("matsu.png")
physics.addBody( matsuShape, physicsData:get("matsu") )
matsuShape.x = screenW / 2;
matsuShape.y = matsuShape.height / 2;
local xyText = display.newText( "xy", 0, 0, native.systemFont, 24 )
xyText.x = display.contentWidth / 2
xyText.y = 0
xyText:setTextColor( 255,110,110 )
local idText = display.newText( "id", 0, 0, native.systemFont, 24 )
idText.x = display.contentWidth / 2
idText.y = 30
idText:setTextColor( 255,110,110 )
system.activate( "multitouch" )
-- Display the Event info on the screen
local function showEvent( event )
xyText.text = "(" .. event.x .. "," .. event.y .. ")"
idText.text = "Id: " .. tostring( event.id )
end
local function onTouch( event )
local t = event.target
showEvent( event )
local phase = event.phase
-- タッチ 開始
if "began" == phase then
display.getCurrentStage():setFocus( t )
t.isFocus = true
-- 最初の位置を保存
t.x0 = event.x - t.x
t.y0 = event.y - t.y
-- タッチ フォーカス中
elseif t.isFocus then
-- 動かしたとき
if "moved" == phase then
-- オブジェクトのタッチした場所を適応
t.x = event.x - t.x0
t.y = event.y - t.y0
-- 終了したとき
elseif "ended" == phase or "cancelled" == phase then
display.getCurrentStage():setFocus( nil )
t.isFocus = false
end
end
return true
end
local function otherTouch( event )
print( "otherTouch: event(" .. event.phase .. ") ("..event.x..","..event.y..")" .. tostring(event.id) )
local s = display.getCurrentStage()
if "began" == event.phase then
showEvent( event )
local scaleFactor = 1.0
local physicsData = (require "matsu").physicsData(scaleFactor)
local matsuMiniShape = display.newImage("matsu_mini.png")
physics.addBody( matsuMiniShape, physicsData:get("matsu_mini") )
matsuMiniShape.x = event.x;
matsuMiniShape.y = event.y;
matsuMiniShape.isFocus = true
matsuMiniShape.id = event.id
matsuMiniShape:addEventListener( "touch", onTouch )
--event.target = matsuMiniShape
end
end
Runtime:addEventListener( "touch", otherTouch )
matsuShape:addEventListener( "touch", onTouch )
ここで注目するのは、physicsData に外部 matsu.lua ファイルを使用しているところ。
local physicsData = (require "matsu").physicsData(scaleFactor)
matsu.lua
-- This file is for use with Corona Game Edition
--
-- This file is automatically generated with PhysicsEdtior (http://physicseditor.de). Do not edit
--
-- Usage example:
-- local scaleFactor = 1.0
-- local physicsData = (require "shapedefs").physicsData(scaleFactor)
-- local shape = display.newImage("objectname.png")
-- physics.addBody( shape, physicsData:get("objectname") )
--
-- copy needed functions to local scope
local unpack = unpack
local pairs = pairs
local ipairs = ipairs
module(...)
function physicsData(scale)
local physics = { data =
{
["matsu"] = {
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 33, 29.5 , 49.5, 21 , 53.5, 45 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 49.5, 21 , 61.5, 8 , 65.5, 34 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -40.5, 28 , -30, 31.5 , -33.5, 39 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -43.5, 62 , -36, 48.5 , -24.5, 44 , 29, 30.5 , 30, 48.5 , -40.5, 72 , -45.5, 68 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -24.5, 44 , -36, 48.5 , -30, 42.5 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 71, 14.5 , 65, 5.5 , 71.5, 3 , 76.5, 17 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -73.5, 3 , -66, 5.5 , -73.5, 16 , -77.5, 16 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 34.5, 72 , -42, 89.5 , -40.5, 72 , 30, 48.5 , 39.5, 68 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -42, 89.5 , 34.5, 72 , 36, 89.5 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 65, 5.5 , -55, -70.5 , -39, -81.5 , 15, -89.5 , 33, -82.5 , 67.5, -43 , 71.5, -25 , 71.5, 3 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 67.5, -43 , 33, -82.5 , 56.5, -64 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -73.5, -35 , -64.5, -59 , -66, 5.5 , -73.5, 3 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 15, -89.5 , -39, -81.5 , -13, -90.5 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 33, 29.5 , 29, 30.5 , 61.5, 8 , 49.5, 21 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -64.5, -59 , -55, -70.5 , 65, 5.5 , 29, 30.5 , -30, 31.5 , -40.5, 28 , -55, 18.5 , -66, 5.5 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -21.5, 38 , 29, 30.5 , -24.5, 44 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -30, 31.5 , 29, 30.5 , -21.5, 38 }
} ,
{
density = 2, friction = 0.3, bounce = 0.3,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 29, 30.5 , 65, 5.5 , 61.5, 8 }
}
}
,
["matsu_mini"] = {
{
density = 2, friction = 0.5, bounce = 0.5,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 11.5, 12.5 , 20, 10 , 20, 18 }
} ,
{
density = 2, friction = 0.5, bounce = 0.5,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 20, 10 , 23.5, 4.5 , 25.5, 12.5 }
} ,
{
density = 2, friction = 0.5, bounce = 0.5,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -12.5, 16.5 , 14.5, 34.5 , -16, 35 , -18.5, 25.5 }
} ,
{
density = 2, friction = 0.5, bounce = 0.5,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -30.5, -9.5 , -26.5, -23.5 , -26, 3 , -30.5, 6.5 }
} ,
{
density = 2, friction = 0.5, bounce = 0.5,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 11.5, 12.5 , -19, -31 , -8, -36 , 6, -36 , 18, -30 , 26.5, -17.5 , 23.5, 4.5 , 20, 10 }
} ,
{
density = 2, friction = 0.5, bounce = 0.5,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { -26.5, -23.5 , -19, -31 , 11.5, 12.5 , 15.5, 26.5 , 14.5, 34.5 , -12.5, 16.5 , -26, 3 }
} ,
{
density = 2, friction = 0.5, bounce = 0.5,
filter = { categoryBits = 1, maskBits = 65535 },
shape = { 23.5, 4.5 , 26.5, -17.5 , 29.5, 6.5 }
}
}
} }
-- apply scale factor
local s = scale or 1.0
for bi,body in pairs(physics.data) do
for fi,fixture in ipairs(body) do
for ci,coordinate in ipairs(fixture.shape) do
fixture.shape[ci] = s * coordinate
end
end
end
function physics:get(name)
return unpack(self.data[name])
end
return physics;
end
これは、サードパーティ製の PhysicsEditor というソフトからビルドしたファイルです。
PhysicsEditor
PhysicsEditor | Edit your box2d and chipmunk shapes with ease
http://www.physicseditor.de/
透過 png のアウトラインパスを解析して .lua ファイルに書き出すソフトです。
これで、物理演算などのオブジェクトの形状衝突に利用できます。

実行すると画面をタップした場所にオブジェクトが追加され、地面に向かって落下するアプリが実行できました。
Corona をつかってみて
Flash をやってきた方にはとてもとっつきやすい感じです。
心配なこととして、
Corona SDK は、Android 2.1以下のサポートをしない方向で動いているみたいです。
http://developer.anscamobile.com/forum/2011/03/01/android-update-please-read
現状 Corona は、ビルドの際に Ansca 社(Corona 開発元)のサーバーを見に行くようです。
なので、Ansca 社のサーバーがなんらかの理由(メンテナンスなど)で利用できないことがあるとビルドができないということになります。
Corona のバージョンアップは、サーバーのバージョンアップと同義なので、過去に Corona でつくったものがビルドできないということになりかねないです。
ビルド時に旧バージョンのものも選択できるように、日本コロナの会のみなさんが積極的に Ansca 社に働きかけているので解決できるといいですね。
日本コロナの会
https://groups.google.com/group/coronaja?hl=ja
Corona は魅力あるソフトなのでこれからもその動向を追ってみます!

