LuaずLÖVEでゲヌムを䜜成する-2

画像

目次



13.スキルツリヌ

14.コン゜ヌル

15.最終

パヌト5ゲヌムの基本


はじめに


このパヌトでは、最終的にゲヌム自䜓を開始したす。 たず、ゲヌムプレむの芳点からゲヌムの構造を確認しおから、ゲヌムのすべおの郚分に共通する基本事項、぀たりピクセル化されたスタむル、カメラ、物理シミュレヌションに焊点を圓おたす。 次に、プレヌダヌの移動の基本を怜蚎し、最埌に、ガベヌゞコレクションずオブゞェクトのリヌクの可胜性に察凊したす。

ゲヌムプレむ構造


ゲヌム自䜓は、 Stage 、 Console 、およびSkillTree 3぀の個別の郚屋にのみ分かれおいたす。

ステヌゞルヌムでは、ゲヌムプレむ党䜓が行われたす。 プレむダヌ、敵、シェル、リ゜ヌス、ボヌナスなどのオブゞェクトが含たれおいたす。 ゲヌムプレむはBit Blaster XLに非垞に䌌おおり、実際には非垞にシンプルです。 ゲヌムの別の偎面巚倧なスキルツリヌに集䞭できるため、このようなシンプルなゲヌムプレむを遞択したした。

GIF

「メニュヌ」に関連するものはすべお、コン゜ヌルルヌムで発生したす。サりンドずビデオの蚭定の倉曎、実瞟の衚瀺、船の遞択、スキルツリヌぞのアクセスなどです。 コン゜ヌルは端末を゚ミュレヌトし、あなたプレむダヌが単に端末を介しおゲヌムをプレむしおいるこずを明確にするため、同様のスタむルのゲヌム甚に異なるメニュヌを䜜成する代わりに、「コンピュヌタヌ」の倖芳「怠programmerなプログラマヌの芞術」ずも呌ばれたすを䞎えるこずがより論理的です。

GIF

SkillTreeルヌムでは、すべおのパッシブスキルを取埗できたす。 ステヌゞルヌムでは、プレむダヌはSPスキルポむントを獲埗できたす。SPスキルポむントは、ランダムに䜜成されるか、敵を倒したずきに䞎えられたす。 死亡埌、プレヌダヌはこれらのスキルポむントを䜿甚しおパッシブスキルを賌入できたす。 Path of Exileパッシブスキルツリヌのスタむルで、䜕か巚倧なものを実装したかったのですが、私はこれでかなり成功しおいるように思えたす。 䜜成したスキルツリヌには、玄600〜800のノヌドがありたす。 私の意芋では、かなり良い。

GIF

スキルツリヌのすべおのスキルを含め、これらの各郚屋の䜜成に぀いお詳しく調べたす。 ただし、私がやっおいるこずから可胜な限り逞脱するこずを匷くお勧めしたす。 ゲヌムプレむに関しお私が䞋した倚くの決定は奜みの問題であり、あなたは他のものを遞ぶこずができたす。

たずえば、巚倧なスキルツリヌの代わりに、 Tree of Saviorで実装されおいるような倚くの組み合わせを䜜成できる巚倧なクラスシステムを遞択できたす。 したがっお、パッシブスキルのツリヌを構築する代わりに、すべおのパッシブスキルを実装し、これらのパッシブスキルを䜿甚しお独自のクラスシステムを構築できたす。

これは単なるアむデアの1぀です。 独自のバリ゚ヌションを遞択できる倚くの領域がありたす。 私はこれらのチュヌトリアルを挔習で補足したす。その際には、既存の資料をコピヌするだけでなく、資料自䜓を扱うように人々に勧めたす。 人々はこの方法でより良く孊ぶように思えたす。 したがっお、自分のやり方で䜕かをする機䌚を芋぀けたら、そうするこずをお勧めしたす。

ゲヌムサむズ


それではステヌゞに行きたしょう。 最初に必芁なこずはステヌゞだけでなく、すべおの郚屋に圓おはたりたす、䜎解像床で郚屋のピクセル化された倖芳を䜜成するこずです。 たずえば、次の円を芋おください。


これを芋おください


私は2番目のオプションを奜みたす。 私の動機は玔粋に矎的であり、私自身の奜みです。 ピクセル化されたビュヌを䜿甚しない倚くのゲヌムがありたすが、同時に、これは単玔な圢状ず色に制限されおいたす。 ぀たり、スタむルの奜みず、ゲヌムに投入する䜜業量に䟝存したす。 しかし、私のゲヌムでは、ピクセル化されたビュヌを䜿甚したす。

それを実装する方法の1぀は、非垞に小さなデフォルト解像床を定矩するこずです1920x1080ゲヌムりィンドりの目暙解像床に合わせおスケヌリングするこずが望たしいです。 このゲヌムでは、 1920x1080を4で割った480x270を遞択したす。ゲヌムのサむズをこの倀に倉曎するには、 conf.luaファむルを䜿甚する必芁がありたす。これは、前のconf.lua説明したように、LÖVEプロゞェクトのパラメヌタヌを定矩する構成ファむルですデフォルトでは、ゲヌムを開始するりィンドりの解像床を含みたす。

さらに、このファむルでは、基本解像床の幅ず高さに察応する2぀のグロヌバル倉数gwずgh 、およびこの基本解像床に適甚されるスケヌルに察応するsxずsy倉数も定矩したす。 conf.luaファむルはconf.luaファむルず同じフォルダヌにある必芁があり、同時に次のようになりたす。

 gw = 480 gh = 270 sx = 1 sy = 1 function love.conf(t) t.identity = nil --    () t.version = "0.10.2" --  LÖVE,      () t.console = false --   (boolean,   Windows) t.window.title = "BYTEPATH" --   () t.window.icon = nil --    ,     () t.window.width = gw --   () t.window.height = gh --   () t.window.borderless = false --       (boolean) t.window.resizable = true --      (boolean) t.window.minwidth = 1 --        () t.window.minheight = 1 --        () t.window.fullscreen = false --    (boolean) t.window.fullscreentype = "exclusive" --           () t.window.vsync = true --    (boolean) t.window.fsaa = 0 --      () t.window.display = 1 --  ,      () t.window.highdpi = false --    dpi     Retina (boolean) t.window.srgb = false --  - sRGB     (boolean) t.window.x = nil --  x      () t.window.y = nil --  y      () t.modules.audio = true --   (boolean) t.modules.event = true --    (boolean) t.modules.graphics = true --    (boolean) t.modules.image = true --    (boolean) t.modules.joystick = true --    (boolean) t.modules.keyboard = true --    (boolean) t.modules.math = true --    (boolean) t.modules.mouse = true --    (boolean) t.modules.physics = true --    (boolean) t.modules.sound = true --    (boolean) t.modules.system = true --    (boolean) t.modules.timer = true --    (boolean),    0 delta time  love.update    0 t.modules.window = true --    (boolean) t.modules.thread = true --    (boolean) end 

今すぐゲヌムを開始するず、りィンドりが小さくなっおいるこずがわかりたす。

ピクセル化されたビュヌを取埗するには、りィンドりを拡倧するずきに、远加の䜜業を行う必芁がありたす。 画面の䞭倮に円 gw/2, gh/2 を描くず、次のようになりたす。


そしお、䟋えば3*gw幅ず3*gh高さでlove.window.setModeを呌び出すこずにより、画面を盎接スケヌリングしたす。次のようになりたす


ご芧のように、円は画面に合わせお拡倧瞮小されず、小さな円のたたでした。 たた、画面を䞭倮にgh/2たせん。3倍にするず、 gw/2ずgh/2画面の䞭心でgh/2なくなるためです。 画面を通垞のモニタヌのサむズに拡倧するず、円も比䟋しおスケヌリングされピクセル化され、その䜍眮も比䟋しお倉わらないように、 480x270基本解像床で小さな円を描画できるようにしたいず思いたす。 この問題を解決する最も簡単な方法はCanvasを䜿甚するこずですCanvasは、他の゚ンゞンではフレヌムバッファヌたたはレンダヌタヌゲットずも呌ばれたす。 最初に、 Stageクラスのコンストラクタヌで基本的な解像床を持぀キャンバスを䜜成したす。

 function Stage:new() self.area = Area(self) self.main_canvas = love.graphics.newCanvas(gw, gh) end 

これにより、サむズが480x270キャンバスが䜜成され、その䞊に描画できたす。

 function Stage:draw() love.graphics.setCanvas(self.main_canvas) love.graphics.clear() love.graphics.circle('line', gw/2, gh/2, 50) self.area:draw() love.graphics.setCanvas() end 

キャンバスの描画方法は、 Canvasペヌゞの䟋で芋るこずができたす。 このペヌゞによるず、キャンバスに䜕かを描画したい堎合、 love.graphics.setCanvasを呌び出すlove.graphics.setCanvasがありたす。これlove.graphics.setCanvas 、すべおの描画操䜜が珟圚蚭定されおいるキャンバスにリダむレクトされたす。 次に、 love.graphics.clearを呌び出しlove.graphics.clear 。これは、珟圚のフレヌムのキャンバスの内容をクリアしたす。これは、前のフレヌムにも描画されおいたためです。 次に、必芁なすべおを描画した埌、 setCanvasを再利甚しsetCanvasが、今回は䜕も枡さないため、タヌゲットキャンバスが最新ではなくなり、描画操䜜のリダむレクトが実行されなくなりたす。

ここで停止するず、画面には䜕も起こりたせん。 これは、描画されたものすべおがキャンバスに移動したためですが、実際にはキャンバス自䜓をレンダリングしおいるわけではありたせん。 そのため、画面䞊にキャンバス自䜓を描画する必芁があり、次のようになりたす。

 function Stage:draw() love.graphics.setCanvas(self.main_canvas) love.graphics.clear() love.graphics.circle('line', gw/2, gh/2, 50) self.area:draw() love.graphics.setCanvas() love.graphics.setColor(255, 255, 255, 255) love.graphics.setBlendMode('alpha', 'premultiplied') love.graphics.draw(self.main_canvas, 0, 0, 0, sx, sy) love.graphics.setBlendMode('alpha') end 

love.graphics.drawを䜿甚しお画面にキャンバスを描画し、さらにlove.graphics.setBlendMode呌び出しでラップしたす。これはLÖVEwikiのCanvasペヌゞによるず、誀ったブレンドを防ぐために䜿甚されたす。 ここでプログラムを実行するず、描画された円が衚瀺されたす。

Canvas sxずsyを増やすために䜿甚したものに泚目しおください。 これらの倉数の倀は1ですが、たずえば倀を3に倉曎するず、次のようになりたす。


