Sticky Projectiles
끈적한 포탄들을 코로나로 구현하는 방법은 아주 간단합니다. 이 장에서는 아래와 같은 내용들을 다룰 겁니다.
1. 포탄이 벽에 붙을 수 있는 충분한 속도가 됐는지 여부를 체크하기 위한 directional velocity 를 어떻게 detect 하는지에 대한 방법
2. weld joint 를 사용해서 포탄을 다른 객체에 붙이는 방법
포탄을 만들고 launching하는 것은 큰 주제 입니다. 그래서 그에 대해서는 깊게 들어가지 않겠습니다. 이 게임을 만들 때 생각해야 할 것은 위 두 경우를 다룰 collision handler 함수 입니다.
우리가 할 첫번째 일은 포탄의 방향과 속도를 감지하는 것입니다. 우선 피타고라스 이론(Pythagorean theorem)을 사용해서 속도를 계산해야 합니다. 그리고 나서 그 값으로 다음의 둘 중 하나를 구현할 수 있습니다. 만약 속도가 충분하다면 포탄과 벽에 weld joint 를 생성할 겁니다. 속도가 충분하지 않으면 아무 joint 도 만들지 않을 겁니다. 그러면 포탄은 땅에 떨어지겠죠.
Detect Directional Velocity
우선 포탄의 vx와 vy linear velocities 를 가져옵니다. 그리고나서 그 값을 공식에 대입시키죠. 그러면 우리가 원하는 속도를 얻을 수 있습니다.
local vx,vy = self:getLinearVelocity() local dirVel = math.sqrt( (vx*vx)+(vy*vy) )
Make Joint — or Don’t!
포탄의 속도에 따라 위에서 언급한 둘 중 한가지를 적용하게 될 겁니다. 속도가 여러분이 원하는 만큼 충분하다면 포탄이 다른곳에 붙을 수 있도록 만듭니다.
if ( dirVel > 330 ) then self:setLinearVelocity( 0,0 ) timer.performWithDelay( 10, resolveColl, 1 ) end
Box2D 에서는 어떤 action들은 같은 time step 에 한꺼번에 실행되지 않는 것들이 있습니다. 왜냐하면 Box2D 엔진이 내부적으로 계산을 하고 있는 상황이기 때문이죠. 우리는 10 밀리세컨드의 timer 가 작동된 후에 joint 를 생성할 겁니다.
function resolveColl() local weldJoint = physics.newJoint( "weld", self, event.other, self.x, self.y ) end
여기까지 하시면 sticky 포탄 시나리오의 아주 기본적인 사항들은 완료 된 겁니다. 예제에 있는 여러 setting 들을 바꿔가면서 이것저것 많이 시도해 보세요.
참고로 전체 소스는 아래와 같습니다.
local physics = require("physics") ; physics.start() ; physics.setGravity( 0.0,9.8 ) ; physics.setDrawMode( "normal" )
physics.setPositionIterations( 16 ) ; physics.setVelocityIterations( 6 )
display.setStatusBar( display.HiddenStatusBar )
--set up some references and other variables
local ox, oy = math.abs(display.screenOriginX), math.abs(display.screenOriginY)
local cw, ch = display.contentWidth, display.contentHeight
local stage = display.getCurrentStage()
--set up terrain and background
local back = display.newImageRect( "sky.jpg", 1024, 768 ) ; back.x = cw/2 ; back.y = ch/2
local wallL = display.newRect( -ox, -oy, 40, ch+oy+oy )
physics.addBody(wallL, "static", { bounce=0.6, friction=1.0 } )
local wallR = display.newRect( cw-40+ox, -oy, 40, ch+oy+oy )
physics.addBody(wallR, "static", { bounce=0.6, friction=1.0 } )
local wallB = display.newRect( -ox, ch-40+oy, cw+ox+ox, 40 )
physics.addBody(wallB, "static", { bounce=0.6, friction=1.0 } )
local wallT = display.newRect( -ox, -oy, cw+ox+ox, 40 )
physics.addBody(wallT, "static", { bounce=0.6, friction=1.0 } )
local text = display.newText( "Tap screen to launch projectiles", 0, 0, "Times", 44 ) ; text:setTextColor(0,0,0,160) ; text.y = 140 ; text.x = cw/2
--set up boolean for projectile firing
local projFiring = false
--set up projectile sheet
local proj
local options = { width=40, height=40, numFrames=2, sheetContentWidth=80, sheetContentHeight=40 }
local projSheet = graphics.newImageSheet( "projspike.png", options )
local seq = { name = "main", frames = {1,2} }
--function to create new projectiles
local function newProj()
proj = display.newSprite( projSheet, seq ) ; proj.x = 150 ; proj.y = 600
physics.addBody( proj, "dynamic", { density=15.0, friction=0.8, bounce=0.3, radius=16 } )
proj.gravityScale = 0
projFiring = false
proj.isBodyActive = false
end
--collision handler
local function projCollide( self,event )
if ( event.phase == "began" ) then
--get world coordinates of projectile for joint reference
self:removeEventListener( "collision", self ) ; self.collision = nil
--delay function to resolve collision
local function resolveColl( timerRef )
if ( timerRef.source.action == "makeJoint" ) then
local weldJoint = physics.newJoint( "weld", self, event.other, self.x, self.y )
end
newProj()
end
--check if velocity of projectile is sufficient to "stick"
local vx,vy = self:getLinearVelocity()
local dirVel = math.sqrt( (vx*vx)+(vy*vy) )
if ( dirVel > 330 ) then --if sufficient, stop velocity and trigger joint creation
self:setLinearVelocity( 0,0 )
local t = timer.performWithDelay( 10, resolveColl, 1 ) ; t.action = "makeJoint"
else --if not sufficient, "break" projectile and create new
self:setFrame(2)
local t = timer.performWithDelay( 10, resolveColl, 1 ) ; t.action = "none"
end
end
end
--screen touch handler
local function touchAction(event)
if ( event.phase == "began" and projFiring == false ) then
projFiring = true
proj.isBodyActive = true
local px,py = event.x-proj.x, event.y-proj.y
proj:applyLinearImpulse( px/2, py/2, proj.x, proj.y )
proj:applyTorque( 1200 )
proj.gravityScale = 1.0
proj.collision = projCollide ; proj:addEventListener( "collision", proj )
end
end
stage:addEventListener( "touch", touchAction )
newProj()
'Corona SDK > Corona Doc' 카테고리의 다른 글
퍼포먼스 최적화(Performance Optimizations) 팁들 소개 -04- (1) | 2013.03.15 |
---|---|
퍼포먼스 최적화(Performance Optimizations) 팁들 소개 -03- (0) | 2013.03.14 |
퍼포먼스 최적화(Performance Optimizations) 팁들 소개 -02- (0) | 2013.03.13 |
퍼포먼스 최적화(Performance Optimizations) 팁들 소개 -01- (0) | 2013.03.13 |
Physics 트릭들 배우기 - Wind Tunnel- (0) | 2013.02.27 |
Physics 트릭들 배우기 - Can I Jump?- (0) | 2013.02.26 |
iOS Build-in 트위터 기능 사용하기 (0) | 2013.02.20 |
iOS 에서 이메일 첨부파일 사용하기 (0) | 2013.02.19 |
멀티 터치 지원하는 모양 맞추기 앱 개발하기 (2) | 2013.02.15 |
Pinch Zoom Rotate 구현하기 - 11/11 - (0) | 2013.02.14 |