Game Development Community

Attaching a shape to a camera?

by Milo D. Cooper · in Torque Game Engine Advanced · 07/06/2007 (6:29 am) · 17 replies

What's the method (if any) for attaching a shape to a camera, so that the shape moves with the camera?

I'm about to code this in C++, but surely I can just do this in TorqueScript.


-- M. Cooper

#1
07/06/2007 (9:36 am)
A better/easier way of looking at this would be to attach the Camera to the Shape. Then the Camera would move when the Shape does. This is something that is done lots of places in Torque games.
#2
07/06/2007 (12:10 pm)
OK, I'll give that method a shot, but I still need to constantly update the position of a TSStatic object in C++.

I wrote a public function to access TSStatic's protected setTransform() function, but the TSStatic object won't budge. Mark (or anyone else), you got any idea how I can move the thing?

StaticShape and Item both have public setTransform() functions. I tried using StaticShape, but I couldn't even get the object to show up, then. Evoking it as an Item made it show up, but I couldn't collide with it, even after making sure that its "collideable" property was set.


-- M. Cooper
#3
07/06/2007 (12:52 pm)
It sounds like what you are describing is "I want to be able to control a player, and have the camera attached to that player"--which is exactly what the Player class does.

An alternative interpretation of what you want might possibly be a combination of PathedCamera, and/or a camera that is not controlled by the player, but by an object. The player would still control an object (that he is not guaranteed to see).

In either of these cases, you probably don't want to be using TSStatic, but something that derives from GameBase (or possibly ShapeBase). A better problem description might help us point you in a better direction.
#4
07/06/2007 (12:54 pm)
Yeah, TSStatic is not designed to be moved. That's why it has "static" in its name. Anything you implement as a TSStatic should be a non-moving, non-interactive "lump." That is all its designed to do and that's all it does.
#5
07/06/2007 (2:14 pm)
Because it has very simplistic collision detection (i.e. the bounding cube), the Player class is of no use to me without extensive modification.

What are the adverse effects of making such unorthodox use of a TSStatic object? What breaks when I relocate an object that was originally designated stationary?

I'm going to look into making the Item class collideable (again, setting the collideable flag has no effect whatsoever). I found a web page regarding this that might bear fruit. Presumably, I can move an item around at will, yes?


-- M. Cooper
#6
07/06/2007 (2:56 pm)
Ok, let me comment on a few things here. First, (and Stephen please correct me if I'm wrong) but all ShapeBase derived objects (or all TSShapeInstance objects) use very simple bounding-box collision. Basically, everything that is not an Interior (DIF) uses simple, convex hull collision. So, you're good there unless you want your player avatar to be a building of some kind.

Second, the effects of using TSStatic is that you are going to be fighting "up hill" the whole way. You will need to write your own code for it to do anything but sit there, because that is all its designed to do.

Let me try an analogy: You are looking for some sort of device to transport you from your house to work every day. You have 3 choices: a car, a bicycle, and a rock. You say, "Hmm, the car and bicycle look pretty complex, so I'll choose this inanimate rock." Now, you are taking out a hammer and chisel and asking us, "I want to make my rock go when I press a pedal, how should I carve this rock?"

Perhaps that analogy is a bit dramatic, but (I think) it is not far off of the truth. Quite literally, TSStatic is designed for rocks, and perhaps trees. TSStatic is designed to sit there, and do nothing. To try and use it as a basis for a fully-featured moving, animated, controllable player avatar or vehicle or something is akin to trying to chisel a rock into a functioning vehicle. You can do it, but why are you putting yourself through that much trouble?

I understand you may not want to use the Player class "whole", so I would suggest creating a new object derived from ShapeBase or GameBase (as Stephen suggests above). Trust me, this will save you a lot of trouble.
#7
07/06/2007 (3:02 pm)
Agreed with Mark, and that's why I asked what the root challenge was--what are you actually trying to do, gameplay wise?

We can give you a better strategy based on better knowledge of your problem set :)

Side Note: the Item class actually does "collide", but it doesn't have a physics response to that collision. That's because the Item class is designed to be used as "pick-ups", so when something collides with it, it does return an ::onCollision() callback, but does not affect the physics of the object that collided with it.
#8
07/06/2007 (4:43 pm)
@Mark: I don't gain anything by using the vehicular objects as opposed to the rock, because as I've written several times, their collision detection is very weak, and useless for my purposes. The rock has far better collision detection than the bike or the car, so I can choose either to teach the rock how to update its position periodically (which should be a piece of cake), or to teach the other objects how to interface with the environment as well as the rock. The trade-off that I've chosen is the former.

Player control is a non-issue, in my case. For what I'm doing, the player has no direct control over the rock. The rock should simply change its location in response to something that the user does. I had considered using a Player object long ago, but I dropped that idea upon discovering that custom collision volumes are, sadly, ignored by Player objects. (Garage Games couldn't even be bothered to make it optional, I guess.)