䜕も芋えたせん しかし、これは、キャンバス480x270䞭倮の円がキャンバス480x270の䞭倮にあるために1440x810 。 画面自䜓のサむズは480x270ため、画面よりも倧きいため、Canvas党䜓を芋るこずができたせん。 これを修正するために、呌び出されたずきに画面自䜓のサむズだけでなく、 sx 、 syを倉曎するresize関数をmain.lua䜜成できたす。

 function resize(s) love.window.setMode(s*gw, s*gh) sx, sy = s, s end 

したがっお、 love.loadでresize(3)をlove.loadず、次のようになりたす。


これが私たちが達成したこずです。 ただし、別の問題がありたす。円はピクセル化されず、がやけお芋えたす。

この理由は、LÖVEでレンダリングされたオブゞェクトを増枛するずきにFilterModeを䜿甚し、このフィルタリングモヌドがデフォルトで'linear'です。 ゲヌムにピクセル化された倖芳を持たせるため、倀を'nearest'に倉曎する必芁がありたす。 love.graphics.setDefaultFilterの最初に匕数'nearest'を指定しおlove.graphics.setDefaultFilterを呌び出すず、問題が解決するはずです。 別の偎面-LineStyleを'rough'に蚭定する必芁がありたす。 デフォルトでは'smooth' 、LÖVEプリミティブぱむリアスを䜿甚しおレンダリングされたすが、これはピクセルスタむルの䜜成には適しおいたせん。 これをすべお実行しおコヌドを再床実行するず、画面は次のようになりたす。


壊れおピクセル化された倖芳が必芁です 最も重芁なこずは、1぀の解像床を䜿甚しおゲヌム党䜓を䜜成できるこずです。 画面の䞭倮にオブゞェクトを䜜成する堎合、その䜍眮x, yはgw/2, gh/2に等しく、最終的な解像床に関係なく、オブゞェクトは垞に画面の䞭倮にあるこずを報告できたす。 これにより、プロセスが倧幅に簡玠化されたす。぀たり、ゲヌムがどのように芋えるか、オブゞェクトが画面䞊でどのように配垃されるかを䞀床だけ心配するだけで枈みたす。

ゲヌムサむズの緎習


65. Steamコンピュヌタ構成調査の「プラむマリディスプレむ解像床」セクションをご芧ください。 Steamナヌザヌのほが半数が䜿甚する最も䞀般的な解像床は1920x1080です。 私たちのゲヌムの基本的な解像床はそれに応じお拡匵されたす。 しかし、2番目に人気のある解像床は1366x768です。 480x270はそれに480x270したせん。 ゲヌムをフルスクリヌンモヌドに切り替えるずきに、非暙準の解像床で䜜業するためにどのようなオプションを提䟛できたすか

66.同じたたは類䌌のテクニックを䜿甚するコレクションからゲヌムを遞択したす基本解像床を䜎くしたす。 通垞、ピクセルグラフィックスを䜿甚したゲヌムで䜿甚されたす。 ゲヌムの基本的な解像床は䜕ですか 基本解像床を正しく入力できない非暙準のアクセス蚱可をゲヌムはどのように凊理したすか デスクトップの解像床を数回倉曎し、毎回異なる解像床でゲヌムを起動しお、倉曎を確認し、ゲヌムがバリ゚ヌションを凊理する方法を理解したす。

カメラ


3぀の郚屋すべおがカメラを䜿甚しおいるため、今すぐ怜蚎するのが論理的です。 チュヌトリアルの第2郚では、タむマヌにハンプラむブラリを䜿甚したした。 このラむブラリには䟿利なカメラモゞュヌルもあり、これも䜿甚したす。 しかし、私は画面を揺する機胜を備えたわずかに修正されたバヌゞョンを䜿甚しおいたす。 ここからファむルをダりンロヌドできたす 。 camera.luaファむルをハンプラむブラリフォルダヌに配眮しそしおcamera.luaの既存のバヌゞョンを䞊曞きしたす、カメラのrequireモゞュヌルをmain.lua远加したす。 Shake.luaファむルをobjectsフォルダヌに配眮したす。

さらに、私が曞いたラむブラリを䜿甚するこずもできたす。このラむブラリはすでにすべおの機胜を備えおいたす。チュヌトリアルの完了埌にこのラむブラリを䜜成したした。そのため、このラむブラリは䜿甚したせん。このラむブラリを䜿甚する堎合は、チュヌトリアルの䜜業を続行できたす。ただし、このラむブラリの機胜を䜿甚するためにいく぀かの偎面を匕き継ぎたす。

カメラを远加したら、次の機胜が必芁です。

 function random(min, max) local min, max = min or 0, max or 1 return (min > max and (love.math.random()*(min - max) + max)) or (love.math.random()*(max - min) + min) end 

任意の2぀の数字の間で乱数を取埗できたす。 Shake.luaファむルがShake.luaするため、これが必芁です。 utils.luaこの関数を定矩した埌utils.lua同様のこずを詊しおください。

 function love.load() ... camera = Camera() input:bind('f3', function() camera:shake(4, 60, 1) end) ... end function love.update(dt) ... camera:update(dt) ... end 

そしお、 Stageクラスで

 function love.load() ... camera = Camera() input:bind('f3', function() camera:shake(4, 60, 1) end) ... end function love.update(dt) ... camera:update(dt) ... end 

f3を抌すずf3画面が揺れ始めたす。


シェヌキング機胜は、 この蚘事で説明した機胜に基づいおいたす。 振幅ピクセル単䜍、呚波数、持続時間を取埗したす。 画面の揺れは、指定された秒数ず指定された呚波数で、振幅から埐々に枛衰しお実行されたす。 呚波数が高いほど、画面は2぀の制限振幅、-振幅の間でより掻発に振動したす。 䜎呚波数は反察になりたす。

たた、カメラはただ特定のポむントに結び付けられおいないこずに泚意するこずも重芁です。そのため、カメラを振るず、すべおの方向にスロヌされたす。぀たり、振動が完了するず、前のgifアニメヌションで芋られるように、別の堎所に䞭倮に配眮されたす。

この問題を解決する1぀の方法は、カメラを䞭倮に配眮するこずです。これはカメラに実装できたすlockPosition function カメラモゞュヌルの修正バヌゞョンでは、最初にdt匕数を受け取るように、カメラのすべおのモヌション関数を倉曎したした。 そしお、次のようになりたす。

 function Stage:update(dt) camera.smoother = Camera.smooth.damped(5) camera:lockPosition(dt, gw/2, gh/2) self.area:update(dt) end 

カメラをスムヌズにするには、 dampedモヌドを5 dampedしたす。 詊行錯誀によっおこれらのパラメヌタヌを掚枬したしたが、䞀般的にこれにより、カメラはスムヌズで快適な方法でタヌゲットポむントに焊点を合わせるこずができたす。 私たちは珟圚ステヌゞルヌムで䜜業しおいるので、このコヌドをステヌゞルヌム内に配眮したす。このルヌムでは、カメラは垞に画面の䞭倮にあり、画面を振る瞬間を陀いお移動するこずはありたせん。 その結果、次の結果が埗られたす。


ゲヌム党䜓では、郚屋ごずに個別のカメラむンスタンスを䜜成する必芁がないため、1぀のグロヌバルカメラを䜿甚したす。 ステヌゞルヌムでは、カメラは揺れ以倖は䜿甚されたせんので、今のずころここで停止したす。 コン゜ヌルルヌムずSkillTreeルヌムでは、カメラはより耇雑な方法で䜿甚されたすが、埌で説明したす。

プレむダヌの物理


これで、ゲヌム自䜓を開始するために必芁なものはすべお揃いたした。 Playerオブゞェクトから始めたす。 Player.luaずいうPlayer.luaのobjectsフォルダヌに新しいファむルを䜜成したす。これは次のようになりたす。

 Player = GameObject:extend() function Player:new(area, x, y, opts) Player.super.new(self, area, x, y, opts) end function Player:update(dt) Player.super.update(self, dt) end function Player:draw() end 

このようにしお、デフォルトで新しいクラスのゲヌムオブゞェクトを䜜成する必芁がありたす。 それらはすべおGameObjectを継承し、同じコンストラクタヌ構造を持ち、関数を曎新および描画したす。 次のように、ステヌゞルヌムでこのPlayerオブゞェクトをむンスタンス化できたす。

 function Stage:new() ... self.area:addGameObject('Player', gw/2, gh/2) end 

むンスタンス化の仕組みをテストし、Playerオブゞェクトが曎新され、 Area描画されるこずを確認するには、その䜍眮に円を描くだけです。

 function Player:draw() love.graphics.circle('line', self.x, self.y, 25) end 

これにより、画面の䞭倮に円が衚瀺されたす。 addGameObjectの呌び出しが䜜成されたオブゞェクトを返すので、 self.player 、 self.playerステヌゞ内にプレヌダヌぞのリンクを保存し、必芁に応じお、添付されたキヌを持぀Playerオブゞェクトのデスむベントを含めるこずができたす。

 function Stage:new() ... self.player = self.area:addGameObject('Player', gw/2, gh/2) input:bind('f3', function() self.player.dead = true end) end 

f3キヌを抌すず、Playerオブゞェクトが消滅する必芁がありたす。぀たり、円の描画が停止したす。 これは、前のパヌトでAreaオブゞェクトコヌドを構成した結果ずしお発生したす。 たた、この方法でaddGameObjectによっお返されたリンクを保存する堎合、 nilぞのリンクが保存される倉数を蚭定しないず、このオブゞェクトは削陀されないこずに泚意するこずも重芁です。 さらに、オブゞェクトをメモリから実際に削陀する堎合は、リンクをnil この堎合、文字列self.player = nil に蚭定するこずを忘れないこずが重芁です属性にdeadをtrueに蚭定するこずに加えお。



それでは、物理孊に移りたしょう。 プレむダヌ敵、シェル、リ゜ヌスなどは物理オブゞェクトになりたす。 このために、私はLÖVEでbox2d統合を䜿甚したすが、box2dのような完党な物理゚ンゞンを䜿甚しおも䜕の有甚性も埗られないため、䞀般的にこれはゲヌムには必芁ありたせん。 私はそれに慣れおいるのでそれを䜿甚したす。 ただし、独自の衝突凊理手順このようなゲヌムでは非垞に簡単ですを䜜成するか、これを行うラむブラリを䜿甚するこずをお勧めしたす。

チュヌトリアルでは、䜜成したwindfieldラむブラリを䜿甚したす。これにより、box2dをLÖVEで䜿甚するのがはるかに簡単になりたす。LÖVEには衝突も凊理する他のラむブラリがありたすHardonColliderたたはbump.luaです。

チュヌトリアルを繰り返すのではなく、衝突を自分で実装するか、これら2぀のラむブラリのいずれかを䜿甚するこずを匷くお勧めしたす。したがっお、継続的に開発する必芁がある胜力を開発するように匷制したす。たずえば、さたざたな゜リュヌションから遞択し、ニヌズに合った゜リュヌションを芋぀けお最適な方法で䜜業するだけでなく、問題に察する独自の゜リュヌションを開発するだけでなく、チュヌトリアルに埓うだけです。

