ç®æ¬¡
- èšäº1
- ããŒã1.ã²ãŒã ãµã€ã¯ã«
- ããŒã2.ã©ã€ãã©ãª
- ããŒã3.éšå±ãšãšãªã¢
- ããŒã4.æŒç¿
- ã»ã¯ã·ã§ã³2
- ããŒã5.ã²ãŒã ã®åºæ¬
- ããŒã6.ãã¬ãŒã€ãŒã¯ã©ã¹ã®åºæ¬
- ã»ã¯ã·ã§ã³3
- ããŒã7.ãã¬ãŒã€ãŒã®ãã©ã¡ãŒã¿ãŒãšæ»æ
- ããŒã8.æµ
- ã»ã¯ã·ã§ã³4
- ããŒã9.ãã£ã¬ã¯ã¿ãŒãšã²ãŒã ãµã€ã¯ã«
- ããŒã10.ã³ãŒãäœæã®ãã©ã¯ãã£ã¹
- ããŒã11.ååçã¹ãã«
- ã»ã¯ã·ã§ã³5
- ããŒã12.ãã®ä»ã®ååçã¹ãã«
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
äž»ãªãã©ã¡ãŒã¿ãŒ
次ã«ããã©ã¡ãŒã¿ãŒã®äœæãéå§ããŸãã æåã«ç¢ºèªãããã©ã¡ãŒã¿ãŒã¯ããŒã¹ãã§ãã ãã¬ã€ã€ãŒããäžããŸãã¯ãäžããæŒããšãè¹ã¯æŒãããããŒã«å¿ããŠé床ãå€æŽããŸãã ãã®åºæ¬æ©èœã«å ããŠãã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ã䜿çšãããšæ¯æžããã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ã䜿çšããªããšåŸã ã«åŸ©å ããããªãœãŒã¹ãå¿ èŠã§ãã 次ã®å€ãšã«ãŒã«ãé©çšããŸãã
- ãã¬ã€ã€ãŒã¯æåã«100åäœã®å éãæã¡ãŸã
- å é床ã䜿çšãããšãå é床ã50åäœæžå°ããŸã
- æ¯ç§10åã®å éåäœãåžžã«çæãããŸã
- å éåäœã®æ°ã0ã«éãããšããã®ããããã£ã¯ãã¯ãŒã«ããŠã³ãããŠåã³äœ¿çšã§ããããã«ãªããŸã§2ç§ããããŸãã
- å éã¯ããå·åŽããç¡å¹ã§ãå éãŠãããã®ãªãœãŒã¹ã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çš®é¡ããã次ã®ããã«æ©èœããŸãã
- 匟è¬ãªãœãŒã¹ã¯ãã¬ã€ã€ãŒã®5åã®åŒŸè¬ã埩å ããæµãæ»ãã ãšãã«äœæãããŸã
- å éãªãœãŒã¹ã¯ããã¬ã€ã€ãŒã®25åã®å éãŠãããã埩å ãããã£ã¬ã¯ã¿ãŒã«ãã£ãŠã©ã³ãã ã«äœæãããŸã
- HPãªãœãŒã¹ã¯ããã¬ãŒã€ãŒãã25 HPã埩å ãããã£ã¬ã¯ã¿ãŒã«ãã£ãŠã©ã³ãã ã«äœæãããŸãã
- SkillPointãªãœãŒã¹ã¯ããã¬ãŒã€ãŒã«1ã€ã®ã¹ãã«ãã€ã³ããè¿œå ãããã£ã¬ã¯ã¿ãŒã«ãã£ãŠã©ã³ãã ã«äœæãããŸãã
- æ»æãªãœãŒã¹ã¯ããã¬ãŒã€ãŒã®çŸåšã®æ»æãå€æŽãããã£ã¬ã¯ã¿ãŒã«ãã£ãŠã©ã³ãã ã«äœæãããŸã
ãã£ã¬ã¯ã¿ãŒïŒãã£ã¬ã¯ã¿ãŒïŒ-æµãšãªãœãŒã¹ã®äœæãå¶åŸ¡ããã³ãŒãã ä»ã®ã²ãŒã ïŒ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ã€ã®è¡çªã¯ã©ã¹ã¯ã次ã®èŠåã«åŸãå¿ èŠããããŸãã
- çºå°ç©ã¯çºå°ç©ãç¡èŠããŸã
- Collectableã¯Collectableãç¡èŠããŸã
- åéç©ã¯çºå°ç©ãç¡èŠããŸã
- 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ã®æ»æããããŸãããããã§ã¯ãã®ãã¡ã®äžéšã®ã¿ãæ€èšããŸããæ»æã·ã¹ãã ã¯éåžžã«ã·ã³ãã«ã§ã次ã®ã«ãŒã«ã«åºã¥ããŠããŸãã
- æ»æïŒäžç«ãé€ãïŒã¯ãåã·ã§ããã§åŒŸè¬ãæ¶è²»ããŸãã
- 匟è¬ã0ã«ãªããšãçŸåšã®æ»æã¯äžç«ã«å€ãããŸãã
- ã©ã³ãã ã«çæããããªãœãŒã¹ã䜿çšããŠãæ°ããæ»æãååŸã§ããŸãã
- æ°ããæ»æãåä¿¡ããããšãçŸåšã®æ»æã眮ãæãããã匟è¬ãå®å šã«åŸ©å ãããŸãã
- åæ»æã¯ç¬èªã®éã®åŒŸè¬ã䜿çšããç¬èªã®ç¹æ§ãæã£ãŠããŸãã
æåã«è¡ãããšã¯ãåæ»æã«ã€ããŠã®æ å ±ãå«ãããŒãã«ãå®çŸ©ããããšã§ãïŒãããã®ãå·åŽãã®æéã匟è¬ãšè²ã®æ¶è²»ãããŒãã«ãå®çŸ©ããŸãã
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.次ã®ã¿ã¹ã¯ãå®è¡ããŸãã
hp
éå§å€ã100ã®å±æ§ãRockã¯ã©ã¹ã«è¿œå ããŸãã- Rock
hit
. :
-
damage
, , 100 -
damage
hp
,hp
0 , Rock «» -
hp
0 ,hit_flash
true, 0,2 â false.hit_flash
true,default_color
,hp_color
.
-
111.æ°ããã¯ã©ã¹ãäœæããŸã
EnemyDeathEffect
ããã®å¹æã¯ãæµãæ»ãã§ãªããžã§ã¯ã
ProjectileDeathEffect
ãšãŸã£ããåãããã«æ¯ãèããšãã«äœæãããŸãããããã ãã倧ãããRockãªããžã§ã¯ãã®ãµã€ãºã«å¯Ÿå¿ããŸãããã®ãªããžã§ã¯ãã¯ã
hp
Rockãªããžã§ã¯ãå±æ§ã0以äžã«ãªã£ããšãã«äœæããå¿ èŠããããŸãã
112.çºå°ç©è¡çªã¯ã©ã¹ãªããžã§ã¯ããšæµè¡çªã¯ã©ã¹ãªããžã§ã¯ãéã®è¡çªã€ãã³ããå®è£ ããŸãããã®å ŽåãProjectileã¯ã©ã¹ã®æŽæ°é¢æ°ã«å®è£ ããå¿ èŠããããŸããã·ã§ã«ãEnemyã¯ã©ã¹ã®ãªããžã§ã¯ãã«ããããããšãã·ã§ã«
hit
ã«ãã£ãŠåŒãèµ·ãããããã¡ãŒãžã®éã§æµã®é¢æ°ãåŒã³åºãå¿ èŠããããŸãïŒããã©ã«ãã§ã¯ãã·ã§ã«ã®å±æ§
damage
ã¯æåã¯100ã«ãªããŸãïŒããããããå Žåãçºå°ç©ã¯ç¬èªã®é¢æ°ãåŒã³åºãå¿ èŠããããŸã
die
ã
113ãPlayerã¯ã©ã¹ã«é¢æ°ãè¿œå ããŸã
hit
ããã®é¢æ°ã¯æ¬¡ã®ããšãè¡ãå¿ èŠããããŸãã
- åŒæ°ãåãåãå¿
èŠãããã
damage
å®çŸ©ãããŠããªãå Žåãããã©ã«ãå€ã¯10ã§ãã - ãã®é¢æ°ã¯ãå±æ§
invincible
ãtrueã«èšå®ãã以å€ã¯äœãããŸããã - 4ã8åã®ãªããžã§ã¯ããäœæããå¿
èŠããããŸã
ExplodeParticle
- é¢æ°
addHP
ïŒãŸãã¯removeHP
ãè¿œå ããããšã決å®ããå ŽåïŒã¯ãå±æ§damage
ãåãåããããã䜿çšããŠPlayerãªããžã§ã¯ãã®HPãäžããå¿ èŠããããŸããé¢æ°addHP
ïŒãŸãã¯removeHP
ïŒã®å éšã§ãhp
0以äžã«ãªããã¬ãŒã€ãŒãæ»ãã å Žåã®ç¶æ³ãåŠçããæ¹æ³ãå®è£ ããå¿ èŠããããŸãã
ããã«ã次ã®æ¡ä»¶ä»ãååŒã¯å ¬æ£ã§ãªããã°ãªããŸããã
- 30,
invincible
true, â false. , 0,2 6, , 0,5 0,25. ,invisible
true false 0,04 ,invincible
true.invisible
true, Player . - 30, 0,1 6, , 0,25 0,75.
ãã®é¢æ°
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ã¯ã©ã¹ã®å±æ§åã¯æ··ä¹±ããŸããïŒãããããªããã©ã®ããã«ååãå€æŽããå¿ èŠããããŸããïŒããã§ãªãå Žåããªãã§ããïŒ