FAQ for PhysX Candy Wrapper

Here is a collection of frequently asked questions that have come up so far.
Suggest a new topic for the FAQ section in the forums.

Questions

Q: Why do I get the following error:
"Property or indexer 'SomeProperty' cannot be assigned to -- it is read-only"?

You must remember the following:

  • Native objects that the PhysX engine works with are stored as small, contiguous blocks of unmanaged memory.
  • Managed wrapper objects (PhysX state as seen from your .Net application) are tiny, as each only contains a single reference to a native PhysX object.
  • When you get a value of a property from a managed object, the value is read directly from the native object's memory.
  • When you set a value of a property on a managed object, the new value is stored directly in the native object's memory.
  • Some complex native PhysX objects encapsulate whole other native objects (a NxMotorDesc is included in NxRevoluteJointDesc).

To access an encapsulated native object in .Net, get a property from the complex wrappper that returns another, smaller wrapper object - a proxy. Both the proxy and its container reference different parts of the same native object.

Here's a C# example:

void ExampleSetMotorError(RevoluteJointDesc rjd) { var motor = new MotorDesc(); // create a new MotorDesc object (a new NxMotorDesc is allocated in the unmanaged universe) // motor.FreeSpin = false; // set some values on the new object motor.MaxForce = 100f; // rjd.Motor = motor; // error CS0200: Property or indexer 'eyecm.PhysX.PulleyJointDesc.Motor' cannot be assigned to -- it is read only // rjd.Motor.Copy( motor ); // OK, you could use this instead, this overwrites the MotorDesc part of rjd's data } void ExampleSetMotorCorrect(RevoluteJointDesc rjd) { var motor = rjd.Motor; // get a reference to the NxMotorDesc part of rjd's native data, nothing new is allocated, rjd.Motor is a proxy // motor.FreeSpin = false; // change values of some properties directly on rjd's native data motor.MaxForce = 100f; // or, alternatively: /* rjd.Motor.FreeSpin = false; // this does exactly the same as the above rjd.Motor.MaxForce = 100f; */ }

Thanks to azreal42.

Top

Q: Why are the wrapper objects implemented as reference types (C# classes) instead of value types?

The native objects that the PhysX engine uses are not simple C-like structs (POD-s). They're C++ classes and most of them include virtual methods. That means their memory layout is more complex than just a sequence of simple values.

If managed wrapper objects were implemented as value types (C# structs), I would be forced to perform a copy of the whole object at each transition from managed to unmanaged and vice versa. Since I liked the idea that I could operate on native PhysX data directly, I implemented the wrappers as reference types.

Top

Q: Can I use PhysX on my Xbox via Candy Wrapper and XNA?

No, not a chance in hell.

The Xbox PhysX license and source code costs $50K. You'll need to be a registered Xbox developer with Microsoft to get access to development tools in order to compile your game. Registration most probably doesn't come cheap. Also, there's no way to compile C++/CLI code for Xbox, so you'll need to develop code in native C++.

Top

Q: Why do I get exceptions when I try to create PhysX objects? What if I don't want error exceptions?

Error reporting in PhysX is done through an error-stream type interface. PhysX Candy Wrapper provides a basic implementation that throws an exception (after dumping the error to the console) each time PhysX complains about an error.

Example: PhysX objects are created from data you provide via Desc objects. Each Object has a corresponding ObjectDesc. It is possible to fill a Desc object with an invalid combination of values. In that case the property IsValid of the Desc object will return false and any attempt to create an object from such a Desc will fail, causing PhysX to report an error thus causing the default ErrorStream object to throw an exception.

If you would like to avoid getting exceptions, even in cases where there are errors, you must derive a class from ErrorStream, override the ReportError method to not throw an exception, and pass your error stream as an argument at Physics creation time:

class MyErrorStream: ErrorStream { public override void ReportError(ErrorCodes ErrorCode, string Message, string File, int Line) { var msg = string.Format( "({0}) \"{1}\" [{2},{3}]", ErrorCode, Message, File, Line ); // Print( msg ); // this is another method you can override } }

Physics InitPhysics() { var errstr = new MyErrorStream(); // return Physics.Create( errstr ); }

Thanks to gambitricky.

Top