フラッピーバード:-行きましょう







これは、コロナでゲームを書く方法についての物語です。

エントリのレベルは最小限です(そして代数学科のオタクは理解します)。



コロナは、すべてのプラットフォームで2Dゲームを作成するためのエンジンであり、タッチタッチの今日は宇宙飛行士の日です。 ゲームのプロットは適切に選択され、もちろん、最初の宇宙飛行士の後に繰り返します

-行こう!

2時間のプログラミングで何が起こりますか?



これが、2時間のプログラミングで得られたものです。



もちろん、私は代数と同じくらい線形のプログラマーなので、このトップスはすべて3分の1の時間しかかかりません。





見つけましたか? はい、これはベトナムのIshkvからのアドオンのゲームです。



アプリケーションが作成者に1日あたり50,000ドルをもたらしたことを思い出させてください。 私の意見では悪くない。



私のクリップで鳥と柱の衝突の破片をよく見ると、碑文HABRが見えます。 この画像を粒子効果のテクスチャとして使用します。



コロナツールのインストール



10分かかり、多くの場所で美しく塗装されています。



gagarinbirdプロジェクトの作成



お使いのマシン(Macを持っています)でCoronaを起動し、[ 新しい空のプロジェクトを作成 ]メニュー項目を選択します



その結果、gagarinbirdディレクトリは指定された場所に作成され、そこにはあらゆる種類の有用なガベージがたくさんあります。そのうち、1つのファイルを編集します。

main.lua
テキストエディター-あなたの裁量で。 プログラミング言語はLuaです。



まず、ゲームには写真と音声が必要です。



著者を苦しめることなくそれらを取得する方法?
  • ファイルFlappy Bird [Dong Nguyen](v1.2 LP os60)をダウンロードします-Orbicos-ICPDA.rc309.ipa
  • ファイルの名前をFlappy Bird [Dong Nguyen](v1.2 LP os60)に変更します-Orbicos-ICPDA.rc309.zip
  • ファイルFlappy Bird [Dong Nguyen](v1.2 LP os60)-Orbicos-ICPDA.rc309.zipを解凍します。
  • Flap.appファイルを右クリックして、[パッケージコンテンツの表示]を選択します
  • 写真とサウンドをgagarinbirdディレクトリにコピーします




便宜上、サブディレクトリgagarinbird / Assetsを作成し、すべての写真をここに配置します。

同様に、gagarinbird / Soundsサブディレクトリを作成し、すべてのサウンドをここに配置します。



コードの最初の2行-チェック音Mu



コードの最初の2行をmain.luaファイルに挿入します



dieSound = audio.loadSound( "Sounds/sfx_die.caf" ) audio.play( dieSound )
      
      





Corona(多くの場合Corona Simulator)の2つのホットボタン/ cmd / + Rをクリックすると、電話のようなウィンドウでアプリケーションが起動し、死音が鳴ります! あぁ、すべてが機能します。

背景はバージンブラックですが、それは重要ではありません-サウンドの再生方法を学習しました。 そして、Android、iPhone、および(許して、主)Windowsの両方で同じように聞こえます。



サウンドをダウンロードしてすべてを美しくする



loadSounds()関数を作成して呼び出します



 local function loadSounds() dieSound = audio.loadSound( "Sounds/sfx_die.caf" ) hitSound = audio.loadSound( "Sounds/sfx_hit.caf" ) pointSound = audio.loadSound( "Sounds/sfx_point.aif" ) swooshingSound = audio.loadSound( "Sounds/sfx_swooshing.caf" ) wingSound = audio.loadSound( "Sounds/sfx_wing.caf" ) boomSound = audio.loadSound( "Sounds/sfx_boom.mp3" ) end -- Start application point loadSounds()
      
      





背景画像をアップロードしてタップタップを処理する



