+1 vote

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.


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):
    for enemy1 in _enemies_type_1:
        var current_enemy = enemy1.get_ref()
        if current_enemy:
            # This is the only method that changes rotation

            if current_enemy.Fa != null:
                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

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

func _rotate_to_target(p_delta, p_target_player):
    if p_target_player == null:
    var the_tplayer = p_target_player.get_ref()
    if !the_tplayer:
    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
    # 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
    var start_pos = _shoot_from_node.get_global_3d_pos()
    the_laser.start_position = Vector2(start_pos.x, start_pos.y)
    _can_shoot_laser = false


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
            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
        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())
        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! =)

in Engine by (96 points)
edited by

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.

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.