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

画像






目次





13.スキルツリヌ



14.コン゜ヌル



15.最終



パヌト7プレヌダヌのオプションず攻撃



はじめに



この郚分では、プレヌダヌに関連するゲヌムプレむの郚分に焊点を圓おたす。 たず、最も基本的なパラメヌタヌである匟薬、加速、ヘルスHP、およびスキルポむントを远加したす。 これらのパラメヌタヌはゲヌム党䜓で䜿甚され、プレヌダヌが䜿甚可胜なすべおのアクションを実行するために䜿甚する䞻なパラメヌタヌです。 その埌、リ゜ヌスオブゞェクト、぀たりプレヌダヌが収集できるオブゞェクトの䜜成に進みたす。 これらには䞊蚘のパラメヌタヌが含たれおいたす。 そしお最埌に、攻撃システムずいく぀かの異なるプレむダヌ攻撃を远加したす。



描画順序



ゲヌムの䞻芁郚分に移る前に、私が芋萜ずしおいたもう1぀の重芁な偎面、぀たり描画順序を考慮する必芁がありたす。



描画順序は、䞊から描画するオブゞェクトず䞋から描画するオブゞェクトを決定したす。 たずえば、特定のむベントが実行されるず、いく぀かの゚フェクトがレンダリングされたす。 プレヌダヌの䞋など、他のオブゞェクトの䞋に゚フェクトが描画される堎合、それらは衚瀺されないか、正しく衚瀺されたせん。 したがっお、それらが垞に他のすべおの䞊に描画されるようにする必芁がありたす。 これを行うには、描画オブゞェクトの順序を蚭定する必芁がありたす。



この問題を解決する方法はかなり簡単です。 GameObject



クラスでは、最初はすべおの゚ンティティに察しお50であるdepth



属性を定矩し、その埌、各クラスのコンストラクタヌ定矩で、オプションでオブゞェクトの各クラスのdepth



属性を個別に蚭定できたす。 考えは、より深いオブゞェクトは䞊に描画し、深さはより䞋に描画するこずです。 ぀たり、たずえば、他のすべおの䞊にすべおの効果を描画する堎合、倀75などのdepth



属性に単玔に割り圓おるこずができたす。



 function TickEffect:new(area, x, y, opts) TickEffect.super.new(self, area, x, y, opts) self.depth = 75 ... end
      
      





内郚では、次のように機胜したす。各フレヌムで、各オブゞェクトのdepth



属性でgame_objects



のリストを゜ヌトしたす。



 function Area:draw() table.sort(self.game_objects, function(a, b) return a.depth < b.depth end) for _, game_object in ipairs(self.game_objects) do game_object:draw() end end
      
      





ここでは、レンダリングの前に、 table.sort



を䜿甚しお、 depth



属性で゚ンティティを䞊べ替えたす。 深さが小さい゚ンティティはテヌブルの前面に移動したす。぀たり、最初に他のすべおの䞋に描画され、深さが倧きい゚ンティティはテヌブルの最埌に移動し、最埌に䞊に描画されたす。 異なる皮類のオブゞェクトに異なる深さを蚭定しようずするず、これが機胜するこずがわかりたす。



このアプロヌチでは、1぀の小さな問題が発生したす。䞀郚のオブゞェクトは同じ深さを持ち、これが発生するず、 game_objects



テヌブルが絶えず゜ヌトされるずきにgame_objects



が発生する堎合がgame_objects



たす。 オブゞェクトの奥行きが同じ堎合、あるフレヌムでは1぀のオブゞェクトが別のオブゞェクトの䞊に衚瀺されたすが、次のフレヌムではその䞋に衚瀺されるため、ちら぀きが発生したす。 これの可胜性は小さいですが、これは起こる可胜性があり、これを防ぐ必芁がありたす。



これを解決する1぀の方法は、オブゞェクトの深さが同じ堎合に別の゜ヌトパラメヌタヌを定矩するこずです。 私たちの堎合、別のパラメヌタヌずしおオブゞェクト䜜成時間を遞択したした。



 function Area:draw() table.sort(self.game_objects, function(a, b) if a.depth == b.depth then return a.creation_time < b.creation_time else return a.depth < b.depth end end) for _, game_object in ipairs(self.game_objects) do game_object:draw() end end
      
      





぀たり、深さが同じ堎合、以前に䜜成されたオブゞェクトが先に描画され、埌で䜜成されたす。 これは論理的な解決策であり、テストするず機胜するこずがわかりたす。



描画順序の挔習



93.オブゞェクトの順序を倉曎しお、奥のほうが奥に、奥の方が奥に描画されるようにしたす。 オブゞェクトの深さが同じ堎合は、䜜成時間順に䞊べ替える必芁がありたす。 前に䜜成したオブゞェクトを最埌に描画し、埌で䜜成したオブゞェクトを最初に描画する必芁がありたす。



94.以䞋に瀺すような䞊面の2.5Dゲヌムでは、゚ンティティを適切な順序でレンダリングする、぀たり䜍眮y



で゜ヌトする必芁がありたす。 y倀が倧きい぀たり、画面の䞋郚に近い゚ンティティを最埌に描画し、y倀が小さい゚ンティティを最初に描画する必芁がありたす。 この堎合、゜ヌト機胜はどのようになりたすか



GIF






䞻なパラメヌタヌ



次に、パラメヌタヌの䜜成を開始したす。 最初に確認するパラメヌタヌはブヌストです。 プレむダヌが「䞊」たたは「䞋」を抌すず、船は抌されたキヌに応じお速床を倉曎したす。 この基本機胜に加えお、アクセラレヌションを䜿甚するず枯枇し、アクセラレヌションを䜿甚しないず埐々に埩元されるリ゜ヌスも必芁です。 次の倀ずルヌルを適甚したす。



  1. プレむダヌは最初に100単䜍の加速を持ちたす
  2. 加速床を䜿甚するず、加速床が50単䜍枛少したす
  3. 毎秒10個の加速単䜍が垞に生成されたす
  4. 加速単䜍の数が0に達するず、このプロパティは「クヌルダりン」しお再び䜿甚できるようになるたで2秒かかりたす。
  5. 加速は、「冷华」が無効で、加速ナニットのリ゜ヌスが0より倧きい堎合にのみ実行できたす


ルヌルは少し耇雑に芋えたすが、本圓に簡単です。 最初の3぀は数倀のタスクであり、最埌の2぀は無限の加速を防ぐために必芁です。 リ゜ヌスが0に達するず、垞に1に回埩したす。これにより、プレヌダヌが絶えず加速を䜿甚する状況が発生する可胜性がありたす。 この状況を防ぐには、「冷华」が必芁です。



次に、これをコヌドに远加したす。



 function Player:new(...) ... self.max_boost = 100 self.boost = self.max_boost end function Player:update(dt) ... self.boost = math.min(self.boost + 10*dt, self.max_boost) ... end
      
      





これにより、ルヌル1および3を実装したす。最初に、 boost



の倀はmax_boost



、぀たり100であり、倀max_boost



たで、1秒あたり10を远加しおboost



したす。 たた、プレヌダヌが加速するずきに毎秒50ナニットを匕くだけで、ルヌル2を実装できたす。



 function Player:update(dt) ... if input:down('up') then self.boosting = true self.max_v = 1.5*self.base_max_v self.boost = self.boost - 50*dt end if input:down('down') then self.boosting = true self.max_v = 0.5*self.base_max_v self.boost = self.boost - 50*dt end ... end
      
      





このコヌドの䞀郚はすでにここにありたした。぀たり、远加された行はself.boost -= 50*dt



でした。 ここで、ルヌル4を確認するには、 boost



が0に達したずきに冷华が2秒間開始されるこずを確認する必芁がありたす。 ここではより倚くの可動郚品が䜿甚されるため、これは少し耇雑です。 コヌドは次のようになりたす。



 function Player:new(...) ... self.can_boost = true self.boost_timer = 0 self.boost_cooldown = 2 end
      
      





たず、3぀の倉数を玹介したす。 can_boost



は、加速を実行できるタむミングを報告するために䜿甚されたす。 プレヌダヌはゲヌムの開始時に加速できる必芁があるため、デフォルトではtrueです。 boost



が0に達するずfalseに蚭定され、 boost_cooldown



秒埌にtrueに蚭定されたす。 boost_timer



倉数は、 boost



が0になっおから経過した時間をboost_cooldown



、この倉数がboost_cooldown



を超えるず、 can_boost



はtrueに蚭定されたす。



 function Player:update(dt) ... self.boost = math.min(self.boost + 10*dt, self.max_boost) self.boost_timer = self.boost_timer + dt if self.boost_timer > self.boost_cooldown then self.can_boost = true end self.max_v = self.base_max_v self.boosting = false if input:down('up') and self.boost > 1 and self.can_boost then self.boosting = true self.max_v = 1.5*self.base_max_v self.boost = self.boost - 50*dt if self.boost <= 1 then self.boosting = false self.can_boost = false self.boost_timer = 0 end end if input:down('down') and self.boost > 1 and self.can_boost then self.boosting = true self.max_v = 0.5*self.base_max_v self.boost = self.boost - 50*dt if self.boost <= 1 then self.boosting = false self.can_boost = false self.boost_timer = 0 end end self.trail_color = skill_point_color if self.boosting then self.trail_color = boost_color end end
      
      





それは耇雑に思えたすが、コヌドは私たちが達成したかったものを単に実装しおいたす。 input:down



でキヌが抌されたかどうかをチェックする代わりに、 boost



1より䞊ルヌル5であり、 can_boost



がtrueルヌル5であるこずもチェックしたす。 boost



が0に達したら、 can_boost



およびcan_boost



倉数をfalseに蚭定し、 boost_timer



を0にリセットしたすboost_timer



は各フレヌムでboost_timer



に远加されるboost_timer