携帯電話の画面全体に背景画像を描くことを学ぶ



  local function initBackGround() local ground = display.newImageRect( "Assets/ground.png", display.actualContentWidth, display.actualContentHeight ) ground.x = display.contentCenterX ground.y = display.contentCenterY end --    initBackGround()
      
      





(ctrl + R)を実行して、このような美しい画像を取得します







ほら、今、私たちは好きなように絵を描き、どこにでも置いて、変形することができます。



例えば



 ground.rotation = 90
      
      





背景画像を90度回転します。



画面に突進を追加します。



  ground:addEventListener("tap", wing) local function wing() audio.play( wingSound ) end
      
      





地面でのすべてのクリックをキャッチし、wing()関数を呼び出すリスナーを追加しました。

コードを見ると、地面にあるそれぞれの突く部分がwing.cafの音を発生させるはずです。



私たちは始めます-すべてが機能します。



飛行物理学とタイマー



コロナには、重力と衝突を伴う物理ライブラリがあります。 しかし、私たちのゲームにとっては冗長です。 オブジェクト(鳥、地球、極)を追加し、パラメータを設定するには、地球の重力場で衝突や動力学をチェックするタイマー(毎秒40回)を開始するだけでなく、より多くのコードが必要になります。 Earth窓の地球。 気が散ってすみません。



タイムマシンの言語でダイナミクスを作りましょう。



 --  ,    25  gameLoopTimer = timer.performWithDelay( 25, gameLoop, 0 ) local function gameLoop() vBird = vBird + dt * g yBird = yBird + dt * vBird end
      
      





1秒あたり40回、関数gameLoop()が呼び出されます



鳥の動きのダイナミクスは、この機能の2行に記録されています。 ここで、gは重力加速度です(iPhoneの場合、毎秒800ピクセル)



dt = 0.025-タイムステップ



uBird-X軸に沿った鳥の速度

vBird-Y軸に沿った鳥の速度



xBird-鳥のX座標

yBird-y軸に沿った鳥の座標



柱と表面のダイナミクスはさらに単純です-移動はX軸に沿ってのみ発生します



  for i=1,3 do pipes[i].x = pipes[i].x + dt * uBird end
      
      





ゲームの状態



すべてのレンガは準備ができており、エレガントな牛のプログラムですべてをつなぐことが残っています。 したがって、このゲームには4つの状態があります。



状態0(gameStatus = 0)すべてが凍結され、ゲームを開始する準備ができました。 画面をクリックするのを楽しみにしています。 押すと、状態1に進みます。

状態1(gameStatus = 1)鳥が飛ぶ、柱が動く、重力が働く。 画面をタップすると、鳥の速度がまっすぐ上がります(vBird = jumpSpeed)。

状態2(gameStatus = 2)鳥は緑色の柱と衝突し、厳密に倒れ、柱は立っており、重力が働いています。 画面をタップしても何にも影響しません。

状態3(gameStatus = 3)鳥は地球と衝突し、すべてが凍結し、採点し、飛行の結果を示しました。 クリックして状態0になるのを待っています。



原則として、状態1と2は、後者に0の水平速度を割り当てることで組み合わせることができます。これは好みの問題です。



翼とスプライトのアニメーション



鳥の傾きは速度ベクトルに比例します。

これは、角度の逆正接に等しくなります。



  bird.rotation = math.atan(vBird/uBird)
      
      





画面をクリックしたときに鳥の羽ばたきをアニメーション化するには、コロナスプライトリストが使用されます。 これは、PNG画像よりも少し複雑です。







アニメーションフレームを別のpngファイルに作成します。 サイズ400 x 100ピクセル。 各内部スプライトのサイズは100あたり100です。つまり、4つのフレームがあります。



