Manipulating Objects Using Cursor
by Michael Perry · in Torque Game Engine · 09/28/2006 (8:42 am) · 13 replies
Greetings everyone! I want to have the WorldEditor's ability of selecting, rotating, and moving game objects. However, I want to do this from a 1st person perspective and I don't want to use gizmos. I'm trying to achieve game play similar to Oblivion, using a hand cursor to grab and manipulate objects. I've successfully implemented Dave Myers's Object Selection resource into my game (great resource btw). Following examples from the WorldEditor class, I can now rotate objects in place. Unfortunately, I'm having some problems getting the repositioning to occur. Here's what I've done:
1) Created a new class called CustomSelector, which is identical to the WorldEditor::Selection() class found in engine/editor/worldEditor.h/cpp. It has the same functions and variables, just a different name. CustomSelector is also a singleton, so I can instantiate it wherever I need it and it will still have the object I've selected.
2) In engine/game/gameConnection.cpp, after modifying it using Dave' resource, I add the selected object to my CustomSelector's internal list.
3) I modified GameTSCtrl to contain functions and variables needed to use CustomSelector and perform manipulations, similarly to how WorldEditor uses the Selection class. Most new functions and variables are identical to those found in the WorldEditor class such as on3DMouseDragged, mGridSize, ect. I've stripped out functionality I don't need, but there is something that is messing up the variables I'm passing to my CustomSelector::offset(Point3f&) function. I'll post the code I've copied from WorldEditor into GameTSCtrl in my next post, and hopefully someone will be able to point out the obvious mistake I'm making =) Once everything is fixed, I'll post as a resource if anybody wants it.
1) Created a new class called CustomSelector, which is identical to the WorldEditor::Selection() class found in engine/editor/worldEditor.h/cpp. It has the same functions and variables, just a different name. CustomSelector is also a singleton, so I can instantiate it wherever I need it and it will still have the object I've selected.
2) In engine/game/gameConnection.cpp, after modifying it using Dave' resource, I add the selected object to my CustomSelector's internal list.
3) I modified GameTSCtrl to contain functions and variables needed to use CustomSelector and perform manipulations, similarly to how WorldEditor uses the Selection class. Most new functions and variables are identical to those found in the WorldEditor class such as on3DMouseDragged, mGridSize, ect. I've stripped out functionality I don't need, but there is something that is messing up the variables I'm passing to my CustomSelector::offset(Point3f&) function. I'll post the code I've copied from WorldEditor into GameTSCtrl in my next post, and hopefully someone will be able to point out the obvious mistake I'm making =) Once everything is fixed, I'll post as a resource if anybody wants it.
About the author
Programmer.
#4
Then if you needed depth movement, you add a control that lets you extend or retract the set distance, like the telekinisis spell in Oblivion. I'm not sure if that's what you are already trying to do, but it seems the best way to handle 3d object manipulation from a first person viewpoint.
10/03/2006 (1:52 pm)
I'm really bad at math, so I have no idea what any of that stuff does. But how exactly do you want to move the object around? The simplest way I would think, is to use the vector of your original raycast that found the item. Take that vector and extend it along the distance you needed to select the item originally, and do this from wherever you move the mouse pointer around to get the endpoint to place the object at. I think that would result in you dragging the object around in a 2d controllable manner like the objects do in Oblivion (though they obviously have Havok thrown over their interactions). Then if you needed depth movement, you add a control that lets you extend or retract the set distance, like the telekinisis spell in Oblivion. I'm not sure if that's what you are already trying to do, but it seems the best way to handle 3d object manipulation from a first person viewpoint.
#5
10/24/2006 (10:37 am)
Thanks again for all the input everyone. I stepped away from this part of the project to work on some other tasks, which luckily gave me time to let my brain relax. After a few minutes of staring at the code, and putting a crap-ton of printouts, I fixed all my math woes and have achieved what I wanted. I'm one step closer to a complete mission editor. As I've stated in other posts, when I have everything smoothed out, I'll post a resource for all to enjoy.
#6
[EDIT]
Dear inspectPostApply(),
You are wonderful. You once again have fixed my problems
[i][/EDIT][i]
10/25/2006 (12:39 pm)
So, I've run into a bug that the WorldEditor suffers from. I thought I was moving an object around, but when I open the WorldEditor, it pops back into it's original spot, like I never made any changes. The bug is fixed in TGE 1.5, but I can't download my copy right now due to slow connections and download speed (yes I read Ben's post, and I can wait patiently to apply the fix later). I'm so close and frustrated, but I can't help but laugh =)[EDIT]
Dear inspectPostApply(),
You are wonderful. You once again have fixed my problems
[i][/EDIT][i]
#7
10/27/2006 (7:26 am)
Please link your resource here so folks following this thread can find it easily. Thanks for the work you've done, this should be really helpful to alot of people.
#8
Here's what I got so far:
Current Bugs:
Future Features:
Possible Implementations:
The future is looking exciting =)
10/27/2006 (7:48 am)
You got it! I didn't think anyone was actually reading this anymore, since I keep solving the problems.Here's what I got so far:
1. Selecting an object using mouse cursor 2. Highlighting selected object 3. Dragging and rotating selected object around screen 4. Displaying animated/3D disembodied hand in the world representing cursor (like Black and White)
Current Bugs:
1. 3D Hand & Selected Object don't "play nice", fight for positioning 2. Highlighting uses debug bounding box, which doesn't display properly with scaled objects. Need to use lighting based method. 3. Rotation is way too fast, and offset variable for rotation amount is not being resest. 4. Translate occasionally skips
Future Features:
1. Multiple selection of objects (exists, just need to implement) 2. De-select objects (exists, just need to implement) 3. Moving interiors (not sure if I should even try, but might be fun) 4. Applying physics to movements, like Black & White or Oblivion.
Possible Implementations:
1. Use in my [url=http://www.garagegames.com/mg/forums/result.thread.php?qt=51911]Custom Mission Editor[/url] 2. Player interaction with world objects for all kits (FPS, RTS, ect) 3. Motion based games (if you have a P5)
The future is looking exciting =)
Quote:
Read. Read Code. Code
#9
10/27/2006 (8:32 am)
Well, you definitely have one person reading it. I can see how this functionality could be useful in many different types of projects.
#10
i'm not very good in programming and i want to add "dragging selection object" feature in my game,thanks
08/09/2009 (10:40 pm)
can you post it as resources?i'm not very good in programming and i want to add "dragging selection object" feature in my game,thanks
#11
Oh, and url's don't work inbetween code tags.
Custom Mission Editor
08/10/2009 (7:17 am)
I'm watching this. :-)Oh, and url's don't work inbetween code tags.
Custom Mission Editor
#12
You do realize that you just dug up two of Mich's threads in a row that are 3 years old right?
08/10/2009 (8:06 am)
@MikeYou do realize that you just dug up two of Mich's threads in a row that are 3 years old right?
Employee Michael Perry
ZombieShortbus
In GameTSCtrl.cpp: // Dave's resource told me to put this in void GameTSCtrl::onMouseDown(const GuiEvent &evt) { MatrixF mat; Point3F vel; [b]mMouseDown = true; // Toggle tracks if mouse button was pressed down mouseLock(); // defined in GuiControl.cpp, let's me jump into 3DMouse ops mHitMousePos = evt.mousePoint;[/b] // Track where the mouse was clicked on screen ... // The rest of the function contains code from Dave's resource } // New mouse event not usually found in GameTSCtrl [b]void GameTSCtrl::onMouseDragged(const GuiEvent &event) { make3DMouseEvent(mLastEvent, event); // Copied from WorldEditor on3DMouseDragged(mLastEvent); // New mouse event not usually called in GameTSCtrl } [/b] // *NOTE*: EVERYTHING BELOW THIS LINE IS NEW CODE // SO I'M NOT GOING TO USE BOLD, EXCEPT WHERE MY PROBLEM IS void GameTSCtrl::on3DMouseDragged(const Gui3DMouseEvent2 & event) { // Instantiate my CustomSelector class CustomSelector* mSelector = CustomSelector::Instance(); mLastRotation = 0.f; // Get centroid, extract the Euler, and find out what object we are manipulating mHitCentroid = mSelector->getCentroid(); mHitRotation = extractEuler(mSelector->getObjByIndex(0)->getTransform()); mHitObject = mSelector->getObjByIndex(0); // If the object exists, let's do stuff to it if(mSelector[0].getId()) { // Determine the current movement mode based on the modifiers: if( event.modifier & SI_ALT ) { // it's either rotate or scale // probably rotate more often... so rotate = ALT, scale = ALT CTRL if(event.modifier & SI_CTRL) mCurrentMode = Scale; // Probably won't be using this else mCurrentMode = Rotate; } else mCurrentMode = Move; // Are we moving or rotating, let's make a stripped down switch statement similiar to // what is found in WorldEditor::on3DMouseDragged(), starting at line 2038 of worldEditor.cpp switch(mCurrentMode) { [b] case Move: { CollisionInfo info; collide(event, info); mHitInfo = info; F32 cos = mDot(event.vec, Point3F(0,0,-1)); F32 a = event.pos.z - mHitInfo.pos.z; mHitOffset = mHitInfo.pos - mSelector->getCentroid(); setCursor(HandCursor); if(cos != 0.f) { F32 c = a / cos; Point3F projPnt = event.vec * c; projPnt += event.pos; projPnt -= mHitOffset; // F32 z = projPnt.z; // *NOTE* before I started using snapPoint // the in game object would just shake a little in place // after inplementing snapPoint, the object WOULD // move noticeably once, then start shaking projPnt = snapPoint(projPnt); projPnt.z = z; mSelector->offset(projPnt - mSelector->getCentroid()); updateClientTransforms(*mSelector); } break; }[/b] case Rotate: { // default to z axis S32 axis = 2; F32 angle = (event.mousePoint.x - mHitMousePos.x) * mMouseRotateScale; EulerF rot(0.f, 0.f, 0.f); ((F32*)rot)[axis] = (angle - mLastRotation); Point3F centroid = mSelector->getCentroid(); mSelector->rotate(rot, centroid); updateClientTransforms(*mSelector); mLastRotation = angle; break; } } } }For debug purposes, I've been printing out what I've been passing into mSelector->offset(). Here are my most recent results. Notice how the first attempt to move is a success, then the remainder of the results aren't working out.
Offset: -3.182114 3.789185 0.000000 <==== GOOD
Offset: 0.000000 0.000000 0.000000 <==== Bad
Offset: -0.000511 -0.012222 0.000000 <==== Bad
Offset: -0.000694 -0.016632 0.000000
Offset: 0.000004 0.000000 0.000000
Offset: 0.031898 -0.074219 0.000000
Offset: 0.007164 -0.009583 0.000000
Offset: 0.000000 0.000000 0.000000
Offset: -0.002197 0.000198 0.000000
Offset: 480.000000 -970.000000 0.000000 <==== YIKES!!!!!
Offset: 420.000000 -880.000000 0.000000
Offset: 380.000000 -820.000000 0.000000
Offset: 330.000000 -750.000000 0.000000
Offset: 330.000000 -750.000000 0.000008
Offset: 300.000000 -710.000000 0.000000
*EDITS for code formatting*
[10/25/06]
I wouldn't follow this code since it does not work properly, I'll post the proper stuff in my resource when it's done.
[10/25/06]