繰り返したすが、このチュヌトリアルで挔習を行う䞻な理由の1぀は、玠材の習埗に積極的に関䞎しおいる堎合にのみ孊習するこずです。緎習は、資料に慣れるもう1぀の機䌚です。チュヌトリアルを繰り返しただけで、知らないこずに察凊するこずを孊ばなければ、実際に孊ぶこずはありたせん。したがっお、ここのチュヌトリアルから逞脱しお、物理/衝突郚分を自分で実装するこずを匷くお勧めしたす。

可胜であれば、ラむブラリwindfieldをダりンロヌドしお、そのrequireをファむルに远加できたすmain.lua。そのドキュメントによるず、2぀の䞻芁な抂念がありたす- WorldずCollider。ワヌルドはシミュレヌションが行われる物理的な䞖界であり、コラむダヌはこの䞖界の䞭でシミュレヌトされる物理的なオブゞェクトです。぀たり、ゲヌムには物理的な䞖界の倖芳が必芁であり、プレむダヌはこの䞖界内のコラむダヌになりたす。呌び出しを远加しお

、クラス内に䞖界を䜜成AreaしたすaddPhysicsWorld。

 function Area:addPhysicsWorld() self.world = Physics.newWorld(0, 0, true) end 

したがっお.world、物理䞖界を含む領域の属性を蚭定したす。たた、このワヌルドが存圚する堎合は、このワヌルドを曎新する必芁がありたす必芁に応じお、デバッグのために描画したす。

 function Area:update(dt) if self.world then self.world:update(dt) end for i = #self.game_objects, 1, -1 do ... end end function Area:draw() if self.world then self.world:draw() end for _, game_object in ipairs(self.game_objects) do game_object:draw() end end 

ゲヌムオブゞェクトの曎新情報を䜿甚するため、すべおのゲヌムオブゞェクトを曎新する前に物理䞖界を曎新したす。これは、物理シミュレヌションがこのフレヌムの前に実行される堎合にのみ可胜です。最初にゲヌムオブゞェクトを曎新する堎合、前のフレヌムからの物理情報を䜿甚し、これによりフレヌムが壊れたす。実際、これはプログラムの動䜜に倧きな圱響を䞎えたせんが、抂念的な芳点からはより混乱したす。

チャレンゞを通しお平和を加えたしたaddPhysicsWorldすべおの゚リアに物理的な䞖界を持たせたくないため、Areaコンストラクタに远加しただけではありたせん。たずえば、コン゜ヌルルヌムでもオブゞェクトを䜿甚しお゚ンティティを管理したすが、この領域に物理的な䞖界をアタッチする必芁はありたせん。したがっお、単䞀の関数を呌び出すこずにより、オプションにしたす。次のように、ステヌゞルヌム゚リアに物理䞖界のむンスタンスを䜜成できたす。

 function Stage:new() self.area = Area(self) self.area:addPhysicsWorld() ... end 

そしお、䞖界ができたので、Playerコラむダヌを远加できたす。

 function Player:new(area, x, y, opts) Player.super.new(self, area, x, y, opts) self.x, self.y = x, y self.w, self.h = 12, 12 self.collider = self.area.world:newCircleCollider(self.x, self.y, self.w) self.collider:setObject(self) end 

ここで、プレヌダヌが゚リアぞのリンクを持っおいるこずがどのように圹立぀かに泚目しおください。この方法で、゚リアのワヌルドオブゞェクトにアクセスしお、新しいコラむダヌを远加できるからです。このようなパタヌン゚リア内の゚ンティティぞのアクセスは頻繁に繰り返されたす。たずえば、すべおのオブゞェクトGameObjectが同じコンストラクタヌを持぀ように䜜成し、Area所属するオブゞェクトぞの参照を取埗したす。

コンストラクタの属性を持぀、我々プレむダヌwずhその幅ず高さを定矩し、我々は新しいを远加12次ず等しいですCircleCollider半埄が幅に等しい。幅ず高さを決定する堎合、円の圢でコラむダヌを䜜成するこずはあたり論理的ではありたせんが、異なる皮類の船を远加するず芖芚的にすべおの船の幅ず高さが異なるため、物理的にコラむダヌは垞に円になるため、将来的には有甚ですすべおの船が平等なチャンスを持ち、プレむダヌにずっお予枬可胜な行動をずるようにしたす。

コラむダヌを远加した埌setObject、Playerオブゞェクトを新しく䜜成されたコラむダヌにバむンドする関数を呌び出したす。これは、2぀のコラむダヌが衝突したずきに、オブゞェクトではなくコラむダヌの芳点から情報を取埗できるため䟿利です。たずえば、PlayerがProjectileず衝突する堎合、PlayerずProjectileを衚す2぀のコラむダヌがありたすが、オブゞェクト自䜓はない堎合がありたす。setObjectそしおgetObjectColliderが属するオブゞェクトを蚭定および取埗できたす。

これで、最終的にPlayerをそのサむズに応じおレンダリングできたす。

 function Player:draw() love.graphics.circle('line', self.x, self.y, self.w) end 

今すぐゲヌムを開始するず、プレヌダヌを衚す小さな円が衚瀺されたす。


物理挔習プレヌダヌ


自分で衝突を䜜成するか、衝突/物理の代替ラむブラリの1぀を遞択する堎合、これらの挔習を実行する必芁はありたせん。

67.物理䞖界のy軞の重力を512に倉曎したす。Playerオブゞェクトはどうなりたすか

68.呌び出しの3番目の匕数は䜕を行い、.newWorldfalseに蚭定するずどうなりたすかtrue / falseを蚭定する利点はありたすかどれ

プレむダヌの動き


このゲヌムでのプレヌダヌの動きは次のように動䜜したす。プレヌダヌが動く䞀定の速床ず、「巊」たたは「右」を保持するこずで倉曎できる角床がありたす。これを実装するには、いく぀かの倉数が必芁です。

 function Player:new(area, x, y, opts) Player.super.new(self, area, x, y, opts) ... self.r = -math.pi/2 self.rv = 1.66*math.pi self.v = 0 self.max_v = 100 self.a = 100 end 

ここrで、プレむダヌが移動する角床を定矩したす。最初は重芁です-math.pi/2、぀たり、䞊向きです。 LÖVEの角床は時蚈回りに瀺されおいたす。぀たりmath.pi/2、䞋向きで、a -math.pi/2は䞊向きです0は右向きです。倉数rvは、プレヌダヌが「巊」たたは「右」を抌したずきに角床が倉化する割合です。次に、がvあり、プレヌダヌの速床を瀺し、プレヌダヌmax_vの最倧速床を瀺したす。最埌の属性はa、プレヌダヌの加速を衚す属性です。すべおの倀は詊行錯誀によっお取埗されたす。

これらすべおの倉数を考慮しおプレヌダヌの䜍眮を曎新するために、同様のこずができたす

 function Player:update(dt) Player.super.update(self, dt) if input:down('left') then self.r = self.r - self.rv*dt end if input:down('right') then self.r = self.r + self.rv*dt end self.v = math.min(self.v + self.a*dt, self.max_v) self.collider:setLinearVelocity(self.v*math.cos(self.r), self.v*math.sin(self.r)) end 

最初の2行は、巊右のキヌを抌したずきに䜕が起こるかを決定したす。䜿甚する入力ラむブラリによるず、これらのバむンディングは事前に定矩する必芁があり、ファむルでこれを行いたしたmain.luaすべおにグロヌバル入力オブゞェクトを䜿甚するため。

 function love.load() ... input:bind('left', 'left') input:bind('right', 'right') ... end 

そしお、プレヌダヌが「巊」たたは「右」を抌すrず、プレヌダヌの角に察応する属性1.66*math.piが、察応する方向のラゞアンに倉わりたす。ここで、この倀にを掛けるdt、぀たりこの倀は1秒ごずに制埡されるこずに泚意するこずも重芁です。぀たり、角床の倉化率は1.66*math.piラゞアン/秒で枬定されたす。これは、ゲヌムサむクルの仕組みの結果であり、チュヌトリアルの最初の郚分で分析したした。

その埌、属性を蚭定したすv。それはもう少し耇雑ですが、他の蚀語でそれをやった堎合、それはあなたに銎染みがあるはずです。最初の蚈算の圢匏はself.v = self.v + self.a*dt、぀たり、加速床の分だけ速床を䞊げるだけです。この堎合、1秒あたり100ず぀増やしたす。しかし、属性も定矩したしたmax_v、最倧蚱容速床を制限する必芁がありたす。制限しない堎合、無期限にself.v = self.v + self.a*dt増加vし、プレむダヌは゜ニックになりたす。しかし、これは必芁ありたせんこれを防ぐ1぀の方法は次のずおりです。

 function Player:update(dt) ... self.v = self.v + self.a*dt if self.v >= self.max_v then self.v = self.max_v end ... end 

さらに、vそれが倧きくmax_vなったら、この倀に制限し、それを超えないようにしたす。これを蚘述する別の簡単な方法math.minは、枡されたすべおの匕数の䞭で最小倀を返す関数を䜿甚するこずです。私たちのケヌスでは、我々は結果を枡すself.v + self.a*dtず、self.max_v加算結果が倧きい堎合にはmax_v、その埌、math.min戻っおmax_vそれは小さい合蚈よりもあるずしお、。これは、Luaおよび他のプログラミング蚀語でもで非垞に䞀般的で䟿利なパタヌンです。

最埌に、setLinearVelocityxずyのコラむダヌ速床を属性に蚭定したすvオブゞェクトの角床に応じお適切な倀を掛けたす。䞀般的なケヌスでは、特定の方向に䜕かを動かしたいずきに角床を付けたい堎合、それcosを䜿甚しおx軞にsin沿っお移動し、y軞に沿っお移動する必芁がありたす。これは、2Dゲヌムの開発でも非垞に䞀般的なパタヌンです。あなたが孊校でそれを理解したず仮定しお、これに぀いおは説明したせんそうでない堎合は、䞉角法の基本をGoogleで怜玢しおください。

クラスに最埌の倉曎を加えるこずができたすが、GameObjectこれは非垞に簡単です。物理゚ンゞンを䜿甚しおいるため、速床ず䜍眮など、いく぀かの倉数に2぀の衚珟が栌玍されおいたす。属性x, yずを䜿甚しおプレヌダヌの䜍眮ず速床を取埗し、を䜿甚しvおコラむダヌの䜍眮ず速床を取埗したすgetPositionおよびgetLinearVelocity。これら2぀のビュヌを同期するこずは論理的であり、これを自動的に実珟する1぀の方法は、すべおのゲヌムオブゞェクトの芪クラスを倉曎するこずです。

 function GameObject:update(dt) if self.timer then self.timer:update(dt) end if self.collider then self.x, self.y = self.collider:getPosition() end end 

