Game Development Community

Creating a link point at the point of collision?

by Corey Martin · in Torque Game Builder · 03/15/2005 (5:19 pm) · 14 replies

What would be the best way to go about creating a link point on the destination object of a collision at the point of collision with the source object? In other words, if a projectile were to collide with a player (with the projectile being the source of the collision and the player being the destination of the collision), what would be the best way of creating a link point on the player where the the two of them collided? Currently, inside the onCollision callback, I am subtracting the vector of the collision point from the destination objects (which would be our player) position, and normalising it. This is not an optimal solution, I realize. Any enlightment would be greatly appreciated!

#1
03/16/2005 (1:02 am)
No problem.

The collision point will be the contact point which is passed when the collision occurs.

Assuming "%contactPoint" is your point of collision between objects "%srcObj" and "%dstObj"...

%srcObj.mount( %dstObj, %dstObj.getLocalPoint(%contactPoint) );

"getLocalPoint()" converts a world-position into a local (object) position for a specific object. This takes factors such as the objects position, size and rotation into account for you automagically.

Hope this helps,

- Melv.
#2
03/16/2005 (4:53 am)
Thanks much for the reply! This helps a lot with pointing me in the right direction.

My next problem is that getLocalPoint doesn't seem to be returning proper values. Here are some of my results:

When %dstObj is at the coords 44.666248 0.00000
Contact point is 47.7500000 0.000000
%dst.getLocalPoint returns 18.483250 0.0000000

Any idea why i'm getting these bad values?

Edit: I spoke to someone in the #torque2d irc channel and he also claimed to be having trouble with getLocalPoint not returning the expected results (between -1 and 1). Perhaps something fishy is afoot?

Edit2:
I ran a few more tests, to see what kind of values I was getting.

$player.getPosition() = 0.000 0.000
$player.getLocalPoint( "0 5" ) will yield "0 1"
$player.getLocalPoint("0 10") will yield "0 2"
$player.getLocalPoint("0 20") will yield "0 4"
$player.getLocalPoint("20 0") will yield "4 0"
#3
03/16/2005 (6:39 am)
What size is your object? 10x10? If so, those values are correct.

If your object is sized 10x10 and its position is (0,0) then the lower middle mount point is "0 1" which would be at (0,5) in the world.

- Melv.
#4
03/16/2005 (6:41 am)
-------

edit: checking for accuracy, first
#5
03/17/2005 (4:37 am)
Sorry to keep bringing this one up, but i'm simply not yielding proper results from getLocalPoint. here is my current scenario:

All I have is a player set up with the standard PlayerMoveUp() PlayerStopMoveUp() type functions to allow you to move on screen. In the stop movement functions, I have an echo spit out two things. First, it spits out the position of the $player, and second, it spits out $player.getLocalPoint( "45.75 0.00" ), which is just to the right of the players starting position. Thus, everytime you press a movement key and stop, and check your console, you should see your position coords, and the local point position of 45.7500 0.00. Now, as I pointed out, I tried this test with "0 0" (and it WAS a size 10 10 object) and it seemed fine. Now, again with a size 10 10 object, here are the results i get with 45.75 0.00

$player = 0 0
local point for 45.75 0.00 = 9.550 0.00

$player = 40.167397 0.0
local point for 45.75 0.00 = 17.583 0.00
*** This one isn't even CLOSE! And its RIGHT NEXT TO IT! This is why I believe getLocalPoint is throwing bad values. It gets more interesting though..

$player = -45.188110 -0.8187

local point for 45.75 0.00 = 0.5123 0.7605
*** This is the really bad one. Its almost as if theres an absolute value being used somewhere it shouldn't or something. In any case, i'm not doing anything tricky at all, and have forgotten the mounting for now. I'm merely moving $player and reporting his localPosition calls relative to a static point.

Any help would be appreciated! So far I haven't been able to effectively use getLocalPoint at all :(


EDIT:
Furthering this experiment, I updated the echo functions to now change the position which is passed to getLocalPoint. In this new experiment, it grabs the position of the player, and vectorAdd's "-6 0" to it. This means that everytime getLocalPoint is called, it is being called with the position of the player -6, so it should be 6 units directly to his left. Now, logically, this should mean that im getting the same result each time from getlocalpoint, because the point is not changing relative to the player. Instead, the further I move, the further off the numbers become, simply increasing in size.
#6
03/17/2005 (5:29 am)
You may be having this fixed issue.

Be aware that the link points are only updated once per-frame. Someone mentioned that they wanted to set the position/size/rotation and instantly interrogate the link-point. Because this is a synchronous call, the link-points wouldn't have previously been updated.

If you are setting a position and then instantly interrogating a link-point then this is your current problem. It is highly inefficient for T2D to calculate all the interelated properties for an object everytime a call is made so potential updates such as these are done each frame.

