Game Development Community

C# Typecasting problem with T2DSceneObject

by Laurence Grant · in Torque X 2D · 01/08/2007 (11:05 am) · 5 replies

Hey guys, I'm not a C# guy, and just learning the basics as I play with TGBX. Maybe this is the wrong forum, but since it's the main area for C# and Torque development, I thought I'd start here.

Anyway, I have a class that extends T2DSceneObject like this:

public class _3DSceneObject : T2DSceneObject
{
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;

.. methods here
}

Then I copied some original code which looked like this,

T2DSceneObject _ball = (T2DSceneObject)(TorqueObjectDatabase.Instance.FindObject("BBall") as T2DStaticSprite).Clone();


and modified it to this


_3DSceneObject _ball = (_3DSceneObject)(TorqueObjectDatabase.Instance.FindObject("BBall") as T2DStaticSprite).Clone();


Now it's complaining that it can't type case from T2DStaticSprite to _3DSceneObject. I thought since _3DSceneObject was extending T2DSceneObject, I should be able to do this. I also assumed the T2DStaticSprite was a subtype of T2DSceneObject, but then I noticed T2DStaticSprite actually extends T2DSceneObject, the opposite of what I originally thought. I tried changing my class to extend T2DStaticSprite, but I still get the same typecasting error. Any suggestions would be greatly appreciated.

Thanks

#1
01/08/2007 (5:39 pm)
Don't think you can do that. The type of BBall is T2DStaticSprite (it seems from your sample at least) and you are trying to type cast it to a _3DSceneObject. You can typecast a _3DSceneObject to a T2DStaticSprite but not the other way around. Note that this is because the object you are trying to cast doesn't actually contain the float x, y and z values and other methods in the memory structure. You might be able to get away with it if you provide some sort of explicit cast procedure for your _3DSceneObject but I'm not 100% sure since I'm still fairly new to C# though I know a bit about C++.
#2
01/08/2007 (6:06 pm)
Also, _3DSceneObject "is a" T2DSceneObject. T2DStaticSprite "is a" T2DSceneObject. But _3DSceneObject "IS NOT A" T2DStaticSprite. So in addition to the "wrong way" casting you're doing, _3DSceneObject has no business getting anywhere near a T2DStaticSprite reference.
#3
01/08/2007 (7:34 pm)
Ben, I've tried creating _3DSceneObject to extend both T2DSceneObject and T2DStaticSprite, with the same results.

Brian, I understand that neither T2DSceneObject nor T2DStaticSprite have the additional fields that _3DSceneObject has, but all the additional data is defined in the constructor. I thought this was a common sort of practice, to extend class, but if I can't initialize the base class its a problem.

I know I could just create an attribute of type T2DSceneObject in _3DSceneObject, but then the interface changes, and I wanted to keep it as transparent as possible.

I guess it makes sense that what I'm doing is backwards, but it just seems to me like it's something that you should be able to do.

If anyone else has any more suggestions I'd be happy to hear them.
#4
01/08/2007 (8:22 pm)
The problem you have is that you have this situation
A
    / \
   B  C
Both B and C inherit from class A. You are trying to cast an object of class B to class C which is not something I have ever seen supported by polymorphism or inheritence.

Semantically you could say that A represents humans and B represents men and C women. Men and women are a subclass of humans, but you run into problems when you try to convert a man into a woman or vice versa. You might be able to force a conversion but things are going to get ugly at that point.

This was why I mentioned you might be able to provide an explicit cast function so that the cast from T2DStaticSprite to _3dSceneObject was handled by hand by you, but you would have to create data out of nothingess to fill in the fields for your class and throw out information that relates to the sprite.
#5
01/09/2007 (4:09 am)
Good replies. One way to do the "cast" that Brian is talking about would be to create a _3DSceneObject constructor that takes a StaticSprite as an argument. In that constructor you would basically copy all the field values over to the new object and populate the _3DSceneObject fields however you want, because as Brian said, you would be creating data out of 'nothingness'.

If you want it to have static sprite qualities and render as a static sprite, you'll need your class to be derived from static sprite and not scene object (unless you're a masochist and want to rewrite all the render code).

If you don't want to render it as a static sprite then I have to ask, why are you creating it from a static sprite instance? Exactly what is this _3DSceneObject supposed to do?

Also, for the sake of being perfectly clear, you actually *can* cast an object that's being stored in a parent reference to a child object reference. You can't store a reference in a field that is a reference of a different type (i.e. miscast), and you can't cast an object to a type that the object itself is not an instance of or derived from (you can, but you'll get a null reference).

For example...

// in this case, _3DSceneObject is derived from T2DSceneObject
T2DSceneObject SORef;
T2DStaticSprite SpriteRef;
_3DSceneObject MyRef;

// this is valid - creata a static sprite instance and store 
// it in a static sprite reference
SpriteRef = new T2DStaticSprite();

// so are these - cast the object to a T2DSceneObject and store 
// that in a T2DSceneObject reference
SORef = SpriteRef as T2DSceneObject;
SORef = (T2DSceneObject) SpriteRef;

// these will result in 'null' because the object itself is not 
// a _3DSceneObject, nor is it derived from _3DSceneObject
// HOWEVER, will not result in an error
MyRef = SpriteRef as _3DSceneObject;

// this will result in an error
// trying to store a T2DStaticSprite in a T2DSceneObject reference without casting
SORef = SpriteRef;

// so will this
MyRef = (T2DSceneObject) SpriteRef;