I have a soldier, if you click on him, he is set to active unit (click off him he deactivates). He is bought and spawned through a building you can build.
My problem, is that I can’t figure out a good way to make him go towards the place I right-clicked.
I had an empty parented to him, and if he is active and I right-click on the ground, the position of the empty would go there and he would steer to there. But the empty is parented to him. So I had it remove parent when I clicked on the ground. But the way I got that empty was through a child list. So I tried to parent it back to the owner after the steering was done, but then it couldn’t do that because the child link was broken and the reference couldn’t be made.
I can make the soldier attack specific enemies on a right-click. So I am going to have to work that in to the solution.
None of the child list methods are working. I had it print the object it got, and it was right. But it didn’t set it as the steering target and if didn’t assign the right object as dest. Assigning the target outside of the if statements is the only way I can get this to even remotely work. But both ways (find property in object or find name in list) don’t removeParent()
Here is the full script:
import bge
def main():
cont = bge.logic.getCurrentController()
owner = cont.owner
scene = bge.logic.getCurrentScene()
steer = owner.actuators['Steering']
lmb = owner.sensors['Mouse']
rmb = owner.sensors['Mouse2']
overany = owner.sensors['Mouse3']
active = owner['active']
time = owner['time']
children = owner.children
for dest in children:
if dest.name == 'where':
print ('works', dest)
dest.removeParent()
steer.target = dest
cont.activate(steer)
if active == False:
owner.setVisible(False)
#selecting
if lmb.positive:
if overany.hitObject == owner:
owner['active'] = True
if 'soldier' in overany.hitObject:
owner['active'] = True
if not 'soldier' in overany.hitObject:
owner['active'] = False
#active unit
if active == True:
owner.setVisible(True)
#action
if rmb.positive:
if 'ground' in overany.hitObject:
dest.worldPosition = overany.hitPosition
i dont see why it is not working for you, i extracted a part of your code, and did it like this
import bge
cont = bge.logic.getCurrentController()
owner = cont.owner
scene = bge.logic.getCurrentScene()
steer = owner.actuators['Steering']
children = owner.children
for dest in children:
if dest.name == 'where':
print ('works', dest)
dest.removeParent()
steer.target = dest
cont.activate(steer)
and it worked, i tested it with a script, maybe making it with a module is screwing things up
Huh. I am using 2.65, if that means anything. The module doesn’t matter. Script does the same thing. Ugh.
I am going to download 2.66a and see what happens
Nope, still doesn’t work. I think it has to do with:
dest.position = overany.hitPosition
EDIT!!
I moved all that under the rmb if statement. And it works! but I can only do it once :\
#active unit
if active == True:
owner.setVisible(True)
#action
if rmb.positive:
if 'ground' in overany.hitObject:
children = owner.children
for dest in children:
if dest.name == 'where':
dest.removeParent()
steer.target = dest
cont.activate(steer)
print ('works, ob being seeked is', dest)
dest.position = overany.hitPosition
children = owner.children
for dest in children:
if dest.name == 'where':
print ('works', dest)
dest.removeParent()
steer.target = dest
cont.activate(steer)
dest is always going to be the last child in the list (regardless of the name) unless you invoke break after you’ve found the object in question.
when calling removeParent(), dest will no longer be a child of owner
You could replace that block of code with this one (untested):
if not 'target' in owner:
for dest in owner.children:
if dest.name == 'where':
print ('works', dest)
dest.removeParent()
owner['target'] = dest
if 'target' in owner:
steer.target = owner['target']
cont.activate(steer)
else:
print ("Warning - target not defined")
Hmm… you were on the right track.
One could do steer.target = dest in the loop and call it good.
We shouldn’t need to constantly reassign the target object, assuming it doesn’t change when targeting an enemy (which is feasible, as you can re-position and parent the target to anything)
EDIT
Revised code:
if not 'target' in owner:
for dest in owner.children:
if dest.name == 'where':
print ('works', dest)
dest.removeParent()
owner['target'] = dest
steer.target = dest
cont.activate(steer)
EDIT defining “target = steering.target” fixed it. Thanks guys for the help!
I haven’t fiddled with it yet, but I need the child to be called once. I want to add in a boolean so it goes false when you defined dest.
Bah! Even then I can only get it to work once.
I about ready to rip Python a new one. Even though all the checks are good, it won’t do whhat I think I am telling it to do. It tells me that “target is referenced before assigned”. Even though the boolean reads True.
if rmb.positive:
if 'ground' in overany.hitObject:
if owner['get'] == False:
for dest in children:
if dest.name == 'where':
dest.removeParent()
steer.target = dest
target = steer.target
cont.activate(steer)
print ('works, obj being seeked is', target)
target.worldPosition = overany.hitPosition
owner['get'] = True
if owner['get'] == True:
target.worldPosition = overany.hitPosition # This target it says is being reffed before assigned >:(
print ('works2, obj being seeked is', dest)
cont.activate(steer)
Forgive my noobism, and I might be totally wrong. But can’t you get the object from a list of objects in the scene, instead of getting it from a list of children? Maybe that’ll fix it… Don’t quote me on it, though.
I am spawning the soldier in. So using children is the (as far as I know) the best way. The problem with getting it out of the scene objects list, is that then every soldier would need a unique name to look for. Spawning all I have to look for in the children is the one name.
Python isn’t being a whiny ****. It’s genuinely unable to find the variable you’ve referenced:
In the second if statement you reference target. However, you define target in a local scope, meaning that it is only defined when the code block is executed; if owner[‘get’] == False.
Some tips:
Don’t use if owner[‘get’] == False. Use
if not owner['get']:
Don’t then do the reverse condition. Just change if owner[‘get’] == True (which should be if “owner[‘get’]:”) to “else:”
Oh right, you’e adding more. Well, can’t you spawn in a general object where you click, then have all active units pathfind to it?
That would probably require a full change to your current system I realize, but if Blender itself can do it, you can too! xD
(By the way, how do you get an object to snap to a mouse click point? I’m new to post-2.5 Blender, so I’m trying to learn what I can. :P)
Ahh, I just needed to know that .hitPosition variable. Thank you!
Sorry to ask for help in the place where you’re asking for help… I hate to have been rude.