I've already got code in place to update a camera's position periodically; I'm just trying to port that over to some class that supports a physical response to collision detection superior to bounding cubes. It's starting to look like TSStatic is my *only* option (since, again, I am unable to get StaticShape to display anything -- I'm using TGEA).

Of course, if you're saying that it's easier to teach the bike and the car how to collide as well as the rock than it is to tell the rock to change its position periodically, then great, tell me how. Perhaps there are special types of collision volumes on Player objects of which I could make use...?

@Stephen: I've already explained what I'm trying to do. I'm trying to change the position of an object that supports custom collision volumes. That's all; it is really that simple. If I can't do that (!), then please let me know, and I'll move on to some other solution.

Thanks for your time, guys.


-- M. Cooper
#9
07/06/2007 (5:07 pm)
To be blunt, you didn't describe your game play mechanic, you described your attempted solution to a game play mechanic that you've not yet described to us.

Also, you have some misunderstandings of how collision works: The rock "has better collision" because the shape has a collision mesh that more accurately describes the shape of the underlying dts model--has nothing to do with the collision implementation itself.

Quote:
The rock should simply change its location in response to something that the user does.

In what way? either you are controlling the rock, or you are impacting the rock. And TSStatic doesn't respond to collisions by moving, so I'm not sure what you mean by the above quote.

Your original request was how to move a shape based on a camera's motion--something that is very non-intuitive to many of us, so we asked what your game play mechanic you wanted to implement was to get a better idea as to how to implement a solution.

Your (probable, I don't know how you implemented it) solution for "periodically updating the camera's position" implies use of time based processing (probably ::processTick()?), but since TSStatic does not inherit from GameBase, it does not receive ticks from the simulation. That is most probably what you are missing.

In general, the best design practice for getting a behavior or functionality that isn't directly supported is to create a new class derived from an appropriate level in the hierarchy, and implement/re-implement any subsystems that you find useful from other classes, or your own work. In this case, it sounds as if you need some of what SceneObject does (allows you to render), some of what GameBase does (response to ticks from the simulation), some of what TSStatic does (render dts shapes), combined with collision hulls (again part of dts shapes, but implemented in a different area), and a model with accurate collision hulls.

Off the top of my head, I'd suggest looking into the RigidShape class--should be able to find as a resource. You could also possibly look to Projectile's collision and physics for ideas as to how to update your object's position, but it'll have to derive from GameBase in any case.
#10
07/06/2007 (5:45 pm)
Actually, I got it working with the Item class.

Sweet, thanks.


-- M. Cooper
#11
07/07/2007 (2:27 pm)
Having gotten things working, I figure it's kind of rude not to respond to Stephen's last post, so:

Quote:Also, you have some misunderstandings of how collision works: The rock "has better collision" because the shape has a collision mesh that more accurately describes the shape of the underlying dts model--has nothing to do with the collision implementation itself.

Actually, I understand perfectly how collision detection works (I've been making games professionally for over 15 years). My point was that Mark's suggestion that I employ the Player class (car, bike) instead of the TSStatic class (rock) assumed that I didn't require the better collision afforded out of the box by the latter. (Again, why you people at Garage Games didn't make custom collision volumes for the Player class optional out of the box is beyond me.)

Quote:Milo:"The rock should simply change its location in response to something that the user does." Stephen: In what way? either you are controlling the rock, or you are impacting the rock. And TSStatic doesn't respond to collisions by moving, so I'm not sure what you mean by the above quote.

You and Mark are thinking very provincially, and therefore making the incorrect assumption that control over or contact with the rock by the player is involved.

For example, I might want to move the rock to the left a bit when the player looks up, or when he sits idle for 14 minutes, or when he types "howdy doody" in his chat box. Or when his camera moves. I didn't give you any specifics because I wanted basic functionality that I could use in multiple scenarios. I simply wanted a way to move an object that supported custom collistion volumes (e.g. TSStatic, Item) from point A to point B; I wasn't looking for some specific cause->effect implementation. "In what way" was immaterial.

Quote:Your (probable, I don't know how you implemented it) solution for "periodically updating the camera's position" implies use of time based processing (probably ::processTick()?), but since TSStatic does not inherit from GameBase, it does not receive ticks from the simulation. That is most probably what you are missing.

... Which is why I initially moved the TSStatic in response to camera movement (i.e. via the camera's advanceTime() function). See?


-- M. Cooper
#12
07/07/2007 (3:19 pm)
As I recall, the camera classes should support the use of .dts shapes in stock Torque. However, I don't believe they have any type of collision functionality.
#13
07/07/2007 (3:37 pm)
Quote:As I recall, the camera classes should support the use of .dts shapes in stock Torque. However, I don't believe they have any type of collision functionality.

Well, for my purposes, it's necessary to have the camera and the so-called "rock" move in tandem. It isn't an either/or deal.

Originally, since I already had the camera moving properly, I decided to try to move the "rock" in the camera's advanceTime() function. That's where I ran into problems (and I'd still like to know why, some day).

In any case, the issue has been resolved -- but doing so was definitely more difficult than it should have been.

As for Stephen's suggestion of using RigidShape, I briefly considered that, but before long I discovered that attempting to compile it for use with TGEA (I mentioned earlier that I'm using TGEA, not TGE) resulted in so many errors that I abandoned the pursuit. Shame, too -- I'll probably need that functionality later on.


-- M. Cooper
#14
07/08/2007 (8:11 am)
Quote:
Actually, I understand perfectly how collision detection works

I should have been more complete in my statement, and added in "within Torque's different classes". The Player class does not use collision hulls due to a performance optimization choice. It stops at bounding box collision test.

Quote:
You and Mark are thinking very provincially, and therefore making the incorrect assumption that control over or contact with the rock by the player is involved.

For example, I might want to move the rock to the left a bit when the player looks up, or when he sits idle for 14 minutes, or when he types "howdy doody" in his chat box.

In our defense, you didn't really give us much to work with :) Not knowing your background or level of experience, I normally approach questions from a "make sure the questioner understands the basic concepts, and understand what the questioner is actually trying to do in case they are mis-using a reference implementation in a manner it isn't intended due to not understanding a root system.

As it turns out, that wasn't a great approach to use with you (due to your experience level), and I apologize for that, but I normally read 800+ messages a day, and it's sometimes difficult to identify the questioner's knowledge level right off the bat.

Quote:
.. Which is why I initially moved the TSStatic in response to camera movement (i.e. via the camera's advanceTime() function). See?

Keep in mind ::advanceTime() only occurs on the client, so this technique is probably not networkable without additional work. If you are making a simulation change based only on an ::advanceTime() occurrence, you are most probably only changing the client simulation, and/or crossing over to the server space due to the client and the server running in the same executable--either of which will break down in a multi-player scenario.
#15
07/08/2007 (8:29 am)
I think it's also important for all readers (not just Milo, this is a general response) to keep in mind that classes below the GameBase/ShapeBase level are reference implementations to demonstrate various techniques. These reference implementations happen to be ones that were originally created for Tribes, and have received incremental enhancements as the product has evolved, but in general they were designed against game requirements, not "generic engine that does everything" requirements.

Some examples:

--We discussed above the need for StaticShape style collision accuracy (which is also available in Vehicle), and compared it briefly to the Player class. Given that collision is a high performance requirement area, optimizations are made whenever possible, and appropriate. With players for example, it was decided that the trade off of only using bounding boxes as final collision determination, because players were both the class that would be expected to be causing most of our collisions (projectiles being the other), and also that a bounding box approximation for a collision volume was actually rather accurate given the bipedal nature of Tribes players. Vehicle uses the collision hulls mechanism because by nature, most vehicles are not symmetric about the Z (up) axis, and axis aligned bounding boxes (which Torque uses) do not accurately reflect true collision requirements to any satisfactory degree as a final collision test.

--Milo commented twice on "making collision volumes optional for Player class" twice--and the above description was the reason. The general expectation for Torque development is to identify your requirements, determine what class(es) if any meet a majority of those requirements, and derive a new class from the appropriate point in the hierarchy to implement your functionality. In Milo's use case, his initial statement was a very correct one for him--that's exactly what he wanted to do. It's also one that simply isn't a normal mechanism, and hasn't been implemented directly in any of the reference classes. Personally, that bodes well for me on his project--innovative game mechanics for the win!

For Milo: Now that I have a better understanding of your game mechanic (at least I think I do), I'd suggest analyzing the following approach and see if it fits your needs better:

--Review the way the Player class can "mount" a vehicle, and how the Move struct is passed from the Player::processTick() method directly to the vehicle a player is mounted to (first twenty or so lines of code in Player::processTick() ).

Since Camera derives from GameBase, if it's set as the control object for the client, it receives the Move struct generated by the client across the network, and the Move struct is delivered to the Camera::processTick() as an argument. you could either use the same technique as is used in a Player mounting a Vehicle (store a pointer to the "rock", send all or part of the Move struct to the "rock" and process there).

Alternatively, you could take a look at the way ShapeBase implements more normal mounting, and use that mechanism for "mounting" the rock to your camera. It will take a bit of refactoring most likely.

Keep in mind that both of these would require deriving from GameBase, since this is where processTick() (and as I said above, therefore game time processing) behavior is implemented.
#16
07/08/2007 (6:46 pm)
Stephen, thanks for the responses; they were enlightening. The solution that I've implemented is functional, but I'm sure that it could be much better.

What I need to do is to move a server object with collision volumes at random, and have the client's camera update its position accordingly.

Per Mr. Dynna's suggestion, I'm currently reviewing the Vehicle class as a candidate for the server object. Just so I'm clear: processTick() guarantees 1 update for every 32ms (though not necessarily *at* every 32ms), and interpolateTick() is called every frame, with its argument representing a percentage (1.0 being 100%) of 32ms since the last time the function was called. Is this all correct?


-- M. Cooper
#17
07/08/2007 (7:46 pm)
Correct on both counts :)

processTick() with a fixed tick being intended for physics related operations, and interpolateTick() intended (primarily) for smooth render positions between physics ticks.