Game Development Community

mouse move to clicked point (diablo style movement)

by Peter Mowry · in Torque 3D Professional · 05/26/2009 (12:02 am) · 25 replies

// I'm ignoring the ghost param for now...
function serverCmdTarget(%client, %mouseVec, %cameraPoint, %ghost)
{  
   echo("hello world");

   //Determine how far should the picking ray extend into the world?
   %selectRange = 200;

   // scale mouseVec to the range the player is able to select with mouse
   %mouseScaled = VectorScale(%mouseVec, %selectRange);

   // cameraPoint = the world position of the camera
   // rangeEnd = camera point + length of selectable range
   %rangeEnd = VectorAdd(%cameraPoint, %mouseScaled);
   %FirstSearchMask = $TypeMasks::InteriorObjectType;
   %SecondSearchMask = $TypeMasks::TerrainObjectType;

   // Search for objects within the range that fit the masks above. If we are
   // in first person mode, we make sure player is not selectable by setting
   // fourth parameter (exempt from collisions) when calling ContainerRayCast

   $obstruction = ContainerRayCast (%cameraPoint, %rangeEnd, %FirstSearchMask);

   if(!$obstruction)
   {
      %scanTarg = ContainerRayCast (%cameraPoint, %rangeEnd, %SecondSearchMask);
   }
   // a target in range was found so select it

   if (%scanTarg)
   {
      %targetObject = getWords(%scanTarg,1,3);

      %target = %client.ResolveGhost(%ghost);

      // I'm ignoring the ghost param for now...
      //AIManager.MovePlayer(%target, %targetobject);
      theEgg.SetMoveDestination(%moveto); 
   }
}

function helloWorld(%val)
{
   if (%val)
   {
      %coord = Playgui.getMouse3dPos();
      %vec = Playgui.getMouse3dVec();
      commandToServer('Target', %vec, %coord, theEggRobot);
      cursorOff();
   }
}

moveMap.bind( keyboard, l, helloWorld );
moveMap.bind( mouse0, "button0", helloWorld );

I did echo("hello world") to make sure it at least does get to serverCmdTarget()

I guess the general idea is I need to implement getMouse3dPos() and getMouse3dVec() in C++ code? Or can I just use something that's already in Torque 3D?

Page «Previous 1 2
#1
05/26/2009 (12:04 am)
scripts/client/default.bind.cs (601): Unknown command getMouse3dPos.
Object PlayGui(1466) PlayGui -> GameTSCtrl -> GuiTSCtrl -> GuiContainer -> GuiControl -> SimGroup -> SimSet -> SimObject
scripts/client/default.bind.cs (602): Unknown command getMouse3dVec.
Object PlayGui(1466) PlayGui -> GameTSCtrl -> GuiTSCtrl -> GuiContainer -> GuiControl -> SimGroup -> SimSet -> SimObject
scripts/client/default.bind.cs (604): Unknown command getSelectedObj.
Object ServerConnection(2361) ServerConnection -> GameConnection -> NetConnection -> SimGroup -> SimSet -> SimObject
scripts/client/default.bind.cs (606): Unknown command GetGhostIndex.
Object ServerConnection(2361) ServerConnection -> GameConnection -> NetConnection -> SimGroup -> SimSet -> SimObject
scripts/client/default.bind.cs (614): Unable to find function cursorOff

[Edit: error message is just shown to explain that getMouse3dPos() and getMouse3dVec() I guess need to be implemented yet]

-- www.garagegames.com/community/forums/viewthread/57120
-- www.garagegames.com/community/resource/view/7335/12#comments

#2
05/26/2009 (12:54 am)
Well I implemented getMouse3dPos() and getMouse3dVec() based on www.garagegames.com/community/resource/view/7335/12#comments, but no luck so far...


#3
05/26/2009 (1:05 am)
getMouse3dPos() and getMouse3dVec(), always return (0 0 0).... I think the problem is that implementing GameTSCtrl::onMouseDown() is not enough... I also have to get it to be called from somewhere?

I don't think the example is what I want though, because GuiShapeNameHud::onMouseDown() is the right place though, b/c that's for selecting objects, and I just want the getMouse3dVec() getMouse3dVec() values...

#4
05/26/2009 (6:59 am)
Peter, don't bind the click to button0. Instead, move your helloWorld() code into GameTSCtrl::onMouseDown(). The resource you linked calls that when a GameTSCtrl is clicked.