ここでは、次の凊理が行われたす。オブゞェクトの属性が定矩されおいる堎合collider、
それxずyコラむダヌの䜍眮にむンストヌルされたす。そしお、コラむダヌの䜍眮が倉わるず、オブゞェクト自䜓のこの䜍眮の衚珟もそれに応じお倉わりたす。

ここでプログラムを実行するず、次のように衚瀺されたす。

GIF

そのため、巊たたは右キヌを抌すず、通垞、Playerオブゞェクトは画面䞊を動き回り、方向を倉えるこずがわかりたす。ここでも重芁な点が1぀ありたすworld:draw()。Area オブゞェクトでは、呌び出しによっおコラむダヌが描画されたす。実際、コラむダヌだけでなく、この行をコメントアりトしおPlayerオブゞェクトを盎接描画するこずも論理的です。

 function Player:draw() love.graphics.circle('line', self.x, self.y, self.w) end 

最埌にできるこずは、プレむダヌが「芋る」方向を芖芚化するこずです。これは、プレむダヌの䜍眮から圌が指瀺されおいる偎に線を匕くだけで実行できたす。

 function Player:draw() love.graphics.circle('line', self.x, self.y, self.w) love.graphics.line(self.x, self.y, self.x + 2*self.w*math.cos(self.r), self.y + 2*self.w*math.sin(self.r)) end 

そしお、次のようになりたす。

GIF

これらは䞉角法の基本でもあり、ここでは以前に適甚したのず同じ考え方を䜿甚したす。䜍眮が䜍眮に察しお特定の角床になるように、䜍眮Bをdistance単䜍ずする䜍眮を取埗する堎合、パタヌンは次のようになりたす。これは2Dゲヌムの開発で非垞に頻繁に䜿甚されたす少なくずも、私には思えたす。このパタヌンを盎感的に理解するこずはあなたにずっお有甚です。ABangleAbx = ax + distance*math.cos(angle)by = ay + distance*math.sin(angle)

プレむダヌの動きの緎習


69.次の角床を床に倉換し粟神的に、どの象限に属するか巊䞊、右䞊、巊䞋、たたは右䞋を䌝えたす。LÖVEでは、孊校で教えられたように、コヌナヌは反時蚈回りでカりントされるこずを忘れないでください。

 math.pi/2 math.pi/4 3*math.pi/4 -5*math.pi/6 0 11*math.pi/12 -math.pi/6 -math.pi/2 + math.pi/4 3*math.pi/4 + math.pi/3 math.pi 

70.加速属性が必芁aですか存圚しない堎合、プレヌダヌの曎新機胜はどのようになりたすかその存圚に利点はありたすか

71.䜿甚される角床が等しく、距離がの堎合、䜍眮から(x, y)ポむントの䜍眮を取埗したす。BA-math.pi/4100


72.䜿甚する角床が等しく、距離が等しい堎合、䜍眮から(x, y)ポむントの䜍眮を取埗したす。䜍眮ず、およびそれらの間の距離ず角床は、前の挔習ず同じたたです。CBmath.pi/450AB


73.前の2぀の挔習に基づいお、ある地点Aから特定の地点に到達する必芁があるずきに䜿甚される䞀般的なパタヌンを教えおくださいC。角床ず距離を介しお到達できる䞭間地点のみを䜿甚できたすか

74.プレヌダヌ属性ずコラむダヌ属性ビュヌの同期で䜍眮ず速床が蚀及されおいたすが、回転はどうですかコラむダヌには、を介しおアクセスできるねじれがありたすgetAngle。同様に属性を介しお同期しないのはなぜrですか

ごみ収集


物理゚ンゞンず動きのコヌドを远加したので、これたで欠けおいたもの、぀たりメモリリヌクの凊理に集䞭できたす。プログラミング環境で発生する可胜性のある問題の1぀は、メモリリヌクです。これは、あらゆる皮類の吊定的な結果に぀ながる可胜性がありたす。 Luaなどのマネヌゞコヌド蚀語では、完党なメモリ管理よりもブラックボックスにデヌタが隠れるため、これはさらに厄介な問題になりたす。

ガベヌゞコレクタヌは次のように機胜したす。オブゞェクトを参照する参照がない堎合は削陀されたす。぀たり、倉数のみが参照するテヌブルがあるa堎合、割り圓おを実行するずきにa = nilガベヌゞコレクタは、参照されたテヌブルを他の誰も参照しおいないこずを理解するため、将来のガベヌゞコレクションサむクルでメモリから削陀できたす。 1぀のオブゞェクトが耇数回参照され、これらすべおのポむントからリンクを削陀するのを忘れるず、問題が発生したす。

たずえば、を䜿甚しお新しいオブゞェクトを䜜成するaddGameObjectず、オブゞェクトがリストに远加されたす.game_objects。これは、このオブゞェクトを指す単䞀のリンクず芋なされたす。ただし、オブゞェクト自䜓もこの関数で返されたす。したがっお、以前はこのようなこずを行いたしたself.player = self.area:addGameObject('Player', ...)。぀たり、Areaオブゞェクト内のリストにオブゞェクトぞのリンクを栌玍するこずに加えお、倉数ぞのリンクも栌玍したすself.player。぀たり、私たちが蚀うずきself.player.deadPlayerオブゞェクトはAreaオブゞェクトのゲヌムオブゞェクトのリストから削陀されたすが、それを指すため、メモリから削陀するこずはできたせんself.player。぀たり、この堎合、実際にメモリからPlayerオブゞェクトを削陀するには、dead倀をtrue に蚭定しおから実行する必芁がありself.player = nilたす。

これは起こりうるこずのほんの䞀䟋ですが、そのような問題はどこにでもありたす。サヌドパヌティのラむブラリを䜿甚する堎合は特に泚意する必芁がありたす。たずえば、私が曞いた物理ラむブラリには関数がありたすsetObjectColliderがオブゞェクトぞの参照を保存するようにオブゞェクトを枡したす。オブゞェクトが死んだ堎合、メモリから削陀されたすかいいえ、Colliderはただリンクを保存しおいるためです。他の条件でのみ同じ問題。問題を解決する1぀の方法はdestroy、リンクの削陀を凊理するために䜜成された関数を䜿甚しおオブゞェクトを明瀺的に削陀するこずです。

぀たり、すべおのオブゞェクトに次を远加できたす。

 function GameObject:destroy() self.timer:destroy() if self.collider then self.collider:destroy() end self.collider = nil end 

珟圚、すべおのオブゞェクトにデフォルトでこの機胜がありたすdestroy。この関数は、destroyEnhancedTimerオブゞェクトの関数、およびコラむダヌColliderの関数を呌び出したす。これらの関数は、ナヌザヌがおそらくメモリから削陀したいアむテムを逆参照したす。たずえばCollider:destroy、アクションの1぀に呌び出しがありたすself:setObject(nil)。このオブゞェクトを砎棄するため、Colliderにリンクを保存する必芁がなくなりたした。

次のように、゚リア曎新機胜を倉曎するこずもできたす。

 function Area:update(dt) if self.world then self.world:update(dt) end for i = #self.game_objects, 1, -1 do local game_object = self.game_objects[i] game_object:update(dt) if game_object.dead then game_object:destroy() table.remove(self.game_objects, i) end end end 

deadオブゞェクト属性がtrueの堎合、ゲヌムオブゞェクトのリストから削陀するこずに加えお、そのdestroy関数を呌び出しお、それぞの参照を削陀したす。この抂念を拡匵しお、物理䞖界自䜓にWorlddestroyがあるこずを認識でき、それを䜿甚しおAreaオブゞェクトを砎棄できたす。

 function Area:destroy() for i = #self.game_objects, 1, -1 do local game_object = self.game_objects[i] game_object:destroy() table.remove(self.game_objects, i) end self.game_objects = {} if self.world then self.world:destroy() self.world = nil end end 

゚リアを砎壊するずき、最初に゚リア内のすべおのオブゞェクトを砎壊し、次に物理䞖界が存圚する堎合はそれを砎壊したす。次のアクションに合わせおステヌゞルヌムを倉曎できたす。

 function Stage:destroy() self.area:destroy() self.area = nil end 

関数を倉曎するこずもできたすgotoRoom

 function gotoRoom(room_type, ...) if current_room and current_room.destroy then current_room:destroy() end current_room = _G[room_type](...) end 

current_room既存の倉数が属性であるかどうか、およびdestroy実際に郚屋が含たれおいるかどうかを確認したす。その堎合、destroy関数を呌び出したす。そしお、察象の郚屋に行きたす。

destroy関数を远加した埌は、すべおのオブゞェクトが次のパタヌンに埓う必芁があるこずを忘れないでください。

 NewGameObject = GameObject:extend() function NewGameObject:new(area, x, y, opts) NewGameObject.super.new(self, area, x, y, opts) end function NewGameObject:update(dt) NewGameObject.super.update(self, dt) end function NewGameObject:draw() end function NewGameObject:destroy() NewGameObject.super.destroy(self) end 

もちろん、これはすべお良いこずですが、実際にメモリからアむテムを削陀したかどうかを確認するにはどうすればよいですか私が奜きな1぀の投皿で答えを芋぀けたしたが、リヌクを远跡する比范的簡単な解決策もありたす

 function count_all(f) local seen = {} local count_table count_table = function(t) if seen[t] then return end f(t) seen[t] = true for k,v in pairs(t) do if type(v) == "table" then count_table(v) elseif type(v) == "userdata" then f(v) end end end count_table(_G) end function type_count() local counts = {} local enumerate = function (o) local t = type_name(o) counts[t] = (counts[t] or 0) + 1 end count_all(enumerate) return counts end global_type_table = nil function type_name(o) if global_type_table == nil then global_type_table = {} for k,v in pairs(_G) do global_type_table[v] = k end global_type_table[0] = "table" end return global_type_table[getmetatable(o) or 0] or "Unknown" end 

このコヌドは投皿で説明されおいるため解析したせんが、に远加しおからmain.lua、love.load次のコヌドを内郚に远加したす。

 function love.load() ... input:bind('f1', function() print("Before collection: " .. collectgarbage("count")/1024) collectgarbage() print("After collection: " .. collectgarbage("count")/1024) print("Object count: ") local counts = type_count() for k, v in pairs(counts) do print(k, v) end print("-------------------------------------") end) ... end 

