Enemy AI: chasing a player without Navigation2D or A* pathfinding

栏目: IT技术 · 发布时间: 4年前

内容简介:Making a game where your enemies need to chase the player?  This starts out easy, make the enemy run towards the player!  But what happens when they are behind a tree?  Or around the corner of a wall?  Well, now your enemy looks quite silly as it is stuck

Making a game where your enemies need to chase the player?  This starts out easy, make the enemy run towards the player!  But what happens when they are behind a tree?  Or around the corner of a wall?  Well, now your enemy looks quite silly as it is stuck against the object, running in place.  Not good!

To solve this, you could use the Navigation2D or AStar nodes built into Godot ( here's a tutorial by GDQuest covering both of them ).  But for Helms of Fury we used a different method which works great for our game and we wanted to share in this tutorial.  Here's how it looks:

Enemy AI: chasing a player without Navigation2D or A* pathfinding

Getting Started

We are going to assume you are making your enemies as KinematicBody2D objects, and that you are using a State Machine to manage their states.  Not sure what a State Machine is?  I like this article explaining State Machines and why you would use them - and here's another article on implementing simple State Machines in Godot .

To begin with, here is a simple Chase state for a dumb enemy that just runs towards its target, and probably gets stuck on something along the way:

# ChaseState.gd

func _init(enemy, params):
  enemy.dir = (enemy.target.position - enemy.position).normalized()

func _physics_process(delta):
  var motion = enemy.dir * enemy.speed
  enemy.move_and_slide(motion)

Scent Trails

To improve this we make the player leave a trail of their past positions as they move.  This way, if the enemy cannot see the player, it can check if it can see any of these past positions, then follow them to the player.  Since this is similar to how a dog would track something, we'll call it a scent trail.

So to make this scent trail work we need to add a Timer node to our player, make it autostart and set a wait_time (we used 0.1s), then add some code so when it times out it drops a scent.

# Player.gd
extends KinematicBody2D

const scent_scene = preload("res://Player/Scent.tscn")

var scent_trail = []

func _ready():
  $ScentTimer.connect("timeout", self, "add_scent")

func add_scent():
  var scent      = scent_scene.instance()
  scent.player   = player
  scent.position = player.position

  Game.level.effects.add_child(scent)
  scent_trail.push_front(scent)

Then we have to make our actual Scent.tscn that gets dropped.  This is just a simple Node2D scene that includes a Timer, so that the scent can expire.

# Scent.gd
extends Node2D

var player

func _ready():
  $Timer.connect("timeout", self, "remove_scent")

func remove_scent():
  player.scent_trail.erase(self)
  queue_free()

If you want the scents to be visible while debugging, you can add a ColorRect node to them, then just hide it once its working.  With this in place you should see scent's being left behind your player as you run around.

Now we want our enemies to embrace their inner bloodhounds and follow these new scents when they cannot see the player.  But to make that work, we will need to add a RayCast2D node to our enemies, and setup Physics Layers in Godot so our ray knows what it can collide with.

Physics Layers

To set up Physics Layers in Godot you want to click on Project from the top menu, then Project Settings, then near the bottom on the left side is a Layer Names section, and you want to choose 2D Physics.

Enemy AI: chasing a player without Navigation2D or A* pathfinding

Name these whatever you like for your game.  Once you have them named, go through the objects in your game, and in the Property Inspector sidebar you can expand Collision then click ·· to assign them.  For your objects you want to assign them as Layers.

Enemy AI: chasing a player without Navigation2D or A* pathfinding

With Physics Layers assigned to your objects, now you want to update the RayCast2D on your enemies to check against the layers enemies cannot move through (in our case its solid, object, crate, hole, gate_closed)

And with our Physics Layers all setup, our last step is to update our Chase state.

# ChaseState.gd

func _init(enemy, params):
  chase_target()

func chase_target():
  var look     = enemy.get_node("RayCast2D")
  look.cast_to = (enemy.target.position - enemy.position)
  look.force_raycast_update()

  # if we can see the target, chase it
  if !look.is_colliding():
    enemy.dir = look.cast_to.normalized()

  # or chase first scent we can see
  else:
    for scent in enemy.target.scent_trail:
      look.cast_to = (scent.position - enemy.position)
      look.force_raycast_update()

      if !look.is_colliding():
        enemy.dir = look.cast_to.normalized()
        break

func _physics_process(delta):
  var motion = enemy.dir * enemy.speed
  enemy.move_and_slide(motion)

So now when an enemy enters the Chase state it tries to raycast to the player and if nothing is in the way - chase em!  If something is in the way, it goes through the scent trail in order and tries to raycast to each scent until it can see one, then - chase it!

And it now works, your enemies are bloodhounds!  To improve this further you may want collision avoidance between enemies, but perhaps that's a tutorial for another day ;)

That's a Wrap!

If you liked this tutorial and want more, follow us on twitter @abitawake .  And if you're a fellow indie developer, consider giving our ManaKeep web service a try =)

Curious about the game we are working on?  Check out helmsoffury.com (spark some joy and wishlist us on Steam!)


以上所述就是小编给大家介绍的《Enemy AI: chasing a player without Navigation2D or A* pathfinding》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

逆向工程权威指南

逆向工程权威指南

Dennis Yurichev(丹尼斯) / 安天安全研究与应急处理中心 / 人民邮电出版社 / 2017-3-1 / 168

逆向工程是一种分析目标系统的过程,旨在于识别系统的各组件以及组件间关系,以便于通过其它形式、或在较高的抽象层次上,重建系统的表征。 本书专注于软件的逆向工程,是写给初学者的一本经典指南。全书共分为12个部分,共102章,涉及X86/X64、ARM/ARM-64、MIPS、Java/JVM等重要话题,详细解析了Oracle RDBMS、Itanium、软件狗、LD_PRELOAD、栈溢出、EL......一起来看看 《逆向工程权威指南》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具