èšäºã®æåã®éšåã¯
ãã¡ãã§ãã
ããŒã6.è¡çªã®åé¿
é©åãªNPCããã²ãŒã·ã§ã³ã«ã¯ãå€ãã®å Žåãé害ç©ãåé¿ããæ©èœãå¿
èŠã§ãã ãã®ããŒãã§ã¯ããã£ã©ã¯ã¿ãŒãåšå²ã®é害ç©ãå®å
šã«ãããããšãå¯èœã«ããã¹ãã¢ãªã³ã°åäœã®
è¡çªåé¿ã«ã€ããŠèª¬æããŸãã
ã¯ããã«
è¡çªãåé¿ããåºæ¬çãªèãæ¹ã¯ãé害ç©ãåãã劚ããã»ã©æ¥è¿ãããã³ã«ãé害ç©ãåé¿ããããã®å¶åŸ¡åãçæããããšã§ãã ç°å¢å
ã«è€æ°ã®é害ç©ãããå Žåã§ãããã®åäœã¯ãããã®1ã€ãåæã«äœ¿çšããŠåé¿åãèšç®ããŸãã
ãã£ã©ã¯ã¿ãŒã®åã«ããé害ç©ã®ã¿ãåæãããŸãã æãè
åšãããããã®ã§ãæãè¿ããã®ãè©äŸ¡ã®ããã«éžæãããŸãã ãã®çµæããã£ã©ã¯ã¿ãŒã¯ããšãªã¢å
ã®ãã¹ãŠã®é害ç©ãå®å
šã«ãããããããšãªãã次ã
ãšç§»åããèœåãæã¡ãŸãã
ãã£ã©ã¯ã¿ãŒã®åã«ããé害ç©ãåæãããæãè¿ãïŒæãå±éºãªïŒé害ç©ãéžæãããŸããè¡çªåé¿åäœã¯ãçµè·¯æ¢çŽ¢ã¢ã«ãŽãªãºã ã§ã¯ãããŸããã ãã£ã©ã¯ã¿ãŒãç°å¢å
ã§ç§»åãããé害ç©ãé¿ããåŸã
ã«ãããã¯ãéãæããæ¹æ³ãèŠã€ããŸãããããšãã°ãLãŸãã¯Tã®åœ¢ã®é害ç©ãããå ŽåãããŸãæ©èœããŸããã
ãã³ãïŒãã®è¡çªåé¿åäœã¯Fleeã«äŒŒãŠããããã«èŠãããããããŸããããéèŠãªéãããããŸãã å£ã«æ²¿ã£ãŠç§»åãããã£ã©ã¯ã¿ãŒã¯ããã®ãã¹ããããã¯ãããšãã«ã®ã¿åé¿ããéããè¡åã¯åžžã«ãã£ã©ã¯ã¿ãŒãå£ããæŒãã®ããŸãã
楜ãã¿ã«ããŠ
ç°å¢å
ã®é害ãåé¿ããããã«å¿
èŠãªæåã®ã¹ãããã¯ããã®èªèã§ãã ãã£ã©ã¯ã¿ãŒãå¿é
ããå¿
èŠãããå¯äžã®é害ã¯ã圌ã®åã«ãããçŸåšã®ã«ãŒãããããã¯ããé害ã§ãã
åã®èšäºã§èª¬æããããã«ããã£ã©ã¯ã¿ãŒã®ç§»åæ¹åã¯é床ãã¯ãã«ãè¡šããŸãã ããã䜿çšããŠã
ahead
ãšããæ°ãããã¯ãã«ãäœæããŸããããã¯ãé床ãã¯ãã«ã®ã³ããŒã§ãããé·ãã¯ç°ãªããŸãã
ahead
ãã¯ãã«ã¯ããã£ã©ã¯ã¿ãŒã®èŠç·ã§ãããã®ãã¯ãã«ã¯æ¬¡ã®ããã«èšç®ãããŸãã
ahead = position + normalize(velocity) * MAX_SEE_AHEAD
ahead
ãã¯ãã«ã®é·ãïŒ
MAX_SEE_AHEAD
ã䜿çšããŠèª¿æŽå¯èœïŒã¯ããã£ã©ã¯ã¿ãŒããèŠãããšãã§ãããè·é¢ã決å®ããŸãã
MAX_SEE_AHEAD
ã°å€ã
MAX_SEE_AHEAD
ããã£ã©ã¯ã¿ãŒã¯é ãé¢ããŠããŠãè
åšãšããŠèªèããããããé害ç©ãåé¿ããã®ãæ©ããªããŸãã
åæ¹ã®é·ããé·ãã»ã©ããã£ã©ã¯ã¿ãŒã¯é害ç©ãåé¿ããããã®æªçœ®ãæ©ããŸãã
è¡çªãã§ãã¯
è¡çªããã§ãã¯ããã«ã¯ãåé害ç©ïŒãŸãã¯ãããèšè¿°ããé·æ¹åœ¢ïŒã幟äœåŠçãªåœ¢ã§èšè¿°ããå¿
èŠããããŸãã æè¯ã®çµæã¯ãçïŒ2次å
-åïŒã䜿çšããããšã§åŸããããããç°å¢å
ã®åé害ç©ã¯ãã®ããã«èšè¿°ããå¿
èŠããããŸãã
1ã€ã®è§£æ±ºçã¯ãã»ã°ã¡ã³ããšçäœã®äº€å·®ç¹ã®è¡çªããã§ãã¯ããããšã§ããã»ã°ã¡ã³ãã¯
ahead
ã®ãã¯ãã«ã§ãããçäœã¯é害ç©ã§ãã ãã®ã¢ãããŒãã¯æ©èœããŸãããç§ã¯ãã®åçŽåã䜿çšããŸãããã®åçŽåã¯ç解ãããããåæã«åæ§ã®çµæããããããŸãïŒæã«ã¯ããã«è¯ããªããŸãïŒã
ahead
ãã¯ãã«ã¯ãå¥ã®ååã®é·ãã®ãã¯ãã«ãäœæããããã«äœ¿çšãããŸãã
åãæ¹åãååã®é·ããå
ã®ãã¯ãã«
ahead2
ã
ahead
ãšãŸã£ããåãããã«èšç®ãããŸããããã®é·ãã¯ååã«ãªããŸãã
ahead = position + normalize(velocity) * MAX_SEE_AHEAD ahead2 = position + normalize(velocity) * MAX_SEE_AHEAD * 0.5
è¡çªãã§ãã¯ãå®è¡ããŠãããã2ã€ã®ãã¯ãã«ã®ãããããé害ç©ã®çå
ã«ãããã©ããããã¹ãããŸãã ããã¯ããã¯ãã«ã®ç«¯ãšçã®äžå¿ãšã®éã®è·é¢ãæ¯èŒããããšã§ç°¡åã«è¡ããŸãã
è·é¢ãçã®ååŸä»¥äžã®å Žåããã¯ãã«ã¯çã®å
åŽã«ãããè¡çªãæ€åºãããŸãã
d <rã®å Žåãåæ¹ã®ãã¯ãã«ã¯é害ç©ãšäº€å·®ããŸãã ããæ確ã«ããããã«ãahead2ã®ãã¯ãã«ã¯åé€ãããŸããåæ¹ã®ããã2ã€ã®ãã¯ãã«ã®
ãããããé害ç©ã®çå
ã«ããå Žåããã®é害ç©ã¯ãã¹ããããã¯ããŸãã 2ç¹éã®
ãŠãŒã¯ãªããè·é¢ã®å®çŸ©ã䜿çšã§ããŸãã
private function distance(a :Object, b :Object) :Number { return Math.sqrt((ax - bx) * (ax - bx) + (ay - by) * (ay - by)); } private function lineIntersectsCircle(ahead :Vector3D, ahead2 :Vector3D, obstacle :Circle) :Boolean {
ãã£ã©ã¯ã¿ãŒã®ãã¹ãããã€ãã®é害ç©ããããã¯ããŠããå Žåãæãè¿ãïŒæãå±éºãªïŒé害ç©ãèšç®ã®ããã«éžæãããŸãã
èšç®ã®ããã«ãæãè¿ãé害ç©ïŒæãå±éºãªãã®ïŒãéžæãããŸãã
åé¿èšç®
åé¿ã®åã¯ããã£ã©ã¯ã¿ãŒãé害ç©ããé ãããçäœãåé¿ã§ããããã«ããŸãã ããã¯ãçã®äžå¿ïŒäœçœ®ãã¯ãã«ïŒãš
ahead
ãã¯ãã«ã䜿çšããŠåœ¢æããããã¯ãã«ã䜿çšããŠå®è£
ã§ããŸãã ãã®åé¿åã¯æ¬¡ã®ããã«èšç®ããŸãã
avoidance_force = ahead - obstacle_center avoidance_force = normalize(avoidance_force) * MAX_AVOID_FORCE
avoidance_force
èšç®åŸã
MAX_AVOID_FORCE
ãã€ãŸã
avoidance_force
ã®é·ãã決å®ããå€ã«ãã£ãŠæ£èŠåããã³ã¹ã±ãŒãªã³ã°ãããŸãã
MAX_AVOID_FORCE
å€ã
MAX_AVOID_FORCE
ãåé¿ã®åã匷ããªãããã£ã©ã¯ã¿ãŒãé害ç©ããé ããããŸãã
åé¿åã®èšç®ã ãªã¬ã³ãžè²ã®ç Žç·ã¯ãé害ç©ãé¿ããããã«ãã£ã©ã¯ã¿ãŒããã©ããã¹ã瀺ããŠããŸãã
ãã³ãïŒãšã³ãã£ãã£
ã®äœçœ®ã¯ãã¯ãã«ãšããŠèšè¿°ã§ãããããä»ã®ãã¯ãã«ãåãšãšãã«èšç®ã«äœ¿çšã§ããŸãã
é害ç©åé¿
åé¿åãè¿ã
collisionAvoidance()
ã¡ãœããã®å®æããå®è£
ã¯ã次ã®ããã«ãªããŸãã
private function collisionAvoidance() :Vector3D { ahead = ...;
åé¿ã®åã¯ããã£ã©ã¯ã¿ãŒã®é床ãã¯ãã«ã«è¿œå ããå¿
èŠããããŸãã åã®èšäºã§èª¬æããããã«ããã¹ãŠã®å¶åŸ¡åã1ã€ã«çµåããŠããã£ã©ã¯ã¿ãŒã«äœçšãããã¹ãŠã®ã¢ã¯ãã£ããªåäœãè¡šãåãäœæã§ããŸãã
åé¿åã®è§åºŠãšæ¹åãäžå®ã§ããã°ãã·ãŒã¯ãã¯ã³ããŒãªã©ãä»ã®å¶åŸ¡åã«å¹²æžããŸããã éåžžã®æ¹æ³ã§åé¿ããã£ã©ã¯ã¿ãŒã®é床ã«è¿œå ãããŸãã
steering = nothing();
ã²ãŒã ãæŽæ°ããããã³ã«ãã¹ãŠã®ã¹ãã¢ãªã³ã°åäœãåèšç®ããããããé害ç©ããã¹ããããã¯ããŠããéããåé¿åãã¢ã¯ãã£ãã«ãªããŸãã
é害ç©ã
ahead
ã®ãã¯ãã«ã®ã»ã°ã¡ã³ãã暪åãã®ãåæ¢ãããšãåé¿åã¯ãŒãã«ãªãïŒå¹æã¯ãããŸããïŒãåèšç®ãããŠå¥ã®è
åšã®é害ç©ãåé¿ããŸãã ãã®çµæãé害ãåé¿ã§ãããã£ã©ã¯ã¿ãŒãåŸãããŸãã
è¡çªèªèã®æ¹å
çŸåšã®å®è£
ã«ã¯ãè¡çªèªèã«é¢é£ãã2ã€ã®åé¡ããããŸãã æåã¯ã
ahead
ãã¯ãã«ãé害ç©ã®ç¯å²å€ã«ãããããã£ã©ã¯ã¿ãŒãé害ç©ã«è¿ãããïŒãŸãã¯å
éšïŒå Žåã«çºçããŸãã
ãããçºçããå Žåãè¡çªãæ€åºãããªãããããã£ã©ã¯ã¿ãŒã¯é害ç©ã«è§ŠããŠïŒãŸãã¯é²å
¥ããŠïŒåé¿ããã»ã¹ãã¹ãããããŸãã
ahead
ã®ãã¯ãã«ãé害ç©ã®å€åŽã«ããå ŽåããããŸããããã£ã©ã¯ã¿ãŒã¯å
åŽã«ãããŸãããã®åé¡ã¯ãè¡çªãã§ãã¯ã«3çªç®ã®ãã¯ãã«ãã€ãŸããã£ã©ã¯ã¿ãŒã®äœçœ®ãã¯ãã«ãè¿œå ããããšã§ä¿®æ£ã§ããŸãã 3ã€ã®ãã¯ãã«ã䜿çšãããšãè¡çªèªèã倧å¹
ã«åäžããŸãã
2çªç®ã®åé¡ã¯ããã£ã©ã¯ã¿ãŒãé害ç©ã«è¿ã¥ããé害ç©ããé ããããšãã«çºçããŸãã ãã£ã©ã¯ã¿ãŒãåã«ä»ã®æ¹åãåããŠããå Žåã§ããæäœãããšè¡çªããããšããããŸãã
ãã£ã©ã¯ã¿ãŒãã¡ããã©å転ããŠããå Žåã§ããæ瞊ã¯è¡çªã«ã€ãªããå¯èœæ§ããããŸãããã®åé¡ã¯ããã£ã©ã¯ã¿ãŒã®çŸåšã®é床ã«å¿ããŠ
ahead
ã®ãã¯ãã«ã®ã¹ã±ãŒã«ãå€æŽããããšã§è§£æ¶ã§ããŸãã ããšãã°ã
ahead
ãã¯ãã«ãèšç®ããã³ãŒãã¯æ¬¡ã®ããã«å€æŽãããŸãã
dynamic_length = length(velocity) / MAX_VELOCITY ahead = position + normalize(velocity) * dynamic_length
dynamic_length
å€æ°ã¯0ãã1ãŸã§å€åããŸãããã£ã©ã¯ã¿ãŒããã«ã¹ããŒãã§ç§»åãããšãã
dynamic_length
ã¯1ã§ãã æåãæžéãŸãã¯å éããå Žåã
dynamic_length
ã¯0以äžïŒäŸïŒ0.5ïŒã§ãã
ãããã£ãŠããã£ã©ã¯ã¿ãŒã移åããã«åã«æäœããå Žåã
dynamic_length
ã¯ãŒãã«ãªãåŸåããããè¡çªã®ãªããŒããã¯ãã«ã
ahead
äœæããŸãã
ãã¢ïŒãŸã³ãã®æéïŒ
é害ç©åé¿è¡åãå®éã«ç€ºãã«ã¯ããŸã³ãã®å€§çŸ€ãæé©ã§ãã 以äžã¯ãããŠã¹ã«ãŒãœã«ãã·ãŒã¯ïŒã·ãŒã¯ïŒããè€æ°ã®ãŸã³ãïŒãã¹ãŠé床ãç°ãªãïŒã®ãã¢ã§ãã
Flashã®ã€ã³ã¿ã©ã¯ãã£ããã¢ã¯
ãã¡ãã§ãã
ãããã«
è¡çªåé¿åäœã«ããããã¹ãŠã®ãã£ã©ã¯ã¿ãŒãç°å¢å
ã®é害ç©ããããããšãã§ããŸãã ã²ãŒã ãæŽæ°ããããã³ã«ãã¹ãŠã®å¶åŸ¡åãæ°ãã«åèšç®ãããããããã£ã©ã¯ã¿ãŒã¯ããŸããŸãªé害ç©ãšåé¡ãªã察話ããåžžã«æãè
åšã®ããïŒæãè¿ãïŒåæãè¡ããŸãã
ãã®åäœã¯ãã¹ãèŠã€ããããã®ã¢ã«ãŽãªãºã ã§ã¯ãããŸããããå¯éãããããã§åŸãããçµæã¯éåžžã«èª¬åŸåããããŸãã
ããŒã7.ãã¹ããã©ã
ãã¹ããã©ããšããã¿ã¹ã¯ã¯ãã²ãŒã éçºã§ããééããŸãã ãã®ããŒãã§ã¯ããã€ã³ããšã»ã°ã¡ã³ãã§æ§æãããç¹å®ã®ãã¹ããã£ã©ã¯ã¿ãŒããã©ãããšãã§ãããã¹ãã¢ãªã³ã°åäœã®
ãã¹ãã©ããŒã€ã³ã°ãèŠãŠãããŸãã
ã¯ããã«
ãã¹è¿œè·¡åäœã¯ãããã€ãã®æ¹æ³ã§å®è£
ã§ããŸãã
Reynoldsã®åæ
å®è£
ã§ã¯ãã»ã°ã¡ã³ãã§æ§æããããã¹ã䜿çšãããã¬ãŒã«äžã®åè»ã®ããã«ãæåãå³å¯ã«ããã«ç¶ããŸãã
ç¶æ³ã«ãã£ãŠã¯ããã®ç²ŸåºŠã¯å¿
èŠãããŸããã ãã£ã©ã¯ã¿ãŒã¯ã»ã°ã¡ã³ãã«æ²¿ã£ãŠãã¹ã«æ²¿ã£ãŠç§»åã§ããŸãããã¬ãŒã«ã®ããã§ã¯ãªãã
ã¹ããããšããŠäœ¿çšããŸãã
ãã®ãã¥ãŒããªã¢ã«ã§çŽ¹ä»ãããã©ããŒã¢ããã®å®è£
ã¯ãã¬ã€ãã«ãºãææ¡ããå®è£
ã®ç°¡ç¥åã§ãã ãŸããè¯ãçµæãåŸãããŸãããå°åœ±ãã¯ãã«ã®ãããªéãæ°åŠèšç®ã«ã¯ããŸãé¢ä¿ããŸããã
ãã¹ãèšå®ãã
ãã¹ã¯ãã»ã°ã¡ã³ãã§æ¥ç¶ãããäžé£ã®ãã€ã³ãïŒããŒãïŒãšããŠå®çŸ©ã§ããŸãã æ²ç·ã䜿çšããŠãã¹ãèšè¿°ããããšãã§ããŸããããã€ã³ããšã»ã°ã¡ã³ãã䜿çšããæ¹ãç°¡åã§ãã»ãŒåãçµæãåŸãããŸãã
æ²ç·ã䜿çšããå¿
èŠãããå Žåãããããå€ãã®æ¥ç¶ç¹ã«æžããããšãã§ããŸãã
æ²ç·ãšç·åãPath
ã¯ã©ã¹ã¯ãã«ãŒããèšè¿°ããããã«äœ¿çšãããŸãã å®éãã¯ã©ã¹ã«ã¯ãã€ã³ãã®ãã¯ãã«ãšããã®ãªã¹ããåŠçããããã®ããã€ãã®ã¡ãœããããããŸãã
public class Path { private var nodes :Vector.<Vector3D>; public function Path() { this.nodes = new Vector.<Vector3D>(); } public function addNode(node :Vector3D) :void { nodes.push(node); } public function getNodes() :Vector.<Vector3D> { return nodes; } }
åãŠã§ã€ãã€ã³ãã¯
Vector3D
ã§ãããããã¯ãã£ã©ã¯ã¿ãŒã®
position
ããããã£ãã©ã®ããã«æ©èœãããã«äŒŒã空éå
ã®
position
ã§ãã
ããŒãããããŒããžç§»å
ãã¹ãããã²ãŒãããããã«ããã£ã©ã¯ã¿ãŒã¯ã«ãŒãã®çµç¹ã«å°éãããŸã§ããŒãããããŒãã«ç§»åããŸãã
ãã¹äžã®åãã€ã³ããç®æšãšèŠãªãããšãã§ãããããSeekã®åäœã䜿çšã§ããŸãã
ãããã€ã³ãããå¥ã®ãã€ã³ãã«ã·ãŒã¯ãå®è¡ããŸãããã£ã©ã¯ã¿ãŒã¯ãå°éãããŸã§çŸåšã®ãã€ã³ãã«åããåŸåãããã次ã®ãŠã§ã€ãã€ã³ããçŸåšã®ãã€ã³ãã«ãªããŸãã è¡çªã®åé¿ã«é¢ããéšåã§åè¿°ããããã«ãååäœã®åã¯ã²ãŒã ã®æŽæ°ããšã«åéèšãããŸããã€ãŸããããããŒãããå¥ã®ããŒããžã®ç§»è¡ã¯ãã¹ã ãŒãºã«ããã€ã®éã«ãçºçããŸãã
ããã²ãŒã·ã§ã³ããã»ã¹ãåŠçããã«ã¯ããã£ã©ã¯ã¿ãŒã¯ã©ã¹ã«2ã€ã®è¿œå ã®ããããã£ãå¿
èŠã§ããçŸåšã®ããŒãïŒãã£ã©ã¯ã¿ãŒãçã£ãŠããããŒãïŒãšãããã«ç¶ããã¹ãžã®ãªã³ã¯ã§ãã ã¯ã©ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
public class Boid { public var path :Path; public var currentNode :int; (...) private function pathFollowing() :Vector3D { var target :Vector3D = null; if (path != null) { var nodes :Vector.<Vector3D> = path.getNodes(); target = nodes[currentNode]; if (distance(position, target) <= 10) { currentNode += 1; if (currentNode >= nodes.length) { currentNode = nodes.length - 1; } } } return null; } private function distance(a :Object, b :Object) :Number { return Math.sqrt((ax - bx) * (ax - bx) + (ay - by) * (ay - by)); } (...) }
pathFollowing()
ã¡ãœããã¯ããã¹
pathFollowing()
匷ããçæããŸãã 圌ã¯åŒ·ããäœæããŸããããç®æšãæ£ããéžæããŸãã
path != null
ãã¹ãã¯ããã£ã©ã¯ã¿ãŒããã¹ããã©ããã©ããã確èªããŸãã ãã®å Žåã
currentNode
ããããã£ã
currentNode
ããŠããã€ã³ãã®ãªã¹ãã§çŸåšã®ã¿ãŒã²ããïŒãã£ã©ã¯ã¿ãŒãç®æãã¹ãã¿ãŒã²ããïŒãæ€çŽ¢ããŸãã
çŸåšã®ã¿ãŒã²ãããšãã£ã©ã¯ã¿ãŒã®äœçœ®ã®éã®è·é¢ã
10
æªæºã®å Žåãããã¯ãã£ã©ã¯ã¿ãŒãçŸåšã®ããŒãã«å°éããããšãæå³ããŸãã ãããçºçãããšã
currentNode
1ãã€å¢å ããããããã£ã©ã¯ã¿ãŒã¯ãã¹äžã®æ¬¡ã®ãã€ã³ãã«åããåŸåããããŸãã ãã¹å
ã®ãã€ã³ããçµäºãããŸã§ãããã»ã¹ãç¹°ãè¿ãããŸãã
åã®èšç®ãšè¿œå
ãã£ã©ã¯ã¿ãŒããã¹ã®åããŒãã«ããã·ã¥ããããã«äœ¿çšãããåã¯ãã·ãŒã¯åäœã®åã§ãã 察å¿ããã³ãŒãã¯ãã§ã«
pathFollowing()
ã¡ãœããã§éžæãããŠããããããã®ããŒãã«ãã£ã©ã¯ã¿ãŒãããã·ã¥ããåãè¿ãå¿
èŠããããŸãã
private function pathFollowing() :Vector3D { var target :Vector3D = null; if (path != null) { var nodes :Vector.<Vector3D> = path.getNodes(); target = nodes[currentNode]; if (distance(position, target) <= 10) { currentNode += 1; if (currentNode >= nodes.length) { currentNode = nodes.length - 1; } } } return target != null ? seek(target) : new Vector3D(); }
ãã¹ããã©ã匷ããèšç®ããåŸãéåžžã©ããããã£ã©ã¯ã¿ãŒã®é床ãã¯ãã«ã«è¿œå ããå¿
èŠããããŸãã
steering = nothing();
ãã¹ããã©ãå¶åŸ¡åã¯ããã£ã©ã¯ã¿ãŒãã¿ãŒã²ãããæãŸããããã«åžžã«æ¹åãå€ãã远跡ã®åäœã«éåžžã«äŒŒãŠããŸãã éãã¯ããã£ã©ã¯ã¿ãŒãåãã®ãªãç®æšãç®æããŠåªåãããšããäºå®ã«ãããŸããç®æšã«å°éãããšãç¡èŠããŠå¥ã®ç®æšãç®æããŸãã
çµæã¯æ¬¡ã®ããã«ãªããŸãã
Flashã®ã€ã³ã¿ã©ã¯ãã£ããã¢ã¯
ãã¡ãã§ãã
ã¢ãŒã·ã§ã³ã¹ã ãŒãžã³ã°
çŸåšã®å®è£
ã§ã¯ããã¹äžã®çŸåšã®ãã€ã³ãããã¿ãããããŠæ¬¡ã®ãã€ã³ããéžæããã«ã¯ããã¹ãŠã®ãã£ã©ã¯ã¿ãŒãå¿
èŠã§ãã ãããã£ãŠããã£ã©ã¯ã¿ãŒã¯ãããšãã°ã¿ãŒã²ããã«å°éãããŸã§åãæãããã«ã¿ãŒã²ããã®åšãã移åãããªã©ãæãŸãããªãåãã®ãã¿ãŒã³ãå®è¡ã§ããŸãã
èªç¶çã§ã¯ããã¹ãŠã®åã
ã¯æå°åªåã®ååã«åŸãåŸåããããŸãã ããšãã°ã人ã¯å»äžã®çãäžãåžžã«ç§»åããããã§ã¯ãããŸããã åã«æ²ãã£ãŠããå Žåãå£ã«è¿ã¥ããŠè·é¢ãçž®ããŸãã
ãã®ãã¿ãŒã³ã¯ããã¹ã«ååŸãè¿œå ããããšã§åäœæã§ããŸãã ååŸã¯ãã€ã³ãã«é©çšãããã«ãŒãã®ãå¹
ããšèŠãªãããšãã§ããŸãã 圌ã¯ããã¹ã«æ²¿ã£ãŠç§»åããŠããã£ã©ã¯ã¿ãŒããã€ã³ãããã©ãã ã移åã§ããããå¶åŸ¡ããŸãã
ãã¹ããã©ãéã®ååŸã®åœ±é¿ããã£ã©ã¯ã¿ãŒãšãã€ã³ãéã®è·é¢ãååŸä»¥äžã§ããå Žåããã€ã³ãã«å°éãããšèŠãªãããŸãã ãããã£ãŠããã¹ãŠã®ãã£ã©ã¯ã¿ãŒã¯ãã»ã°ã¡ã³ãããã³ãã€ã³ãã
ã¬ã€ããšããŠäœ¿çšããŠç§»åã
ãŸã ã
Flashã®ã€ã³ã¿ã©ã¯ãã£ããã¢ã¯
ãã¡ãã§ãã
ååŸã倧ããã»ã©ãã«ãŒããåºããªããã¿ãŒã³äžã«ãã£ã©ã¯ã¿ãŒãä¿æãããã€ã³ããŸã§ã®è·é¢ãé·ããªããŸãã ååŸã®å€ãå€æŽããŠãããŸããŸãªç¹°ãè¿ããã¿ãŒã³ãäœæã§ããŸãã
åæ¹ããã³åŸæ¹
å Žåã«ãã£ãŠã¯ããã¹ã®æåŸã«å°éãããšããã£ã©ã¯ã¿ãŒãåãç¶ããããšã圹ç«ã€å ŽåããããŸãã ããšãã°ãããããŒã«ãã¿ãŒã³ã§ã¯ããã£ã©ã¯ã¿ãŒã¯æåŸã«å°éãããšãåããã€ã³ãããã©ã£ãŠã«ãŒãã®æåã«æ»ãå¿
èŠããããŸãã
ããã¯ã
pathDir
ããããã£ãæåã¯ã©ã¹ã«è¿œå ããããšã§å®çŸã§ããŸãã æåããã¹ã«æ²¿ã£ãŠç§»åããæ¹åãå¶åŸ¡ããæŽæ°å€ã§ãã
pathDir
ã
1
å Žåããã£ã©ã¯ã¿ãŒã¯ãã¹ã®æåŸã«ç§»åããŸãã
-1
ã¯ãå
é ãžã®ç§»åã瀺ããŸãã
pathFollowing()
ã¡ãœããã¯æ¬¡ã®ããã«å€æŽã§ããŸãã
private function pathFollowing() :Vector3D { var target :Vector3D = null; if (path != null) { var nodes :Vector.<Vector3D> = path.getNodes(); target = nodes[currentNode]; if (distance(position, target) <= path.radius) { currentNode += pathDir; if (currentNode >= nodes.length || currentNode < 0) { pathDir *= -1; currentNode += pathDir; } } } return target != null ? seek(target) : new Vector3D(); }
åã®ããŒãžã§ã³ãšã¯ç°ãªããä»ã§ã¯
pathDir
ã®å€ã
currentNode
ããããã£ã«è¿œå ãããŸãïŒåã«
1
è¿œå ããã®ã§ã¯ãªãïŒã ããã«ããããã£ã©ã¯ã¿ãŒã¯çŸåšã®æ¹åã«åºã¥ããŠãã¹äžã®æ¬¡ã®ãã€ã³ããéžæã§ããŸãã
ãã®åŸããã¹ãã¯ãã£ã©ã¯ã¿ãŒãã«ãŒãã®çµããã«å°éãããã©ããããã§ãã¯ããŸãã ãã®å Žåã
pathDir
-1
ãä¹ç®ãããå€ãéã«ãªãããã£ã©ã¯ã¿ãŒã¯åãã®æ¹åãéã«ããŸãã
ãã®çµæãååŸã«ç§»åãããã¿ãŒã³ãåŸãããŸãã
ãããã«
ãã¹è¿œåŸåäœã«ããããã£ã©ã¯ã¿ãŒã¯æå®ããããã¹ã«æ²¿ã£ãŠç§»åã§ããŸãã ã«ãŒãã¯ãã€ã³ãã«ãã£ãŠå®çŸ©ããããã®å¹
ã調æŽããŠãããèªç¶ã«èŠããåãã®ãã¿ãŒã³ãäœæã§ããŸãã
ãã®ããŒãã§èª¬æããå®è£
ã¯ãã¬ã€ãã«ãºã«ãã£ãŠææ¡ãã
ããã¹ã®åæåäœãåçŽåãããã®ã§ãããããã§ããã£ãšããããèªç¶ãªçµæãçã¿åºããŸãã
ããŒã8.ãªãŒããŒã«åŸã
ãã£ã©ã¯ã¿ãŒïŒãŸãã¯ãã£ã©ã¯ã¿ãŒã®ã°ã«ãŒãïŒã¯ããã¹ããã©ãããšãã§ããããšã«å ããŠããã£ã©ã¯ã¿ãŒïŒåéé·ãªã©ïŒããã©ãããšãã§ããªããã°ãªããŸããã ãã®åé¡ã¯ã
ãªãŒããŒã®æ¬¡ã®åäœã䜿çšããŠè§£æ±ºã§ããŸãã
ã¯ããã«
ãªãŒããŒã远跡ããåäœã¯ããã£ã©ã¯ã¿ãŒã®ã°ã«ãŒããç¹å®ã®ãã£ã©ã¯ã¿ãŒïŒãªãŒããŒïŒã远跡ããããã«é
眮ãããä»ã®å¶åŸ¡åã®çµã¿åããã§ãã ç°¡åãªã¢ãããŒãã§ã¯ãã·ãŒã¯ãŸãã¯è¿œè·¡ã®åäœã䜿çšããŠãã©ããŒãã¿ãŒã³ãäœæã§ããŸãããçµæã¯ããŸãè¯ããããŸããã
ã·ãŒã¯åäœã§ã¯ããã£ã©ã¯ã¿ãŒã¯ã¿ãŒã²ããã«åãã£ãŠãé
ããæ©ããã¿ãŒã²ãããšåãå Žæã«ç§»åããŸãã äžæ¹ã远跡è¡åã¯ããã£ã©ã¯ã¿ãŒãå¥ã®ãã£ã©ã¯ã¿ãŒã«æŒãä»ããŸããããããè¿œããããã ãã§ãªããäºæž¬ã«åºã¥ããŠãã£ããããããšãç®çãšããŠããŸãã
ãªãŒããŒããã©ããŒãããšãã®ã¿ã¹ã¯ã¯ããªãŒããŒã®ååè¿ãã«ãããã
圌ã®å°ãåŸãã«ããããšã§ãã ããã«ããã£ã©ã¯ã¿ãŒãé ãã«ãããšãã¯ããªãŒããŒã«éã移åããå¿
èŠããããŸãããè·é¢ãçããªããšé
ããªããŸãã ããã¯ã3ã€ã®ã¹ãã¢ãªã³ã°åäœã®çµã¿åããã«ãã£ãŠå®çŸã§ããŸãã
- å°çïŒåŸã
ã«æžéããŠåããæ¢ããŠããªãŒããŒã«åãã£ãŠåããŸãã
- åé¿ïŒãã£ã©ã¯ã¿ãŒããªãŒããŒã®é²è·¯ã«ããå Žåã¯ãçŽ æ©ã移åããå¿
èŠããããŸãã
- åé¢ ïŒè€æ°ã®ãã£ã©ã¯ã¿ãŒããªãŒããŒãè¿œãããããšããæ··éãé¿ããŸãã
以äžã§ã¯ããªãŒããŒããã©ããŒããããã®ãã¿ãŒã³ãäœæããããã«ããããã®ååäœãã©ã®ããã«çµã¿åãããããšãã§ãããã説æããŸãã
ãã©ããŒããé©åãªãã€ã³ããèŠã€ãã
ãã©ããŒã®éçšã§ããã£ã©ã¯ã¿ãŒã¯ææ®å®ã®åŸãã«ããè»éã®ããã«ããªãŒããŒã®å°ãåŸãã«çãŸãããã«åªããã¹ãã§ãã ãã©ããŒã¢ãããã€ã³ãïŒ
behind
ãšåŒã°ããïŒã¯ããã£ã©ã¯ã¿ãŒã®æ¹åãè¡šããããã¿ãŒã²ããã®é床ã«åºã¥ããŠç°¡åã«èšç®ã§ããŸãã æ¬äŒŒã³ãŒãã¯æ¬¡ã®ãšããã§ãã
tv = leader.velocity * -1; tv = normalize(tv) * LEADER_BEHIND_DIST; behind = leader.position + tv;
é床ãã¯ãã«ã«
-1
æãããšãçµæã¯é床ãã¯ãã«ã®
éã«ãªããŸãã 次ã«ããã®çµæã®ãã¯ãã«ïŒ
tv
ãšåŒã°ããïŒãæ£èŠåãã¹ã±ãŒãªã³ã°ãããã£ã©ã¯ã¿ãŒã®çŸåšäœçœ®ã«è¿œå ã§ããŸãã
ããã»ã¹ã®èŠèŠçè¡šçŸã¯æ¬¡ã®ãšããã§ãã
ã·ãŒã±ã³ã¹ãã€ã³ããèŠã€ããããã«äœ¿çšããããã¯ãã«æŒç®ãLEADER_BEHIND_DIST
ã倧ããã»ã©ããªãŒããŒãšãã®èåŸã®ãã€ã³ãéã®è·é¢ã倧ãããªããŸãã ãã£ã©ã¯ã¿ãŒã¯ãã®ãã€ã³ãããã©ãã®ã§ããªãŒããŒããé ããªãã»ã©ããã£ã©ã¯ã¿ãŒã¯é ããªããŸãã
ãã©ããŒãšå°ç
次ã®ã¹ãããã¯ãã£ã©ã¯ã¿ãŒããªãŒããŒãã€ã³ãã«ç¶ãããšbehind
ã§ããä»ã®ãã¹ãŠã®åäœãšåæ§ã«ã次ã®ããã»ã¹ã¯ã¡ãœããã«ãã£ãŠçæãããåã«ãã£ãŠå¶åŸ¡ãããŸãfollowLeader()
ã private function followLeader(leader :Boid) :Vector3D { var tv :Vector3D = leader.velocity.clone(); var force :Vector3D = new Vector3D();
ãã®ã¡ãœããã¯ãã€ã³ãbehind
ãèšç®ãããã®ãã€ã³ãã«å°éããåãäœæããŸãã次ã«ãfollowLeader
ä»ã®ãã¹ãŠã®åäœãšåæ§ã«ããã£ã©ã¯ã¿ãŒã®å¶åŸ¡åã«åŒ·ããè¿œå ã§ããŸãã steering = nothing();
ãã®å®è£
ã®çµæããã£ã©ã¯ã¿ãŒã®ã°ã«ãŒããbehind
ãªãŒããŒã®ãã€ã³ãã«å°éã§ããããã«ãªããŸãïŒFlashã®ã€ã³ã¿ã©ã¯ãã£ããã¢ïŒã
æ··éåé¿
ãªãŒããŒã«åŸããšããã£ã©ã¯ã¿ãŒãäºãã«è¿ãããŠãçµæãäžèªç¶ã«èŠãããããããŸããããã¹ãŠã®ãã£ã©ã¯ã¿ãŒã¯åæ§ã®åã®åœ±é¿ãåãããããåãããã«åãããæãã圢æããåŸåããããŸãããã®ãã¿ãŒã³ã¯ã矀ãè¡åãå°ãèŠåã®1ã€ã§ããåé¢ã®å©ããåããŠä¿®æ£ã§ããŸããåé¢ã®åã§ã¯ããã£ã©ã¯ã¿ãŒã®ã°ã«ãŒããç©ã¿éãªããäºãã®éã«äžå®ã®è·é¢ãç¶æããããšã¯ã§ããŸãããåé¢åã¯æ¬¡ã®ããã«èšç®ã§ããŸãã private function separation() :Vector3D { var force :Vector3D = new Vector3D(); var neighborCount :int = 0; for (var i:int = 0; i < Game.instance.boids.length; i++) { var b :Boid = Game.instance.boids[i]; if (b != this && distance(b, this) <= SEPARATION_RADIUS) { force.x += b.position.x - this.position.x; force.y += b.position.y - this.position.y; neighborCount++; } } if (neighborCount != 0) { force.x /= neighborCount; force.y /= neighborCount; force.scaleBy( -1); } force.normalize(); force.scaleBy(MAX_SEPARATION); return force; }
次ã«ãåé¢ã®åãåã«è¿œå ããŠããªãŒããŒãç®æããšåæã«followLeader
ãã£ã©ã¯ã¿ãŒãäºãã«åŒãé¢ãããšãã§ããŸãã private function followLeader(leader :Boid) :Vector3D { var tv :Vector3D = leader.velocity.clone(); var force :Vector3D = new Vector3D();
ãã®çµæãããèªç¶ãªèŠãç®ã®ãã¿ãŒã³ãåŸãããŸãïŒFlash ãã¢ïŒã
éªéã«ãªããªã
ãªãŒããŒãçªç¶çŸåšã®æ¹åãå€ãããšããã£ã©ã¯ã¿ãŒãéªéãããå¯èœæ§ããããŸããç»å Žäººç©ã¯ãªãŒããŒã«åŸãããããªãŒããŒã®åã«åœŒã眮ããŠããã®ã¯éè«ççã§ãããã£ã©ã¯ã¿ãŒããªãŒããŒã®éªéã«ãªã£ãå Žåã圌ã¯ããã«é¢ããŠéãã¯ãªã¢ããå¿
èŠããããŸããããã¯åäœãåé¿ããããšã§å®çŸã§ããŸãããªãŒããŒã®éãé¿ããæåã®èŠèªæ§ã®åéã§ã®ãªãŒããŒã¯ãæã
ã¯è¡çªåé¿ã®è¡åã®é害ç©ãèªèããæ¹æ³ãšäŒŒãæŠå¿µã䜿çšãããã©ããããã§ãã¯ããããã«ïŒãªãŒããŒã®çŸåšã®é床ãšæ¹åã«åºã¥ããŠããæã
ã¯ïŒãšåŒã°ãããã®åã«ãã€ã³ããæ圱ããŠããŸãahead
ïŒãahead
ããšãã°30
ããªãŒããŒã®ãã€ã³ããšãã£ã©ã¯ã¿ãŒã®éã®è·é¢ãçãå Žåããã£ã©ã¯ã¿ãŒã¯ãªãŒããŒã®èŠéå
ã«ããã移åããã¯ãã§ãããã€ã³ãã¯ahead
ãbehind
ãã€ã³ããšåãæ¹æ³ã§èšç®ãããŸããéãã¯ãé床ãã¯ãã«ãå転ããªãããšã§ãã tv = leader.velocity; tv = normalize(tv) * LEADER_BEHIND_DIST; ahead = leader.position + tv;
followLeader()
æåãã¹ã³ãŒãå
ã«ãããã©ããã確èªããããã«ã¡ãœãããå€æŽããå¿
èŠããããŸãããããçºçããå Žåãå€force
ïŒæ»ãevade(leader)
å€ïŒãã€ãŸããªãŒããŒã®äœçœ®ãåé¿ããåãå€æ°ã«è¿œå ãããŸãïŒé£ç¶ãè¡šãïŒïŒ private function followLeader(leader :Boid) :Vector3D { var tv :Vector3D = leader.velocity.clone(); var force :Vector3D = new Vector3D();
ãã¹ãŠã®ãã£ã©ã¯ã¿ãŒã¯ãäžåºŠãªãŒããŒã®èŠçã«å
¥ããšãçŸåšã®äœçœ®ãå³åº§ã«åé¿ããŸãïŒFlash ãã¢ïŒããã³ãïŒãªãŒããŒããã©ããŒããåã¯ãããã€ãã®åã®çµã¿åããã§ãããã£ã©ã¯ã¿ãŒãè¿œåŸã®åã®åœ±é¿ãåããå Žåãå®éã«ã¯å°çãåé¢ãåé¿ã®åã®åœ±é¿ãåæã«åããŸãã
ãã¢
以äžã¯ããªãŒããŒããã©ããŒããåäœã瀺ããã¢ã§ããéãå
µå£«ïŒãªãŒããŒïŒã¯ããŠã¹ã«ãŒãœã«ã«é¢é£ããŠå°çåäœãå®è¡ããç·ã®å
µå£«ã¯ãªãŒããŒã«åŸããŸãããã¬ã€ã€ãŒãç»é¢ãã¯ãªãã¯ãããšããã¹ãŠã®å
µå£«ãã«ãŒãœã«ã®æ¹åã«åããå€ããŠæã¡ãŸããã¢ã³ã¹ã¿ãŒã¯æ°ç§ããšã«å°çåäœãã©ã³ãã ãªãã€ã³ãã«é©çšããŸããFlashã®ã€ã³ã¿ã©ã¯ãã£ããã¢ã¯ãã¡ãã§ãã
ãããã«
ãªãŒããŒã®è¿œåŸåäœã«ããããã£ã©ã¯ã¿ãŒã®ã°ã«ãŒãã¯ç¹å®ã®ç®æšããã©ããªãããå°ãé
ãããšãããšãã§ããŸããããã«ããã£ã©ã¯ã¿ãŒã¯ããªãŒããŒã®éªéãããŠããå ŽåããªãŒããŒã®çŸåšäœçœ®ãé¿ããŸãããªãŒããŒã«åŸãè¡åã¯ãå°çãåé¿ãåé¢ãªã©ã®ä»ã®ããã€ãã®è¡åã®çµã¿åããã§ããããšã«æ³šæããããšãéèŠã§ããåçŽãªåäœãçµã¿åãããŠãéåžžã«è€éãªã¢ãŒã·ã§ã³ãã¿ãŒã³ãäœæã§ããããšã瀺ããŠããŸããããŒã9.ãã¥ãŒ
éšå±ãAIå¶åŸ¡ã®ãšã³ãã£ãã£ã§æºããããŠããã²ãŒã ã·ãŒã³ãæ³åããŠãã ãããäœããã®çç±ã§ã圌ãã¯éšå±ãåºãŠãã¢ãéããªããã°ãªããŸãããã©ã³ãã ã«ãäºããéãæããã®ã§ã¯ãªããäžå¯§ã«äžŠãã§ããããšãæããŸãããããã¥ãŒããªã¢ã«ã®ãã®éšåã§ã¯ã矀è¡ãåããããšã³ãã£ãã£ã®ãã§ãŒã³ãäœæããããŸããŸãªã¢ãããŒãã§ããã¥ãŒïŒãã¥ãŒïŒã®åäœãç解ããŸãã
ã¯ããã«
ãã®ãã¥ãŒããªã¢ã«ã®ã³ã³ããã¹ãã§ã¯ããã¥ãŒã€ã³ã°ã¯ãããæç¹ã§ã®å°çãèŸæ±åŒ·ãåŸ
ã£ãŠãããã£ã©ã¯ã¿ãŒã®è¡ãäœæããããã»ã¹ã§ããè¡ã®æåã®äººã移åãããšãä»ã®äººã圌ãè¿œãããã圌ã®åŸãã«ã¯ãŽã³ã䌞ã³ãŠããé»è»ã«äŒŒããã¿ãŒã³ãäœæããŸããåŸ
æ©äžããã£ã©ã¯ã¿ãŒã¯ãã¥ãŒããé¢ããããšã¯ã§ããŸããããã¥ãŒã®åäœã説æããããŸããŸãªå®è£
ãå®èšŒããã«ã¯ãããã¥ãŒã®ããã·ãŒã³ãã䜿çšãããã¢ãæé©ã§ããè¯ãäŸã¯ãAIå¶åŸ¡ãšã³ãã£ãã£ããã¢ããåºãŠéšå±ããåºãããšããéšå±ã§ãïŒFlash ãã¢ïŒããã®ã·ãŒã³ã¯ãåè¿°ã®2ã€ã®åäœãã·ãŒã¯ãšè¡çªåé¿ã䜿çšããŠäœæãããŸããããã¢ã¯ã2ã€ã®é·æ¹åœ¢ã®é害ç©ã§æ§æãããŠããããã®éã«ééïŒåºå
¥å£ïŒããããŸãããã£ã©ã¯ã¿ãŒã¯ããã®ãã¢ã®åŸãã«ãããã€ã³ããæ¢ããŸããããã«éãããšããã£ã©ã¯ã¿ãŒã¯ç»é¢ã®äžéšã«ç§»åããŸãããã¥ãŒã®åäœããªããã°ãã·ãŒã³ã¯éav人ã®å€§çŸ€ã®ããã«èŠããç®çå°ã«å°çããã®ã«èŠåŽããŸããåäœã®å®è£
åŸã矀éã¯éšå±ãã¹ã ãŒãºã«é¢ããåãäœæããŸãã
楜ãã¿ã«ããŠ
ãã£ã©ã¯ã¿ãŒã䞊ã¶å¿
èŠãããæåã®èœåã¯ã誰ãã圌ã®åã«ãããã©ããã調ã¹ãèœåã§ãããã®æ
å ±ã«åºã¥ããŠã圌ã¯ç§»åãç¶ãããåæ¢ãããã決å®ã§ããŸããåã®é£äººã®ååšã確èªããããè€éãªæ¹æ³ãååšããã«ãããããããç§ã¯ãã€ã³ããšãã£ã©ã¯ã¿ãŒã®éã®è·é¢ã«åºã¥ããŠåçŽåãããæ¹æ³ã䜿çšããŸãããã®ã¢ãããŒãã¯ãåæ¹ã®é害ç©ã確èªããããã®è¡çªåé¿åäœã§äœ¿çšãããŸãããåã®ãã€ã³ãã§é£äººããã§ãã¯ããŸããååã®ãããããããã£ã©ã¯ã¿ãŒã®åã«æ圱ããahead
ãŸãããã®ç¹ãšé£æ¥ãããã£ã©ã¯ã¿ãŒã®éã®è·é¢ã以äžã§ããå ŽåMAX_QUEUE_RADIUS
ãããã¯åã«èª°ããããŠãã£ã©ã¯ã¿ãŒãåæ¢ããããšãæå³ããŸãããã€ã³ãã¯ahead
次ã®ããã«èšç®ãããŸãïŒæ¬äŒŒã³ãŒãïŒïŒ
æåã®æ¹åãäžããé床ã¯ããšMAX_QUEUE_AHEAD
åŒã°ããæ°ãããã¯ãã«ãäœæããããã«æ£èŠåããã³ã¹ã±ãŒãªã³ã°ãããŸãqa
ãqa
ãã¯ãã«ã«è¿œå ãããšãposition
çµæã¯ãã£ã©ã¯ã¿ãŒMAX_QUEUE_AHEAD
ãããŠãããã®è·é¢ã«ãããã£ã©ã¯ã¿ãŒã®åã®ãã€ã³ãã«ãªããŸããããã¯ãã¹ãŠã¡ãœããã§ã©ããã§ããŸãgetNeighborAhead()
ïŒ private function getNeighborAhead() :Boid { var i:int; var ret :Boid = null; var qa :Vector3D = velocity.clone(); qa.normalize(); qa.scaleBy(MAX_QUEUE_AHEAD); ahead = position.clone().add(qa); for (i = 0; i < Game.instance.boids.length; i++) { var neighbor :Boid = Game.instance.boids[i]; var d :Number = distance(ahead, neighbor.position); if (neighbour != this && d <= MAX_QUEUE_RADIUS) { ret = neighbor; break; } } return ret; }
ãã®ã¡ãœããã¯ããã€ã³ãahead
ãšä»ã®ãã¹ãŠã®æåãšã®éã®è·é¢ããã§ãã¯ããæåã®æåãè¿ãMAX_QUEUE_AHEAD
ãŸããè·é¢ã¯ä»¥äžã§ããæåãèŠã€ãããªãå Žåãã¡ãœããã¯ãè¿ããŸãnull
ã
ãã¥ãŒã€ã³ã°ã¡ãœããã®äœæ
ä»ã®ãã¹ãŠã®åäœãšåæ§ã«ããã¥ãŒã€ã³ã°ãã¯ãŒã¯æ¬¡ã®ã¡ãœããã§èšç®ããqueue()
ãŸãã private function queue() :Vector3D { var neighbor :Boid = getNeighborAhead(); if (neighbor != null) {
çµægetNeighborAhead()
ã¯å€æ°ã«æ ŒçŽãããŸãneighbor
ãã®å Žåneighbor != null
ãå
ã«èª°ããããŸãããã以å€ã®å Žåããã¹ã¯æ確ã§ããæ¹æ³queue()
ã䞊ã³ã«è¡åã®ãã¹ãŠã®ä»ã®æ¹æ³ã¯ãæ¹æ³èªäœã«é¢é£ä»ããããé§ååã§ããåãè¿ãã¹ãã§ããããqueue()
ã¯å€§ãããªãã§é»åãè¿ããŸãããã€ãŸããå¹æã¯ãããŸããããããŸã§ãã¢ã®ããã·ãŒã³ã®ãã¹ãŠã®ãã£ã©ã¯ã¿ãŒã®ã¡ãœããupdate()
ã¯ã次ã®ããã«ãªããŸãïŒæ¬äŒŒã³ãŒãïŒã public function update():void { var doorway :Vector3D = getDoorwayPosition(); steering = seek(doorway);
queue()
ãŒãã®ãã¯ãŒãè¿ãããããã£ã©ã¯ã¿ãŒã¯è¡ãäœæããã«åãç¶ããŸããé£äººãå
ã«çºèŠããããšãã圌ãã¯äœããã®è¡åãåãæã§ãã
ãã©ãã£ãã¯ã®åæ¢ã«é¢ããããã€ãã®èšè
ã¹ãã¢ãªã³ã°åäœã¯åžžã«å€åããåã«åºã¥ããŠãããããã·ã¹ãã å
šäœãéåžžã«åçã«ãªããŸããããå€ãã®åã䜿çšãããã»ã©ãç¹å®ã®åã®ãã¯ãã«ãç¹å®ããŠãã£ã³ã»ã«ããããšãããé£ãããªããŸããã¹ãã¢ãªã³ã°åäœã«é¢ãããã®äžé£ã®ãã¥ãŒããªã¢ã«ã§äœ¿çšãããå®è£
ã§ã¯ããã¹ãŠã®åãå ç®ãããŸãããããã£ãŠãåããã£ã³ã»ã«ããã«ã¯ãåãåèšç®ãå€æããçŸåšã®å¶åŸ¡åã®ãã¯ãã«ã«è¿œå ãçŽãå¿
èŠããããŸããããã¯ããã£ã©ã¯ã¿ãŒãåæ¢ãããããã«é床ããã£ã³ã»ã«ãããå°çåäœã§çºçããããšã§ããããããããšãã°è¡çªåé¿ãé亡ãªã©ã®è¡åã«ãããŠãããã€ãã®åãäžç·ã«äœçšãããšã©ããªããŸããïŒä»¥äžã®ã»ã¯ã·ã§ã³ã§ã¯ããã£ã©ã¯ã¿ãŒãæ¢ããæ¹æ³ã«ã€ããŠ2ã€ã®ã¢ã€ãã¢ãæäŸããŸãã1ã€ç®ã¯ãé床ãã¯ãã«ã«çŽæ¥äœçšããä»ã®ãã¹ãŠã®å¶åŸ¡åãç¡èŠãããããŒãã¹ããããã¢ãããŒãã䜿çšããŸãã2çªç®ã¯ããšåŒã°ããåãã¯ãã«ã䜿çšããŠãbrake
ä»ã®ãã¹ãŠã®å¶åŸ¡åããã£ã³ã»ã«ããŸããã€ãŸãããã£ã©ã¯ã¿ãŒã匷å¶çã«åæ¢ããŸãã
ã¹ãããã¢ãŒã·ã§ã³ïŒãããŒãã¹ãããã
ããã€ãã®å¶åŸ¡åã¯ããã£ã©ã¯ã¿ãŒã®é床ãã¯ãã«ã«åºã¥ããŠããŸãããã®ãã¯ãã«ãå€åãããšãä»ã®ãã¹ãŠã®åã«åœ±é¿ããŸããã€ãŸããåèšç®ããå¿
èŠããããŸãããããŒãã¹ããããã®ã¢ã€ãã¢ã¯éåžžã«åçŽã§ããåã«ãã£ã©ã¯ã¿ãŒãããå Žåãé床ãã¯ãã«ããããªãã³ã°ãããŸãã private function queue() :Vector3D { var neighbor :Boid = getNeighborAhead(); if (neighbor != null) { velocity.scaleBy(0.3); } return new Vector3D(0, 0); }
äžèšã®ã³ãŒãã§ã¯ãæåãåã«ããå Žåããã¯ãã«ã¹ã±ãŒã«ã¯çŸåšã®å€ïŒé·ãïŒããvelocity
æžå°ã30%
ãŸãããã®çµæãåãã¯å€§å¹
ã«æžå°ããŸããããã£ã©ã¯ã¿ãŒãããããã³ã°ãã¹ãé¢ãããšæçµçã«éåžžã®å€ã«æ»ããŸããããã¯ãåæŽæ°ã§åããã©ã®ããã«èšç®ãããããåæããããšã§ç解ãããããªããŸãïŒ velocity = truncate (velocity + steering , MAX_SPEED); position = position + velocity;
åvelocity
ãäœäžãç¶ããå Žåãåã«steering
åºã¥ããŠãããããåã§ãããçºçãvelocity
ãŸããããã¯ã極端ã«äœãå€ãããããæªåŸªç°ãäœãåºããŸãvelocity
ããããŠããã£ã©ã¯ã¿ãŒã¯åããæ¢ããŸããããªãã³ã°ããã»ã¹ãå®äºãããšãã²ãŒã ã®æŽæ°ããšã«ãã¯ãã«velocity
ããããã«å¢å ãã匷床ã«ã圱é¿ãsteering
ãŸããåŸã
ã«ããã€ãã®æŽæ°ãã®æå¿ãã¯ãã«velocity
ãšsteering
ãã®æ£åžžå€ã«ããããŒãã¹ãããããœãªã¥ãŒã·ã§ã³ã¯ã次ã®çµæãäœæããŸãïŒãã©ãã·ã¥ãã¢ïŒãçµæã¯éåžžã«åŠ¥åœã§ãããããã§ãå°ããæ©æ§çãã«èŠããŸããå®éã®çŸ€éã§ã¯ãéåžžãåå è
ã®éã«ç©ºãã¹ããŒã¹ã¯ãããŸããã
ã¹ãããã¢ãŒã·ã§ã³ïŒå¶åå
åäœãåæ¢ãã2çªç®ã®ã¢ãããŒãã§ã¯ããã¹ãŠã®ã¢ã¯ãã£ããªå¶åŸ¡åã匷å¶çã«ãã£ã³ã»ã«ãããããããæ©æ§çãªãçµæã¯å°ãªããªãbrake
ãŸãã private function queue() :Vector3D { var v :Vector3D = velocity.clone(); var brake :Vector3D = new Vector3D(); var neighbor :Boid = getNeighborAhead(); if (neighbor != null) { brake.x = -steering.x * 0.8; brake.y = -steering.y * 0.8; v.scaleBy( -1); brake = brake.add(v); } return brake; }
brake
ã¢ã¯ãã£ããªåå¶åŸ¡åãåã«ãŠã³ãããã³å転ããŠåãäœæãã代ããã«ãçŸåšé©çšãããŠãããã¹ãŠã®å¶åŸ¡åãå«ãbrake
çŸåšã®ãã¯ãã«ã«åºã¥ããŠèšç®steering
ãããŸããæå¶åã®è¡šçŸã匷brake
åä¿¡ã³ã³ããŒãã³ãx
ãšy
匷ãã¯steering
ãããããæç»ããèŠæš¡ã§ããããå€æŽããŸã0.8
ãããã¯brake
ã倧ããã80ïŒ
steering
ã§ãå察æ¹åãæããŠããããšãæå³ããŸãããã³ãïŒåã®çŽæ¥äœ¿çšã¯steering
å±éºã§ããããqueue()
ããã£ã©ã¯ã¿ãŒã«é©çšãããæåã®åäœã§ããå Žåãåsteering
ã¯ã空ãã«ãªããŸãããããã£ãŠãä»ã®ãã¹ãŠã®åäœã¡ãœããqueue()
ãåŒã³åºããŠããã圌ãå®å
šãã€æçµçãªåãç²åŸã§ããããã«ããå¿
èŠããããŸãsteering
ã匷ãbrake
ããã£ã©ã¯ã¿ãŒã®é床ãçžæ®ºããã¯ãã§ããããã¯ã-velocity
匷床ãè¿œå ããããšã«ãã£ãŠè¡ããbrake
ãŸãããã®æ¹æ³ã®åŸqueue()
æçµçãªåãåãæ»ãããšãã§ãbrake
ãŸããå¶ååã䜿çšããçµæã¯æ¬¡ã®ããã«ãªããŸããFlashã®ã€ã³ã¿ã©ã¯ãã£ããã¢ã¯ãã¡ãã§ãã
æåãªãŒããŒã¬ã€ã®åæž
ãã¹ãŠã®ãã£ã©ã¯ã¿ãŒã空ã®ã¹ããŒã¹ãåããããšããŠãããããæå¶ã®ãããœãªã¥ãŒã·ã§ã³ã¯ãã¡ã«ããºã ãã®çµæãšæ¯èŒããŠããèªç¶ãªçµæãçã¿åºããŸãããã ããæ°ããåé¡ãçºçããŸããæåãäºãã«éãªãåã£ãŠããŸãããããæé€ããããã«ããããŒãã¹ããããã¢ãããŒããå°ãä¿®æ£ããããŒãžã§ã³ã§ãã¬ãŒããœãªã¥ãŒã·ã§ã³ãæ¹åã§ããŸãã private function queue() :Vector3D { var v :Vector3D = velocity.clone(); var brake :Vector3D = new Vector3D(); var neighbor :Boid = getNeighborAhead(); if (neighbor != null) { brake.x = -steering.x * 0.8; brake.y = -steering.y * 0.8; v.scaleBy( -1); brake = brake.add(v); if (distance(position, neighbor.position) <= MAX_QUEUE_RADIUS) { velocity.scaleBy(0.3); } } return brake; }
æ°ãããã¹ãã¯ãæè¿åããã§ãã¯ããããã«äœ¿çšãããŸããä»åã¯ãè·é¢ã枬å®ããããã«ãã€ã³ãã䜿çšãã代ããã«ahead
ãæ°ãããã¹ãã¯æåãã¯ãã«éã®è·é¢ããã§ãã¯ããŸãposition
ïŒMAX_QUEUE_RADIUSã®ååŸå
ã§ãåæ¹ã§ã¯ãªãäœçœ®ãäžå¿ãšããæè¿åããã§ãã¯ããŸãããã®æ°ãããã¹ãã¯ååŸã®äžã«ã©ããªæãè¿ãé£äººãããããã§ãã¯ããŸãMAX_QUEUE_RADIUS
ããä»ããã¯ãã¯ãã«ã®äžå€®ã«ããposition
ãŸããå
éšã«èª°ããããå Žåãããã¯åšå²ã®é åããã£ã±ãã«ãªããããŠããããã£ã©ã¯ã¿ãŒãéãªãå§ããå¯èœæ§ãããããšãæå³ããŸãããªãŒããŒã¬ã€ã¯ããã¯ãã«velocity
ãçŸåšã®å€ã®30ïŒ
ã«æŽæ°ãããã³ã«ã¹ã±ãŒãªã³ã°ããããšã§åæžã§ããŸãããããŒãã¹ããããã¢ãããŒããšåæ§ã«ããã¯ãã«ãããªãã³ã°ãããšãvelocity
åãã倧å¹
ã«æžå°ããŸããçµæã¯ãæ©æ§çãã§ã¯ãªãããã«èŠããŸããããã£ã©ã¯ã¿ãŒã¯ãŸã æžå£ã§äº€å·®ããŠããããããŸã äžå®å
šã§ãïŒã㢠Flashã§ïŒã
åé¢ãè¿œå ãã
ãã£ã©ã¯ã¿ãŒã¯èª¬åŸåã®ããæ¹æ³ã§æžå£ã«å°éããããšããŸãããéè·¯ãçããªããšãã¹ãŠã®ç©ºãã¹ããŒã¹ãåããããšããŸãããæžå£ã§ã¯äºãã«è¿ã¥ããããŸãããã®åé¡ã¯ãåé¢åãè¿œå ããããšã§è§£æ±ºã§ããŸãã private function queue() :Vector3D { var v :Vector3D = velocity.clone(); var brake :Vector3D = new Vector3D(); var neighbor :Boid = getNeighborAhead(); if (neighbor != null) { brake.x = -steering.x * 0.8; brake.y = -steering.y * 0.8; v.scaleBy( -1); brake = brake.add(v); brake = brake.add(separation()); if (distance(position, neighbor.position) <= MAX_QUEUE_RADIUS) { velocity.scaleBy(0.3); } } return brake; }
ãªãŒããŒè¿œåŸåäœã§ä»¥å䜿çšãããŠããåé¢åããã©ãŒã¹ã«è¿œå ããbrake
ããã£ã©ã¯ã¿ãŒãåæ¢ãããšåæã«ãäºãã«è§Šããªãããã«ããŸãããã®çµæãæžå£ããæãåºãããšããä¿¡é Œã§ãã矀è¡ãåŸãããŸããFlashã®ã€ã³ã¿ã©ã¯ãã£ããã¢ã¯ãã¡ãã§ãã
ãããã«
ãã¥ãŒã®åäœã«ããããã£ã©ã¯ã¿ãŒã¯äžåã«äžŠã³ãç®çå°ã«å°çãããŸã§èŸæ±åŒ·ãåŸ
ã€ããšãã§ããŸãã䞊ãã§ããéããã£ã©ã¯ã¿ãŒã¯äœçœ®ãé£ã³è¶ããŠãããŒããããããšããªãã圌ã¯èªåã®åã«ç«ã£ãŠãããã£ã©ã¯ã¿ãŒãåãããšãã«ã®ã¿åããŸãããã®ãã¥ãŒããªã¢ã«ã«ç€ºãããŠããæžå£ã®ã·ãŒã³ã¯ããã®åäœãããã«å€çšéã§ã«ã¹ã¿ãã€ãºå¯èœã§ãããã瀺ããŠããŸããããããªå€æŽã§ããŸã£ããç°ãªãçµæãäœæãããããŸããŸãªç¶æ³ã«åãããŠç°¡åã«èª¿æŽã§ããŸãããã®åäœã¯ãè¡çªåé¿ãªã©ãä»ã®åäœãšçµã¿åãããããšãã§ããŸãããã®æ°ããæ¯ãèãã楜ããã§ããã ããã²ãŒã ã§æåçãªçŸ€è¡ãäœæããããã«ããã䜿çšããããšãé¡ã£ãŠããŸãïŒ