I made a change to T2D (see thread above) that updated the mount/link points if a "setPosition()", "setRotation()" or "setSize()" call was made. This is not done from the related C++ calls but only if called from script. Each frame may involve several calls to these functions in C++ and would hurt performance.

The modification for the script-functions above are to make the following call in the consoleMethod...

// Update Container Configuration.
object->updateContainerConfig();

You'll see this in the next update.

Hope this helps,

- Melv.
#7
03/17/2005 (5:38 am)
I'll check into that post and see if I can glean some insight. Although, i'm not even using link points anymore, having gone straight to mount as you pointed out, and I still get bad getLocalPoint data =\. Although, the formula for obtaining a local point was explained in that post, so i'll see what happens when I implement it manually.

Edit:
I was able to put together a function for obtaining local point based on the information Josh Williams posted. It'll work for now :)
#8
03/18/2005 (9:17 pm)
I have been having problems with getLocalPoint, here is an example. to test it, add the following to client.cs from the example project from the sdk

function setupT2DScene()
{
// Create fxSceneGraph2D.
new fxSceneGraph2D(t2dSceneGraph);

// Associate Scenegraph with Window.
sceneWindow2D.setSceneGraph( t2dSceneGraph );

// Set Camera Position to be centered on (0,0) with
// view width/height of (100/80).
sceneWindow2D.setCurrentCameraPosition( "0 0 100 75" );


// ************************************************************************
//
// Add your custom code here...
//
// ************************************************************************

datablock fxImageMapDatablock2D(IMAGEMAP_BRICK)
{
mode = full;
textureName = "~/client/images/brick";
};

$brick = new fxStaticSprite2D() {scenegraph = t2dSceneGraph;};
$brick .setPosition("-20 -20");
$brick.setSize("8 8");
$brick.setImageMap(IMAGEMAP_BRICK);
}

function sceneWindow2D::onMouseMove(%this, %modifier, %worldPosition, %mouseClicks)
{
%local_point = $brick.getLocalPoint(%worldPosition);

%x = mAbs(getWord(%local_point, 0));
%y = mAbs(getWord(%local_point, 1));

if (%x < 1 && %y < 1)
{
$brick.setSize("12 12");
}
else
{
$brick.setSize("8 8");
}
}

if you test this, brick resizes when the mouse is nowhere near it and doesn't when the mouse is over it.
#9
03/18/2005 (9:36 pm)
If i roll my own checking function, it works as desired.

function sceneWindow2D::onMouseMove(%this, %modifier, %worldPosition, %mouseClicks)
{
if (isMouseOver($brick, %worldPosition))
{
$brick.setSize("12 12");
}
else
{
$brick.setSize("8 8");
}
}

function isMouseOver(%sprite, %mouse_position)
{
%sprite_x = (getWord(%sprite.getPosition(), 0) - (getWord(%sprite.getSize(), 0) / 2));
%sprite_y = (getWord(%sprite.getPosition(), 1) - (getWord(%sprite.getSize(), 1) / 2));
%sprite_w = getWord(%sprite.getSize(), 0);
%sprite_h = getWord(%sprite.getSize(), 1);

%mouse_x = getWord(%mouse_position, 0);
%mouse_y = getWord(%mouse_position, 1);

if (%mouse_x > %sprite_x && %mouse_x < (%sprite_x + %sprite_w) &&
%mouse_y > %sprite_y && %mouse_y < (%sprite_y + %sprite_h))
{
return true;
}
else
{
return false;
}
}
#10
03/19/2005 (4:34 am)
John,

You will be pleased to know that your first code submission does work with the latest T2D so expect that to work in the next update.

One thing to be cautious of is that "getLocalPoint()" also takes rotation into account which requires doing an inverse-transform of the rotation for the check.

All will be well soon. :)

- Melv.
#11
03/19/2005 (9:00 am)
Well, so far the best value i have received from buying t2d isn't t2d, it's having melv around to answer all my questions! :) thanks melv!
#12
03/19/2005 (11:50 am)
Not a problem John, glad to help. :)

- Melv.
#13
03/20/2005 (9:05 am)
Corey/John,

If you want to make this work in the meantime, you can make the minor modification I did in the engine to make it work,

The problem was in the function "fxSceneObject2D::getLocalPoint()".

Change the function to the following...
// Get Local Point.
fxVector2D fxSceneObject2D::getLocalPoint( const fxVector2D &worldPoint )
{
	fxVector2D localPoint;

	// Transform into object-space.
	inverseTransformPoint2D( getInverseRotationMatrix(), worldPoint, getPosition(), localPoint );
	// Get Object Half-Size.
	fxVector2D halfSize = getParentPhysicsModel().getHalfSize();
	// Scale Local Point by Size.
	localPoint.set( localPoint.mX / halfSize.mX, localPoint.mY / halfSize.mY );
	// Return Local-Point.
	return localPoint;
}

- Melv.
#14
03/20/2005 (9:09 am)
Woot! Thanks muchly, Melv!

I'm sure this will be a lot faster than doing it from script :)