我们在上一节的基础上,为炮塔添加两个Area2D,分别表示注意范围和攻击范围。并且设置其碰撞形状为两个半径不同的圆形。

当玩家进入炮塔的注意范围时,炮塔会将自己旋转到玩家的方向,但不开火。
而当玩家进入炮塔 的攻击范围时,则炮塔开始自动攻击。
我们创建一个玩家场景:

将其添加到player组。
添加代码如下:
extends KinematicBody2Dvar speed = 80.0var velocity = Vector2.ZEROfunc _physics_process(delta):var dir = Input.get_vector("ui_left","ui_right","ui_up","ui_down")velocity = move_and_slide(dir * speed)
在主场景中我们实例化一个Player场景,并为其添加一个Camera2D节点,并勾选其Current属性,作为当前相机。
此时玩家已经可以自由移动,并且视图始终以玩家为中心。
我们修改炮塔的代码如下:
extends StaticBody2Dconst bullet = preload("res://bullet.tscn")onready var body = $base/bodyonready var bullet_start_pos = $base/body/body/Position2Dvar is_noticed = falsevar playerfunc _process(delta):if is_noticed:body.look_at(player.global_position)else:body.rotation_degrees += 1func shoot():var b= bullet.instance()add_child(b)b.dir = global_position.direction_to(get_global_mouse_position())b.global_position = bullet_start_pos.global_positionb.global_rotation = b.dir.angle()func _on_notice_area_body_entered(mbody):if mbody.is_in_group("player"):player = mbodyis_noticed = truepassfunc _on_notice_area_body_exited(mbody):if mbody.is_in_group("player"):is_noticed = falsepass
其中为notice_area连接信号,body_entered和body_exited,用于当玩家进入注意范围后,将炮塔指向玩家的位置。
运行效果:
我们继续修改:
extends StaticBody2Dconst bullet = preload("res://bullet.tscn")onready var body = $base/bodyonready var bullet_start_pos = $base/body/body/Position2Dvar is_noticed = falsevar can_attack = falsevar playerfunc _process(delta):if is_noticed:body.look_at(player.global_position)if can_attack:shoot(player.global_position)else:body.rotation_degrees += 1func shoot(pos:Vector2):var b= bullet.instance()add_child(b)b.dir = global_position.direction_to(pos)b.global_position = bullet_start_pos.global_positionb.global_rotation = b.dir.angle()func _on_notice_area_body_entered(mbody):if mbody.is_in_group("player"):player = mbodyis_noticed = truepassfunc _on_notice_area_body_exited(mbody):if mbody.is_in_group("player"):is_noticed = falsepassfunc _on_attack_area_body_entered(mbody):if mbody.is_in_group("player"):can_attack = truepassfunc _on_attack_area_body_exited(mbody):if mbody.is_in_group("player"):can_attack = falsepass
运行效果:
可以看到,由于我们的炮塔没有攻击的时间间隔,所以每物理帧都会发射一枚炮弹,也就是一分钟之内发射60发。
为了控制炮塔发射炮弹的时间间隔,我们添加一个Timer节点。
我们继续修改代码如下:
extends StaticBody2Dconst bullet = preload("res://bullet.tscn")var is_noticed = falsevar can_attack = falsevar cool_down = 0.5 # 发射间隔时间,单位:秒var playeronready var body = $base/bodyonready var bullet_start_pos = $base/body/body/Position2Donready var CD_timer =$CD_timer # 发射的时间间隔func _process(delta):if is_noticed:body.look_at(player.global_position)if can_attack:if CD_timer.is_stopped():CD_timer.start(cool_down)else:CD_timer.stop()else:body.rotation_degrees += 1func shoot(pos:Vector2):var b= bullet.instance()add_child(b)b.dir = global_position.direction_to(pos)b.global_position = bullet_start_pos.global_positionb.global_rotation = b.dir.angle()func _on_notice_area_body_entered(mbody):if mbody.is_in_group("player"):player = mbodyis_noticed = truepassfunc _on_notice_area_body_exited(mbody):if mbody.is_in_group("player"):is_noticed = falsepassfunc _on_attack_area_body_entered(mbody):if mbody.is_in_group("player"):can_attack = truepassfunc _on_attack_area_body_exited(mbody):if mbody.is_in_group("player"):can_attack = falsepassfunc _on_CD_timer_timeout():shoot(player.global_position)pass
运行效果:
