BOOK: Get closest scene objects
by Sean Monahan · in Torque X 2D · 01/17/2009 (12:49 am) · 10 replies
I'm throwing this question out to John K specifically because I'm borrowing some code from his TX book, but any insight is much appreciated.
To start, some background: I'm using an inventory management system as described in the TX book except I don't want the player to pick up items when the two collide. Instead I want the player to have to press a button (the X button on the gamepad in this case) when within range of the item. My game has limited inventory slots so I want the player to be able to make decisions about what they are picking up and when.
To this end I've created a PickUpDetectorComponent that allows me to set the range, display a "you can now pick something up" graphic when the player is in range, and do the actual pick up. This is where things get a hairy.
In the PickupDetectorComponent's ProcessTick method I'm running code very similar to the GetClosestEnemy code in TXBook (p. 198). This allows me to see if any pickups are in range and display my "pick up graphic". So that's good. Now, if the player presses the X button this code block is run:
Again, this is almost line for line from TXBook and it works...sorta. I can find pickups in range no problem, but when I compute the distance (Vector2.Distance) I always get a value that is much larger than my pickup range (with my range set to 4.0 I'll get a distance of 9.3431235).
So what's happening is the scene graph is finding pickups in range but when I compute the distance between the player and the pickup it's not in range.
All this leads me to think that SceneGraph.FindObjects finds objects that are within the specified range not object positions. What I mean, is that I think SceneGraph.FindObjects will find an object whose, say, corner may be within range but not it's position (center?).
To get around all this I cooked up the following:
Translated into English: if SceneGraph.FindObjects finds it it's good enough for me and I'll just compare differences to each other as opposed to the pickup range.
So I have a solution to my problem, which is nice (typing this post helped my figure it out!) but I still want to know what, exactly, is SceneGraph.FindObjects returning? In this case it doesn't really matter to me that my pickups are technically out of range as it looks and feels right in the game, but I could see it mattering at some future date. Plus I'm curious now.
To start, some background: I'm using an inventory management system as described in the TX book except I don't want the player to pick up items when the two collide. Instead I want the player to have to press a button (the X button on the gamepad in this case) when within range of the item. My game has limited inventory slots so I want the player to be able to make decisions about what they are picking up and when.
To this end I've created a PickUpDetectorComponent that allows me to set the range, display a "you can now pick something up" graphic when the player is in range, and do the actual pick up. This is where things get a hairy.
In the PickupDetectorComponent's ProcessTick method I'm running code very similar to the GetClosestEnemy code in TXBook (p. 198). This allows me to see if any pickups are in range and display my "pick up graphic". So that's good. Now, if the player presses the X button this code block is run:
float closest = _range;
T2DSceneObject closestPickup = null;
foreach (T2DSceneObject pickup in listPickups)
{
float distance = Vector2.Distance(SceneObject.Position,
pickup.Position);
if (distance < closest)
{
closestPickup = pickup;
}
}
return closestPickup;Again, this is almost line for line from TXBook and it works...sorta. I can find pickups in range no problem, but when I compute the distance (Vector2.Distance) I always get a value that is much larger than my pickup range (with my range set to 4.0 I'll get a distance of 9.3431235).
So what's happening is the scene graph is finding pickups in range but when I compute the distance between the player and the pickup it's not in range.
All this leads me to think that SceneGraph.FindObjects finds objects that are within the specified range not object positions. What I mean, is that I think SceneGraph.FindObjects will find an object whose, say, corner may be within range but not it's position (center?).
To get around all this I cooked up the following:
if (closestPickup != null && (distance < closest))
{
closestPickup = pickup;
closest = distance;
}
else
{
// This will happen on the first loop thru
closestPickup = pickup;
closest = distance;
}Translated into English: if SceneGraph.FindObjects finds it it's good enough for me and I'll just compare differences to each other as opposed to the pickup range.
So I have a solution to my problem, which is nice (typing this post helped my figure it out!) but I still want to know what, exactly, is SceneGraph.FindObjects returning? In this case it doesn't really matter to me that my pickups are technically out of range as it looks and feels right in the game, but I could see it mattering at some future date. Plus I'm curious now.
#2
01/19/2009 (9:40 am)
Good call on the tick count. It's added.
#3
01/19/2009 (5:12 pm)
Follow up question: how do you access the rectangle that encloses a scene object? I'm interested in this in relation to the other thread about AI vision and obstructing views.
#4
John K.
www.envygames.com
01/20/2009 (12:29 am)
The property is WorldCollisionClipRectangle, attached to the T2DSceneObject. It's read-only.John K.
www.envygames.com
#6
As soon as I type T2DSceneGraph. intellisense only gives me: "Equals" "ReferenceEquals" and "TorqueObjectFlags". What am I doing wrong?
Brian
01/20/2009 (5:35 pm)
Out of curiosity, in order to use the code from page 198, do we need to include anything in addition to the default using statements? I get to here:T2DSceneGraph.Instance.FindObjects(SceneObject.Position, MaxRange, typeEnemy, (uint)0xFFFFFFFF, listEnemies);
As soon as I type T2DSceneGraph. intellisense only gives me: "Equals" "ReferenceEquals" and "TorqueObjectFlags". What am I doing wrong?
Brian
#7
I do believe the code you have is for TX 3. In TX 2, I've found this works:
01/20/2009 (7:25 pm)
@BrianI do believe the code you have is for TX 3. In TX 2, I've found this works:
// Grab a reference to our scene graph
T2DSceneGraph graph = TorqueObjectDatabase.Instance.FindObject<T2DSceneCamera>
("Camera").SceneGraph as T2DSceneGraph; // Break added to fit post
graph.FindObjects(SceneObject.Position, Range, Detects, (uint)0xFFFFFFFF, objects);
#8
Thanks for that! I literally typed that code line for line as to what my copy of the book said. I thought I was going insane! Thanks for showing me how to get a reference to the scenegraph. If I ever get this game finished I'm working on, I'll give you a shout out in the credits from saving my head from getting bruised from banging on my desk. Thanks a million!
Brian
/me turns off happy mode, takes another pull of bawls, and trudges on.
01/20/2009 (7:34 pm)
@SeanThanks for that! I literally typed that code line for line as to what my copy of the book said. I thought I was going insane! Thanks for showing me how to get a reference to the scenegraph. If I ever get this game finished I'm working on, I'll give you a shout out in the credits from saving my head from getting bruised from banging on my desk. Thanks a million!
Brian
/me turns off happy mode, takes another pull of bawls, and trudges on.
#9
SWEET! Yeah man, after the site got it's face lift I saw a bunch of blog posts with people bitching and moaning about, "the community is dead this" and, "the community is dead that" and I decided that we make the community. Plus I've spent a fair amount of time sorting out a lot of these problems for myself and figure I should share the knowledge.
01/20/2009 (7:38 pm)
Quote:
If I ever get this game finished I'm working on, I'll give you a shout out in the credits from saving my head from getting bruised from banging on my desk.
SWEET! Yeah man, after the site got it's face lift I saw a bunch of blog posts with people bitching and moaning about, "the community is dead this" and, "the community is dead that" and I decided that we make the community. Plus I've spent a fair amount of time sorting out a lot of these problems for myself and figure I should share the knowledge.
#10
Brian
01/20/2009 (7:43 pm)
Yeah, now if we can only get a TX Specific chat channel and some way to filter resources for TX, we'd be in a lot better shape. :) Thanks again for the help!Brian
Associate John Kanalakis
EnvyGames
You've definitely figured it out. The FindObjects() method performs its distance search based on the square (rect) that encloses the scene object. As you pointed out, that will return the closest corner. And as you've guessed, the position of an object is at its very center.
If you hadn't already solved this with a component, I might also suggest you consider a solution like this:
Still go with the collide delegate option. When the collision occurs, set a flag that "enables" a pickup, but doesn't actually perform the pickup. Your game HUD can periodically check for this flag and show an on-screen prompt to pick up an item. Then, in your button press code, check this enable flag to see if a pickup can occur.
The reason for this option is that won't have another component with more process ticks eating away at your CPU, even when your player is nowhere near any pickup items. Remember - ticks are great, but they're also evil and can be abused. Even if you don't change anything and keep your component, consider adding an int variable, like TickSinceLastChecked = 0. Then, on each tick, increament that number. And only when TickSinceLastChecked == 10 (or whatever) then perform your scenegraph-wide search and set the variable back to 0.
John K.
www.envygames.com