このコヌドの機胜ナヌザヌがをクリックf1するず、ガベヌゞコレクションサむクルの前埌のメモリ量が衚瀺され、メモリ内のオブゞェクトのタむプも衚瀺されたす。これは、たずえば、オブゞェクトが内郚にある新しいステヌゞルヌムを䜜成しお削陀し、ステヌゞが䜜成される前ずメモリが同じたたはほが同じであるこずを確認できるようになったため䟿利です。同じたたである堎合、メモリリヌクはありたせん。メモリリヌクがない堎合は、問題が発生しおいるため、それらの゜ヌスを探す必芁がありたす。


ガベヌゞコレクションの挔習


75.キヌf2をバむンドしお、電話で新しいステヌゞルヌムを䜜成しおアクティブにしたすgotoRoom。

76.f3珟圚の郚屋の砎壊の鍵を瞛る。

77.を抌しお、䜿甚メモリ量を数回確認しf1たす。その埌f2、キヌずキヌを数回抌しお、f3新しい郚屋を䜜成および砎壊したす。もう䞀床を数回抌しお、䜿甚されおいるメモリの量を確認しf1たす。メモリヌの量は以前のたたですか、それずもそれ以䞊ですか

78.ステヌゞルヌムを蚭定しお、1぀ではなく100個のPlayerオブゞェクトを䜜成し、同様のこずを行いたす。

 function Stage:new() ... for i = 1, 100 do self.area:addGameObject('Player', gw/2 + random(-4, 4), gh/2 + random(-4, 4)) end end 

たた、プレヌダヌの曎新機胜を倉曎しお、プレヌダヌオブゞェクトが移動しないようにしたすモヌションコヌドをコメントアりトしたす。䜿甚メモリ量は倉曎されたしたか党䜓的な結果は倉わりたしたか



パヌト6プレヌダヌクラスの基本


はじめに


このセクションでは、Playerクラスに機胜を远加するこずに焊点を圓おたす。たず、プレむダヌの攻撃ずProjectileオブゞェクトを確認したす。次に、プレヌダヌの2぀の䞻な特性である、ブヌストずサむクル/ティックに焊点を圓おたす。そしお最埌に、ゲヌムに远加されるコンテンツの最初の郚分、぀たりさたざたなプレむダヌの船の䜜成を開始したす。このパヌトから始めお、ゲヌムプレむに関連する瞬間のみに焊点を圓おたす前の5぀のパヌトは準備段階でした。

プレむダヌ攻撃


このゲヌムのプレむダヌは次のように攻撃したす。毎秒n、攻撃が起動し、自動的に開始されたす。最終的に、16皮類の攻撃を受けたすが、それらのほずんどは、プレむダヌの船の芖線の方向ぞの砲撃に関連しおいたす。たずえば、これは誘導ミサむルによる攻撃です。

GIF

この攻撃はより速く発射されたすが、ランダムな角床で

GIF

攻撃ずシェルにはあらゆる皮類の特性があり、さたざたな偎面の圱響を受けたすが、それらの基瀎は垞に同じです。

たず、プレむダヌに毎秒攻撃させる必芁がありnたす。n攻撃によっお異なる数倀ですが、デフォルトでは重芁0.24です。これは、前のパヌトで説明したタむマヌラむブラリを䜿甚しお簡単に実装できたす。

 function Player:new() ... self.timer:every(0.24, function() self:shoot() end) end 

したがっお、関数shootを0.24秒ごずに呌び出し、この関数内に、発射物オブゞェクトの䜜成を凊理するコヌドを配眮したす。

これで、撮圱機胜内で䜕が起こるかを指定できたす。たず、小さな効果があり、ショットを瀺したす。実際には、次のルヌルを開発したした。ゲヌムから゚ンティティを䜜成たたは削陀するずき、付随する効果が衚瀺され、゚ンティティが画面からどこにも衚瀺されたり消えたりするずいう事実を隠したす。さらに、党䜓的な倖芳を改善する必芁がありたす。

この新しい効果を䜜成するには、最初に新しいゲヌムオブゞェクトを䜜成する必芁がありたすShootEffect今、あなたはすでにこれを行う方法を知っおいるはずです。この効果は、発射物が䜜成された䜍眮の隣に短時間画面䞊に残る単玔な正方圢である必芁がありたす。これを実珟する最も簡単な方法は、次のようなものを䜿甚するこずです。

 function Player:shoot() self.area:addGameObject('ShootEffect', self.x + 1.2*self.w*math.cos(self.r), self.y + 1.2*self.w*math.sin(self.r)) end 

 function ShootEffect:new(...) ... self.w = 8 self.timer:tween(0.1, self, {w = 0}, 'in-out-cubic', function() self.dead = true end) end function ShootEffect:draw() love.graphics.setColor(default_color) love.graphics.rectangle('fill', self.x - self.w/2, self.y - self.w/2, self.w, self.w) end 

そしお、次のようになりたす。

GIF

゚フェクトコヌドは非垞にシンプルです。これは、幅が8の正方圢で、0.1秒生存しおいたすtween。この時間の間に幅は、関数を䜿甚しお0になりたす。これたでのずころ、1぀の問題がありたす。゚フェクトの䜍眮は静的であり、プレヌダヌに远埓したせん。効果の持続時間が短いため、これは重芁ではないように芋えたすが、0.5秒以䞊に倉曎しおみおください。

この問題を解決する1぀の方法は、ShootEffectオブゞェクトをPlayerオブゞェクトぞの参照ずしお枡すこずです。したがっお、ShootEffectオブゞェクトは、その䜍眮をPlayerオブゞェクトず同期できたす。

 function Player:shoot() local d = 1.2*self.w self.area:addGameObject('ShootEffect', self.x + d*math.cos(self.r), self.y + d*math.sin(self.r), {player = self, d = d}) end 

 function ShootEffect:update(dt) ShootEffect.super.update(self, dt) if self.player then self.x = self.player.x + self.d*math.cos(self.player.r) self.y = self.player.y + self.d*math.sin(self.player.r) end end function ShootEffect:draw() pushRotate(self.x, self.y, self.player.r + math.pi/4) love.graphics.setColor(default_color) love.graphics.rectangle('fill', self.x - self.w/2, self.y - self.w/2, self.w, self.w) love.graphics.pop() end 

playerShootEffectオブゞェクトの属性にはopts、プレヌダヌのシュヌト機胜のテヌブルを介しお倀が割り圓おられたすself。これはself.player、ShootEffectオブゞェクトでPlayerオブゞェクトぞのリンクぞのアクセスを取埗できるこずを意味したす。通垞、オブゞェクトは他のオブゞェクトの関数から䜜成されるため、オブゞェクトぞの参照をこの方法で互いに枡したす。぀たり、を枡すずself、必芁なものが埗られたす。さらにd、Playerオブゞェクトの䞭心から゚フェクトが衚瀺される距離の倀を属性に割り圓おたす。これもテヌブルを䜿甚しお実装されたすopts。

次に、ShootEffectの曎新関数で、その䜍眮をプレヌダヌの䜍眮の倀に割り圓おたす。アクセスする倉数が蚭定されおいるかどうかを確認するこずは垞に重芁ですif self.player then、そうでない堎合、゚ラヌが発生するためです。たた、ゲヌムの今埌の䜜成䞭に、゚ンティティが他の堎所から参照される堎合が非垞に頻繁にあり、それらの倀にアクセスしようずしたすが、既に死んでいるため、これらの倀は蚭定されず、゚ラヌが発生したす。このこずを忘れずに、お互いの内郚の゚ンティティをこのように参照するこずが重芁です。

最埌に、ここで最埌に行うこずは、正方圢をプレヌダヌの角床ず同期させ、45床回転させお芋栄えを良くするこずです。これを行うにはpushRotate、次のような関数を䜿甚したす。

 function pushRotate(x, y, r) love.graphics.push() love.graphics.translate(x, y) love.graphics.rotate(r or 0) love.graphics.translate(-x, -y) end 

これは、遷移を遷移スタックに転送する単玔な関数です。本質的に、圌女は私たちが電話をするたでr、ポむントの呚りですべおをオンx, yにしたすlove.graphics.pop。぀たり、この䟋では、正方圢があり、プレヌダヌの角床に45床pi / 4ラゞアンを足した数だけ䞭心の呚りを回転させたす。完党を期すために、スケヌリングを含むこの関数の別のバヌゞョンを衚瀺できたす。

 function pushRotateScale(x, y, r, sx, sy) love.graphics.push() love.graphics.translate(x, y) love.graphics.rotate(r or 0) love.graphics.scale(sx or 1, sy or sx or 1) love.graphics.translate(-x, -y) end 

これらの関数は非垞に有甚であり、ゲヌム党䜓で䜿甚するため、それらを詊しおよく理解しおください

プレむダヌ攻撃挔習


80.珟時点では、プレヌダヌのコンストラクタヌで初期タむマヌ呌び出しのみを䜿甚したす。これにより、0.24秒ごずにシュヌト関数が呌び出されたす。Playerには、self.attack_speed5秒ごずに1〜2の範囲のランダムな倀に倉化する属性があるずしたす。

 function Player:new(...) ... self.attack_speed = 1 self.timer:every(5, function() self.attack_speed = random(1, 2) end) self.timer:every(0.24, function() self:shoot() end) 

プレヌダヌのオブゞェクトをどのように倉曎しお、0.24秒ごずに発砲するのではなく、1秒ごずに撃぀ようにし0.24/self.attack_speedたすかeveryシュヌト機胜の呌び出しの簡単な倉曎は機胜しないこずに泚意しおください。

81。前の郚分では、ガベヌゞコレクションを芋お、忘れられたリンクが危険であり、リヌクに぀ながる可胜性があるずいう事実に぀いお話したした。この郚分では、PlayerおよびShootEffectオブゞェクトの䟋を䜿甚しお、盞互にオブゞェクトを参照できるこずを説明したした。この堎合、ShootEffectがPlayerぞのリンクを含む短呜のオブゞェクトである堎合、このオブゞェクトをガベヌゞコレクタヌによっお削陀できるようにPlayerぞのリンクを逆参照するこずを心配する必芁がありたすかより䞀般的には、この方法で盞互に参照するオブゞェクトの逆参照をい぀凊理する必芁がありたすか

82.䜿甚しお、pushRotateプレヌダヌを䞭心に180床回転させたす。次のようになりたす。

GIF

83.䜿甚しお、pushRotateラむンを90床回転させ、プレヌダヌの䞭心を䞭心ずした動きの方向を瀺したす。次のようになりたす。

GIF

84.䜿甚しお、pushRotateプレヌダヌがプレヌダヌの䞭心の呚りを移動しおいる方向に線を90床回転したす。次のようになりたす。

GIF

85.䜿甚しお、pushRotateShootEffectオブゞェクトをプレヌダヌの䞭心の呚りに90床回転したすプレヌダヌの方向に察しお既に回転しおいるずいう事実に加えお。次のようになりたす。

GIF

プレむダヌシェル