Wait, did you ONLY implement the getMouse3dPos() and getMouse3dVec(), or did you also implement this code from the resource as well:
//--------------------------------------------------------------------------
// object selection additions
//--------------------------------------------------------------------------
void GameTSCtrl::onMouseDown(const GuiEvent &evt)
{
   MatrixF mat;
   Point3F vel;

   if ( GameGetCameraTransform(&mat, &vel) )
   {
      //get the camera position
      Point3F pos;
      mat.getColumn(3,&pos);

      //take our mouse coordinates and create (x,y,z) screen coordinates
      Point3F screenPoint(evt.mousePoint.x, evt.mousePoint.y, -1);

      //take our screen coordinates and get the corresponding
      //world coordinates (this is what unproject does for us)
      Point3F worldPoint;

      if (unproject(screenPoint, &worldPoint))
      {
         mMouse3DPos = pos;

         //create a vector that points from our starting point (the
         //camera position) and heads towards our point we have chosen
         //in the world

         mMouse3DVec = worldPoint - pos;
         mMouse3DVec.normalizeSafe();

         //call client script handler
         Con::executef(this, 1, "onMouseDown");
      }
   }
}

This is where the mouse 3D pos and vec are updated.
#5
05/26/2009 (7:31 pm)
@Playlore: thank you for helping with this...

Yes I also implemented GameTSCtrl::onMouseDown() in C++ code (EnginesourceT3DgameTSCtrl.cpp). The only difference is that (Con::executef(this, 1, "onMouseDown");) didn't compile so I changed it to (Con::executef(this, "onMouseDown");)

It doesn't work though (yet). I don't know what you mean about not bounding mouse0 to my helloWorld() function... I think I need to bind it to something, because the default mouse0 shoots a rocket for Torque 3D.
#6
05/26/2009 (7:45 pm)
Btw, I'm guessing you meant PlayGui::onMouseDown() for the TorqueScript code?

scripts/gui/playGui.cs

function PlayGui::onMouseDown(%this)  
{  
   // mouseVec = vector from camera point to 3d mouse coords (normalized)  
   %mouseVec = %this.getMouse3DVec();  
  
   // cameraPoint = the world position of the camera  
   %cameraPoint = %this.getMouse3DPos();  
  
   commandToServer('Target', %mouseVec, %cameraPoint, theEgg);
   //commandToServer('SelectObject', %mouseVec, %cameraPoint);  
}

I undid the mouse0 binding too, but now the player just shoots rockets again.

#7
05/26/2009 (7:49 pm)
Also, it seems like there should be a mouse0 bind involved somewhere...
#8
05/26/2009 (7:59 pm)
No, two entirely separate systems. What happens is you're either in 'character control' mode, or you're interacting with the gui.

You need to be in GUI mode for the gameTSCtrl to receive the onMouseDown event, you should delete playGui.noCursor, and then you will get your cursor back, when you click, you'll get you onMouseDown event.

I've currently got this working for me in T3D no problems.


Edit: Give me just a sec and I'll post a resource for ya
#9
05/26/2009 (8:27 pm)
On second thought, I'll worry about a full resource later.

http://cantanogames.com/misc/gameTSMouseControl.zip

I moved the code that the resource has you put inside of GameTSCtrl and put it my own class (I do this so that I don't have to merge my code changes every time GG releases an update), so that's the first change.

Second, instead of receiving the event, and then asking for the pos and vector of the mouse, I give them to you. To use this code, change your playGui from gameTSCtrl to gameTSMouseControl, and then you can use the following function to get info,

function PlayGui::onMouseDown(%this, %modifiers, %pos, %vec)
{
    //Do whatever ya want here
    commandToServer('SelectObject', %vec, %pos);  
}

#10
05/26/2009 (8:45 pm)
What is (turn delete playGui.noCursor)?

Also, you saw that my post is asking about (diablo style click-to-move), not about (select object), not (3rd person cross-hair)?

I guess you're saying you made a generic resource for getting the mouse cursor's 3d pos and 3d vec... And that we can just PlayGui::onMouseDown() for all 3 of those scenarios, and more. If that's the case, I'll be excited to try it out :-)

#11
05/26/2009 (8:46 pm)
Btw, the tank demo video (cursor aiming) looks awesome :-)
#12
05/26/2009 (9:00 pm)
Yeah, that's the part about //Do whatever you want here

