我们在上一节的基础上,为炮塔添加两个Area2D,分别表示注意范围和攻击范围。并且设置其碰撞形状为两个半径不同的圆形。
    image.pngimage.png
    当玩家进入炮塔的注意范围时,炮塔会将自己旋转到玩家的方向,但不开火。
    而当玩家进入炮塔 的攻击范围时,则炮塔开始自动攻击。
    我们创建一个玩家场景:
    image.pngimage.png
    将其添加到player组。
    image.png
    添加代码如下:

    1. extends KinematicBody2D
    2. var speed = 80.0
    3. var velocity = Vector2.ZERO
    4. func _physics_process(delta):
    5. var dir = Input.get_vector("ui_left","ui_right","ui_up","ui_down")
    6. velocity = move_and_slide(dir * speed)

    在主场景中我们实例化一个Player场景,并为其添加一个Camera2D节点,并勾选其Current属性,作为当前相机。
    image.png
    此时玩家已经可以自由移动,并且视图始终以玩家为中心。
    我们修改炮塔的代码如下:

    1. extends StaticBody2D
    2. const bullet = preload("res://bullet.tscn")
    3. onready var body = $base/body
    4. onready var bullet_start_pos = $base/body/body/Position2D
    5. var is_noticed = false
    6. var player
    7. func _process(delta):
    8. if is_noticed:
    9. body.look_at(player.global_position)
    10. else:
    11. body.rotation_degrees += 1
    12. func shoot():
    13. var b= bullet.instance()
    14. add_child(b)
    15. b.dir = global_position.direction_to(get_global_mouse_position())
    16. b.global_position = bullet_start_pos.global_position
    17. b.global_rotation = b.dir.angle()
    18. func _on_notice_area_body_entered(mbody):
    19. if mbody.is_in_group("player"):
    20. player = mbody
    21. is_noticed = true
    22. pass
    23. func _on_notice_area_body_exited(mbody):
    24. if mbody.is_in_group("player"):
    25. is_noticed = false
    26. pass

    其中为notice_area连接信号,body_entered和body_exited,用于当玩家进入注意范围后,将炮塔指向玩家的位置。
    image.png
    运行效果:
    22223.gif
    我们继续修改:

    1. extends StaticBody2D
    2. const bullet = preload("res://bullet.tscn")
    3. onready var body = $base/body
    4. onready var bullet_start_pos = $base/body/body/Position2D
    5. var is_noticed = false
    6. var can_attack = false
    7. var player
    8. func _process(delta):
    9. if is_noticed:
    10. body.look_at(player.global_position)
    11. if can_attack:
    12. shoot(player.global_position)
    13. else:
    14. body.rotation_degrees += 1
    15. func shoot(pos:Vector2):
    16. var b= bullet.instance()
    17. add_child(b)
    18. b.dir = global_position.direction_to(pos)
    19. b.global_position = bullet_start_pos.global_position
    20. b.global_rotation = b.dir.angle()
    21. func _on_notice_area_body_entered(mbody):
    22. if mbody.is_in_group("player"):
    23. player = mbody
    24. is_noticed = true
    25. pass
    26. func _on_notice_area_body_exited(mbody):
    27. if mbody.is_in_group("player"):
    28. is_noticed = false
    29. pass
    30. func _on_attack_area_body_entered(mbody):
    31. if mbody.is_in_group("player"):
    32. can_attack = true
    33. pass
    34. func _on_attack_area_body_exited(mbody):
    35. if mbody.is_in_group("player"):
    36. can_attack = false
    37. pass

    运行效果:
    22224.gif
    可以看到,由于我们的炮塔没有攻击的时间间隔,所以每物理帧都会发射一枚炮弹,也就是一分钟之内发射60发。
    为了控制炮塔发射炮弹的时间间隔,我们添加一个Timer节点。
    image.png
    我们继续修改代码如下:

    1. extends StaticBody2D
    2. const bullet = preload("res://bullet.tscn")
    3. var is_noticed = false
    4. var can_attack = false
    5. var cool_down = 0.5 # 发射间隔时间,单位:秒
    6. var player
    7. onready var body = $base/body
    8. onready var bullet_start_pos = $base/body/body/Position2D
    9. onready var CD_timer =$CD_timer # 发射的时间间隔
    10. func _process(delta):
    11. if is_noticed:
    12. body.look_at(player.global_position)
    13. if can_attack:
    14. if CD_timer.is_stopped():
    15. CD_timer.start(cool_down)
    16. else:
    17. CD_timer.stop()
    18. else:
    19. body.rotation_degrees += 1
    20. func shoot(pos:Vector2):
    21. var b= bullet.instance()
    22. add_child(b)
    23. b.dir = global_position.direction_to(pos)
    24. b.global_position = bullet_start_pos.global_position
    25. b.global_rotation = b.dir.angle()
    26. func _on_notice_area_body_entered(mbody):
    27. if mbody.is_in_group("player"):
    28. player = mbody
    29. is_noticed = true
    30. pass
    31. func _on_notice_area_body_exited(mbody):
    32. if mbody.is_in_group("player"):
    33. is_noticed = false
    34. pass
    35. func _on_attack_area_body_entered(mbody):
    36. if mbody.is_in_group("player"):
    37. can_attack = true
    38. pass
    39. func _on_attack_area_body_exited(mbody):
    40. if mbody.is_in_group("player"):
    41. can_attack = false
    42. pass
    43. func _on_CD_timer_timeout():
    44. shoot(player.global_position)
    45. pass

    运行效果:
    22225.gif