これで射撃効果が埗られたので、シェル自䜓に進むこずができたす。発射䜓には、プレむダヌのメカニズムず非垞によく䌌た移動メカニズムがありたす。これは、この角床に応じお速床を蚭定できる角床を持぀物理オブゞェクトです。開始するには、シュヌト関数内に呌び出しを蚘述したしょう

 function Player:shoot() ... self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r), self.y + 1.5*d*math.sin(self.r), {r = self.r}) end 

そしお、予期しないこずは䜕もありたせん。Projectileの初期䜍眮を蚭定するにdは、以前に定矩した倉数ず同じ倉数を䜿甚し、プレヌダヌの角床を属性ずしお枡したすr。ShootEffectオブゞェクトずは異なり、Projectileオブゞェクトは䜜成時にプレヌダヌのコヌナヌ以倖を必芁ずしないため、プレヌダヌをリンクずしお枡す必芁はありたせん。

それでは、Projectileコンストラクタヌを芋おみたしょう。発射物オブゞェクトには、サヌクルコラむダヌプレヌダヌなど、移動の速床ず方向もありたす。

 function Projectile:new(area, x, y, opts) Projectile.super.new(self, area, x, y, opts) self.s = opts.s or 2.5 self.v = opts.v or 200 self.collider = self.area.world:newCircleCollider(self.x, self.y, self.s) self.collider:setObject(self) self.collider:setLinearVelocity(self.v*math.cos(self.r), self.v*math.sin(self.r)) end 

この属性sはコラむダヌの半埄ですr。この倉数は移動角床に既に䜿甚されおいるため、ずしお指定されおいたせん。䞀般的に、私は、倉数を䜿甚するオブゞェクトのサむズを蚭定するにはw、h、rたたはをs。オブゞェクトが長方圢の堎合は最初の2぀、円の堎合は最埌の2぀。倉数rがすでに方向に䜿甚されおいる堎合この堎合のように、radiusずしお䜿甚されsたす。ほずんどの堎合、これらのオブゞェクトには、衝突に関連するすべおの䜜業を行うコラむダヌが既にあるため、これらの属性は䞻に芖芚化に䜿甚されたす。

ここで䜿甚する別の偎面は、前述の蚭蚈opts.attribute or default_valueです。方法のおかげでor Luaで動䜜したす。このコンストラクトを䜿甚しお、以䞋を簡単に枡すこずができたす。

 if opts.attribute then self.attribute = opts.attribute else self.attribute = default_value end 

属性が存圚するかどうかを確認し、この属性に倉数を蚭定したす。存圚しない堎合は、デフォルト倀を割り圓おたす。その堎合、self.s倀opts.sが定矩されおいる堎合は倀が割り圓おられ、定矩されおいない堎合は倀が割り圓おられたす2.5。同じこずが圓おはたりself.vたす。最埌に、で発射䜓の速床を蚭定したす。これは、発射䜓setLinearVelocityの初期速床ずプレむダヌから送信される角床を瀺したす。プレヌダヌの動きず同じアプロヌチを䜿甚するため、これをすでに理解しおいる必芁がありたす。

次のように発射物を曎新およびレンダリングしおいる堎合

 function Projectile:update(dt) Projectile.super.update(self, dt) self.collider:setLinearVelocity(self.v*math.cos(self.r), self.v*math.sin(self.r)) end function Projectile:draw() love.graphics.setColor(default_color) love.graphics.circle('line', self.x, self.y, self.s) end 

次のようになりたす。

GIF

プレむダヌシェル挔習


86.プレむダヌのシュヌト機胜で、5で䜜成された発射䜓のサむズ/半埄を倉曎し、速床を150で倉曎したす。87

.シュヌト機胜を倉曎しお、1぀ではなく3぀のシェルを䜜成したす。 30床。次のようになりたす。

GIF

88.シュヌト関数を倉曎しお、1぀のシェルではなく3぀のシェルを䜜成し、各サむドシェルの䜍眮が䞭倮のシェルに察しお8ピクセルだけオフセットされるようにしたす。次のようになりたす。

GIF

89.発射物の初期速床を100に倉曎し、䜜成埌0.5秒以内に400に加速したす。

プレむダヌず発射䜓の死


プレヌダヌが移動しお簡単な攻撃を行えるようになったので、ゲヌムの远加ルヌルに泚意する必芁がありたす。これらのルヌルの1぀は、プレむダヌがゲヌム゚リアの端に觊れた堎合、圌は死ななければならないずいうこずです。同じこずがシェルにも圓おはたりたす。なぜなら、シェルは䜜成されおも砎壊されるこずはなく、ある時点で非垞に倚くのシェルが存圚するため、ゲヌムの速床が倧幅に䜎䞋するからです。

Projectileオブゞェクトから始めたしょう

 function Projectile:update(dt) ... if self.x < 0 then self:die() end if self.y < 0 then self:die() end if self.x > gw then self:die() end if self.y > gh then self:die() end end 

プレむ゚リアの䞭心がにあるこずgw/2, gh/2、぀たり巊䞊隅が0, 0にあり、右䞋隅がにあるこずがわかりgw, ghたす。そしお、発射䜓の曎新関数にいく぀かの条件構造を远加し、その䜍眮を確認する必芁がありたすdie。境界の倖偎にある堎合は、関数を呌び出す必芁がありたす。

同じロゞックがPlayerオブゞェクトに適甚されたす。

 function Player:update(dt) ... if self.x < 0 then self:die() end if self.y < 0 then self:die() end if self.x > gw then self:die() end if self.y > gh then self:die() end end 

では、関数に進みたしょうdie。それは非垞に単玔であり、本質的に、dead゚ンティティの属性をtrueに蚭定しおから芖芚効果を䜜成するだけです。発射物の堎合、䜜成される゚フェクトは呌び出されProjectileDeathEffectたす。 ShootEffectの堎合のように、これは短時間画面䞊に残り、その埌消えたすが、いく぀かの違いがありたす。䞻な違いは、ProjectileDeathEffectがしばらくちら぀き、その埌通垞の色に戻っおフェヌドするこずです。これにより、軜くお面癜い綿の効果が生たれたす。したがっお、コンストラクタヌは次のようになりたす。

 function ProjectileDeathEffect:new(area, x, y, opts) ProjectileDeathEffect.super.new(self, area, x, y, opts) self.first = true self.timer:after(0.1, function() self.first = false self.second = true self.timer:after(0.15, function() self.second = false self.dead = true end) end) end 

効果がどの段階にあるかを瀺す2぀の属性- firstずを特定secondしたした。圌が最初の段階にいる堎合、圌は癜い色を持ち、2番目の段階で圌は圌の本圓の色を取りたす。2番目のステヌゞが完了した埌、゚フェクトは「消滅」しdeadたす。これは、trueに蚭定するこずによっお行われたす。これはすべお0.25秒0.1 + 0.15以内に発生したす。぀たり、非垞に短呜で迅速な効果です。゚フェクトは、ShootEffectレンダリングメ゜ッドず非垞によく䌌た方法でレンダリングされたす。

 function ProjectileDeathEffect:draw() if self.first then love.graphics.setColor(default_color) elseif self.second then love.graphics.setColor(self.color) end love.graphics.rectangle('fill', self.x - self.w/2, self.y - self.w/2, self.w, self.w) end 

ここでは、゚フェクトの段階に応じお色を蚭定し、この色の長方圢を描画したす。この効果をdieProjectileオブゞェクトの関数に実装したす。

 function Projectile:die() self.dead = true self.area:addGameObject('ProjectileDeathEffect', self.x, self.y, {color = hp_color, w = 3*self.s}) end 

ゲヌムの色数には限りがあるこずを以前に蚀及するのを忘れおいたした。私はアヌティストではないので、色に぀いお考えるのに倚くの時間を費やしたくありたせん。そのため、いく぀かのよく䞀臎する色を遞択しお、ゲヌム党䜓で䜿甚したした。これらの色はで定矩されglobals.lua、次のようになりたす。

 default_color = {222, 222, 222} background_color = {16, 16, 16} ammo_color = {123, 200, 164} boost_color = {76, 195, 217} hp_color = {241, 103, 69} skill_point_color = {255, 198, 93} 

発射䜓の死の゚フェクトでは、色hp_color赀を䜿甚しお゚フェクトの倖芳を瀺したすが、将来的には発射䜓オブゞェクトの色を正しく䜿甚する予定です。攻撃の皮類によっお色が異なるため、死の効果も攻撃に応じお色が異なりたす。珟圚の効果は次のずおりです。

GIF



それでは、Playerのデス効果に移りたしょう。最初に行うこずはdie、Projectileオブゞェクトの関数をコピヌしdead、プレヌダヌが画面の境界に達したずきに属性をtrueに蚭定するこずです。これにより、芖芚効果を死に远加できたす。プレむダヌが死亡したずきの䞻な特殊効果はExplodeParticle、爆発のようなものず呌ばれる粒子ビヌムです。䞀般的な堎合、粒子は初期䜍眮からランダムな角床で移動し、長さが埐々に枛少する線になりたす。これはほがこの方法で実装できたす。

 function ExplodeParticle:new(area, x, y, opts) ExplodeParticle.super.new(self, area, x, y, opts) self.color = opts.color or default_color self.r = random(0, 2*math.pi) self.s = opts.s or random(2, 3) self.v = opts.v or random(75, 150) self.line_width = 2 self.timer:tween(opts.d or random(0.3, 0.5), self, {s = 0, v = 0, line_width = 0}, 'linear', function() self.dead = true end) end 

ここで、いく぀かの属性を特定したした。それらのほずんどは、それ自䜓が語っおいたす。さらに、0.3〜0.5秒の間隔で、トゥむヌンを䜿甚しおラむンのサむズ、速床、幅を0に倉曎し、トランゞションが完了するず、パヌティクルは「消滅」したす。パヌティクルモヌションコヌドはProjectileずPlayerに䌌おいるため、スキップしたす。圌女はちょうど圌女の速床で角床に埓いたす。

そしお最埌に、粒子は線ずしお描かれたす

 function ExplodeParticle:draw() pushRotate(self.x, self.y, self.r) love.graphics.setLineWidth(self.line_width) love.graphics.setColor(self.color) love.graphics.line(self.x - self.s, self.y, self.x + self.s, self.y) love.graphics.setColor(255, 255, 255) love.graphics.setLineWidth(1) love.graphics.pop() end 

通垞、回転するものこの堎合はパヌティクルの方向の角床を描画する必芁がある堎合、角床0右方向であるかのように描画したす。぀たり、この堎合、巊から右に線を匕く必芁があり、その䞭心が回転䜍眮になりたす。぀たりs、実際には行のサむズの半分であり、フルサむズではありたせん。たた、このlove.graphics.setLineWidthラむンを䜿甚しお、最初は倪字にし、時間ずずもに现くしたす。

パヌティクルは非垞に簡単な方法で䜜成されたす。関数でそれらの乱数を䜜成するだけですdie

 function Player:die() self.dead = true for i = 1, love.math.random(8, 12) do self.area:addGameObject('ExplodeParticle', self.x, self.y) end end 

最埌にできるこずは、キヌをバむンドしおdiePlayer 関数をトリガヌするこずです。これは、画面の端でぱフェクトを完党に芋るこずができないためです。

 function Player:new(...) ... input:bind('f4', function() self:die() end) end 

そしお、次のようになりたす。

GIF

しかし、写真はあたり印象的ではありたせんでした。瞬間をより劇的にするために、時間を少し遅くするこずができたす。ほずんどの人はこれに気付かないでしょうが、泚意深く芋れば、倚くのゲヌムはプレむダヌがダメヌゞを受けるか死ぬ時間をわずかに遅くしたす。ダりンりェルが良い䟋です。このビデオはゲヌムプレむを瀺しおいたす。あなたが自分でそれを芳察しお気付くように、私は損傷が行われた時間に泚意したした。

これを自分で実装するのは非垞に簡単です。最初に、グロヌバル倉数slow_amountを定矩love.loadしお初期倀1を割り圓おたす。この倉数を䜿甚しお、すべおの曎新関数で枡されたデルタを乗算したす。したがっお、時間を50遅くする必芁がある堎合は、slow_amount0.5の倀。この乗算の実行は次のようになりたす。

 function love.update(dt) timer:update(dt*slow_amount) camera:update(dt*slow_amount) if current_room then current_room:update(dt*slow_amount) end end 

そしお今、それを起動させる関数を決定する必芁がありたす。䞀般的なケヌスでは、短時間で時間の膚匵を元に戻す必芁がありたす。したがっお、この関数にスロヌダりンレベルずずもにその期間を远加するこずは論理的です。

 function slow(amount, duration) slow_amount = amount timer:tween('slow', duration, _G, {slow_amount = 1}, 'in-out-cubic') end 

぀たり、呌び出しslow(0.5, 1)ずは、ゲヌムの速床が最初に50に䜎䞋し、1秒埌に最高速床に戻るこずを意味したす。ここで、tween関数は文字列を䜿甚するこずに泚意するこずが重芁'slow'です。前の郚分で説明したように、これは、別のスロヌ関数のトゥむヌンがただアクティブな状態でスロヌ関数が呌び出されるず、この前のトゥむヌンがキャンセルされ、新しいトゥむヌンが継続するこずを意味したす。これにより、1぀の倉数で2぀のトゥむヌン関数が同時に実行されなくなりたす。プレむダヌの死亡䞭

に電話をかけるずslow(0.15, 1)、次のものが埗られたす。

GIF

ここで、画面の揺れを远加するこずもできたす。カメラモゞュヌルには既にfunction :shakeがあるため、次を远加できたす。

 function Player:die() ... camera:shake(6, 60, 0.4) ... end 

最埌に、いく぀かのフレヌムで画面をちら぀くこずができたす。これは、気づかないかもしれない倚くのゲヌムで䜿甚されおいる別の効果ですが、党䜓ずしお芖芚効果の良い印象を䜜り出したす。この効果は非垞に単玔です。呌び出されるflash(n)ず、画面がnフレヌムの間背景でちら぀きたす。そのような可胜性を実珟する䞀぀の方法は、グロヌバル倉数を定矩するこずflash_framesでlove.load最初にれロであるが。flash_framesnilに等しい堎合、これは効果が非アクティブであるこずを意味し、nilに等しくない堎合、アクティブになりたす。フリッカヌ関数は次のようになりたす。

 function flash(frames) flash_frames = frames end 

これで関数で蚭定できたすlove.draw

 function love.draw() if current_room then current_room:draw() end if flash_frames then flash_frames = flash_frames - 1 if flash_frames == -1 then flash_frames = nil end end if flash_frames then love.graphics.setColor(background_color) love.graphics.rectangle('fill', 0, 0, sx*gw, sy*gh) love.graphics.setColor(255, 255, 255) end end 

最初に、各フレヌムflash_framesで1 ず぀枛少し、次に、到達-1するず゚フェクトが完了しおいるため、nilを割り圓おたす。そしお、効果が完了しない堎合、background_color画面党䜓を芆う色の倧きな長方圢を描くだけです。これを関数に远加するずdie次のようになりたす。

 function Player:die() self.dead = true flash(4) camera:shake(6, 60, 0.4) slow(0.15, 1) for i = 1, love.math.random(8, 12) do self.area:addGameObject('ExplodeParticle', self.x, self.y) end end 

そうするこずで、以䞋が埗られたす。

GIF

これは非垞に匱くお埮劙な効果ですが、そのような小さなディテヌルは党䜓像をより匷力で矎しいものにしたす。

デスプレヌダヌ/発射䜓の緎習


90.firstおよび属性secondを䜿甚せずに、新しい属性のみを䜿甚せずにProjectileDeathEffectオブゞェクトの色を倉曎する効果を他にどのように実珟できたすcurrent_colorか

91.関数を倉曎しお、flashフレヌムではなく秒単䜍で期間を取埗したす。どちらが良いですか、それずも単なる奜みの問題ですかタむマヌは秒ではなくフレヌムを䜿甚しお継続時間を枬定できたすか

プレむダヌタクト


次に、Playerのもう1぀の重芁な偎面であるサむクルメカニズムに進みたす。ゲヌムは、パッシブスキルのツリヌに、各サむクルでトリガヌされる可胜性のあるスキルがあるように機胜したす。サむクルは、n秒ごずに機胜する単なるカりンタヌです。䞻なタスクを蚭定する必芁がありたす。このため、tick5秒ごずに関数呌び出しを行いたす。

 function Player:new(...) ... self.timer:every(5, function() self:tick() end) end 

tick関数では、たずTickEffect、各メゞャヌで機胜する小さな芖芚効果を远加したす。この効果は、Downwellの曎新効果に䌌おいたす䞊蚘のDownwellに関するビデオを参照。これは、プレむダヌず短時間オヌバヌラップする倧きな長方圢です。次のようになりたす。

GIF

最初に気付くのは、倧きな長方圢がプレヌダヌを芆い、時間ずずもに小さくなるこずです。しかし、ShootEffectず同様に、圌もプレむダヌをフォロヌしたす。぀たり、TickEffectオブゞェクトぞの参照ずしおPlayerオブゞェクトを枡す必芁があるこずを理解しおいたす。

 function Player:tick() self.area:addGameObject('TickEffect', self.x, self.y, {parent = self}) end 

 function TickEffect:update(dt) ... if self.parent then self.x, self.y = self.parent.x, self.parent.y end end 

たた、長方圢は時間の経過ずずもに小さくなりたすが、高さだけが小さくなりたす。これを実装する最も簡単な方法は次のずおりです。

 function TickEffect:new(area, x, y, opts) TickEffect.super.new(self, area, x, y, opts) self.w, self.h = 48, 32 self.timer:tween(0.13, self, {h = 0}, 'in-out-cubic', function() self.dead = true end) end 

しかし、これを行おうずするず、長方圢が本来のように立ち䞊がらず、プレヌダヌの䞭心付近で単玔に小さくなるこずがわかりたす。この問題を解決する1぀の方法は、時間y_offsetずずもに増加する属性を導入するこずです。これはy、TickEffectオブゞェクトの䜍眮から枛算されたす。

 function TickEffect:new(...) ... self.y_offset = 0 self.timer:tween(0.13, self, {h = 0, y_offset = 32}, 'in-out-cubic', function() self.dead = true end) end function TickEffect:update(dt) ... if self.parent then self.x, self.y = self.parent.x, self.parent.y - self.y_offset end end 

このようにしお、目的の効果を埗るこずができたす。今のずころ、ティック関数はこれですべおです。埌で特性ず受動的スキルを远加し、新しいコヌドが衚瀺されたす。

プレむダヌの加速


ゲヌムプレむのもう1぀の重芁な偎面は加速です。ナヌザヌが抌し䞊げるず、プレヌダヌはより速く動き始めなければなりたせん。そしお、ナヌザヌが「䞋」を抌すず、プレヌダヌはよりゆっくりず動き始めなければなりたせん。この加速メカニズムはゲヌムプレむの基本的な郚分です。メゞャヌず同様に、たず基本を䜜成し、次にそれらに新しい機胜を远加したす。

たず、キヌ管理を構成する必芁がありたす。プレヌダヌにはmax_v、プレヌダヌが移動できる最倧速床を蚭定する属性がありたす。䞊/䞋を抌すず、この倀が倉化し、倧きく/小さくなりたす。ここでの問題は、キヌを攟した埌、通垞の倀に戻す必芁があるこずです。したがっお、ベヌス倀を栌玍する別の倉数ず、珟圚の倀を含む別の倉数が必芁です。

修食子によっお倉曎する必芁がある぀たり、基本倀ず珟圚の倀が必芁ゲヌム内の特性速床などの存圚は、非垞に䞀般的なパタヌンです。埌で、ゲヌムに新しい特性ず受動的なスキルを远加し、これをより詳现に怜蚎したす。ただし、珟時点ではbase_max_v、最倧速床の初期倀/基本倀を含む属性を远加したす。通垞の属性max_vには、可胜なすべおの修食子が適甚される珟圚の最倧速床が含たれたす加速床など。

 function Player:new(...) ... self.base_max_v = 100 self.max_v = self.base_max_v end function Player:update(dt) ... self.max_v = self.base_max_v if input:down('up') then self.max_v = 1.5*self.base_max_v end if input:down('down') then self.max_v = 0.5*self.base_max_v end end 

このコヌドでは、各フレヌムにmax_v倀を割り圓お、base_max_v䞊䞋キヌが抌されおいるかどうかを確認し、それに応じお倉曎したすmax_v。泚意するこずが重芁です-これは、setLinearVelocity䜿甚埌に呌び出しmax_vが発生する必芁があるこずを意味したす。そうしないず、すべおがバラバラになりたす。基本的な加速機胜ができたので、芖芚効果を远加できたす。これを行うには、プレむダヌのオブゞェクトに排気トレヌスを远加したす。



GIF

トレヌス䜜成は䞀般的なパタヌンに埓いたす。各フレヌムごずに新しいオブゞェクトを䜜成し、䞀定時間、トゥむヌン関数を䜿甚しおオブゞェクトのサむズを瞮小したす。時間が経぀に぀れお、オブゞェクトの埌にオブゞェクトを䜜成し、それらが隣同士に描画されたす。前に䜜成されたものは小さくなりたすが、䜜成されたばかりのものは倧きくなりたす。それらはすべおプレむダヌの䞋郚に䜜成され、プレむダヌが移動するず、必芁なトレヌス効果が埗られたす。

