RTS unit movement system

Hi there.
Before you go around saying that “A RTS is a lot of work”, the game i’m doing is mostly a hybrid between tower defense and a RTS, the only AI i’m doing is some simple AI for some ships (mainly resource collectors and builders.). Just so you know :wink:

So, i’ve got a selection system done for an unit (a ship, to say it like that.). The ship is floating around and i’ve got the movement system done.
What i did was use the steering actuator to track to an object, wich follows the mouse position on a plane named “floor” after i use the right click.
This system works pretty well when it comes to having only one unit. but on the main scene, i linked the group containing all the unit, and once i duplicated it, the system would only work on the duplicated linked object, and the original one would follow the position of the first unit without being ordered to do so.

So i tought that a way to achieve what i want was to store the mouse position once i clicked on the “floor” object on a property, and then use that property to align the unit and apply movement. However storing the mouse position in the plane on a property doesn’t seems to work.

It would be a great help if anyone could tell me exactly how i can store the mouse position after i left click on the “floor” object, and use it to align the unit (speficically on the -Y axis) to that point? Any help is appreciated :slight_smile:

Edit: Just so you know, the unit is set to Static so it can float around.

You say the position of the mouse in the 3d space? i think you are using a mouse over any, that sensor have a property in python named: hitPosition, use something like this:


import bge
cont = bge.logic.getCurrentController()
own = cont.owner

sensor = cont.sensors[0]
own["mouse_position"] = sensor.hitPosition

or position of the object on which the mouse is:


import bge
cont = bge.logic.getCurrentController()
scene = bge.logic.getScene()
own = cont.owner

object = scene.objects

sensor = cont.sensors[0]
own["mouse_position"] = object[str(sensor.hitObject)].worldPosition

Your code works, and i got the mouse position on the plane, to the property. But now i’m having a hard time trying to get the unit to align with those coordinates. I guess a little help with that could come handy :S

i use this code

def pathFind():  
    cont = logic.getCurrentController()
    scene = logic.getCurrentScene()
    own = cont.owner
    
    speed = own["speed"]
    
    pathFind = cont.actuators["pathFind"]


    for path in own.children:
        if path.name == "path":
            pathFind.target = path
            path.removeParent()
            
    render.drawLine(own.position, (pathFind.target).position, [0.0, 1.0, 0.0])        
        
    pathFind.velocity = speed
    pathFind.navmesh = scene.objects["NavMesh"]
    cont.activate(pathFind)

basicly what it does is that the"target destination" object is parented to the unit on a hidden layer, when i spawn the unit via add object, the target is spawned too, inmediatly after the unit is spawned i assign the name of the target destination to the steering actuator and then i remove the parent, i hope this helps you!

Thanks! After a few days of work, i managed to implement it to the system. The units track each of their track points properly now, but the only thing i’m having a LOT of trouble now, is that the track point objects move ALL together if i select one of the units and if i assign it a position: http://imgur.com/Y7bD7mn

The “destination objects” each have a property called “selected”, so if the ship is selected, the D.O (Destination object) is marked as selected too, and can track the position of the mouse on a plane called “floor” if the property “selected” is true. Here’s the script i use for it:

from bge import logic, events, render
import bge


scene = logic.getCurrentScene()
cont = logic.getCurrentController()
own = cont.owner
ownName = own.name
print(ownName)


def getCoords(cont):
    if own['selected'] == True:
       mouse = cont.sensors['mouse']
       rmb = mouse.getButtonStatus(events.RIGHTMOUSE)
       if rmb == 1 and mouse.hitObject.name=='land':
            cont.owner.position = mouse.hitPosition
            print(cont.owner.position)
       else:
            return
    elif own["selected"] == False:
        main()
        
def visible(cont):
    render.showMouse(True)


def main(cont): 
         
    if own['selected'] == True:
        
        getCoords(cont)
        visible(cont)


            

EDIT: Managed to get the points to not move together, but now the problem is, only the point that was added first can move :stuck_out_tongue: and the others which were added after it copy it’s location for some reason.

So if anyone could help me solve this, it would be a BIG help :slight_smile:

Well it would be a lot easier if you had a blend file.
I don’t understand your system pretty well right now, but I think you should define

own = cont.owner

in each function. This will prevent many errors, especially if you’re using the code on more than one object.

Defining own = cont.owner on each function caused the target objects to not move at all.

Here’s a blend file. Sorry if it’s a little messy, i’m still learning Python haha :slight_smile:unit_test.blend (1.83 MB)

The unit is on the secon layer. It has an empty called “bp_col_parent” which controls the movement and pathfinding of each unit. The main unit itself is the hitbox called “collector_hitbox_main”, this one controls selecting and stuff.

The destination object is parented to bp_col_parent. After the unit gets selected, the destination object from the Children list on bp_col_parent gets removed from its parent, allowing it to move freely without having to follow the unit.

It think you’ll understand how it works while looking at the blend file :wink:

EDIT: On the first layer, there’s a test to see how a lot of units behave with each other. That’s where the problem is. Select the unit that gets added first (The one on the left bottom corner empty) and give it a destination with the right click. Then try to move any other units and you’ll see the problem.

Ok select group with object or raybox etc.

each item needs a empty that is its own nav target,

make a list of the items in the group

when the mouse is clicked, a distance check then finds who is closest, then moves his nav target to mouse.hitPosition

all others in groups nav targets are moved onto the leader and then parented.

I’ve already got the whole move to position thingy done (except for group moving). My problem is that the nav targets of recently added units don’t move, and only follow the position of the nav target that was added first. It would be nice if you could check the file i provided earlier :slight_smile:

what I am saying,

you are making a list of nav Targets?
Select ships, get a list of each ships navtarget

leader = closest unit (remove from list)
for item in NavTargets:
(tab)item.world Position = leader.world Position

So how do you box select at the moment in your file?

Ok, I took a look. (by the way, you have a pretty good ship model)
I really don’t know what I did but it works : unit_test.blend (1.9 MB)

But personnally I would rewrite it from scratch.
Firstly I would say your system is unoptimised, with lots of sensors triggering controllers each frame, with 20 ships your game is going to lag at hell.
Your ships are all checking with mouse over sensors, clicking, selecting. I think it would be better if you had one main object that checks selecting and moving ships. You would have a list of your ships, then that main object would check if your mouse is over one of these ships; the moving logic can be done on the ships themselves. Because mouse over sends every frame a ray from the camera, and just now your ships are all sending rays wich are not necessary (except if you have more than one mouse). One mouse over any on the main object will do the job.
There are also lot of times you are constantly checking unnecessary things in the scripts (for example you loop every frame in all object’s children to set the target of the actuator, when you only need that in an init script). If you’re a beginner I recommand checking Yo Frankie’s logic and scripts, they’re a bit dated but they’re very well written.

Haha thanks! I’ve been quite a lot more on modelling and stuff than on Python for a long time :wink:

I’ll try to set it up like you said. I wasn’t thinking on performance hits and stuff when i was making that system haha, all i had in mind was to finish it already. Noobie mistake i guess.

Anyway thanks for the help! Next thing is box selecting :slight_smile:

hey sorry for late answer i was afk during the weekend (not really afk, but afk from blender lol) im sending you via pm a old project i had, i hope it helps!

in my opinion the GUI should manage much more logic.

the connection units/GUI should happen with a system of messages.

we say each units can have 2/3 property writable from the GUI .

message_GUI_selected = bool
message_GUI_mission = str
message_GUI_target = Vector

these here “messages” that send the GUI
while the unit keep its state (not writable to others)

selected
mission
target