The Godot Q&A is currently undergoing maintenance!

Your ability to ask and answer questions is temporarily disabled. You can browse existing threads in read-only mode.

We are working on bringing this community platform back to its full functionality, stay tuned for updates.

godotengine.org | Twitter

0 votes

Hello,

I've been trying to develop different kind of games
Started from breakout clone, infinite side scroller, vertical scrolling shooter, etc all these are controlled using button presses.

I'm new to Godot and my next project I want to go ahead in is RTS.
The issue I'm having is that I cant get my units to "animate" towards their goals.

So what I am trying to accomplish is:
After selecting a unit I want the unit to move to the clicked empty spot.
I can get it to the destination in an instant but not by "animation"(tweening? not sure if I'm calling it correct)

I have tinkered for a while and noticed I need to make use of vectors.
Even though I found (and learned) quite a bit about them, I still have a hard time to make proper use of it.

Looking for a guide/tutorial didn't have the success I hoped.
Hopefully one of you can aid me in the right direction.

Thank you for your time reading trough this!

Cheers,
Santouryuu

Edit: I should have added I'm focused on 2D only at the moment

in Engine by (15 points)
edited by

2 Answers

0 votes
Best answer

Maybe Path2D/Curve2D 'll help you. After pathfinding (by a* or custom pathfinder), you should have var with list of vectors with position of each tile(?) or point (in global, or
fictitious units (like tiles), if 2nd option, you must multiple vector in set_pos() by size of tile).
When you have it, you should do (in animation, or (i think better) in _process() an animation.
If it don't work on tiles, you may use Path2D and get_baked_points(), like

_process(delta):
   set_pos(your_path_2d.get_baked_points()[number_of_frame])

EDIT: Final code:
GitHub demo
Map code:

tool
extends Polygon2D

# map size in pxs
export var map_size_x = 500
export var map_size_y = 500
# move map from left top corner
export var init_pos_x = 150
export var init_pos_y = 150

func _ready():
    # create polygon
    set_pos(Vector2(init_pos_x,init_pos_y))
    set_polygon(Vector2Array([
    Vector2(0,0),
    Vector2(map_size_x,0),
    Vector2(map_size_x,map_size_y),
    Vector2(0,map_size_y)]
    ))
    # move Nav2D poly to true pos (with position of map node)
    var _buff_poly = Vector2Array([])
    for i in get_polygon():
        _buff_poly.append(i+get_pos())
    # set polygon to Nav2D
    var _nav_poly = NavigationPolygon.new()
    _nav_poly.add_outline(_buff_poly)
    _nav_poly.make_polygons_from_outlines()
    get_node(\"Navigation2D\").navpoly_create(_nav_poly,Matrix32(0,Vector2(1,1)))

Unit code:

extends Sprite

var movement_path = Curve2D.new()
var speed = 250.0
var pos_on_path = 0

func _ready():
    # that's in pixels (probably)
    movement_path.set_bake_interval(1)
    set_process_unhandled_input(true)
    set_fixed_process(true)

func _unhandled_input(event):
    if event.type == InputEvent.MOUSE_BUTTON and event.pressed:
        if event.button_index == BUTTON_RIGHT:
            movement_path.clear_points()
            movement_path.add_point(get_pos())
            movement_path.add_point(event.global_pos)
            var _buffer = get_node(\"../A passable map/Navigation2D\").get_simple_path(movement_path.get_point_pos(0),movement_path.get_point_pos(1))
            movement_path.clear_points()
            for i in _buffer:
                movement_path.add_point(i)
            pos_on_path = 0

func _fixed_process(delta):

    if round(pos_on_path+speed*delta) < movement_path.get_baked_points().size():
        pos_on_path += speed*delta
        set_pos(movement_path.get_baked_points()[round(pos_on_path)])
by (186 points)
selected by

Thanks for your reply!
If tried using the function get_baked_points, since I m not using tilemaps.
but it keep giving me an error.
I have the following:

func _fixed_process(delta):
    if get_node("../Navigation2D").path.size():
        set_pos(get_node("../Navigation2D").path.get_baked_points())

I get the errror:

Invalid call. Nonexistent function 'get_baked_points' in base
'Vector2Array'.

I have printed the path it does return some values I have an example at the bottom)

What do you mean by [numberofframe], am I missing something?

if I print get_node("../Navigation2D").path I receive:

[(81.000305, 125.136993), (413, 382)]

The problem is get_baked_points return array of points, so you can't just use set_pos(). You must use set_pos(get_baked_points()[a]). That a is number of backed point, like pixel by pixel. So if you want move 1px/frame you should have something like this:

act_pos_in_array = 0
func _process(delta):
   set_pos(get_baked_points()[act_pos_in_array])
   if act_pos_in_array < get_baked_points().size()
      act_pos_in_array += 1

Other thing, what's path in your code?

First of all thanks for sticking with me!
And I Apologize for my late reply.

I kinda got it to work sprite moves now but not in a smooth motion.
It goes to the first point than waits a little then goes to the next and again halts for a fraction of a second.

func _input(event):
if event.type == InputEvent.MOUSE_BUTTON and event.pressed:
    if event.button_index == BUTTON_RIGHT:
        end = event.global_pos
        start = get_node("Tank").get_pos()
        transition = 0

func _process(delta):

path = get_node("Navigation2D").get_simple_path(start, end)
if path.size() < path_points:
    transition = 0

path_points = path.size()

if path_points < 2: return
var sprite = get_node("Tank")

sprite.set_global_pos(sprite.get_global_pos().linear_interpolate(path[1], transition))
start = sprite.get_global_pos()
transition += speed * delta
if transition > 1: transition = 0

This is currently the code.
Tank is a rigidbody2d object.

I would very much appreciate it if you were able to tell me a way to make the motion smoother

I think, i can't explain that easly. I pushed demo project to GitHub, hope it will be helpful.
It's not best way to do that, but it works, so it's good to prototyping...

Again thank you very much!!
At least I get the logic behind it now.
Cheers buddy

0 votes

I think what you need to look at is linear interpolation (lerping). This should give you the movement from their unit's current Vector2 to the new one.

by (108 points)

Thanks for your reply!
I have looked into lerping.
I got the sprite moving sadly enough not the way I want.
Clicking on the destination creates multiple point at which the sprite needs to move along.
Every time I click I can see the path plotted.
But the sprite doesn't move past the first point.
I have tried multiple ways but with no success.
I have the following at the moment:

  func _input(event):
    if event.type == InputEvent.MOUSE_BUTTON and event.button_index == BUTTON_LEFT:
        mPos = event.global_pos
        var uPos = get_global_pos()
        var spriteRect = Rect2(uPos.x, uPos.y, tsize.x, tsize.y)
        if spriteRect.has_point(mPos):
            selectorNode.set_opacity(1)
        elif selectorNode.get_opacity():
            destination = mPos

func _fixed_process(delta):
    if destination != null:
        if get_node("../Navigation2D").path.size():
            var path = get_node("../Navigation2D").path
            for i in range(path.size()):
                print(i)
                set_global_pos(get_global_pos().linear_interpolate(path[i], delta))
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 [email protected] with your username.