AI Control Object - SetAimObject
by Jonathan Noyola · in Torque Game Engine · 01/28/2010 (1:05 am) · 21 replies
I have the game set up to spawn an AIPlayer as the player. It is set up to be the client's control object, which all works fine.
My game is a 3rd person rpg, so when I click on an object, I want my player to turn towards it, then possibly walk closer/attack/use.
The problem is that I can't get any of the AIPlayer functionality out of my player. None of the methods work, specifically the setAimObject, because that's the one I'm working with right now.
I've called it from the console as the following:
player1.setaimobject(1956); "AIPlayer Object.setaimobject(another AIPlayer Object);"
1941.setaimobject(1956); "Client object.setaimobject(AIPlayer object);"
ServerConnection.getcontrolobject.setaimobject(1956);
I don't know what the problem is. Can someone please help me.
EDIT: When I call getaimobject(), it echoes the correct object, so the problem is the player just doesn't turn around.
My game is a 3rd person rpg, so when I click on an object, I want my player to turn towards it, then possibly walk closer/attack/use.
The problem is that I can't get any of the AIPlayer functionality out of my player. None of the methods work, specifically the setAimObject, because that's the one I'm working with right now.
I've called it from the console as the following:
player1.setaimobject(1956); "AIPlayer Object.setaimobject(another AIPlayer Object);"
1941.setaimobject(1956); "Client object.setaimobject(AIPlayer object);"
ServerConnection.getcontrolobject.setaimobject(1956);
I don't know what the problem is. Can someone please help me.
EDIT: When I call getaimobject(), it echoes the correct object, so the problem is the player just doesn't turn around.
About the author
I've been programming for 10 years now. Proficient in many programming languages. Stanford '16: BS CS, BS Math, MS CS (Artificial Intelligence). Favorite games: GW2, LoL, Borderlands, NWN2
#2
Sadly, I could not find the original forum I retrieved this function from. In either case, it is pretty straight forward. It forces an object to look at another by altering the looking object's transformation. Sadly, since it is a one time thing, for true locking on this script would have to be called multiple times.
EDIT:
I didn't quite address this, but the lookAtTarget does not change the player's pitch, so the player won't change how far up or down he/she is looking.
EDIT: EDIT:
I might have something that might help that, though... but it is even less sophisticated.
01/28/2010 (2:36 am)
Aha. A couple of years ago I got this function from the forums (back when it was garagegames ;) ).function lookAtTarget( %this, %target)
{
//echo(%target.getTransform());
%targetVector = getWords(%target.getTransform(), 0, 2);
//echo("TargetVector is:" SPC %targetVector);
%thisVector = getWords(%this.getTransform(), 0, 2);
//echo("My Vector is:" SPC %thisVector);
%forward = VectorSub(%targetVector, %thisVector);
//echo("Resulting Vector:" SPC %forward);
%x = getWord(%forward, 0);
%y = getWord(%forward, 1);
%angle = -mAtan(-%x, %y);// returns angle in radians
// make trans from position, axis and angle
%trans = getWords(%this.getTransform(), 0, 2);
%trans = %trans SPC "0 0 1" SPC %angle;
%this.setTransform(%trans);
}Sadly, I could not find the original forum I retrieved this function from. In either case, it is pretty straight forward. It forces an object to look at another by altering the looking object's transformation. Sadly, since it is a one time thing, for true locking on this script would have to be called multiple times.
EDIT:
I didn't quite address this, but the lookAtTarget does not change the player's pitch, so the player won't change how far up or down he/she is looking.
EDIT: EDIT:
I might have something that might help that, though... but it is even less sophisticated.
#3
This code is actually mine, for once. It is a bit wrong in that I didn't make the SmoothMoving function a client command, but aside from that it should work. This function can give you the power to force the look to be immediate or slow, whatever you like. It does move the pitch of the player so that the cursor should line up with the object, but, once again, it won't stay locked, so if the object moves, you look at nothing important.
EDIT: Took my own advice and just changed it SmoothMoving to clientCmd. And actually added client to function call.
01/28/2010 (2:45 am)
function ClientPlayerLookAtPoint(%player, %point, %time, %fps)
{
if(%fps == 0)
%fps = 12;
%count = getWordCount(%point);
if(%count == 1)
{
if(isObject(%point))
{
echo("Getting Object Position...");
%point = %point.getWorldBoxCenter();
}
}
else if(%count == 3)
{
%point = %point;
echo("Using Given Point...");
}
else
{
%point = "0 0 0";
echo("Using Origin as Point...");
}
%eyevec = %player.getEyeVector();
%eyepoint = %player.getEyePoint();
%result = VectorNormalize(VectorSub(%point, %eyepoint));
%bvec = VectorNormalize(getWords(%result,0,1) SPC 0);
%bEyeVec = VectorNormalize(getWords(%eyevec,0,1) SPC 0);
%bAngle = mAcos(VectorDot(VectorNormalize(%bvec), VectorNormalize(%bEyeVec)));
if(mAcos(VectorDot(RotateVector(%bvec,"0 0" SPC %bAngle/100), %bEyeVec)) > %bAngle)
%bAngle *= -1;
%AngleA = mAcos(VectorDot(%eyevec,VectorNormalize(setWord(%eyevec,2,0))));
if(getWord(%eyevec,2) < 0)
%AngleA *= -1;
%AngleB = mAcos(VectorDot(%result,VectorNormalize(setWord(%result,2,0))));
if(getWord(%result,2) < 0)
%AngleB *= -1;
echo("AngleA: " @ %AngleA);
echo("AngleB: " @ %AngleB);
%reps = mCeil(%time / 1000 * %fps);
%times = mCeil(%time/%reps);
echo(%time);
echo(%fps);
commandToClient(%player.client,'SmoothMoving',(-1 * (%AngleB - %AngleA))/%reps, %bAngle/%reps,%reps,%times);
}
function clientCmdSmoothMoving(%pitch, %yaw, %reps, %times)
{
$mvPitch += %pitch;
$mvYaw += %yaw;
%reps--;
if(%reps <= 0)
return;
schedule(%times, 0, SmoothMoving, %pitch, %yaw, %reps, %times);
}This code is actually mine, for once. It is a bit wrong in that I didn't make the SmoothMoving function a client command, but aside from that it should work. This function can give you the power to force the look to be immediate or slow, whatever you like. It does move the pitch of the player so that the cursor should line up with the object, but, once again, it won't stay locked, so if the object moves, you look at nothing important.
EDIT: Took my own advice and just changed it SmoothMoving to clientCmd. And actually added client to function call.
#4
01/28/2010 (5:30 am)
If you're setting the AIPlayer as the client's control object, then the client's move values are getting sent to the AIPlayer, overriding all its AI stuff. Try removing any references to setControlObject relating to your AIPlayer.
#5
@ Daniel: I don't really understand. I removed the setControlObject call in GameConnection::CreatePlayer, but then the game wouldn't play. It finished loading, but just sat there with the loading bar full. Also, how will the game know who I'm controlling if I remove this command?
Thank you both for the help
01/28/2010 (7:39 pm)
@ Michael: Thank you for the functions. I will definitely use those. Even if I can get this problem fixed another way, I know I have other uses for those functions.@ Daniel: I don't really understand. I removed the setControlObject call in GameConnection::CreatePlayer, but then the game wouldn't play. It finished loading, but just sat there with the loading bar full. Also, how will the game know who I'm controlling if I remove this command?
Thank you both for the help
#6
The idea of a 'control object' is that the object you specify will receive move input from one client - move inputs being which keys are pressed, where the mouse is moving, etc. These inputs are sent even if you're not pressing any keys and the mouse is stationary. And the Player class will only let the AI routine have a go at navigating if there is no move coming from its controller - i.e., if there isn't a controller. It would be easier to show you if you had the source code.
EDIT: Are you using TGE or T3D? There's a good tutorial on creating the sort of gameplay you're after for T3D - I'm not sure how much of it applies to TGE, but most of the gameplay stuff should be applicable. Just go to the documentation link in the 'support' header menu.
01/28/2010 (7:45 pm)
Hmm, sorry, I guess that makes sense. You do need a control object to play - but if you want the AIPlayer to be AI-controlled, the AIPlayer can't be the control object. So set the control object to be the camera instead (%this.camera in GC::createPlayer).The idea of a 'control object' is that the object you specify will receive move input from one client - move inputs being which keys are pressed, where the mouse is moving, etc. These inputs are sent even if you're not pressing any keys and the mouse is stationary. And the Player class will only let the AI routine have a go at navigating if there is no move coming from its controller - i.e., if there isn't a controller. It would be easier to show you if you had the source code.
EDIT: Are you using TGE or T3D? There's a good tutorial on creating the sort of gameplay you're after for T3D - I'm not sure how much of it applies to TGE, but most of the gameplay stuff should be applicable. Just go to the documentation link in the 'support' header menu.
#7
I'm call the following on the server side:
commandToClient(%client,'SmoothMoving',(-1 * (%AngleB - %AngleA))/%reps, %bAngle/%reps,%reps,%times);
All of the variables are defined. The function is on the client side.
The error I'm getting is:
serverCmdSmoothMoving: Unknown command.
For some reason it thinks I'm calling a serverCmd!
01/28/2010 (8:24 pm)
I'm having another problem with this.I'm call the following on the server side:
commandToClient(%client,'SmoothMoving',(-1 * (%AngleB - %AngleA))/%reps, %bAngle/%reps,%reps,%times);
All of the variables are defined. The function is on the client side.
The error I'm getting is:
serverCmdSmoothMoving: Unknown command.
For some reason it thinks I'm calling a serverCmd!
#8
01/28/2010 (8:27 pm)
Honestly I'm not really sure which one I'm using, if you could tell me how to find out, I could do that.
#9
For the player object I would rather try to do it this way, than to use the other "cheating" functions, because this way I can use all AIPlayer methods.
01/28/2010 (8:32 pm)
If I wanted to set the control object to the camera so I can use AIPlayer methods (which does work), then is there any way to still be able to control the player with the keyboard?For the player object I would rather try to do it this way, than to use the other "cheating" functions, because this way I can use all AIPlayer methods.
#10
EDIT: Wait.. the server problem might be linked with what client you are calling. In my original function, there is no "%client" variable, so the client would actually be on "%player.client"
01/28/2010 (8:48 pm)
hmm... I am not sure when it thinks it is a server function... I know that one thing I found out that you might want to be aware of is that, if you set the control object to the camera, then any health bar or energy bar on the player interface will always show empty.EDIT: Wait.. the server problem might be linked with what client you are calling. In my original function, there is no "%client" variable, so the client would actually be on "%player.client"
#11
01/28/2010 (8:50 pm)
I do not believe that you can have the camera as the control object AND the $mv variables apply to the character... This might be a problem for one of the advanced camera resources.
#12
EDIT: I did define %client, that's not the problem
01/28/2010 (9:01 pm)
I actually redid the health and energy system, so that will work fine after a few changes. Something I'm noticing, though, is that I'm having to change all of my ServerConnection's to LocalClientConnection. I don't think this will work multiplayer. Do you know if LocalClientConnection will work if I only use it client-side?EDIT: I did define %client, that's not the problem
#13
As it stands, you could use the WASD keys to send commandToServer functions to the server, and in those commands set the AIPlayer's movement destination to somewhere extremely north, south, east or west. Basically somewhere far enough away that you appear to be moving in a compass direction. This method would take a lot of tweaking to get right, but it should work, ish.
01/28/2010 (10:01 pm)
Quote:If I wanted to set the control object to the camera so I can use AIPlayer methods (which does work), then is there any way to still be able to control the player with the keyboard?Yes - if you have the source code :P.
As it stands, you could use the WASD keys to send commandToServer functions to the server, and in those commands set the AIPlayer's movement destination to somewhere extremely north, south, east or west. Basically somewhere far enough away that you appear to be moving in a compass direction. This method would take a lot of tweaking to get right, but it should work, ish.
#14
Quick Q:
Previously, I was referring to my player as ServerConnection.getControlObject(), but since I can't do that anymore, what do you recommend I do?
EDIT: "ServerConnection.player" doesn't work. For some reason, when it sets the "player", it uses LocalClientConnection, but as I am making a multiplayer game, I can't use "LocalClientConnection.player"
EDIT: By the way, the WASD control system won't be as bad as you described, because the direction will be relative to the player, so I can use getForwardVector(), etc. to make it work correctlty.
01/28/2010 (10:06 pm)
Yes, I will do your 2nd suggestion. That one seems to suit me right now. Especially because I'm trying to do as much of this by myself as I can.Quick Q:
Previously, I was referring to my player as ServerConnection.getControlObject(), but since I can't do that anymore, what do you recommend I do?
EDIT: "ServerConnection.player" doesn't work. For some reason, when it sets the "player", it uses LocalClientConnection, but as I am making a multiplayer game, I can't use "LocalClientConnection.player"
EDIT: By the way, the WASD control system won't be as bad as you described, because the direction will be relative to the player, so I can use getForwardVector(), etc. to make it work correctlty.
#15
01/29/2010 (7:50 pm)
Quote:"ServerConnection.player" doesn't work. For some reason, when it sets the "player", it uses LocalClientConnection, but as I am making a multiplayer game, I can't use "LocalClientConnection.player"Hmm. In game.cs, in createPlayer, it sets %this.player. To refer to a player on the server, you'd need to use the client connection object... I'm not sure how you'd do this arbitrarily short of looping through the client group, but if you want the player in a commandToServer, the client is already passed as one of the parameters of the function.
function serverCmdMovePlayer(%client,%dir)
{
%player = %client.player;
//Do stuff
#16
but how can I refer to the player on the client side?
Would the following work?
01/29/2010 (10:07 pm)
That will work for the server side,but how can I refer to the player on the client side?
Would the following work?
function serverCmdReturnPlayerName(%client)
{
return %client.player.getName();
}
#17
01/29/2010 (11:56 pm)
Why would you need to reference the player on the client side?
#18
01/30/2010 (3:31 am)
I had certain variables that were properties of the player (like experience), but I guess I could do this another way.
#19
As for letting the client know who it's in control of, for whatever purpose (maybe creating client-side visual effects, who knows) you could send a commandToClient whenever the server assigns them an AIPlayer, with the ghost ID of the AIPlayer.
01/30/2010 (10:01 pm)
You shouldn't store experience on the client anyway - players could 'cheat' by modifying the values. If you're working on just a single-player game the effect isn't so important, but it's still good practice to give the server authority over any sensitive information, and only transmit it to the client when necessary (for example, if you wanted a GUI to display your experience points, the client would ask the server how many experience points it has - but never tells the server how many points it has).As for letting the client know who it's in control of, for whatever purpose (maybe creating client-side visual effects, who knows) you could send a commandToClient whenever the server assigns them an AIPlayer, with the ghost ID of the AIPlayer.
#20
01/31/2010 (2:05 am)
That makes sense, thanks.
Michael Ruben Lugo
There is one other, less sophisticated solution... let me find it...