Vector help
by Adam Beer · in Torque 3D Professional · 10/13/2014 (1:32 pm) · 7 replies
Im in the middle of creating a builder system for my game Undead Shadows, and am having some issues with the math behind it all. I want the player to be able to place planks of wood/metal around windows and doors or between anything that can touch both sides of the planks.
My issue is getting the vector math right for all of this. I have the plank floating 2 meters in front of the player and its heights and rotation is correct based on the eye vector, however I want to do a raycast from each end of the plank to check for correct placement in windows and doors. Here is a crappy diagram of what I'm trying to accomplish:

With the current code, I am just doing a raycast from the left side but when I rotate around start point of the raycast is incorrect. Here is the code:
I am not good with vector math so this may be something really easy. Anyone have and advice on how to accomplish these raycasts properly? Thanks!
My issue is getting the vector math right for all of this. I have the plank floating 2 meters in front of the player and its heights and rotation is correct based on the eye vector, however I want to do a raycast from each end of the plank to check for correct placement in windows and doors. Here is a crappy diagram of what I'm trying to accomplish:

With the current code, I am just doing a raycast from the left side but when I rotate around start point of the raycast is incorrect. Here is the code:
function checkClientBuilderSnap()
{
// Player Object
%this = ServerConnection.getControlObject();
%eyeVec = %this.getEyeVector();
%eyeTrans = %this.getEyeTransform();
%eyeTrans = VectorAdd("-1 0 0", %eyeTrans);
// extract the position of the player's camera from the eye transform (first 3 words)
%eyePos = getWord(%eyeTrans, 0) SPC getWord(%eyeTrans, 1) SPC getWord(%eyeTrans, 2);
// normalize the eye vector
%nEyeVec = VectorNormalize(%eyeVec);
// scale (lengthen) the normalized eye vector according to the search range
%scEyeVec = VectorScale(%nEyeVec, 2);
// add the scaled & normalized eye vector to the position of the camera
%eyeEnd = VectorAdd(%eyePos, %scEyeVec);
%raycast = containerRayCast(%eyePos, %eyeEnd, $TypeMasks::StaticObjectType, $builderDummyobj);
if(%raycast != 0)
{
%rot = getWords(%trans, 3, 6);
// $builderDummyObj is the client-side object we use as a placement checker
$builderDummyObj.setTransform(getWords(%raycast, 1, 3) SPC %rot);
return true;
}
else
return false;
}I am not good with vector math so this may be something really easy. Anyone have and advice on how to accomplish these raycasts properly? Thanks!
About the author
Adam is the owner of Ignition Games, an indie game and software development company.
#2
10/13/2014 (4:31 pm)
Thanks for the reply Richard! Unfortunately that line doesnt affect the position of the raycast, but thank you for pointing that one out! I should revise my code here; the reason I know the raycast is off is because I have another dummy object that uses the octahedron shape to show me where the raycast start position is:function checkClientBuilderSnap()
{
if(isObject($builderDummyobjL))
$builderDummyobjL.delete();
$builderDummyobjL = new StaticClientShape()
{
datablock = "ClientBuilderDummy";
};
// Player Object
%this = ServerConnection.getControlObject();
// Transform of the player object
%trans = %this.getTransform();
%eyeVec = %this.getEyeVector();
%eyeTrans = %this.getEyeTransform();
%eyeTrans = VectorAdd("-1 0 0", %eyeTrans);
// extract the position of the player's camera from the eye transform (first 3 words)
%eyePos = getWord(%eyeTrans, 0) SPC getWord(%eyeTrans, 1) SPC getWord(%eyeTrans, 2);
// normalize the eye vector
%nEyeVec = VectorNormalize(%eyeVec);
// scale (lengthen) the normalized eye vector according to the search range
%scEyeVec = VectorScale(%nEyeVec, 2);
// add the scaled & normalized eye vector to the position of the camera
%eyeEnd = VectorAdd(%eyePos, %scEyeVec);
// -------------------------
$builderDummyobjL.setTransform(%eyeEnd); // <----- the %eyeEnd isnt being setup properly
// -------------------------
%raycast = containerRayCast(%eyePos, %eyeEnd, $TypeMasks::StaticObjectType, $builderDummyobj);
if(%raycast != 0)
{
%rot = getWords(%trans, 3, 6);
$builderDummyObj.setTransform(getWords(%raycast, 1, 3) SPC %rot);
return true;
}
else
return false;
}
#3
It starts off correct when I dont turn at all:

But when I turn 90 degrees or 270 degrees, the position is in front/behind the plank:
10/13/2014 (4:41 pm)
Here is whats happening visually:It starts off correct when I dont turn at all:

But when I turn 90 degrees or 270 degrees, the position is in front/behind the plank:
#4
10/17/2014 (5:26 pm)
Anyone have any ideas?
#5
At first glance, I noticed that you are creating a new 'StaticClientShape' object which must be a new object type that you created. I would imagine you did this so that the placement 'Dummy' object would only be for the client to see.
My guess is that in your new object's .cpp file you don't have any sort of ghosting at all taking place and the object needs a 'transform' flag to network the transform information in pack/unpackUpdate().
EDIT: I actually messed around with this a bit this evening and got a working implementation of it using a StaticShape object. Feel free to contact me if interested =)
11/07/2014 (11:05 am)
Did you ever make any progress on this Adam? It's pretty interesting and there are several ways this could be useful for build/survival type games.At first glance, I noticed that you are creating a new 'StaticClientShape' object which must be a new object type that you created. I would imagine you did this so that the placement 'Dummy' object would only be for the client to see.
My guess is that in your new object's .cpp file you don't have any sort of ghosting at all taking place and the object needs a 'transform' flag to network the transform information in pack/unpackUpdate().
EDIT: I actually messed around with this a bit this evening and got a working implementation of it using a StaticShape object. Feel free to contact me if interested =)
#6
Because its derived from ShapeBase I stuck an eye node to one end of the plank and a mount0 node to the other and was able to get the position of each end using getEyePoint() and getSlotTransform(0) which was the start point for my raycasts.
The only thing I have left to do is calculating the angle the plank needs to be at if both raycasts from each edge hit.
11/07/2014 (1:59 pm)
I actually got most of it working the way I want with a little out of the box approach. You are correct, the StaticClientShape class is a copy a StaticShape so its derived from shapebase. The only changes were to the netFlags, I cleared the ScopeAlways and Ghostable so its a true client side object.Because its derived from ShapeBase I stuck an eye node to one end of the plank and a mount0 node to the other and was able to get the position of each end using getEyePoint() and getSlotTransform(0) which was the start point for my raycasts.
The only thing I have left to do is calculating the angle the plank needs to be at if both raycasts from each edge hit.
#7
11/07/2014 (3:15 pm)
Nice man, good idea about the mounts. Glad you got it working!
Torque Owner Richard Ranft
Roostertail Games
function checkClientBuilderSnap() { // Player Object %this = ServerConnection.getControlObject(); %eyeVec = %this.getEyeVector(); %eyeTrans = %this.getEyeTransform(); %eyeTrans = VectorAdd("-1 0 0", %eyeTrans); // extract the position of the player's camera from the eye transform (first 3 words) %eyePos = getWord(%eyeTrans, 0) SPC getWord(%eyeTrans, 1) SPC getWord(%eyeTrans, 2); // normalize the eye vector %nEyeVec = VectorNormalize(%eyeVec); // scale (lengthen) the normalized eye vector according to the search range %scEyeVec = VectorScale(%nEyeVec, 2); // add the scaled & normalized eye vector to the position of the camera %eyeEnd = VectorAdd(%eyePos, %scEyeVec); %raycast = containerRayCast(%eyePos, %eyeEnd, $TypeMasks::StaticObjectType, $builderDummyobj); if(%raycast != 0) { // ---------------------------------------------------------------------- %rot = getWords(%trans, 3, 6); // <----- %trans is undefined.... // ---------------------------------------------------------------------- // $builderDummyObj is the client-side object we use as a placement checker $builderDummyObj.setTransform(getWords(%raycast, 1, 3) SPC %rot); return true; } else return false; }Not sure if that'll fix it exactly, but it looks like that is not what you intended.