、2秒埌にcan_boost



をtrueに蚭定し、再び加速できたすルヌル4。



䞊蚘のコヌドは、完了状態の加速メカニズムです。 ここでは、このコヌドをい、無秩序で、悪い決定を組み合わせお呌び出すこずができるこずに泚意しおください。 しかし、それはたさにゲヌムプレむの特定の偎面を凊理するコヌドのほずんどがどのように芋えるかです。 ここでは、いく぀かのルヌルに埓うず同時にそれらに埓う必芁がありたす。 そのようなコヌドに慣れる必芁があるように思えたす。



すべおの䞻芁なパラメヌタヌのうち、加速だけでも耇雑なロゞックを持っおいる可胜性がありたす。 匟薬ずHPの2぀の重芁なオプションがありたすが、どちらもはるかに簡単です。 匟薬はプレむダヌの攻撃䞭に消費され、ゲヌム䞭にリ゜ヌスが収集されるず埩元され、プレむダヌがダメヌゞを受けるずHPが枛少し、リ゜ヌスが収集されるず埩元されたす。 これで、アクセラレヌションで行ったように、それらをメむンパラメヌタずしお単玔に远加できたす。



 function Player:new(...) ... self.max_hp = 100 self.hp = self.max_hp self.max_ammo = 100 self.ammo = self.max_ammo end
      
      





資源



私は、䞻芁なパラメヌタヌの1぀に圱響するリ゜ヌスを小さなオブゞェクトず呌びたす。 ゲヌムには、このようなオブゞェクトが5皮類あり、次のように機胜したす。





ディレクタヌディレクタヌ-敵ずリ゜ヌスの䜜成を制埡するコヌド。 他のゲヌムL4Dなどでこのような名前が付けられおおり、適切だず思われたため、それを呌び出したした。 コヌドのこの郚分で䜜業する぀もりはないので、各リ゜ヌスの䜜成をキヌに関連付けお、䜜業を簡単にテストしたす。



匟薬リ゜ヌス



匟薬から始めたしょう。 最終結果は次のようになりたす。



GIF






小さな緑色の長方圢は匟薬の資源です。 プレむダヌが圌に觊れるず、リ゜ヌスが砎壊され、プレむダヌは5ナニットの匟薬を受け取りたす。 新しいAmmo



クラスを䜜成し、定矩から始めるこずができたす。



 function Ammo:new(...) ... self.w, self.h = 8, 8 self.collider = self.area.world:newRectangleCollider(self.x, self.y, self.w, self.h) self.collider:setObject(self) self.collider:setFixedRotation(false) self.r = random(0, 2*math.pi) self.v = random(10, 20) self.collider:setLinearVelocity(self.v*math.cos(self.r), self.v*math.sin(self.r)) self.collider:applyAngularImpulse(random(-24, 24)) end function Ammo:draw() love.graphics.setColor(ammo_color) pushRotate(self.x, self.y, self.collider:getAngle()) draft:rhombus(self.x, self.y, self.w, self.h, 'line') love.graphics.pop() love.graphics.setColor(default_color) end
      
      





匟薬リ゜ヌスは、最初はsetLinearVelocity



およびapplyAngularImpulse



によっお蚭定された、ランダムな䜎速および回転で䜜成された物理的な長方圢です。 さらに、このオブゞェクトはdraft



ラむブラリを䜿甚しおレンダリングされたす。 これは、自分で行うよりも䟿利にあらゆる皮類の図圢を描画できる小さなラむブラリです。 私たちの堎合、単玔に任意の長方圢のようにリ゜ヌスを描画できたすが、この方法で行うこずにしたした。 ラむブラリを自分でむンストヌルし、ドキュメントを読み、その機胜に぀いお孊習しおいるこずを前提ずしたす。 さらに、 getAngle



の結果を䜿甚しお、物理オブゞェクトの回転を考慮したす。



これをすべおテストするために、これらのオブゞェクトのいずれかの䜜成をキヌにバむンドできたす。



 function Stage:new() ... input:bind('p', function() self.area:addGameObject('Ammo', random(0, gw), random(0, gh)) end) end
      
      





ここでゲヌムを開始しおPを数回抌すず、オブゞェクトの䜜成方法ず移動/回転が衚瀺されたす。



次に䜜成する必芁があるのは、プレヌダヌずリ゜ヌス間の衝突の盞互䜜甚です。 この盞互䜜甚はすべおのリ゜ヌスに䜿甚され、ほずんど垞に同じです。 最初に行うこずは、プレむダヌの物理オブゞェクトず物理匟薬オブゞェクトの衝突むベントをむンタヌセプトするこずです。 これを実装する最も簡単な方法は、 (collision classes)



を䜿甚する (collision classes)



です。 たず、既存のオブゞェクトの衝突の3぀のクラスを定矩できたすプレヌダヌ、発射物、およびリ゜ヌス。



 function Stage:new() ... self.area = Area(self) self.area:addPhysicsWorld() self.area.world:addCollisionClass('Player') self.area.world:addCollisionClass('Projectile') self.area.world:addCollisionClass('Collectable') ... end
      
      





そしお、これらの各ファむルPlayer、Projectile、Ammoでは、 setCollisionClass



を䜿甚しお衝突型衝突クラスを蚭定できたす他のファむルでこのコヌドを繰り返したす。



 function Player:new(...) ... self.collider:setCollisionClass('Player') ... end
      
      





それ自䜓は䜕も倉曎せず、物理オブゞェクト間の衝突のむベントをむンタヌセプトできる基盀を䜜成したす。 たずえば、コリゞョンクラスCollectable



を倉曎しおPlayer



無芖する堎合



 self.area.world:addCollisionClass('Collectable', {ignores = {'Player'}})
      
      





ゲヌムを開始するず、プレむダヌが匟薬リ゜ヌスオブゞェクトを物理的に無芖するこずに気付くでしょう。 これは私たちが目指しおいるものではありたせんが、衝突クラスでできるこずの良い䟋ずしお圹立ちたす。 これら3぀の衝突クラスは、次の芏則に埓う必芁がありたす。



  1. 発射物は発射物を無芖したす
  2. CollectableはCollectableを無芖したす
  3. 収集物は発射物を無芖したす
  4. PlayerはCollectableで衝突むベントを生成したす


ルヌル1、2、3は、 addCollisionClass



呌び出しに小さな倉曎を加えるこずで実装できたす。



 function Stage:new() ... self.area.world:addCollisionClass('Player') self.area.world:addCollisionClass('Projectile', {ignores = {'Projectile'}}) self.area.world:addCollisionClass('Collectable', {ignores = {'Collectable', 'Projectile'}}) ... end
      
      





衝突クラスを宣蚀する順序が重芁であるこずは泚目に倀したす。 たずえば、ProjectileクラスずCollectableクラスの宣蚀を入れ替えるず、Collectable衝突クラスがProjectile衝突クラスぞのリンクを䜜成するため、Projectile衝突クラスがただ定矩されおいないため゚ラヌが発生したす。



4番目のルヌルは、 enter



を呌び出すこずで実装できたす。



 function Player:update(dt) ... if self.collider:enter('Collectable') then print(1) end end
      
      





コヌドを実行するず、プレヌダヌが匟薬リ゜ヌスず衝突するたびに、コン゜ヌルに1が衚瀺されたす。



Ammo



クラスに远加する必芁のあるもう1぀の芁玠は、プレヌダヌぞのオブゞェクトのゆっくりした動きです。 これを行う最も簡単な方法は、 Seek Behavior動䜜を远加するこずです。 シヌク動䜜の私のバヌゞョンは、ExampleによるProgramming Game AIの曞籍に基づいおいたす。これには、䞀般的な制埡動䜜の非垞に優れた遞択がありたす。 正盎なずころ、どのように動䜜するのか芚えおいないので、動䜜の詳现は説明したせん。したがっお、興味がある堎合は自分で理解しおくださいD



 function Ammo:update(dt) ... local target = current_room.player if target then local projectile_heading = Vector(self.collider:getLinearVelocity()):normalized() local angle = math.atan2(target.y - self.y, target.x - self.x) local to_target_heading = Vector(math.cos(angle), math.sin(angle)):normalized() local final_heading = (projectile_heading + 0.1*to_target_heading):normalized() self.collider:setLinearVelocity(self.v*final_heading.x, self.v*final_heading.y) else self.collider:setLinearVelocity(self.v*math.cos(self.r), self.v*math.sin(self.r)) end end
      
      





ここで、匟薬リ゜ヌスが存圚する堎合、 target



に向けられたす。そうでない堎合、リ゜ヌスは最初に指定された方向に移動したす。 target



は、次のようにStage



で蚭定されるプレヌダヌぞのリンクが含たれたす。



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





残っおいるのは、匟薬リ゜ヌスが収集されたずきに発生するアクションを凊理するこずだけです。 䞊蚘のgifアニメヌションでは、パヌティクルで小さな効果が再珟され発射䜓が「死ぬ」ずきの効果に䌌おいたす、プレむダヌは+5の匟薬を受け取りたす。



゚フェクトから始めたしょう。 この゚フェクトは、 ProjectileDeathEffect



オブゞェクトず同じロゞックを䜿甚したす。小さな癜い閃光が発生し、゚フェクトの実際の色が衚瀺されたす。 ここでの唯䞀の違いは、正方圢を描画する代わりに、菱圢、぀たり、匟薬リ゜ヌス自䜓を描画するために䜿甚したのず同じ図を描画するこずです。 この新しいAmmoEffect



オブゞェクトに名前をAmmoEffect



たす。 ProjectileDeathEffect



䌌おいるため、詳现に怜蚎したせん。 ただし、次のように呌び出したす。



 function Ammo:die() self.dead = true self.area:addGameObject('AmmoEffect', self.x, self.y, {color = ammo_color, w = self.w, h = self.h}) for i = 1, love.math.random(4, 8) do self.area:addGameObject('ExplodeParticle', self.x, self.y, {s = 3, color = ammo_color}) end end
      
      





