[Godot 2] Predict target position not working

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By equus

Edit 2: I noticed I forgot an operator that I put in the actual code of enemy, when calculating the angle, but I did not put it here in the question. I updated the line now.
Edit: added code of ai_controller.gd, enemy shoot code and methods used in shoot code.

Hello!

I’m making a shooter game and I want to enemies fire bullets at a predicted player position. The enemies need to rotate to that position. My code was working when I made it for 2d, but I changed the game to a 3D view. I still using 2d for all the calculations. My approach was to keep z positions locked in -10 for all the objects that need calculations. So, I’m using only x and y to make the calculations and ignoring z positions (because all z positions are the same). I’m keeping the rotations only in z axis. After doing all this, the enemy started to miss the target. I researched a lot but I did not find an answer.

I’m using Godot 2.1.5

Here is the code:


------------ Code in ai_controller.gd------------
func _fixed_process(p_delta):
	ai_movement_process(_enemies_type_1)
	for enemy1 in _enemies_type_1:
		var current_enemy = enemy1.get_ref()
		if current_enemy:
			# This is the only method that changes rotation
			current_enemy.update_rotation(p_delta)

```
		current_enemy.check_player_distance_to_shoot()
		if current_enemy.Fa != null:
			current_enemy.update_ship_velocity()
			current_enemy.reduce_player_speed_if_close_to()
			var new_pos = current_enemy.get_global_2d_pos() + current_enemy.current_velocity * p_delta
			if new_pos.x < 0:
				new_pos.x = 0
			elif new_pos.x > 5000:
				new_pos.x = 5000
			if new_pos.y < 0:
				new_pos.y = 0
			elif new_pos.y > 5000:
				new_pos.y = 5000
			current_enemy.set_global_2d_pos(new_pos)
```

------------Code in enemy.gd------------
extends Spatial

func _rotate_to_target(p_delta, p_target_player):
	if p_target_player == null:
		return
	
	var the_tplayer = p_target_player.get_ref()
	
	if !the_tplayer:
		return
	
	target_p_pos = _global_node.get_projectile_future_point(_shoot_from_node.get_global_2d_pos(), \
	laser_shot_speed, the_tplayer.get_global_2d_pos(), the_tplayer.current_velocity)
	
	var my_pos = get_global_2d_pos()
	
	var ang = -(target_p_pos - my_pos).angle()
	
	# Now I'm setting the angle straight
	set_2d_rot(ang) 
	
	# I was using interpolation but it didn't worked either
	set_2d_rot(lerp_angle(get_2d_rot(), ang, rotation_velocity * p_delta))

func shoot(p_weapon):
	var the_laser = _laser_scn.instance()
	the_laser.w_damage = laser_shot_damage
	the_laser.w_fire_rate = laser_shot_fire_rate
	the_laser.w_speed = laser_shot_speed
	the_laser.w_range = laser_shot_range
	_node_to_attach_weapons_node.add_child(the_laser)
			
	var start_pos = _shoot_from_node.get_global_3d_pos()
	the_laser.set_global_3d_pos(start_pos)
	the_laser.start_position = Vector2(start_pos.x, start_pos.y)
	the_laser.set_2d_rot(get_2d_rot())
	_can_shoot_laser = false
	_timer_laser_fire_rate.start()

------------https://forum.godotengine.org-28776/rotate-kinematicbody2d-based-mouse-position-varying-rate------------

func lerp_angle(p_start, p_end, p_delta): #In radians
	if abs(p_start - p_end) >= PI: 
		if p_start > p_end:
			p_end += 2 * PI
		else:
			p_start += 2 * PI
			
	return lerp(p_start, p_end, p_delta)


------------Code in player.gd and enemy.gd and all objects that need position and rotation calculations in 2d------------

func get_global_2d_pos():
	var pos = get_global_transform().origin
	return Vector2(pos.x, pos.y)
	
func get_global_3d_pos():
	return get_global_transform().origin

func set_global_3d_pos(p_position):
	set_global_transform(Transform(get_global_transform().basis, p_position)) 
	
func get_2d_rot():
	return get_rotation().z

func set_2d_rot(p_rotation):
	set_rotation(Vector3(get_rotation().x, get_rotation().y, p_rotation))
	

------------Code in _global_node------------

func get_projectile_future_point(p_my_position, p_projectile_velocity, p_target_position, p_target_velocity):
	var target_dir = (p_target_position - p_my_position).normalized()
	var target_vel_ortho = p_target_velocity.dot(target_dir) * target_dir
	var target_vel_tang = p_target_velocity - target_vel_ortho
	var shot_vel_tang = target_vel_tang
	var shot_speed = shot_vel_tang.length()
	
	var direction = Vector2()
	
	if shot_speed > p_projectile_velocity.length():
	    direction = p_target_velocity.normalized() * shot_speed
	else:
	    var shot_speed_ortho = sqrt(p_projectile_velocity.length() * p_projectile_velocity.length() - shot_speed * shot_speed)
	    var shot_vel_ortho = target_dir * shot_speed_ortho
	    
	    direction = shot_vel_ortho + shot_vel_tang
	
	var pos_norm = (p_my_position - p_target_position).length()
	var time_to_collision = pos_norm
	
	if p_projectile_velocity.length() > p_target_velocity.length():
		time_to_collision /= (p_projectile_velocity.length() - p_target_velocity.length())
	else:
		time_to_collision /= p_projectile_velocity.length()
		
	var shot_velocity = direction
	var collision_point = p_my_position + shot_velocity * time_to_collision
		
	return collision_point

Thanks in advance! =)

Edit: the code is not working after I changed some parameters. I don’t know why.

It is working now. I think I modified some code and forgot that I had modified. I’m seeing the spaceships hitting the player most of times. I remember it was little different when I was using 2d but it is working pretty close of what I wanted to it works. I changed some parameters when I started using 3d and I think the difference I’m seeing now is because of this.

Thanks for the people who helped in facebook group.

equus | 2018-12-13 18:44