鳥の初期化コードは次のとおりです



 local function setupBird() local options = { width = 100, height = 100, numFrames = 4, sheetContentWidth = 400, -- width of original 1x size of entire sheet sheetContentHeight = 100 -- height of original 1x size of entire sheet } local imageSheet = graphics.newImageSheet( "Assets/bird.png", options ) local sequenceData = { name="walking", start=1, count=3, time=300, loopCount = 2, -- Optional ; default is 0 (loop indefinitely) loopDirection = "forward" -- Optional ; values include "forward" or "bounce" } bird = display.newSprite( imageSheet, sequenceData ) bird.x = xBird bird.y = yBird end
      
      





さて、画面をクリックすると、コード行を呼び出します



 bird:play()
      
      





そして、鳥は2回連続して羽ばたきします。



衝突とパーティクル効果



衝突チェックは基本です。



まず、地球の表面との衝突を確認します



  if yBird>yLand then yBird = yLand crash() end
      
      





第二に、柱との衝突チェック



  local function checkCollision(i) local dx = 40 --      local dy = 50 --      local boom = 0 local x = pipes[i].x local y = pipes[i].y if xBird > (x-dx) and xBird < (x+dx) then if yBird > (y+dy) or yBird < (y-dy) then boom = 1 end end return boom end
      
      





鳥が柱と衝突するポイントにパーティクルエフェクトを追加します。



コードは扱いにくいように見えますが、エフェクトの20個のパラメーターを変更すると、驚くべき爆発、フラッシュ、火の玉が得られます。



 local function setupExplosion() local dx = 31 local p = "Assets/habra.png" local emitterParams = { startParticleSizeVariance = dx/2, startColorAlpha = 0.61, startColorGreen = 0.3031555, startColorRed = 0.08373094, yCoordFlipped = 0, blendFuncSource = 770, blendFuncDestination = 1, rotatePerSecondVariance = 153.95, particleLifespan = 0.7237, tangentialAcceleration = -144.74, startParticleSize = dx, textureFileName = p, startColorVarianceAlpha = 1, maxParticles = 128, finishParticleSize = dx/3, duration = 0.75, finishColorRed = 0.078, finishColorAlpha = 0.75, finishColorBlue = 0.3699196, finishColorGreen = 0.5443883, maxRadiusVariance = 172.63, finishParticleSizeVariance = dx/2, gravityy = 220.0, speedVariance = 258.79, tangentialAccelVariance = -92.11, angleVariance = -300.0, angle = -900.11 } emitter = display.newEmitter(emitterParams ) emitter:stop() end
      
      





このコードはコメントなしで残します。パラメーターを自分でお楽しみください。



 local function explosion() emitter.x = bird.x emitter.y = bird.y emitter:start() end
      
      





機能爆発()は、鳥が柱に衝突したときに呼び出されます。 ゲーム内のすべての写真のスタイルでエフェクトをピクセル化できませんでした。 おそらく、これを行う方法についてのアドバイスがあります。 どちらかといえば、スケールは動作しませんでした。



ありがとう



プロジェクト全体は、5月の休暇中にCorona MarketplaceからSMSなしで無料でダウンロードできます。 コードは管理されます。



とりわけ、私はコロナの伝道者になり、最初の給料を受け取りました。これはすべて、Habréの出版のおかげです。 リソース、そしてもちろんあなたの読者に感謝します。 代数学者の皆さん、こんにちは。



プロジェクトコード



1つのmain.luaファイルのプロジェクトコード
 ----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- local gameStatus = 0 local yLand = display.actualContentHeight - 160 local hLand = 60 local xLand = display.contentCenterX local yBird = display.contentCenterY-50 local xBird = display.contentCenterX-50 local wPipe = display.contentCenterX+10 local yReady = display.contentCenterY-140 local uBird = -200 local vBird = 0 local wBird = -320 local g = 800 local dt = 0.025 local score = 0 local bestScore = 0 local scoreStep = 5 local bird local land local title local getReady local gameOver local emitter local board local scoreTitle local bestTitle local silver local gold local pipes = {} local function loadSounds() dieSound = audio.loadSound( "Sounds/sfx_die.caf" ) hitSound = audio.loadSound( "Sounds/sfx_hit.caf" ) pointSound = audio.loadSound( "Sounds/sfx_point.aif" ) swooshingSound = audio.loadSound( "Sounds/sfx_swooshing.caf" ) wingSound = audio.loadSound( "Sounds/sfx_wing.caf" ) boomSound = audio.loadSound( "Sounds/sfx_boom.mp3" ) end local function calcRandomHole() return 60 + 20*math.random(10) end local function loadBestScore() local path = system.pathForFile( "bestscore.txt", system.DocumentsDirectory ) -- Open the file handle local file, errorString = io.open( path, "r" ) if not file then -- Error occurred; output the cause print( "File error: " .. errorString ) else -- Read data from file local contents = file:read( "*a" ) -- Output the file contents bestScore = tonumber( contents ) -- Close the file handle io.close( file ) end file = nil end local function saveBestScore() -- Path for the file to write local path = system.pathForFile( "bestscore.txt", system.DocumentsDirectory ) local file, errorString = io.open( path, "w" ) if not file then -- Error occurred; output the cause print( "File error: " .. errorString ) else file:write( bestScore ) io.close( file ) end file = nil end local function setupBird() local options = { width = 70, height = 50, numFrames = 4, sheetContentWidth = 280, -- width of original 1x size of entire sheet sheetContentHeight = 50 -- height of original 1x size of entire sheet } local imageSheet = graphics.newImageSheet( "Assets/bird.png", options ) local sequenceData = { name="walking", start=1, count=3, time=300, loopCount = 2, -- Optional ; default is 0 (loop indefinitely) loopDirection = "forward" -- Optional ; values include "forward" or "bounce" } bird = display.newSprite( imageSheet, sequenceData ) bird.x = xBird bird.y = yBird end local function prompt(tempo) bird:play() end local function initGame() score = 0 scoreStep = 5 title.text = score for i=1,3 do pipes[i].x = 400 + display.contentCenterX * (i-1) pipes[i].y = calcRandomHole() end yBird = display.contentCenterY-50 xBird = display.contentCenterX-50 getReady.y = 0 getReady.alpha = 1 gameOver.y = 0 gameOver.alpha = 0 board.y = 0 board.alpha = 0 audio.play( swooshingSound ) transition.to( bird, { time=300, x=xBird, y=yBird, rotation = 0 } ) transition.to( getReady, { time=600, y=yReady, transition=easing.outBounce, onComplete=prompt } ) end local function wing() if gameStatus==0 then gameStatus=1 getReady.alpha = 0 end if gameStatus==1 then vBird = wBird bird:play() audio.play( wingSound ) end if gameStatus==3 then gameStatus=0 initGame() end end local function setupExplosion() local dx = 31 local p = "Assets/habra.png" local emitterParams = { startParticleSizeVariance = dx/2, startColorAlpha = 0.61, startColorGreen = 0.3031555, startColorRed = 0.08373094, yCoordFlipped = 0, blendFuncSource = 770, blendFuncDestination = 1, rotatePerSecondVariance = 153.95, particleLifespan = 0.7237, tangentialAcceleration = -144.74, startParticleSize = dx, textureFileName = p, startColorVarianceAlpha = 1, maxParticles = 128, finishParticleSize = dx/3, duration = 0.75, finishColorRed = 0.078, finishColorAlpha = 0.75, finishColorBlue = 0.3699196, finishColorGreen = 0.5443883, maxRadiusVariance = 172.63, finishParticleSizeVariance = dx/2, gravityy = 220.0, speedVariance = 258.79, tangentialAccelVariance = -92.11, angleVariance = -300.0, angle = -900.11 } emitter = display.newEmitter(emitterParams ) emitter:stop() end local function explosion() emitter.x = bird.x emitter.y = bird.y emitter:start() end local function crash() gameStatus = 3 audio.play( hitSound ) gameOver.y = 0 gameOver.alpha = 1 transition.to( gameOver, { time=600, y=yReady, transition=easing.outBounce } ) board.y = 0 board.alpha = 1 if score>bestScore then bestScore = score saveBestScore() end bestTitle.text = bestScore scoreTitle.text = score if score<10 then silver.alpha = 0 gold.alpha = 0 elseif score<50 then silver.alpha = 1 gold.alpha = 0 else silver.alpha = 0 gold.alpha = 1 end transition.to( board, { time=600, y=yReady+100, transition=easing.outBounce } ) end local function collision(i) local dx = 40 -- horizontal space of hole local dy = 50 -- vertical space of hole local boom = 0 local x = pipes[i].x local y = pipes[i].y if xBird > (x-dx) and xBird < (x+dx) then if yBird > (y+dy) or yBird < (y-dy) then boom = 1 end end return boom end local function gameLoop() local eps = 10 local leftEdge = -60 if gameStatus==1 then xLand = xLand + dt * uBird if xLand<0 then xLand = display.contentCenterX*2+xLand end land.x = xLand for i=1,3 do local xb = xBird-eps local xOld = pipes[i].x local x = xOld + dt * uBird if x<leftEdge then x = wPipe*3+x pipes[i].y = calcRandomHole() end if xOld > xb and x <= xb then score = score + 1 title.text = score if score==scoreStep then scoreStep = scoreStep + 5 audio.play( pointSound ) end end pipes[i].x = x if collision(i)==1 then explosion() audio.play( dieSound ) gameStatus = 2 end end end if gameStatus==1 or gameStatus==2 then vBird = vBird + dt * g yBird = yBird + dt * vBird if yBird>yLand-eps then yBird = yLand-eps crash() end bird.x = xBird bird.y = yBird if gameStatus==1 then bird.rotation = -30*math.atan(vBird/uBird) else bird.rotation = vBird/8 end end end local function setupLand() land = display.newImageRect( "Assets/land.png", display.actualContentWidth*2, hLand*2 ) land.x = xLand land.y = yLand+hLand end local function setupImages() local ground = display.newImageRect( "Assets/ground.png", display.actualContentWidth, display.actualContentHeight ) ground.x = display.contentCenterX ground.y = display.contentCenterY ground:addEventListener("tap", wing) for i=1,3 do pipes[i] = display.newImageRect( "Assets/pipe.png", 80, 1000 ) pipes[i].x = 440 + wPipe * (i-1) pipes[i].y = calcRandomHole() end getReady = display.newImageRect( "Assets/getready.png", 200, 60 ) getReady.x = display.contentCenterX getReady.y = yReady getReady.alpha = 0 gameOver = display.newImageRect( "Assets/gameover.png", 200, 60 ) gameOver.x = display.contentCenterX gameOver.y = 0 gameOver.alpha = 0 board = display.newGroup() local img = display.newImageRect(board, "Assets/board.png", 240, 140 ) scoreTitle = display.newText(board, score, 80, -18, "Assets/troika.otf", 21) scoreTitle:setFillColor( 0.75, 0, 0 ) bestTitle = display.newText(board, bestScore, 80, 24, "Assets/troika.otf", 21) bestTitle:setFillColor( 0.75, 0, 0 ) silver = display.newImageRect(board, "Assets/silver.png", 44, 44 ) silver.x = -64 silver.y = 4 gold = display.newImageRect(board, "Assets/gold.png", 44, 44 ) gold.x = -64 gold.y = 4 board.x = display.contentCenterX board.y = 0 board.alpha = 0 local txt = { x=display.contentCenterX, y=10, text="", font="Assets/troika.otf", fontSize=35 } title = display.newText(txt) title:setFillColor( 1, 1, 1 ) end -- Start application point loadSounds() setupImages() setupBird() setupExplosion() setupLand() initGame() loadBestScore() gameLoopTimer = timer.performWithDelay( 25, gameLoop, 0 )
      
      








All Articles