|
@@ -1,222 +1,200 @@
|
|
extends KinematicBody
|
|
extends KinematicBody
|
|
|
|
|
|
-# class member variables go here, for example:
|
|
|
|
-# var a = 2
|
|
|
|
-# var b = "textvar"
|
|
|
|
-
|
|
|
|
-const GRAVITY = Vector3(0,-9.8, 0)
|
|
|
|
|
|
+enum State {
|
|
|
|
+ APPROACH = 0,
|
|
|
|
+ AIM = 1,
|
|
|
|
+ SHOOTING = 2,
|
|
|
|
+}
|
|
|
|
|
|
const PLAYER_AIM_TOLERANCE_DEGREES = 15
|
|
const PLAYER_AIM_TOLERANCE_DEGREES = 15
|
|
|
|
|
|
-const STATE_APPROACH = 0
|
|
|
|
-const STATE_AIM = 1
|
|
|
|
-const STATE_SHOOTING = 2
|
|
|
|
-
|
|
|
|
-var state = STATE_APPROACH
|
|
|
|
-
|
|
|
|
const SHOOT_WAIT = 6.0
|
|
const SHOOT_WAIT = 6.0
|
|
-var shoot_countdown = SHOOT_WAIT
|
|
|
|
const AIM_TIME = 1
|
|
const AIM_TIME = 1
|
|
-var aim_countdown = AIM_TIME
|
|
|
|
|
|
|
|
const AIM_PREPARE_TIME = 0.5
|
|
const AIM_PREPARE_TIME = 0.5
|
|
|
|
+const BLEND_AIM_SPEED = 0.05
|
|
|
|
+
|
|
|
|
+var state = State.APPROACH
|
|
|
|
+
|
|
|
|
+var shoot_countdown = SHOOT_WAIT
|
|
|
|
+var aim_countdown = AIM_TIME
|
|
var aim_preparing = AIM_PREPARE_TIME
|
|
var aim_preparing = AIM_PREPARE_TIME
|
|
|
|
+var energy = 5
|
|
|
|
+var dead = false
|
|
|
|
+var test_shoot = false
|
|
|
|
|
|
var player = null
|
|
var player = null
|
|
var velocity = Vector3()
|
|
var velocity = Vector3()
|
|
-
|
|
|
|
var orientation = Transform()
|
|
var orientation = Transform()
|
|
|
|
|
|
-const MAX_ENERGY = 5
|
|
|
|
-
|
|
|
|
-var energy = MAX_ENERGY
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-const BLEND_AIM_SPEED = 0.05
|
|
|
|
|
|
+onready var gravity = ProjectSettings.get_setting("physics/3d/default_gravity") * ProjectSettings.get_setting("physics/3d/default_gravity_vector")
|
|
|
|
|
|
func _ready():
|
|
func _ready():
|
|
- orientation=$"Scene Root".global_transform
|
|
|
|
|
|
+ orientation = global_transform
|
|
orientation.origin = Vector3()
|
|
orientation.origin = Vector3()
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+
|
|
func resume_approach():
|
|
func resume_approach():
|
|
- state = STATE_APPROACH
|
|
|
|
|
|
+ state = State.APPROACH
|
|
aim_preparing = AIM_PREPARE_TIME
|
|
aim_preparing = AIM_PREPARE_TIME
|
|
shoot_countdown = SHOOT_WAIT
|
|
shoot_countdown = SHOOT_WAIT
|
|
-
|
|
|
|
-var dead = false
|
|
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+
|
|
func hit():
|
|
func hit():
|
|
- if (dead):
|
|
|
|
|
|
+ if dead:
|
|
return
|
|
return
|
|
- $AnimationTree["parameters/hit"+["1","2","3"][randi()%3]+"/active"]=true
|
|
|
|
|
|
+ $AnimationTree["parameters/hit" + ["1", "2", "3"][randi() % 3] + "/active"] = true
|
|
$sfx/hit.play()
|
|
$sfx/hit.play()
|
|
- energy-=1
|
|
|
|
- if (energy==0):
|
|
|
|
- dead=true
|
|
|
|
|
|
+ energy -= 1
|
|
|
|
+ if energy == 0:
|
|
|
|
+ dead = true
|
|
var base_xf = global_transform.basis
|
|
var base_xf = global_transform.basis
|
|
- $AnimationTree.active=false
|
|
|
|
|
|
+ $AnimationTree.active = false
|
|
#$death/explosion.play("kaboom")
|
|
#$death/explosion.play("kaboom")
|
|
- $"Scene Root".visible=false
|
|
|
|
- $death.visible=true
|
|
|
|
- $CollisionShape.disabled=true
|
|
|
|
- $death/particles.emitting=true
|
|
|
|
- $death/part_shield1/col1.disabled=false
|
|
|
|
- $death/part_shield1/col2.disabled=false
|
|
|
|
- $death/part_shield1.mode=RigidBody.MODE_RIGID
|
|
|
|
- $death/part_shield2/col1.disabled=false
|
|
|
|
- $death/part_shield2/col2.disabled=false
|
|
|
|
- $death/part_shield2.mode=RigidBody.MODE_RIGID
|
|
|
|
- $death/part_shield3/col1.disabled=false
|
|
|
|
- $death/part_shield3/col2.disabled=false
|
|
|
|
- $death/part_shield3.mode=RigidBody.MODE_RIGID
|
|
|
|
- $death/part_shield2.linear_velocity = (base_xf.x+Vector3(0,1,0)).normalized() * 3
|
|
|
|
- $death/part_shield3.linear_velocity = (Vector3(0,1,0)).normalized() * 3
|
|
|
|
- $death/part_shield1.linear_velocity = (-base_xf.x+Vector3(0,1,0)).normalized() * 3
|
|
|
|
- $death/part_shield2.angular_velocity = (Vector3(randf(),randf(),randf()).normalized() * Vector3(2,2,2) - Vector3(1,1,1)) * 10
|
|
|
|
- $death/part_shield1.angular_velocity = (Vector3(randf(),randf(),randf()).normalized() * Vector3(2,2,2) - Vector3(1,1,1)) * 10
|
|
|
|
- $death/part_shield3.angular_velocity = (Vector3(randf(),randf(),randf()).normalized() * Vector3(2,2,2) - Vector3(1,1,1)) * 10
|
|
|
|
|
|
+ $"Scene Root".visible = false
|
|
|
|
+ $death.visible = true
|
|
|
|
+ $CollisionShape.disabled = true
|
|
|
|
+ $death/particles.emitting = true
|
|
|
|
+
|
|
|
|
+ $death/part_shield1/col1.disabled = false
|
|
|
|
+ $death/part_shield1/col2.disabled = false
|
|
|
|
+ $death/part_shield1.mode = RigidBody.MODE_RIGID
|
|
|
|
+ $death/part_shield2/col1.disabled = false
|
|
|
|
+ $death/part_shield2/col2.disabled = false
|
|
|
|
+ $death/part_shield2.mode = RigidBody.MODE_RIGID
|
|
|
|
+ $death/part_shield3/col1.disabled = false
|
|
|
|
+ $death/part_shield3/col2.disabled = false
|
|
|
|
+ $death/part_shield3.mode = RigidBody.MODE_RIGID
|
|
|
|
+
|
|
|
|
+ $death/part_shield2.linear_velocity = 3 * (Vector3.UP + base_xf.x).normalized()
|
|
|
|
+ $death/part_shield3.linear_velocity = 3 * (Vector3.UP).normalized()
|
|
|
|
+ $death/part_shield1.linear_velocity = 3 * (Vector3.UP - base_xf.x).normalized()
|
|
|
|
+ $death/part_shield2.angular_velocity = (Vector3(randf(), randf(), randf()).normalized() * 2 - Vector3.ONE) * 10
|
|
|
|
+ $death/part_shield1.angular_velocity = (Vector3(randf(), randf(), randf()).normalized() * 2 - Vector3.ONE) * 10
|
|
|
|
+ $death/part_shield3.angular_velocity = (Vector3(randf(), randf(), randf()).normalized() * 2 - Vector3.ONE) * 10
|
|
$sfx/explosion.play()
|
|
$sfx/explosion.play()
|
|
|
|
|
|
|
|
|
|
-func do_shoot():
|
|
|
|
|
|
+func shoot():
|
|
var gt = $"Scene Root/Armature/Skeleton/ray_from".global_transform
|
|
var gt = $"Scene Root/Armature/Skeleton/ray_from".global_transform
|
|
var ray_from = gt.origin
|
|
var ray_from = gt.origin
|
|
var ray_dir = -gt.basis.z
|
|
var ray_dir = -gt.basis.z
|
|
var max_dist = 1000
|
|
var max_dist = 1000
|
|
|
|
|
|
- var col = get_world().direct_space_state.intersect_ray(ray_from,ray_from + ray_dir * max_dist,[self])
|
|
|
|
- if (not col.empty()):
|
|
|
|
|
|
+ var col = get_world().direct_space_state.intersect_ray(ray_from, ray_from + ray_dir * max_dist, [self])
|
|
|
|
+ if not col.empty():
|
|
max_dist = ray_from.distance_to(col.position)
|
|
max_dist = ray_from.distance_to(col.position)
|
|
- if (col.collider == player):
|
|
|
|
- pass # kill
|
|
|
|
- #clip ray in shader
|
|
|
|
- $"Scene Root/Armature/Skeleton/ray_from/ray".get_surface_material(0).set_shader_param("clip",max_dist)
|
|
|
|
- #position explosion
|
|
|
|
|
|
+ if col.collider == player:
|
|
|
|
+ pass # Kill.
|
|
|
|
+ # Clip ray in shader.
|
|
|
|
+ $"Scene Root/Armature/Skeleton/ray_from/ray".get_surface_material(0).set_shader_param("clip", max_dist)
|
|
|
|
+ # Position explosion.
|
|
$"Scene Root/Armature/Skeleton/ray_from/explosion".transform.origin.z = -max_dist
|
|
$"Scene Root/Armature/Skeleton/ray_from/explosion".transform.origin.z = -max_dist
|
|
-
|
|
|
|
-var test_shoot=false
|
|
|
|
-func shoot_check():
|
|
|
|
- test_shoot=true
|
|
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+
|
|
func _physics_process(delta):
|
|
func _physics_process(delta):
|
|
if (test_shoot):
|
|
if (test_shoot):
|
|
- do_shoot()
|
|
|
|
- test_shoot=false
|
|
|
|
-
|
|
|
|
- if (dead):
|
|
|
|
|
|
+ shoot()
|
|
|
|
+ test_shoot = false
|
|
|
|
+
|
|
|
|
+ if dead:
|
|
return
|
|
return
|
|
-
|
|
|
|
- if (not player):
|
|
|
|
- $AnimationTree["parameters/state/current"]=0 # go idle and good bye
|
|
|
|
|
|
+
|
|
|
|
+ if not player:
|
|
|
|
+ $AnimationTree["parameters/state/current"] = 0 # Go idle.
|
|
return
|
|
return
|
|
- var to_player_local = $"Scene Root".global_transform.affine_inverse().xform(player.global_transform.origin)
|
|
|
|
- var to_player_angle = atan2( to_player_local.x, to_player_local.z )
|
|
|
|
-
|
|
|
|
- if (state == STATE_APPROACH):
|
|
|
|
-
|
|
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ if (state == State.APPROACH):
|
|
if (aim_preparing > 0):
|
|
if (aim_preparing > 0):
|
|
- aim_preparing-=delta
|
|
|
|
- if (aim_preparing<0):
|
|
|
|
- aim_preparing=0
|
|
|
|
- $AnimationTree["parameters/aiming/blend_amount"]= aim_preparing / AIM_PREPARE_TIME
|
|
|
|
-
|
|
|
|
|
|
+ aim_preparing -= delta
|
|
|
|
+ if (aim_preparing < 0):
|
|
|
|
+ aim_preparing = 0
|
|
|
|
+ $AnimationTree["parameters/aiming/blend_amount"] = aim_preparing / AIM_PREPARE_TIME
|
|
|
|
|
|
- if (to_player_angle < -deg2rad(PLAYER_AIM_TOLERANCE_DEGREES)):
|
|
|
|
- $AnimationTree["parameters/state/current"]=2
|
|
|
|
- elif (to_player_angle > deg2rad(PLAYER_AIM_TOLERANCE_DEGREES)):
|
|
|
|
- $AnimationTree["parameters/state/current"]=1
|
|
|
|
|
|
+ var to_player_local = global_transform.xform_inv(player.global_transform.origin)
|
|
|
|
+ # The front of the robot is +Z, and atan2 is zero at +X, so we need to use the Z for the X parameter (second one).
|
|
|
|
+ var angle_to_player = atan2(to_player_local.x, to_player_local.z)
|
|
|
|
+ var tolerance = deg2rad(PLAYER_AIM_TOLERANCE_DEGREES)
|
|
|
|
+ if (angle_to_player > tolerance):
|
|
|
|
+ $AnimationTree["parameters/state/current"] = 1
|
|
|
|
+ elif (angle_to_player < -tolerance):
|
|
|
|
+ $AnimationTree["parameters/state/current"] = 2
|
|
else:
|
|
else:
|
|
- $AnimationTree["parameters/state/current"]=3
|
|
|
|
- # facing player, try to shoot
|
|
|
|
- shoot_countdown-=delta
|
|
|
|
- if (shoot_countdown <0):
|
|
|
|
- #see if player can be killed because in sight
|
|
|
|
|
|
+ $AnimationTree["parameters/state/current"] = 3
|
|
|
|
+ # Facing player, try to shoot.
|
|
|
|
+ shoot_countdown -= delta
|
|
|
|
+ if (shoot_countdown < 0):
|
|
|
|
+ # See if player can be killed because in they're sight.
|
|
var ray_from = $"Scene Root/Armature/Skeleton/ray_from".global_transform.origin
|
|
var ray_from = $"Scene Root/Armature/Skeleton/ray_from".global_transform.origin
|
|
- var ray_to = player.global_transform.origin + Vector3(0,1,0) # middle of player
|
|
|
|
- var col = get_world().direct_space_state.intersect_ray(ray_from,ray_to,[self])
|
|
|
|
- if (not col.empty() and col.collider == player):
|
|
|
|
- state = STATE_AIM
|
|
|
|
|
|
+ var ray_to = player.global_transform.origin + Vector3.UP # Above middle of player.
|
|
|
|
+ var col = get_world().direct_space_state.intersect_ray(ray_from, ray_to, [self])
|
|
|
|
+ if not col.empty() and col.collider == player:
|
|
|
|
+ state = State.AIM
|
|
aim_countdown = AIM_TIME
|
|
aim_countdown = AIM_TIME
|
|
aim_preparing = 0
|
|
aim_preparing = 0
|
|
- $AnimationTree["parameters/state/current"]=0
|
|
|
|
-
|
|
|
|
|
|
+ $AnimationTree["parameters/state/current"] = 0
|
|
else:
|
|
else:
|
|
- #player not in sight, do nothing
|
|
|
|
|
|
+ # Player not in sight, do nothing.
|
|
shoot_countdown = SHOOT_WAIT
|
|
shoot_countdown = SHOOT_WAIT
|
|
-
|
|
|
|
- elif (state==STATE_AIM or state==STATE_SHOOTING):
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- if (aim_preparing<AIM_PREPARE_TIME):
|
|
|
|
- aim_preparing+=delta
|
|
|
|
|
|
+
|
|
|
|
+ elif state == State.AIM or state == State.SHOOTING:
|
|
|
|
+ if (aim_preparing < AIM_PREPARE_TIME):
|
|
|
|
+ aim_preparing += delta
|
|
if (aim_preparing > AIM_PREPARE_TIME):
|
|
if (aim_preparing > AIM_PREPARE_TIME):
|
|
aim_preparing = AIM_PREPARE_TIME
|
|
aim_preparing = AIM_PREPARE_TIME
|
|
-
|
|
|
|
- $AnimationTree["parameters/aiming/blend_amount"]=clamp(aim_preparing / AIM_PREPARE_TIME,0,1)
|
|
|
|
-
|
|
|
|
- aim_countdown-=delta
|
|
|
|
- if (aim_countdown<0 and state==STATE_AIM):
|
|
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ $AnimationTree["parameters/aiming/blend_amount"] = clamp(aim_preparing / AIM_PREPARE_TIME, 0, 1)
|
|
|
|
+ aim_countdown -= delta
|
|
|
|
+ if aim_countdown < 0 and state == State.AIM:
|
|
var ray_from = $"Scene Root/Armature/Skeleton/ray_from".global_transform.origin
|
|
var ray_from = $"Scene Root/Armature/Skeleton/ray_from".global_transform.origin
|
|
- var ray_to = player.global_transform.origin + Vector3(0,1,0) # middle of player
|
|
|
|
- var col = get_world().direct_space_state.intersect_ray(ray_from,ray_to,[self])
|
|
|
|
- if (not col.empty() and col.collider == player):
|
|
|
|
- state = STATE_SHOOTING
|
|
|
|
|
|
+ var ray_to = player.global_transform.origin + Vector3.UP # Above middle of player.
|
|
|
|
+ var col = get_world().direct_space_state.intersect_ray(ray_from, ray_to, [self])
|
|
|
|
+ if not col.empty() and col.collider == player:
|
|
|
|
+ state = State.SHOOTING
|
|
$shoot_anim.play("shoot")
|
|
$shoot_anim.play("shoot")
|
|
else:
|
|
else:
|
|
resume_approach()
|
|
resume_approach()
|
|
-
|
|
|
|
- if ($AnimationTree.active):
|
|
|
|
-
|
|
|
|
- var to_cannon_local = $"Scene Root/Armature/Skeleton/ray_from/ray".global_transform.affine_inverse().xform(player.global_transform.origin + Vector3(0,1,0))
|
|
|
|
|
|
+
|
|
|
|
+ if $AnimationTree.active:
|
|
|
|
+ var to_cannon_local = $"Scene Root/Armature/Skeleton/ray_from/ray".global_transform.xform_inv(player.global_transform.origin + Vector3.UP)
|
|
var h_angle = rad2deg(atan2( to_cannon_local.x, -to_cannon_local.z ))
|
|
var h_angle = rad2deg(atan2( to_cannon_local.x, -to_cannon_local.z ))
|
|
var v_angle = rad2deg(atan2( to_cannon_local.y, -to_cannon_local.z ))
|
|
var v_angle = rad2deg(atan2( to_cannon_local.y, -to_cannon_local.z ))
|
|
-
|
|
|
|
-
|
|
|
|
var blend_pos = $AnimationTree["parameters/aim/blend_position"]
|
|
var blend_pos = $AnimationTree["parameters/aim/blend_position"]
|
|
var h_motion = BLEND_AIM_SPEED * delta * -h_angle
|
|
var h_motion = BLEND_AIM_SPEED * delta * -h_angle
|
|
blend_pos.x += h_motion
|
|
blend_pos.x += h_motion
|
|
- blend_pos.x = clamp(blend_pos.x, -1 , 1 )
|
|
|
|
|
|
+ blend_pos.x = clamp(blend_pos.x, -1, 1)
|
|
|
|
|
|
var v_motion = BLEND_AIM_SPEED * delta * v_angle
|
|
var v_motion = BLEND_AIM_SPEED * delta * v_angle
|
|
blend_pos.y += v_motion
|
|
blend_pos.y += v_motion
|
|
- blend_pos.y = clamp(blend_pos.y, -1 , 1 )
|
|
|
|
|
|
+ blend_pos.y = clamp(blend_pos.y, -1, 1)
|
|
|
|
|
|
- $AnimationTree["parameters/aim/blend_position"]= blend_pos
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- var root_motion = $AnimationTree.get_root_motion_transform()
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- # apply root motion to orientation
|
|
|
|
- orientation *= root_motion
|
|
|
|
|
|
+ $AnimationTree["parameters/aim/blend_position"] = blend_pos
|
|
|
|
+
|
|
|
|
+ # Apply root motion to orientation.
|
|
|
|
+ orientation *= $AnimationTree.get_root_motion_transform()
|
|
|
|
|
|
var h_velocity = orientation.origin / delta
|
|
var h_velocity = orientation.origin / delta
|
|
velocity.x = h_velocity.x
|
|
velocity.x = h_velocity.x
|
|
- velocity.z = h_velocity.z
|
|
|
|
- velocity += GRAVITY * delta
|
|
|
|
- velocity = move_and_slide(velocity,Vector3(0,1,0))
|
|
|
|
-
|
|
|
|
- orientation.origin = Vector3() #clear accumulated root motion displacement (was applied to speed)
|
|
|
|
- orientation = orientation.orthonormalized() # orthonormalize orientation
|
|
|
|
|
|
+ velocity.z = h_velocity.z
|
|
|
|
+ velocity += gravity * delta
|
|
|
|
+ velocity = move_and_slide(velocity, Vector3.UP)
|
|
|
|
|
|
- $"Scene Root".global_transform.basis = orientation.basis
|
|
|
|
|
|
+ orientation.origin = Vector3() # Clear accumulated root motion displacement (was applied to speed).
|
|
|
|
+ orientation = orientation.orthonormalized() # orthonormalize orientation.
|
|
|
|
+
|
|
|
|
+ global_transform.basis = orientation.basis
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
|
|
+func shoot_check():
|
|
|
|
+ test_shoot = true
|
|
|
|
+
|
|
|
|
|
|
func _on_area_body_entered(body):
|
|
func _on_area_body_entered(body):
|
|
- if (body is preload("res://player/player.gd")):
|
|
|
|
|
|
+ if body is preload("res://player/player.gd"):
|
|
player = body
|
|
player = body
|
|
- shoot_countdown=SHOOT_WAIT
|
|
|
|
|
|
+ shoot_countdown = SHOOT_WAIT
|
|
|
|
|
|
|
|
|
|
func _on_area_body_exited(body):
|
|
func _on_area_body_exited(body):
|
|
- if (body is preload("res://player/player.gd")):
|
|
|
|
|
|
+ if body is preload("res://player/player.gd"):
|
|
player = null
|
|
player = null
|