ここでは、1぀のAmmoEffect



オブゞェクトを䜜成しおから、 AmmoEffect



個のAmmoEffect



オブゞェクトを䜜成したす。これらは、Playerのデス゚フェクトで既に䜿甚しおいたす。 Ammoオブゞェクトのdie



関数は、Playerず衝突したずきに呌び出されたす



 function Player:update(dt) ... if self.collider:enter('Collectable') then local collision_data = self.collider:getEnterCollisionData('Collectable') local object = collision_data.collider:getObject() if object:is(Ammo) then object:die() end end end
      
      





ここでは、たずgetEnterCollisionData



を䜿甚しお、指定したラベルの最埌の゚ンタヌコリゞョンむベントによっお生成されたコリゞョンデヌタを取埗したす。 次に、 getObject



を䜿甚しお、Collisibleむベントに参加するコラむダヌにアタッチされたオブゞェクトぞのアクセスを取埗したすgetObject



むベントには、Collectable衝突クラスの任意のオブゞェクトを指定できたす。 私たちの堎合、Ammoオブゞェクトしかありたせんが、他のものがある堎合は、それらを区別するコヌドが配眮される堎所です。 そしお、これがたさに私たちがやっおいるこずですgetObject



から受け取ったオブゞェクトがAmmo



クラスかどうかを確認するために、クラシックラむブラリのis



関数を䜿甚したす。 これが実際に匟薬クラスのオブゞェクトである堎合、そのdie



関数を呌び出したす。 次のようになりたす。



GIF






最埌に忘れたのは、匟薬リ゜ヌスを収集するずきにプレむダヌに匟薬+5を远加するこずです。 これを行うには、 addAmmo



関数を定矩したす。この関数は、特定の倀を単玔にammo



倉数に远加し、 max_ammo



超えないこずをmax_ammo



たす。



 function Player:addAmmo(amount) self.ammo = math.min(self.ammo + amount, self.max_ammo) end
      
      





そしお、この関数をobject:die()



埌に远加したす。



加速リ゜ヌスブヌスト



それでは、速床に぀いお説明したしょう。 最終結果は次のようになりたす。



GIF






ご芧のずおり、アむデアは匟薬リ゜ヌスずほが同じで、ブヌストリ゜ヌスの動きがわずかに異なり、芋た目が少し異なり、リ゜ヌスが収集されるずきに再珟される芖芚効果が異なりたす。



䞻なものから始めたしょう。 匟薬を陀くすべおのリ゜ヌスは、画面の巊偎たたは右偎に䜜成され、ゆっくりず反察偎に盎線的に移動したす。 同じこずが敵にも圓おはたりたす。 これにより、プレヌダヌはリ゜ヌスに移動し、必芁に応じおリ゜ヌスを収集するのに十分な時間を確保できたす。



Boost



クラスのメむンの初期コヌドはAmmo



クラスずほが同じです。 次のようになりたす。



 function Boost:new(...) ... local direction = table.random({-1, 1}) self.x = gw/2 + direction*(gw/2 + 48) self.y = random(48, gh - 48) self.w, self.h = 12, 12 self.collider = self.area.world:newRectangleCollider(self.x, self.y, self.w, self.h) self.collider:setObject(self) self.collider:setCollisionClass('Collectable') self.collider:setFixedRotation(false) self.v = -direction*random(20, 40) self.collider:setLinearVelocity(self.v, 0) self.collider:applyAngularImpulse(random(-24, 24)) end function Boost:update(dt) ... self.collider:setLinearVelocity(self.v, 0) end
      
      





ただし、いく぀かの違いがありたす。コンストラクタヌの最初の3行は、オブゞェクトの開始䜍眮を取埗したす。関数は次のようにtable.random



定矩さutils.lua



れたす。



 function table.random(t) return t[love.math.random(1, #t)] end
      
      





ご芧のずおり、圌女はテヌブルからランダムなアむテムを遞択するだけです。この堎合、-1たたは1を遞択するだけで、オブゞェクトを䜜成する偎を瀺したす。倀-1が遞択されおいる堎合、オブゞェクトは画面の巊偎に䜜成され、1の堎合は右偎に䜜成されたす。この遞択された䜍眮の特定の䜍眮は-48



たたはgw+48



に等しくなりたす。぀たり、オブゞェクトは画面の倖偎に䜜成されたすが、その端に十分近くなりたす。



次に、速床のいく぀かの違いを陀いお、匟薬ずほが同じ方法でオブゞェクトを定矩したす。オブゞェクトが右偎に䜜成された堎合は、巊偎に移動し、巊偎にある堎合は右偎に移動する必芁がありたす。したがっお、速床には20〜40のランダムな倀が割り圓おられ、次にが乗算され-direction



たす。これは、オブゞェクトが右偎にある堎合、direction



1に等しい;巊偎に移動したいので、速床は負になりたす反察偎の堎合はその逆。 x軞に沿ったオブゞェクトの速床のコンポヌネントには垞に属性倀が割り圓おられ、v



y 軞に沿ったコンポヌネントは0に蚭定されたす。オブゞェクトを氎平線に沿っお移動するため、yに沿った速床を0に蚭定したす



。最埌の䞻な違いは描画方法です。



 function Boost:draw() love.graphics.setColor(boost_color) pushRotate(self.x, self.y, self.collider:getAngle()) draft:rhombus(self.x, self.y, 1.5*self.w, 1.5*self.h, 'line') draft:rhombus(self.x, self.y, 0.5*self.w, 0.5*self.h, 'fill') love.graphics.pop() love.graphics.setColor(default_color) end
      
      





単䞀の菱圢を描画する代わりに、内郚ず倖郚を1぀ず぀描画したす。これは䞀皮のアりトラむンになりたす。もちろん、奜きなようにオブゞェクトを描画できたすが、私はこの方法を個人的に遞択したした。



それでは、゚フェクトに移りたしょう。ここでは2぀のオブゞェクトが䜿甚されたす。1぀はAmmoEffect



ただし、もう少し耇雑ですに䌌おいたす。2぀目はtextに䜿甚されたす+BOOST



。 AmmoEffectに䌌たものから始めお、名前を付けBoostEffect



たす。



この効果は2぀の郚分で構成されおいたす。癜いフラッシュのある䞭倮ず、消えた埌のフリッカヌ効果です。センタヌは同じようAmmoEffect



に機胜したすが、唯䞀の違いは各フェヌズの実行時間です。最初のフェヌズでは0.1〜0.2、2番目のフェヌズでは0.15〜0.35です。



 function BoostEffect:new(...) ... self.current_color = default_color self.timer:after(0.2, function() self.current_color = self.color self.timer:after(0.35, function() self.dead = true end) end) end
      
      





効果の2番目の郚分は、圌の死の前のちら぀きです。フリッカヌは、倉数を䜜成するこずで実珟できたすvisible



。trueの堎合、効果が描画され、falseの堎合、描画されたせん。この倉数の倀を倉曎するこずにより、目的の効果が埗られたす。



 function BoostEffect:new(...) ... self.visible = true self.timer:after(0.2, function() self.timer:every(0.05, function() self.visible = not self.visible end, 6) self.timer:after(0.35, function() self.visible = true end) end) end
      
      





ここでは、可芖性ず非可芖性を切り替えるために、every



0.05秒の間隔で6回呌び出しを䜿甚し、完了埌、最埌に゚フェクトを衚瀺したす。゚フェクトは0.55秒埌に「死ぬ」ためdead



珟圚の色を蚭定するずきに0.55埌に倀をtrueに蚭定するため、最埌に芋えるようにするこずはそれほど重芁ではありたせん。これで、次のように描画できたす。



 function BoostEffect:draw() if not self.visible then return end love.graphics.setColor(self.current_color) draft:rhombus(self.x, self.y, 1.34*self.w, 1.34*self.h, 'fill') draft:rhombus(self.x, self.y, 2*self.w, 2*self.h, 'line') love.graphics.setColor(default_color) end
      
      





単玔に異なるサむズの内偎ず倖偎のひし圢を描画したす。特定の倀1.34、2は、䞻に詊行錯誀によっお導き出されたす。



この効果のために最埌に行う必芁があるのは、オブゞェクトの存続期間䞭に倖郚のアりトラむン菱圢を増やすこずです。次のようにできたす。



 function BoostEffect:new(...) ... self.sx, self.sy = 1, 1 self.timer:tween(0.35, self, {sx = 2, sy = 2}, 'in-out-cubic') end
      
      





次に、描画関数を次のように倉曎したす。



 function BoostEffect:draw() ... draft:rhombus(self.x, self.y, self.sx*2*self.w, self.sy*2*self.h, 'line') ... end
      
      





この倉数のおかげでsx



ずsy



0.35秒の二重のために、あたりにも、0.35である秒、回路甚の2に増加されたす。最終的に、結果は次のようになりたすdie



匟薬リ゜ヌスで行ったように、このオブゞェクトの機胜をPlayerの衝突むベントに既にリンクしおいるず仮定したす。



GIF









それでは、゚フェクトの他の郚分、クレむゞヌテキストに぀いお芋おみたしょう。このテキスト効果はゲヌムのほがすべおの堎所で䜿甚されるため、正しく実装する必芁がありたす。もう䞀床、どのように芋えるかを瀺したす。



GIF






たず、゚フェクトをいく぀かの郚分に分けたしょう。最初に気付くのは、画面に最初に描かれる線だけですが、最埌に向かっおオブゞェクトのようにちら぀き始めたすBoostEffect



。 FlickerはBoostEffectず同じロゞックを䜿甚したす。぀たり、既に調べたした。



たた、文字列の文字は他の文字にランダムに倉化し始め、各文字の背景もランダムに色が倉化したす。これは、この゚フェクトが各キャラクタヌを個別に凊理し、行党䜓で動䜜しないこずを瀺しおいたす。぀たり、すべおのキャラクタヌをテヌブルに保存し、characters



このテヌブルを凊理しおから、すべおの倉曎ず゚フェクトを䜿甚しお画面䞊のテヌブルから各キャラクタヌを描画する必芁がありたす。



これらすべおを考慮しお、classの基底を決定できInfoText



たす。次のように呌び出したす。



 function Boost:die() ... self.area:addGameObject('InfoText', self.x, self.y, {text = '+BOOST', color = boost_color}) end
      
      





぀たり、文字列は属性に保存されたすtext



。その堎合、クラスの基底の定矩は次のようになりたす。



 function InfoText:new(...) ... self.depth = 80 self.characters = {} for i = 1, #self.text do table.insert(self.characters, self.text:utf8sub(i, i)) end end
      
      





そのため、オブゞェクトの深さは80他のすべおのオブゞェクトよりも高い、぀たりすべおの䞊に描画されるであるず刀断し、元の文字列をテヌブル文字に分割したす。このために、ラむブラリを䜿甚したすutf8



。䞀般に、すべおの皮類の文字をサポヌトするラむブラリを䜿甚しお文字列を操䜜するこずをお勧めしたす。これは、埌で説明するように、オブゞェクトにずっお特に重芁です。



たた、これらのキャラクタヌのレンダリングも個別に行う必芁がありたす。これは、前述のずおり、各キャラクタヌには独自の背景があり、ランダムに倉化するためです。



各文字を個別にレンダリングするロゞックは、文字テヌブルを調べお、䜍眮xに各文字を描画するこずです。䜍眮xは、その前にあるすべおの文字の合蚈です。぀たり、たずえば、最初のO



行内+BOOST



は䜍眮でのレンダリングを意味したすinitial_x_position + widthOf('+B')



。この堎合、幅を取埗する際の問題+B



は、関数を䜿甚するが、Font:getWidth



ただフォントを蚭定しおいないため、䜿甚するフォントに䟝存するこずです。ただし、この問題は簡単に解決できたす



このために、私たちは、フォントを䜿甚m5x7ダニ゚ルLinssenを。このフォントをフォルダヌに入れおresources/fonts



からダりンロヌドできたす。フォルダヌからクラス定矩をロヌドするために䜿甚されるコヌドobjects



挔習14に䌌おいるため、ダりンロヌドに必芁なコヌドは挔習ずしお残しおおきたす。このダりンロヌドプロセスの終了たでに、ダりンロヌドしたfonts



すべおのフォントを次の圢匏で含むグロヌバルテヌブルが䜜成されたす。fontname_fontsize



。この䟋では、次を䜿甚したすm5x7_16



。



 function InfoText:new(...) ... self.font = fonts.m5x7_16 ... end
      
      





そしお、レンダリングコヌドは次のようになりたす。



 function InfoText:draw() love.graphics.setFont(self.font) for i = 1, #self.characters do local width = 0 if i > 1 then for j = 1, i-1 do width = width + self.font:getWidth(self.characters[j]) end end love.graphics.setColor(self.color) love.graphics.print(self.characters[i], self.x + width, self.y, 0, 1, 1, 0, self.font:getHeight()/2) end love.graphics.setColor(default_color) end
      
      





たず、これlove.graphics.setFont



を䜿甚しお、次のレンダリング操䜜で䜿甚するフォントを指定したす。次に、各シンボルを調べお、それらを描画する必芁がありたす。しかし、最初に、xで䜍眮を蚈算する必芁がありたす。これは、その前のすべおの文字の幅の合蚈です。倉数を蓄積する内偎のルヌプwidth



はたさにそれを行いたす。 1行の先頭からi-1珟圚の行の前の文字で始たり、各文字の幅をtotal width



、぀たりすべおの合蚈に加算したす。次に、love.graphics.print



それぞれのキャラクタヌを察応する䜍眮に描画したす。たた、各文字をフォントの高さの半分だけシフトしたすしたがっお、蚭定したy䜍眮に察しお文字が䞭倮に配眮されたす。



これらすべおをテストするず、次の結果が埗られたす。



GIF






たさに必芁なもの



これで、消える前に点滅するテキストに進むこずができたす。この効果は、BoostEffectオブゞェクトず同じロゞックを䜿甚したす。぀たり、単玔にコピヌできたす。



 function InfoText:new(...) ... self.visible = true self.timer:after(0.70, function() self.timer:every(0.05, function() self.visible = not self.visible end, 6) self.timer:after(0.35, function() self.visible = true end) end) self.timer:after(1.10, function() self.dead = true end) end
      
      





これを実行するず、テキストがしばらくの間正垞のたたであり、ちら぀き始めお消えるこずがわかりたす。



そしお今、最も難しいのは、各キャラクタヌをランダムに倉曎するこずです。メむンず背景の色に぀いおも同じこずを行いたす。これらの倉曎は、シンボルがちら぀き始めるのずほが同時に開始されるため、after



䞊蚘で定矩した0.7秒間、コヌドのこの郚分を呌び出し内に配眮したす。これを行いたす-0.035秒ごずに、キャラクタヌを別のランダムなキャラクタヌに倉曎する機䌚のある手順を開始したす。次のようになりたす。



 self.timer:after(0.70, function() ... self.timer:every(0.035, function() for i, character in ipairs(self.characters) do if love.math.random(1, 20) <= 1 then -- change character else -- leave character as it is end end end) end)
      
      





぀たり、0.035秒ごずに、各キャラクタヌは䜕か他のものに倉わる確率が5です。これを終了するには、倉数を远加したすrandom_characters



。これは、文字を倉曎できるすべおの文字を含む文字列です。キャラクタヌを倉曎する必芁がある堎合、この行からランダムにキャラクタヌを遞択したす。



 self.timer:after(0.70, function() ... self.timer:every(0.035, function() local random_characters = '0123456789!@#$%š&*()-=+[]^~/;?><.,|abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYXZ' for i, character in ipairs(self.characters) do if love.math.random(1, 20) <= 1 then local r = love.math.random(1, #random_characters) self.characters[i] = random_characters:utf8sub(r, r) else self.characters[i] = character end end end) end)
      
      





コヌドを実行するず、次のようになりたす。



GIF






同じロゞックを䜿甚しお、シンボルの前景色ず背景色を倉曎できたす。これを行うために、我々は2぀のテヌブルを定矩し、background_colors



そしおforeground_colors



。各テヌブルのサむズはtableず同じでcharacters



、各文字の背景色ず前景色のみが含たれたす。䞀郚のキャラクタヌでこの衚の色が指定されおいない堎合、デフォルトではメむンの色boost_color



ず透明な背景が䜿甚されたす。



 function InfoText:new(...) ... self.background_colors = {} self.foreground_colors = {} end function InfoText:draw() ... for i = 1, #self.characters do ... if self.background_colors[i] then love.graphics.setColor(self.background_colors[i]) love.graphics.rectangle('fill', self.x + width, self.y - self.font:getHeight()/2, self.font:getWidth(self.characters[i]), self.font:getHeight()) end love.graphics.setColor(self.foreground_colors[i] or self.color or default_color) love.graphics.print(self.characters[i], self.x + width, self.y, 0, 1, 1, 0, self.font:getHeight()/2) end end
      
      





定矩されおいる堎合background_colors[i]



珟圚の文字の背景色、背景色に぀いおは、珟圚の文字の適切な䜍眮ずサむズに長方圢を描画するだけです。を䜿甚しsetColor



お珟圚のシンボルのレンダリング色を蚭定するだけで、原色を倉曎したす。foreground_colors[i]



定矩されおいない堎合、デフォルトではequal self.color



になりたす。これはboost_color



、Boostオブゞェクトから呌び出されたずきに正確に転送されるため、このオブゞェクトでは垞にequal です。ただし、self.color



定矩されおいない堎合は、デフォルトで癜default_color



になりたす。テヌブルbackground_colors



ずの䞭に倀を定矩しおいないため、このコヌド自䜓は䜕もしたせんforeground_colors



。



これを行うには、文字をランダムに倉曎するために䜿甚したのず同じロゞックを䜿甚できたす。



 self.timer:after(0.70, function() ... self.timer:every(0.035, function() for i, character in ipairs(self.characters) do ... if love.math.random(1, 10) <= 1 then -- change background color else -- set background color to transparent end if love.math.random(1, 10) <= 2 then -- change foreground color else -- set foreground color to boost_color end end end) end)
      
      





色を眮き換えるコヌドは、色のリストから遞択する必芁がありたす。6色のグロヌバルグルヌプを定矩したので、それらすべおをリストに入れお、それを䜿甚しおそのうちの1぀をランダムに遞択できたすtable.random



。さらに、これに加えお、6぀の゜ヌスのネガずなる6色をさらに定矩したす。぀たり、元の色がある232, 48, 192



堎合、そのネガはずしお定矩できたす255-232, 255-48, 255-192



。



 function InfoText:new(...) ... local default_colors = {default_color, hp_color, ammo_color, boost_color, skill_point_color} local negative_colors = { {255-default_color[1], 255-default_color[2], 255-default_color[3]}, {255-hp_color[1], 255-hp_color[2], 255-hp_color[3]}, {255-ammo_color[1], 255-ammo_color[2], 255-ammo_color[3]}, {255-boost_color[1], 255-boost_color[2], 255-boost_color[3]}, {255-skill_point_color[1], 255-skill_point_color[2], 255-skill_point_color[3]} } self.all_colors = fn.append(default_colors, negative_colors) ... end
      
      





ここでは、各色の察応する倀を含む2぀のテヌブルを定矩し、関数append



を䜿甚しおそれらを結合したす。次に、このようなこずをしおtable.random(self.all_colors)



、この衚で定矩されおいる10個からランダムな色を1぀取埗したす。぀たり、次のこずができたす。



 self.timer:after(0.70, function() ... self.timer:every(0.035, function() for i, character in ipairs(self.characters) do ... if love.math.random(1, 10) <= 1 then self.background_colors[i] = table.random(self.all_colors) else self.background_colors[i] = nil end if love.math.random(1, 10) <= 2 then self.foreground_colors[i] = table.random(self.all_colors) else self.background_colors[i] = nil end end end) end)
      
      





ゲヌムを実行するず、次のように衚瀺されたす。



GIF






以䞊です。埌でこの効果を改善したす挔習を含むが、今のずころこれで十分です。最埌に行う必芁があるのは、加速リ゜ヌスを収集するずきにプレむダヌに+25のブヌストを远加するこずです。これは匟薬リ゜ヌスずたったく同じように機胜するため、コヌドはスキップしたす。



リ゜ヌス挔習



95. Projectile衝突クラスがPlayer衝突クラスを無芖するようにしたす。



96.関数を倉曎しおaddAmmo



、負の倀の远加をサポヌトし、属性ammo



が0を䞋回らないようにしたす。関数addBoost



およびaddHP



HPリ゜ヌスの远加も同様に行いたす別の挔習のタスクになりたす。



97.前の挔習から刀断するず、正の倀ず負の倀を1぀の関数で凊理するか、関数addResource



ず関数に分割する方がよいremoveResource



でしょうか



98.オブゞェクトInfoText



で、シンボルが20倉化する確率、メむンカラヌが5倉化する確率、および背景色が30倉化する確率を倉曎したす。



99.テヌブルを定矩するdefault_colors



、negative_colors



そしおall_colors



におけるInfoText



非ロヌカルおよびグロヌバル。



100は、オブゞェクトの䜍眮をランダム化しInfoText



、それが間に䜜成されるように-self.w



し、self.w



成分xの、間-self.h



およびself.h



成分Yに。属性w



ずは、h



察象ブヌストされ、情報テキストを䜜成したした。



101.次の機胜があるずしたす。



 function Area:getAllGameObjectsThat(filter) local out = {} for _, game_object in pairs(self.game_objects) do if filter(game_object) then table.insert(out, game_object) end end return out end
      
      





フィルタヌ関数が枡すArea内のすべおのゲヌムオブゞェクトを返したす。たた、InfoTextコンストラクタヌで次のように呌び出されるずしたす。



 function InfoText:new(...) ... local all_info_texts = self.area:getAllGameObjectsThat(function(o) if o:is(InfoText) and o.id ~= self.id then return true end end) end
      
      





これは、珟圚ではないすべおの既存および珟圚のInfoTextオブゞェクトを返したす。 InfoTextオブゞェクトが他のInfoTextオブゞェクトず芖芚的に重耇しないようにしおください。぀たり、画面䞊の同じスペヌスを占有せず、テキストが読めなくなるこずはありたせん。これはあなたにずっお郜合の良い方法で行うこずができたす。䞻なこずは、タスクを実行するこずです。



102.コンテンツすべおの機胜ず芖芚効果を備えたHPリ゜ヌスを远加したす。 Boostリ゜ヌスずたったく同じロゞックを䜿甚したすが、+ 25 HPを远加したす。リ゜ヌスず効果は次のようになりたす。



GIF






103.コンテンツすべおの機胜ず芖芚効果を備えたSPリ゜ヌスを远加したす。リ゜ヌスず同じロゞックを䜿甚したすが、+ 1 SPを远加したす。さらに、SPリ゜ヌスは、Playerオブゞェクトの内郚倉数ずしおではなく、グロヌバル倉数ずしお定矩する必芁がありたす。リ゜ヌスず効果は次のようになりたす。



GIF






攻撃



さお、攻撃に移りたしょう。たず、シェルのレンダリング方法を倉曎したす。今ではそれらは円ずしお描かれおいたすが、それらを線にしたいのです。これは次のように実装できたす。



 function Projectile:draw() love.graphics.setColor(default_color) pushRotate(self.x, self.y, Vector(self.collider:getLinearVelocity()):angle()) love.graphics.setLineWidth(self.s - self.s/4) love.graphics.line(self.x - 2*self.s, self.y, self.x, self.y) love.graphics.line(self.x, self.y, self.x + 2*self.s, self.y) love.graphics.setLineWidth(1) love.graphics.pop() end
      
      





この関数でpushRotate



は、発射䜓の速床を䜿甚するため、発射䜓が動く角床に応じお発射䜓を回転させるこずができたす。次に、内郚でlove.graphics.setLineWidth



、属性にほが比䟋する倀を䜿甚しお蚭定したすがs



、それよりわずかに小さくしたす。これは、s



党䜓が倧きいシェルが厚くなるこずを意味したす。次に、でシェルを描画したすlove.graphics.line



。たた-2*self.s



、䞭心から1本の線を匕き、次に䞭心からに別の線を匕くこずも重芁です2*self.s



。各攻撃には独自の色があり、これらの線の1぀の色を倉曎したすが、2番目の線の色は倉曎しないため、これを行いたす。たずえば、これを行う堎合



 function Projectile:draw() love.graphics.setColor(default_color) pushRotate(self.x, self.y, Vector(self.collider:getLinearVelocity()):angle()) love.graphics.setLineWidth(self.s - self.s/4) love.graphics.line(self.x - 2*self.s, self.y, self.x, self.y) love.graphics.setColor(hp_color) -- change half the projectile line to another color love.graphics.line(self.x, self.y, self.x + 2*self.s, self.y) love.graphics.setLineWidth(1) love.graphics.pop() end
      
      





次に、このようになりたす



GIF






したがっお、各攻撃に異なる色を割り圓お、プレむダヌが画面䞊で䜕が起こっおいるかをよりよく理解できるようにするこずができたす。






完成したゲヌムには16の攻撃がありたすが、ここではそのうちの䞀郚のみを怜蚎したす。攻撃システムは非垞にシンプルで、次のルヌルに基づいおいたす。



  1. 攻撃䞭立を陀くは、各ショットで匟薬を消費したす。
  2. 匟薬が0になるず、珟圚の攻撃は䞭立に倉わりたす。
  3. ランダムに生成されたリ゜ヌスを䜿甚しお、新しい攻撃を取埗できたす。
  4. 新しい攻撃が受信されるず、珟圚の攻撃が眮き換えられ、匟薬が完党に埩元されたす。
  5. 各攻撃は独自の量の匟薬を䜿甚し、独自の特性を持っおいたす。


最初に行うこずは、各攻撃に぀いおの情報を含むテヌブルを定矩するこずですそれらの「冷华」の時間、匟薬ず色の消費。テヌブルを定矩したすがglobals.lua



、今のずころは次のようになりたす。



 attacks = { ['Neutral'] = {cooldown = 0.24, ammo = 0, abbreviation = 'N', color = default_color}, }
      
      





定矩枈みの暙準的な攻撃はず呌ばれNeutral



たす。圌女は、ゲヌムで既に持っおいる攻撃のパラメヌタヌを䜿甚したす。これでsetAttack



、ある攻撃を別の攻撃に眮き換える関数を定矩し、次の攻撃のグロヌバルテヌブルを䜿甚できたす。



 function Player:setAttack(attack) self.attack = attack self.shoot_cooldown = attacks[attack].cooldown self.ammo = self.max_ammo end
      
      





次のように呌び出すこずができたす。



 function Player:new(...) ... self:setAttack('Neutral') ... end
      
      





ここではattack



、珟圚の攻撃の名前を含む属性を倉曎するだけです。この属性はshoot



、珟圚アクティブな攻撃を確認し、シェルを䜜成する方法を決定するために、関数で䜿甚されたす。



属性を倉曎するこずもできたすshoot_cooldown



。この属性はただ䜜成しおいたせんが、boost_timer



and 属性に䌌おいたすboost_cooldown



。これは、アクションこの堎合は攻撃が発生する頻床を制埡するために䜿甚されたす。この行を削陀したす。



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





そしお、攻撃のタむミングを手動で蚭定したす。



 function Player:new(...) ... self.shoot_timer = 0 self.shoot_cooldown = 0.24 ... end function Player:update(dt) ... self.shoot_timer = self.shoot_timer + dt if self.shoot_timer > self.shoot_cooldown then self.shoot_timer = 0 self:shoot() end ... end
      
      





機胜の最埌に、匟薬の量も埩元したす。そこで、ルヌル4を実装したす。次にできるこずはshoot



、さたざたな攻撃の存圚を考慮に入れるように関数を少し倉曎するこずです。



 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}) if self.attack == 'Neutral' then 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 end
      
      





発射物を発射する前に、条件付き蚭蚈を䜿甚しおif self.attack == 'Neutral'



珟圚の攻撃を確認したす。16個の攻撃すべおをチェックする必芁があるため、この機胜は埐々に倧きな条件チェヌンに成長したす。






1぀の攻撃を远加しお、どのように芋えるかを芋おみたしょう。远加する攻撃はず呌ばれDouble



たす。次のようになりたす。









ご芧のずおり、圌女は1぀ではなく2぀のシェルで斜めに撃ちたす。最初に、攻撃の説明をグロヌバル攻撃テヌブルに远加する必芁がありたす。この攻撃の冷华時間は0.32秒で、匟薬2個を消費し、その色は次のようになりたすammo_color



これらの倀は詊行錯誀で取埗したした。



 attacks = { ... ['Double'] = {cooldown = 0.32, ammo = 2, abbreviation = '2', color = ammo_color}, }
      
      





これを関数に远加できたすshoot







 function Player:shoot() ... elseif self.attack == 'Double' then self.ammo = self.ammo - attacks[self.attack].ammo self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r + math.pi/12), self.y + 1.5*d*math.sin(self.r + math.pi/12), {r = self.r + math.pi/12, attack = self.attack}) self.area:addGameObject('Projectile', self.x + 1.5*d*math.cos(self.r - math.pi/12), self.y + 1.5*d*math.sin(self.r - math.pi/12), {r = self.r - math.pi/12, attack = self.attack}) end end
      
      





ここでは、1぀ではなく2぀のシェルを䜜成しおいたす。それぞれのシェルは、math.pi / 12ラゞアンたたは15床の角床に向けられおいたす。たた、シェルに攻撃の名前ずしお属性を取埗させたしたattack



。発射物がどのタむプの攻撃に属しおいるかを刀断するのに圹立぀ため、発射物のタむプごずにこれを行いたす。これは、適切な色を蚭定したり、必芁に応じお動䜜を倉曎したりするのに圹立ちたす。Projectileオブゞェクトは次のようになりたす。



 function Projectile:new(...) ... self.color = attacks[self.attack].color ... end function Projectile:draw() pushRotate(self.x, self.y, Vector(self.collider:getLinearVelocity()):angle()) love.graphics.setLineWidth(self.s - self.s/4) love.graphics.setColor(self.color) love.graphics.line(self.x - 2*self.s, self.y, self.x, self.y) love.graphics.setColor(default_color) love.graphics.line(self.x, self.y, self.x + 2*self.s, self.y) love.graphics.setLineWidth(1) love.graphics.pop() end
      
      





コンストラクタヌではcolor



、この攻撃に察しおグロヌバルテヌブルで定矩された色を蚭定したすattacks



。そしお、描画関数では、属性color



であるこの色で線の䞀郚を描画し、もう䞀方である線を描画したすdefault_color



。ほずんどのタむプのシェルでは、パタヌンは同じです。



最埌に忘れおしたったのは、この攻撃をルヌル1に準拠させるこずです。぀たり、適切な量の匟薬を消費させるコヌドを远加するのを忘れたした。これはかなり簡単に修正できたす。



 function Player:shoot() ... elseif self.attack == 'Double' then self.ammo = self.ammo - attacks[self.attack].ammo ... end end
      
      





これにより、ルヌル1が実行されたすダブル攻撃の堎合。ルヌル2を実装するコヌドを远加するこずもできたすammo



。0 になったら、珟圚の攻撃をNeutral



次のように倉曎したす。



 function Player:shoot() ... if self.ammo <= 0 then self:setAttack('Neutral') self.ammo = self.max_ammo end end
      
      





shoot



匟薬の量が0になった埌、プレヌダヌに撃たせたくないので、関数の最埌に移動する必芁があり



たす。これを実行しおプログラムを実行しようずするず、次のようになりたす。



GIF






攻撃挔習



104.CONTENT攻撃を実装しTriple



たす。攻撃テヌブルでの定矩は次のずおりです。



 attacks['Triple'] = {cooldown = 0.32, ammo = 3, abbreviation = '3', color = boost_color}
      
      





そしお、攻撃自䜓は次のようになりたす。



GIF






シェルの角床はinずたったく同じDouble



ですが、䞭倮に攻撃シェルず同じ角床で远加の​​シェルが䜜成されおいNeutral



たす。ダブル攻撃ず同じ手順に埓っお、この攻撃を䜜成したす。



105.CONTENT攻撃を実装しRapid



たす。攻撃テヌブルでの定矩は次のようになりたす。



 attacks['Rapid'] = {cooldown = 0.12, ammo = 1, abbreviation = 'R', color = default_color}
      
      





そしお、攻撃自䜓は次のようになりたす。



GIF






106.CONTENT攻撃を実装しSpread



たす。攻撃の衚におけるその定矩



 attacks['Spread'] = {cooldown = 0.16, ammo = 1, abbreviation = 'RS', color = default_color}
      
      





そしお、攻撃自䜓は次のようになりたす。



GIF






ショットに䜿甚される角床は、-math.pi / 8〜+ math.pi / 8のランダムな倀です。この攻撃のシェルの色も少し異なりたす。色を1぀だけにするのではなく、各フレヌムで色をリストの1぀にall_colors



たたは気分に応じおフレヌム党䜓でランダムに倉曎したす。



107.CONTENT攻撃を実装しBack



たす。攻撃テヌブルでの定矩は次のようになりたす。



 attacks['Back'] = {cooldown = 0.32, ammo = 2, abbreviation = 'Ba', color = skill_point_color}
      
      





そしお、攻撃自䜓は次のようになりたす。



GIF






108.CONTENT攻撃を実装しSide



たす。攻撃の衚におけるその定矩



 attacks['Side'] = {cooldown = 0.32, ammo = 2, abbreviation = 'Si', color = boost_color}
      
      





攻撃自䜓



GIF






109.CONTENTリ゜ヌスを実装しAttack



たす。以䞋のようBoost



でSkillPoint



、攻撃のリ゜ヌスは、画面の巊端たたは右端に䜜成した埌、非垞にゆっくりず内偎に移動されたす。プレヌダヌが攻撃リ゜ヌスず察話するず、関数を䜿甚setAttack



した攻撃は、リ゜ヌスに含たれる攻撃に倉わりたす。



Attackリ゜ヌスは、BoostおよびSkillPointリ゜ヌスず倖芳がわずかに異なりたすが、圌自身ず圌の効果の原理はほずんど同じです。各リ゜ヌスに䜿甚される色はシェルず同じであり、識別子名はabbreviation



衚で名前を付けたものattacks



です。それらは次のようになりたす。



GIF






プレヌダヌによる新しい攻撃を拟うずきは、InfoTextオブゞェクトを䜜成するこずを忘れないでください






パヌト8敵



はじめに



このパヌトでは、いく぀かの敵の䜜成ず、EnemyProjectileクラス、぀たり、䞀郚の敵がプレむダヌを撃぀こずができるシェルを怜蚎したす。この郚分は他の郚分よりも少し短くなりたす。これは、すべおの敵の䜜成に぀いお詳现に説明するのではなく、すべおの敵に぀いおほが同じである䞀般的な動䜜に぀いおのみ説明するためです。



敵



このゲヌムの敵は、前のパヌトで䜜成したリ゜ヌスずほが同じように動䜜したす。画面の巊たたは右の境界付近にランダムな䜍眮yで䜜成され、その埌ゆっくり内偎に移動したす。それらの動䜜のコヌドは、リ゜ヌスに実装したものずほが同じです。



最初に呜名しRock



た敵から始めたす。次のようになりたす。



GIF






このオブゞェクトのコンストラクタコヌドは、コヌドず非垞に䌌おいたすBoost



が、わずかな違いがありたす。



 function Rock:new(area, x, y, opts) Rock.super.new(self, area, x, y, opts) local direction = table.random({-1, 1}) self.x = gw/2 + direction*(gw/2 + 48) self.y = random(16, gh - 16) self.w, self.h = 8, 8 self.collider = self.area.world:newPolygonCollider(createIrregularPolygon(8)) self.collider:setPosition(self.x, self.y) self.collider:setObject(self) self.collider:setCollisionClass('Enemy') self.collider:setFixedRotation(false) self.v = -direction*random(20, 40) self.collider:setLinearVelocity(self.v, 0) self.collider:applyAngularImpulse(random(-100, 100)) end
      
      





ここでは、RectangleColliderの代わりに、オブゞェクトはPolygonColliderを䜿甚したす。createIrregularPolygon



で定矩される関数を䜿甚しお、このポリゎンの頂点を䜜成しutils.lua



たす。この関数は、䞍芏則な長方圢を構成する頂点のリストを返す必芁がありたす。䞍芏則な長方圢ずは、円のように芋えるものを意味したすが、その各頂点は䞭心からわずかに近くたたは遠くにあり、各頂点間の角床もわずかにランダムになりたす。



関数の定矩を開始するには、2぀の匕数を受け取るず蚀うこずができたすsize



ずpoint_amount



。 1぀目は円の半埄を瀺し、2぀目はポリゎンポリゎンを構成するポむントの数を瀺したす。



 function createIrregularPolygon(size, point_amount) local point_amount = point_amount or 8 end
      
      





ここでpoint_amount



、定矩されおいない堎合のデフォルトは8であるず蚀うこずもできたす



。次にできるこずは、すべおのポむントを定矩するこずです。これは、1〜のサむクルで実行できたす。point_amount



各サむクルで、角床の間隔に基づいお次の頂点を決定したす。たずえば、2番目の点の䜍眮を決定するために、その角床はinterval 2*angle_interval



にあるangle_interval



ず蚀えたす2*math.pi/point_amount



。ここではvalue です。぀たり、この堎合、玄90床になりたす。このコヌドを蚘述する方が論理的です。したがっお、



 function createIrregularPolygon(size, point_amount) local point_amount = point_amount or 8 local points = {} for i = 1, point_amount do local angle_interval = 2*math.pi/point_amount local distance = size + random(-size/4, size/4) local angle = (i-1)*angle_interval + random(-angle_interval/4, angle_interval/4) table.insert(points, distance*math.cos(angle)) table.insert(points, distance*math.sin(angle)) end return points end
      
      





ここでangle_interval



、䞊で説明したようにを定矩したすdistance



が、円の半埄内のどこかで、からのランダムオフセットで定矩-size/4



し+size/4



たす。これは、各頂点が円の円呚䞊ではなく、近くのどこかにあるこずを意味したす。たた、角床の範囲を少しランダム化しお、同じ効果を䜜成したす。最埌に、xおよびyコンポヌネントを返されたポむントのリストに远加したす。ポリゎンはロヌカル空間に䜜成されるこずに泚意しおください䞭心が0、0であるず仮定。぀たり、ポリゎンを䜿甚しおオブゞェクトを正しい堎所に配眮する必芁がありたすsetPosition



。



このオブゞェクトのコンストラクタヌのもう1぀の違いは、衝突クラスを䜿甚するこずEnemy



です。他のすべおの衝突クラスず同様に、このクラスも䜿甚前に定矩する必芁がありたす。



 function Stage:new() ... self.area.world:addCollisionClass('Enemy') ... end
      
      





䞀般に、盞互に異なる衝突動䜜を持぀オブゞェクトのタむプには、新しい衝突クラスを远加する必芁がありたす。䟋えば、敵はプレむダヌを物理的に無芖したすが、シェルは無芖したせん。他の皮類のオブゞェクトはこの動䜜を䜿甚しないため、新しい衝突クラスを䜜成する必芁がありたす。発射物の衝突クラスがプレヌダヌのみを無芖し、他のシェルを無芖しない堎合、発射物の衝突クラスは敵にも䜿甚できたす。



Rockオブゞェクトで最埌に行うこずは、それをレンダリングするこずです。これは単なるポリゎンであるため、次のようにしお単玔にポむントを描画できたすlove.graphics.polygon



。



 function Rock:draw() love.graphics.setColor(hp_color) local points = {self.collider:getWorldPoints(self.collider.shapes.main:getPoints())} love.graphics.polygon('line', points) love.graphics.setColor(default_color) end
      
      





最初にこれらのポむントを取埗しPolygonShape:getPoints



たす。ポむントはロヌカル座暙で返されたすが、グロヌバル座暙が必芁なのでBody:getWorldPoints



、ロヌカル座暙をグロヌバル座暙に倉換するためにそれらを䜿甚する必芁がありたす。その埌、ポリゎンを描くこずができ、期埅どおりに動䜜したす。コラむダヌから盎接ポむントを取埗し、コラむダヌが回転するポリゎンpushRotate



であるため、結果のポむントはすでにオブゞェクトの回転を考慮しおいるため、Boostオブゞェクトのようにオブゞェクトを䜿甚しお回転させる必芁はありたせん。



これをすべお行うず、ゲヌムは次のようになりたす。



GIF






敵の挔習



110.次のタスクを実行したす。





111.新しいクラスを䜜成したすEnemyDeathEffect



。この効果は、敵が死んでオブゞェクトProjectileDeathEffect



ずたったく同じように振る舞うずきに䜜成されたすが、それだけが倧きく、Rockオブゞェクトのサむズに察応したす。このオブゞェクトは、hp



Rockオブゞェクト属性が0以䞋になったずきに䜜成する必芁がありたす。



112.発射物衝突クラスオブゞェクトず敵衝突クラスオブゞェクト間の衝突むベントを実装したす。この堎合、Projectileクラスの曎新関数に実装する必芁がありたす。シェルがEnemyクラスのオブゞェクトにヒットするず、シェルhit



によっお匕き起こされたダメヌゞの量で敵の関数を呌び出す必芁がありたすデフォルトでは、シェルの属性damage



は最初は100になりたす。ヒットした堎合、発射物は独自の関数も呌び出す必芁がありたすdie



。



113。Playerクラスに関数を远加したすhit



。この関数は次のこずを行う必芁がありたす。





さらに、次の条件付き取匕は公正でなければなりたせん。





この関数hit



は、プレヌダヌが敵ず衝突したずきに呌び出す必芁がありたす。敵ず衝突した堎合、プレむダヌに30のダメヌゞを䞎える必芁がありたす。






これらの4぀の挔習を完了するず、プレヌダヌ、投射物、敵の岩の間の盞互䜜甚に必芁なものがすべお揃うはずです。これらの盞互䜜甚は他の敵に適甚されたす。すべお次のようになりたす。



GIF






敵の発射物



これで、敵ずの䜜業の別の郚分-砲匟を発射する敵の䜜成に集䞭できたす。そのような機䌚は䞀郚の敵が利甚できるようになるので、Projectileに䌌おいるが敵が䜿甚するオブゞェクトを䜜成する必芁がありたす。これを行うには、オブゞェクトを䜜成したすEnemyProjectile



。



コヌドをコピヌしお少し倉曎するだけで、最初にこのオブゞェクトを䜜成できたすProjectile



。これらのオブゞェクトの䞡方には倚くの共通点がありたす。共通の振る舞いをする共通の発射物オブゞェクトに抜象化できたすが、実際にはゲヌムには2皮類のシェルしかないため、これは必芁ありたせん。コピヌ埌、次の倉曎を行う必芁がありたす。



 function EnemyProjectile:new(...) ... self.collider:setCollisionClass('EnemyProjectile') end
      
      





EnemyProjectile衝突クラスもEnemyProjectileでなければなりたせん。EnemyProjectileオブゞェクトが他のEnemyProjectile、Projectile、およびPlayerを無芖するようにしたす。したがっお、この目暙に察応する衝突クラスを远加したす。



 function Stage:new() ... self.area.world:addCollisionClass('EnemyProjectile', {ignores = {'EnemyProjectile', 'Projectile', 'Enemy'}}) end
      
      





倉曎する必芁がある別の重芁な偎面は損傷です。プレむダヌが発射した通垞の発射物は100ダメヌゞを䞎え、敵の砲匟は10ダメヌゞを䞎えたす。



 function EnemyProjectile:new(...) ... self.damage = 10 end
      
      





たた、Playerず競合するが、他の敵ず競合しないためには、敵が発射したシェルが必芁です。したがっお、Projectileオブゞェクトで䜿甚される衝突コヌドを取埗し、Player自䜓にラップしたす。



 function EnemyProjectile:update(dt) ... if self.collider:enter('Player') then local collision_data = self.collider:getEnterCollisionData('Player') ... end
      
      





最埌に、このオブゞェクトを赀癜ではなく完党に赀にするこずで、プレヌダヌが自分のシェルを敵のものず区別できるようにしたす。



 function EnemyProjectile:draw() love.graphics.setColor(hp_color) ... love.graphics.setColor(default_color) end
      
      





これらの小さな倉曎をすべお行ったので、EnemyProjectileオブゞェクトを䜜成できたした。次に、それを䜿甚する敵を䜜成する必芁がありたす



敵を撃぀



敵のシュヌタヌは次のようになりたす。



GIF






ご芧のずおり、最初は小さな効果が再珟され、次に砲匟が発射されたす。発射物はプレヌダヌず同じように芋えたすが、完党に赀いだけです。



Rockオブゞェクトからコヌドをコピヌするこずで、この敵の䜜成を​​開始できたす。この敵そしお実際すべおの敵は、画面の巊たたは右に珟れおからゆっくりず内偎に移動するずいう共通の特性を持ちたす。Rockオブゞェクトにはすでにこのコヌドが含たれおいるため、これから始めたす。コヌドをコピヌした埌、小さな倉曎を加える必芁がありたす。



 function Shooter:new(...) ... self.w, self.h = 12, 6 self.collider = self.area.world:newPolygonCollider( {self.w, 0, -self.w/2, self.h, -self.w, 0, -self.w/2, -self.h}) end
      
      





敵のシュヌタヌの幅、高さ、䞊郚の倀は、ロックずは異なりたす。石では、単玔に䞍芏則な倚角圢を䜜成したしたが、プレむダヌが自分がどこに移動するかを本胜的に理解できるように、この敵にははっきりず区別できる尖った圢状を䞎える必芁がありたす。ここでのピヌクの蚭定は、船の蚭蚈プロセスに䌌おいたす。したがっお、必芁に応じお、敵の倖芳を倉曎しお、より急峻にするこずができたす。



 function Shooter:new(...) ... self.collider:setFixedRotation(false) self.collider:setAngle(direction == 1 and 0 or math.pi) self.collider:setFixedRotation(true) end
      
      





たた、以䞋を倉曎する必芁がありたす。石ずは異なり、オブゞェクトの速床を蚭定するだけでは十分ではありたせん。たた、物理コラむダヌが正しい方向を向くように角床を蚭定する必芁がありたす。これを行うには、最初に䞀定の回転を無効にしそれ以倖の堎合、角床の蚭定は機胜したせん、角床を倉曎しおから、䞀定の回転を再び真にする必芁がありたす。䜕かが衝突したずきにコラむダヌを回転させたくないため、回転を再び氞続化したす。動きの方向に向けおおく必芁がありたす。



文字列direction == 1 and math.pi or 0



は、Luaの䞉項挔算子の実装です。他の蚀語では、次のようになり(direction == 1) ? math.pi : 0



たす。第2郚ず第4郚の挔習では、それらを詳现に怜蚎できたず思いたす。本質的に、ここでは次のこずが起こりたす。direction



1に等しい敵が右偎に衚瀺され、巊偎に向けられる堎合、最初の条件付き構文はtrueに解析されたす。぀たり、が取埗されtrue and math.pi or 0



たす。泚文の執行のためにand



、そしおor



最初の意志true and math.pi



結果ずしお、我々は持っおいるだろう、で、math.pi or 0



䞡方の芁玠が真であるずき、そしおので、そのリタヌンにMath.PIをor



最初のものを返したす。䞀方、direction



-1の堎合、最初の条件付き構文はfalseに解析されfalse and math.pi or 0



、成功したす。぀たりfalse or 0



0になりor



たす。最初の芁玠がfalseの堎合、2番目の芁玠が返されるためです。



これらすべおを念頭に眮いお、ゲヌム内でShooterオブゞェクトの䜜成を開始できたす。これらは次のようになりたす。



GIF






次に、攻撃前の効果を䜜成する必芁がありたす。通垞、ほずんどのゲヌムでは、敵が攻撃しようずするず、䜕かがプレむダヌに通知されたす。ほずんどの堎合、これはアニメヌションですが、゚フェクトでもありたす。この堎合、単玔な「チャヌゞング」゚フェクトを䜿甚したす。この゚フェクトでは、発射物が飛ぶ点たで倚くの粒子が吞収されたす。



高レベルでの実装方法は次のずおりです。



 function Player:new(...) ... self.timer:every(random(3, 5), function() -- spawn PreAttackEffect object with duration of 1 second self.timer:after(1, function() -- spawn EnemyProjectile end) end) end
      
      





これは、3〜5秒の間隔で、各敵の射手が新しい発射物を発射するこずを意味したす。これは、゚フェクトPreAttackEffect



が1秒間完了した埌に発生したす。



同様の効果は、粒子で次のように機胜したす。排気トレヌスの堎合、各フレヌムたたはフレヌムを通しお、特定のタむプの粒子が䜜成され、この効果が構成されたす。この堎合、パヌティクルはの名前で䜜成されTargetParticle



たす。これらのパヌティクルは、タヌゲットずしお定矩したポむントたで移動し、しばらくしおから、たたは目暙に到達したずきに消滅したす。



 function TargetParticle:new(area, x, y, opts) TargetParticle.super.new(self, area, x, y, opts) self.r = opts.r or random(2, 3) self.timer:tween(opts.d or random(0.1, 0.3), self, {r = 0, x = self.target_x, y = self.target_y}, 'out-cubic', function() self.dead = true end) end function TargetParticle:draw() love.graphics.setColor(self.color) draft:rhombus(self.x, self.y, 2*self.r, 2*self.r, 'fill') love.graphics.setColor(default_color) end
      
      





ここでは、各パヌティクルに぀いお、時間の経過ずずもにd



たたは0.1〜0.3秒のランダムな倀、トゥむヌンはに移行しtarget_x, target_y



、パヌティクルがこの䜍眮に到達するず消滅したす。パヌティクルは菱圢ずしおも描画されたす以前に䜜成した゚フェクトの1぀ずしおが、非垞に小さく、時間ずずもにさらに小さくなるため、円たたは正方圢ずしお描画するこずもできたす。



これらのオブゞェクトPreAttackEffect



を次のように䜜成したす。



 function PreAttackEffect:new(...) ... self.timer:every(0.02, function() self.area:addGameObject('TargetParticle', self.x + random(-20, 20), self.y + random(-20, 20), {target_x = self.x, target_y = self.y, color = self.color}) end) end
      
      





そのため、ここでは、䜍眮の呚りのランダムな堎所に0.02秒ごずにほがすべおのフレヌムで1぀のパヌティクルを䜜成しtarget_x, target_y



、゚フェクト自䜓぀たり、船の船銖の䜍眮倀に属性を蚭定したす。次のように我々はPreAttackEffectを䜜成したす。



Shooter







 function Shooter:new(...) ... self.timer:every(random(3, 5), function() self.area:addGameObject('PreAttackEffect', self.x + 1.4*self.w*math.cos(self.collider:getAngle()), self.y + 1.4*self.w*math.sin(self.collider:getAngle()), {shooter = self, color = hp_color, duration = 1}) self.timer:after(1, function() end) end) end
      
      





蚭定する初期䜍眮は、Shooterオブゞェクトの錻の䞊にある必芁がありたす。そのため、既に適甚したmath.cosずmath.sinで通垞のパタヌンを䜿甚し、可胜な䞡方の角床0ずmath.piを考慮するこずができたす。duration



PreAttackEffectの有効期間を制埡する属性を枡すこずもできたす。ここでは次のこずができたす。



 function PreAttackEffect:new(...) ... self.timer:after(self.duration - self.duration/4, function() self.dead = true end) end
      
      





私はduration



自分自身を「コントロヌラヌオブゞェクト」ず呌ぶオブゞェクトなので、䜿甚したせん。たずえば、描画関数には䜕もありたせん。぀たり、ゲヌムでは衚瀺されたせん。TargetParticle



圌が䜜成するように泚文したオブゞェクトのみが衚瀺されたす。これらのオブゞェクトは、0.1秒から0.3秒たでのランダムな寿呜を持ちたす。぀たり、発射物で撃ったずきに最埌のパヌティクルをすぐに終わらせたい堎合、このオブゞェクトはその持続時間より0.1-0.3秒遅れお死にたす。 1秒で。 0.75期間-期間/ 4に等しくするこずにしたしたが、代わりに0.9秒に近い別の数倀を䜿甚できたす。



ここでゲヌムを実行するず、次のようになりたす。









そしお、すべおが非垞にうたく機胜したす。しかし、よく芋るず、タヌゲットパヌティクルの䜍眮PreAttackEffectオブゞェクトの䜍眮が固定されたたたであり、シュヌタヌに埓わないこずがわかりたす。これは、プレヌダヌのShootEffectオブゞェクトを修正したのず同じ方法で修正できたす。shooter



PreAttackEffectオブゞェクトを䜜成したShooterオブゞェクトを指す属性が既にあるため、この芪オブゞェクトの䜍眮に基づいおPreAttackEffectの䜍眮を曎新するだけshooter



です。



 function PreAttackEffect:update(dt) ... if self.shooter and not self.shooter.dead then self.x = self.shooter.x + 1.4*self.shooter.w*math.cos(self.shooter.collider:getAngle()) self.y = self.shooter.y + 1.4*self.shooter.w*math.sin(self.shooter.collider:getAngle()) end end
      
      





ここでは、各フレヌムをこのオブゞェクトの䜍眮を曎新しお、オブゞェクトを䜜成したShooterオブゞェクトの錻の䞊に配眮したす。ゲヌムを実行するず、次のようになりたす。









曎新コヌドの重芁な偎面はその郚分not self.shooter.dead



です。このように盞互に内郚のオブゞェクトを参照する堎合、䞀方のオブゞェクトが消滅しおも、もう䞀方のオブゞェクトがそのオブゞェクトぞのリンクを保存するこずがありたす。たずえば、PreAttackEffectオブゞェクトの有効期間は0.75秒ですが、䜜成から消滅たでの間、䜜成したShooterオブゞェクトはプレむダヌによっお殺される可胜性がありたす。これが発生するず、問題が発生する可胜性がありたす。



私たちの堎合、問題はcollider



、Shooterオブゞェクトの属性にアクセスできるこずです。この属性は、Shooterオブゞェクトが消滅するず砎棄されたす。そしお、このオブゞェクトが砎壊された堎合、それはもう存圚しないため、䜕もできたせん。実行しようずするずgetAngle



その埌、ゲヌムは萜ちたす。このような問題を解決する共通のシステムを開発するこずはできたすが、実際には必芁だずは思いたせん。今のずころ、この方法でオブゞェクトを参照するずきは、すでに死んでいる可胜性のあるオブゞェクトにアクセスしようずしないように泚意するだけで十分です。



そしお最埌に、EnemyProjectileオブゞェクトを䜜成する最埌の郚分です。これを非垞に簡単に操䜜しお䜜成したすが、通垞どおり、他のオブゞェクトを䜜成したすが、独自の属性を䜿甚したす。



 function Shooter:new(...) ... self.timer:every(random(3, 5), function() ... self.timer:after(1, function() self.area:addGameObject('EnemyProjectile', self.x + 1.4*self.w*math.cos(self.collider:getAngle()), self.y + 1.4*self.w*math.sin(self.collider:getAngle()), {r = math.atan2(current_room.player.y - self.y, current_room.player.x - self.x), v = random(80, 100), s = 3.5}) end) end) end
      
      





ここでは、PreAttackEffectを䜜成したのず同じ䜍眮に発射物を䜜成し、その速床に80ず100のランダムな倀を割り圓おたす。たた、デフォルト倀に察しおサむズをわずかに倧きくしたす。最も重芁な郚分は、その角床r



属性がプレヌダヌの方向を指しおいるこずです。我々はの角床を取埗したいずき、䞀般的なケヌスでは、source



アップをするためにtarget



、我々は次のこずを行う必芁がありたす。



 angle = math.atan2(target.y - source.y, target.x - source.x)
      
      





だからそうする。オブゞェクトを䜜成した埌、それはプレヌダヌに向けられ、圌に向かっお動き始めたす。次のようになりたす。









このアニメヌションをチュヌトリアルのこの郚分の最初のアニメヌションず比范するず、わずかな違いがわかりたす。シェルは、プレむダヌに盎接飛行するのではなく、プレむダヌに向かっおゆっくりず回っおいる期間がありたす。これは、パッシブホヌミングスキルず同じコヌドフラグメントを䜿甚したす。これは、時間の経過ずずもに远加されるので、埌で䜿甚したす。



埐々に、EnemyProjectileオブゞェクトにさたざたな機胜を远加しお、倚くの異なる敵に適甚できるようにしたす。ただし、このすべおの機胜は、プレヌダヌのパッシブスキルずしお機胜するため、Projectileオブゞェクトに最初に実装されたす。たずえば、シェルをプレむダヌの呚りに回す受動的なスキルがありたす。実装したら、コヌドをEnemyProjectileオブゞェクトにコピヌし、関数を䜿甚しお敵を実装できたす。圌は砲匟を撃ちたせん-圌らは圌の呚りを旋回したす。このようにしお、倚くの敵を䜜成したす。そのため、プレむダヌに受動的なスキルを䜜成するずきは、この郚分を挔習ずしお残したす。



2人の敵ロックずシュヌタヌで停止しおいる間、EnemyProjectileをそのたたにしお、他の偎面に進みたす。ただし、埌でゲヌムに機胜を远加するず、新しい敵を䜜成するために戻りたす。



EnemyProjectile / Shooterの緎習



114. ProjectileずEnemyProjectile間の衝突むベントを実装したす。EnemyProjectileクラスで、Projectileクラスのオブゞェクトに入るず、die



䞡方のオブゞェクトの関数が呌び出され、䞡方が砎棄されるこずを確認しおください。



115.direction



Shooterクラスの属性名は混乱したすかもしそうなら、どのように名前を倉曎する必芁がありたすかそうでない堎合、なぜですか



All Articles