This will give you the position and vector, you can do a ray cast to find where on the terrain that hit, and send the command to move your player from there. That was a typo of 'turn delete playGui.noCursor', but you do need to delete playGui.noCursor, either go into the .GUI file and delete that line, or remove that line from within the GUIEditor (It'll be at the bottom with the rest of the dynamic variables.

And thanks, working on porting a lot more stuff.
#13
05/26/2009 (9:29 pm)
1>gameTSMouseControl.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall GameTSMouseCtrl::onMouseUp(struct GuiEvent const &)" (?onMouseUp@GameTSMouseCtrl@@UAEXABUGuiEvent@@@Z)
1>gameTSMouseControl.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall GameTSMouseCtrl::onMouseMove(struct GuiEvent const &)" (?onMouseMove@GameTSMouseCtrl@@UAEXABUGuiEvent@@@Z)

I guess there's a missing step, since GameTSMouseCtrl::onMouseUp() and GameTSMouseCtrl:: onMouseMove() are not yet implemented.

#14
05/26/2009 (9:32 pm)
Whoops, those were something I needed that I removed before uploading, sorry, updated the file: gameTSMouseControl.zip - Or you can just delete the two lines in the header file for those two functions.

Edit: This little snippet may come in handy for ya when debugging to make sure you're selecting what you think you are.

%result = ContainerRayCast (%pos, %rangeEnd, %mask);  

   if(%result)
   {
      %resultpos = getWords(%result,1,3);
      
      %pointer = new TSStatic() {
         canSaveDynamicFields = "1";
         Position = %resultpos;
         shapeName = "core/art/shapes/octahedron.dts";
      };
   }
#15
05/26/2009 (10:03 pm)
Let's say the egg is at:
echo(theegg.getposition());
637.178 585.206 49.5828

Then I click on the egg (my camera is in a diablo-esque angled camera view):
pos: 635.701 570.909 64.5831
vec: 0.073831 0.705959 -0.704394

It seems that I am close, but I think I still need to cast a ray... I guess I can't just do (theEgg.setMoveDestination(%pos);), because that's the position of the camera/mouse. I think what I want is to cast a ray from that using the vec, and collide it with the terrain.

Somehow... O:-)

#16
05/26/2009 (10:14 pm)
I wrote this, basically just copied from www.garagegames.com/community/forums/viewthread/57120/1#comment_form, but createScaledVector() and collideVecWithTerrain() are missing pieces.

function serverCmdTarget(%client, %pos, %vec, %TargType)
{
   echo("pos: ", %pos);
   echo("vec: ", %vec);
   //theEgg.setMoveDestination(%pos);
   
   // 1 Create a vector for mouse click
   //%mousePos = get3DMousePos();
   //%mouseVec = get3DMouseVec();
   
   // Create a vector(line)
   %scaleDistance = 100;
   %extendedVec = createScaledVector(%pos, %vec, %scaleDistance);
   
   // See where vector collides with terrain
   %worldPos = collideVecWithTerrain(%extendedVec);
   echo("worldPos: ", %worldPos);
   
   // Move the player
   theEgg.setMoveDestination(%worldPos);
}

#17
05/26/2009 (10:18 pm)
well I at least saw this:
%extendedVec = VectorScale(%vec, %scaleDistance);

But even if that's right, still gotta see about collideVecWithTerrain()

#18
05/26/2009 (11:17 pm)
Btw, I got it working :-)

@Tim: thanks for sharing the awesome resource :-)

(thanks also to Playlore, and others whose posts I read elsewhere)

Well lots more to figure out, but this is an awesome start :-)

#19
05/26/2009 (11:24 pm)
Oh, and since it's likely to help others, here's the rough code dump... Needs to be cleaned up, but just sharing a code reference to get it working.

function serverCmdTarget(%client, %pos, %vec, %TargType)
{
   echo("pos: ", %pos);
   echo("vec: ", %vec);
   //theEgg.setMoveDestination(%pos);
   
   //Determine how far should the picking ray extend into the world?
   %selectRange = 200;

   // scale mouseVec to the range the player is able to select with mouse
   %mouseScaled = VectorScale(%vec, %selectRange);
   
   // cameraPoint = the world position of the camera
   // rangeEnd = camera point + length of selectable range
   %rangeEnd = VectorAdd(%pos, %mouseScaled);
   %FirstSearchMask = $TypeMasks::InteriorObjectType;
   %SecondSearchMask = $TypeMasks::TerrainObjectType;
   
   // Search for objects within the range that fit the masks above. If we are
   // in first person mode, we make sure player is not selectable by setting
   // fourth parameter (exempt from collisions) when calling ContainerRayCast
   $obstruction = ContainerRayCast (%pos, %rangeEnd, %FirstSearchMask);
   //$obstruction = ContainerRayCast (%pos, %rangeEnd, %SecondSearchMask);
   echo("obstruction: ", $obstruction);
   
   // if we didn't get interior, then try terrain
   if(!$obstruction)
   {
      //%scanTarg = ContainerRayCast (%cameraPoint, %rangeEnd, %SecondSearchMask);
      %scanTarg = ContainerRayCast (%pos, %rangeEnd, %SecondSearchMask);
      echo("scanTarg: ", %scanTarg);
   }
   
   // a target in range was found so select it

   if (%scanTarg)
   {
      echo("scanTarg");
      %targetObject = getWords(%scanTarg,1,3);
      echo("targetObject: ", %targetObject);

      //%target = %client.ResolveGhost(%ghost);

      //AIManager.MovePlayer(%target, %targetobject);
      //theEgg.SetMoveDestination(%moveto); 
      theEgg.setMoveDestination(%targetObject);
   }
}

#20
05/26/2009 (11:26 pm)
And finally, here's a plug for anyone interested in joining a Torque 3D team for serious skilled part-time long-term hobby indie team game project :-)

www.garagegames.com/community/blogs/view/17191

Page «Previous 1 2