これを実装するためTrailParticleに、特定の半埄の円である新しいオブゞェクトを䜜成し、特定の時間、トゥむヌン関数で瞮小するこずができたす。

 function TrailParticle:new(area, x, y, opts) TrailParticle.super.new(self, area, x, y, opts) self.r = opts.r or random(4, 6) self.timer:tween(opts.d or random(0.3, 0.5), self, {r = 0}, 'linear', function() self.dead = true end) end 

たずえば、'in-out-cubic'代わり'linear'にさたざたな遷移モヌドを䜿甚するず、トラックの圢状が倉わりたす。私は最も矎しいように芋えるので、私は線圢を䜿甚したしたが、別のものを遞択できたす。 draw関数は、属性を䜿甚しお、察応する色ず半埄の円を描くだけですr。

Playerオブゞェクトの偎から、次のような新しいTrailParticleを䜜成できたす。

 function Player:new(...) ... self.trail_color = skill_point_color self.timer:every(0.01, function() self.area:addGameObject('TrailParticle', self.x - self.w*math.cos(self.r), self.y - self.h*math.sin(self.r), {parent = self, r = random(2, 4), d = random(0.15, 0.25), color = self.trail_color}) end) 

぀たり、0.01秒ごず぀たり、各フレヌム内に、2〜4のランダムな半埄、0.15〜0.25秒のランダムな持続時間、および色skill_point_color黄色を持぀プレヌダヌ甚の新しいTrailParticleオブゞェクトを䜜成したす。

たた、「䞊」たたは「䞋」を抌すず、粒子の色を青に倉曎できたす。これを行うには、アクセラレヌションコヌドにロゞックを远加する必芁がありたす。぀たり、アクセラレヌションがい぀発生するかを通知する必芁があり、そのためにattributeが必芁ですboosting。この属性を䜿甚するず、加速がい぀発生するかを確認し、それに応じお参照される色を倉曎できたすtrail_color。

 function Player:update(dt) ... self.max_v = self.base_max_v self.boosting = false if input:down('up') then self.boosting = true self.max_v = 1.5*self.base_max_v end if input:down('down') then self.boosting = true self.max_v = 0.5*self.base_max_v end self.trail_color = skill_point_color if self.boosting then self.trail_color = boost_color end end 

そのため、プレヌダヌが加速するず、色が青から青に倉わるこずになりたしtrail_colorたboost_color。

プレむダヌシップグラフィックス


このパヌトで最埌に芋るのは船ですゲヌムには倚くの異なる皮類の船があり、それぞれに独自の特性、受動的なスキル、および倖芳がありたす。ここたでは、倖芳のみに焊点を合わせお1隻の船を远加し、挔習ではさらに7隻を䜜成する必芁がありたす。

たた、コンテンツに蚀及する䟡倀がありたすゲヌムにコンテンツを远加する必芁がある堎合-船、パッシブスキル、さたざたなメニュヌオプション、スキルツリヌの芖芚的構築など、ほずんどの䜜業を自分で行う必芁がありたす。チュヌトリアルでは、これを1぀の䟋のみで行いたす。その埌、新しい類䌌コンテンツを手動で手動で远加する必芁があるため、この䜜業を挔習に入れたす。

これを行う理由は2぀ありたす。たず、すべおの詳现な説明に時間がかかりすぎお、チュヌトリアルが非垞に長くなりたす。第二に、ゲヌムにコンテンツを自分で远加するこずにより、手動䜜業を行う方法を孊ぶ必芁がありたす。ゲヌムの開発のほずんどは、「新しい」ものを䜜成せずにコンテンツを远加するだけです。気に入らないかもしれない倚くの仕事をしなければならないので、あなたはこれを奜たないかもしれたせん。これは、埌で理解するよりも、早く理解するこずをお勧めしたす。これが望たしくない堎合は、たずえば、倚くの手䜜業を必芁ずしないゲヌムの䜜成に集䞭できたす。しかし、私のゲヌムはたったく別のケヌスです。スキルツリヌには玄800のノヌドがあり、それらはすべお手動で蚭定する必芁がありたすツリヌが同じ倧きさの堎合は同じこずをする必芁がありたす。これは、この皮の䜜業が奜きかどうかを理解する絶奜の機䌚です。かどうか。

なるほど、1隻の船から始めたしょう。衚瀺は次のずおりです。

GIF

ご芧のずおり、本䜓ず2぀の翌の3぀の郚分で構成されおいたす。単玔なポリゎンのセットから描画したす。぀たり、3぀の別々のポリゎンを定矩する必芁がありたす。船が右に曲がったかのようにポリゎンの䜍眮を決定したす䞊で説明したように、これは角床0です。次のようなものが埗られたす。

 function Player:new(...) ... self.ship = 'Fighter' self.polygons = {} if self.ship == 'Fighter' then self.polygons[1] = { ... } self.polygons[2] = { ... } self.polygons[3] = { ... } end end 

各ポリゎンテヌブル内で、ポリゎンの頂点を定矩したす。これらのポリゎンを描画するには、いく぀かの䜜業を行う必芁がありたす。最初に、プレヌダヌの䞭心の呚りにポリゎンを回転させる必芁がありたす。

 function Player:draw() pushRotate(self.x, self.y, self.r) love.graphics.setColor(default_color) --    love.graphics.pop() end 

その埌、各ポリゎンを怜​​蚎する必芁がありたす。

 function Player:draw() pushRotate(self.x, self.y, self.r) love.graphics.setColor(default_color) for _, polygon in ipairs(self.polygons) do --     end love.graphics.pop() end 

次に、各ポリゎンを描画したす。

 function Player:draw() pushRotate(self.x, self.y, self.r) love.graphics.setColor(default_color) for _, polygon in ipairs(self.polygons) do local points = fn.map(polygon, function(k, v) if k % 2 == 1 then return self.x + v + random(-1, 1) else return self.y + v + random(-1, 1) end end) love.graphics.polygon('line', points) end love.graphics.pop() end 

最初に行うこずは、すべおのポむントを正しく順序付けるこずです。各ポリゎンはロヌカルに定矩する必芁がありたす。぀たり、その䞭心からの距離は等しいず芋なされ0, 0たす。これは、各ポリゎンがただ䞖界のどの䜍眮にいるかをただ知らないこずを意味したす。

関数fn.mapは、テヌブル内の各芁玠をバむパスし、関数を適甚したす。この堎合、関数はむンデックスのパリティをチェックしたす。奇数の堎合、コンポヌネントxを瀺し、偶数の堎合、コンポヌネントyを瀺したす。぀たり、これらの各ケヌスでは、プレむダヌのxたたはy䜍眮を頂点に远加するだけでなく、-1から1の範囲の乱数を远加するこずで、船がもう少しファゞヌで面癜く芋えるようにしたす。そしお最埌に、love.graphics.polygonこれらすべおのポむントを描画するために呌び出されたす。

各ポリゎンの定矩は次のずおりです。

 self.polygons[1] = { self.w, 0, -- 1 self.w/2, -self.w/2, -- 2 -self.w/2, -self.w/2, -- 3 -self.w, 0, -- 4 -self.w/2, self.w/2, -- 5 self.w/2, self.w/2, -- 6 } self.polygons[2] = { self.w/2, -self.w/2, -- 7 0, -self.w, -- 8 -self.w - self.w/2, -self.w, -- 9 -3*self.w/4, -self.w/4, -- 10 -self.w/2, -self.w/2, -- 11 } self.polygons[3] = { self.w/2, self.w/2, -- 12 -self.w/2, self.w/2, -- 13 -3*self.w/4, self.w/4, -- 14 -self.w - self.w/2, self.w, -- 15 0, self.w, -- 16 } 

最初は本䜓、2番目は䞊翌、3番目は䞋翌です。すべおの頂点は反時蚈回りに順番に決定されたす。ラむンの最初のポむントは垞にコンポヌネントxを瀺し、2番目のポむントはコンポヌネントyを瀺したす。䞊蚘の数字のペアぞの各頂点のバむンドは次のようになりたす。


ご芧のずおり、最初の点は右端にあり、䞭心に揃えられおいたす。぀たり、座暙がありself.w, 0たす。次の芁玠は、最初の芁玠の少し巊䞊にありたす。぀たり、その座暙self.w/2, -self.w/2などです。

最埌に、ポむントを远加した埌、トラックを船に䞀臎させるこずができたす。この堎合、䞊蚘のgifからわかるように、1぀ではなく2぀のトラックがありたす。

 function Player:new(...) ... self.timer:every(0.01, function() if self.ship == 'Fighter' then self.area:addGameObject('TrailParticle', self.x - 0.9*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r - math.pi/2), self.y - 0.9*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r - math.pi/2), {parent = self, r = random(2, 4), d = random(0.15, 0.25), color = self.trail_color}) self.area:addGameObject('TrailParticle', self.x - 0.9*self.w*math.cos(self.r) + 0.2*self.w*math.cos(self.r + math.pi/2), self.y - 0.9*self.w*math.sin(self.r) + 0.2*self.w*math.sin(self.r + math.pi/2), {parent = self, r = random(2, 4), d = random(0.15, 0.25), color = self.trail_color}) end end) end 

ここでは、次のテクニックを䜿甚したす。ゎヌルに到達するために必芁な角床に基づいお、ポむントからポむントに枡したす。必芁なタヌゲットポむントはプレヌダヌの埌ろ埌ろ0.9*self.wにありたすが、それぞれ0.2*self.wがプレヌダヌの動きずは反察の軞に沿っおわずかな距離移動したす。

これはすべお次のようになりたす。

GIF


船のグラフィック挔習


小さなメモラベルCONTENTは、それ自䜓がゲヌムのコンテンツである゚クササむズを瀺したす。このようにマヌクされた゚クササむズには答えがありたせんので、完党に自分で行う必芁がありたすこの瞬間から、たすたす倚くの゚クササむズがこのようになりたす。ゲヌム自䜓に進み始めおおり、その倧郚分はコンテンツを手動で远加するだけだからです。

92.コンテンツさらに7皮類の船を远加したす。新しいタむプの船を远加するにelseif self.ship == 'ShipName' thenは、ポリゎンの定矩ずトレヌスの定矩の䞡方に別の条件付き蚭蚈を远加するだけです。これは私が䜜成した船の倖芳ですただし、もちろん、自分で䜜成しお独自のデザむンを䜜成できたす。

GIF




これらのチュヌトリアルが奜きで、将来䌌たようなものを曞くように刺激したい堎合


itch.ioのチュヌトリアルを賌入するず、ゲヌムの完党な゜ヌスコヌド、挔習1〜9の回答、䞀郚に分かれたコヌドコヌドはチュヌトリアルの各郚の終わりに芋えるはずです、およびゲヌムキヌにアクセスできたす。 Steamで。

Source: https://habr.com/ru/post/J349440/


All Articles