Wednesday 23 November 2011

The Kids get back to nature

Yes, its a coding blog. but sometimes I might want to talk on other things ok.

Today the kids went off to Pulau Ubin, for a nature trip.
They took heaps of photos, of the wildlife, but nothing of themselves.
So here is what they saw:
Wild Boars:

Many different types of Beetle: 

A Fish Eagle: 

And more Wild Boar: :
I'm sure Asterix and Obelix would be very interested in these.
And the kids had a great time. Even my 'city girl' wife, enjoyed herself.

Tuesday 1 November 2011

Rotating objects/bullets about

This may sound a silly title (yes I agree), but I don’t have a better name for it yet. I imagine that someone reading this will say “Duh! You want to rotate the object, just add in a rotation matrix”, yes you are 100% correct.
But that’s not what I’m talking about.

The issue
In your normal FPS game, you use WSAD to move your player about, right. But when you turn your camera in a different direction WSAD still work, but W is still forward, its not on any axis its forward.
Take this chunk of code:
const float SPD=1.0f;
// move the player
if (KeyDown(‘A’))
     mPlayer.mPos.x-=SPD;
if (KeyDown(‘D’))
     mPlayer.mPos.x+=SPD;
if (KeyDown(‘W’))
     mPlayer.mPos.z+=SPD;
if (KeyDown(‘S’))
     mPlayer.mPos.z-=SPD

Yes its move the player about using WSAD, but how do we add in the turning?
const float RSPD=D2R(60); // 60 degrees per second
// turn the player
if (KeyDown(VK_LEFT))
     mPlayer.mTurn.x-=RSPD;  // yaw
if (KeyDown(VK_RIGHT))
     mPlayer.mTurn.x+=RSPD;  // yaw

This will turn the model, but when we press WSAD the player will still move in the same directions as before, it will not take into account the rotation that we have applied.


Using Maths
Now: some of you may remember your basic sine & cosine trigonometry.
And with a little work, you could change this into the proper formula needed for figuring out the correct movement direction.
However I have a quicker simpler solution: using the DirectX matrix code.

Using DirectX Maths
Consider this code:
// DO NOT COPY THIS CODE: it does not work
const float RSPD=D2R(60); // 60 degrees per second
// turn the player
if (KeyDown(VK_LEFT))
     mPlayer.mTurn.x-=RSPD;  // yaw
if (KeyDown(VK_RIGHT))
     mPlayer.mTurn.x+=RSPD;  // yaw
// get the rotation matrix
MATRIX rot=CreateRotationMatrix(mPlayer.mTurn);
// move the player
if (KeyDown(‘A’))
     mPlayer.mPos+=LEFT*rot; // move left
if (KeyDown(‘D’))
     mPlayer.mPos+=RIGHT*rot; // move right
if (KeyDown(‘W’))
     mPlayer.mPos+=FORWARD*rot; // move forward
if (KeyDown(‘S’))
     mPlayer.mPos+=BACK*rot; // move back

What we are doing here is rotating the player like normal. Then when we move the player, instead of moving in the X, Y or Z direction, we take the movement vector & rotate it based upon the players rotation matrix. That way the W is forward, no matter which way the player is facing.

The actual DirectX code is a little more complex than this, but not by much (you just need to know what the funtions are):

// This is valid code
const float RSPD=D2R(60); // 60 degrees per second
// turn the player (as usual)
// ....

// create a rotation matrix using the players turn
D3DXMATRIX rot;
D3DXMatrixRotationYawPitchRoll(&rot,mPlayer.mTurn.x,mPlayer.mTurn.y,mPlayer.mTurn.z);

D3DXVECTOR3 dir(0,0,0); // the direction to move
// update dir
if (KeyDown('A'))    dir.x--; // move left
if (KeyDown('D'))    dir.x++; // move right
if (KeyDown('W'))    dir.z++; // move forward
if (KeyDown('S'))    dir.z--; // move back

// now lets rotate 'dir' by the rotation matrix 'rot'
D3DXVECTOR3 rdir;  // rotated direction
D3DXVec3TransformCoord(&rdir,&dir,&rot);     // rdir=dir*rot

// finally add it to the players position
mPlayer.mPos+=rdir*SPD;

To simplify the coding a little, I captured all the key presses and updated the vector ‘dir’ before performing the final multiplication.
The main piece of code to note is the D3DXVec3TransformCoord which is used to multiply the matrix and vector together.

Using this idea elsewhere

Using this idea elsewhere:
Lets consider firing some shots:

if (player presses fire)
{
    CShot* ptr=new CShot();  // Create the CShot
    ptr->mVel=D3DXVECTOR3(-1,0,0);// set the velocity
    // etc,etc,etc
}

This code assumes the shot is going one way only.

But we can use the same concept to rotate the shots.

if (player presses fire)
{
    CShot* ptr=new CShot();  // Create the CShot
    D3DXVECTOR3 vel(0,0,-1);
    // get the rotation matrix
    D3DXMATRIX rot;
    D3DXMatrixRotationYawPitchRoll(&rot,mPlayer.mTurn.x,mPlayer.mTurn.y,mPlayer.mTurn.z);
    // rotate it
    D3DXVECTOR3 rvel;
    D3DXVec3TransformCoord(&rvel,&vel,&rot);       // rdir=dir*rot;   
    ptr->mVel=rdir; // set the velocity
    // etc,etc,etc
}

You can also use the same idea if you wanted the shot to be fired from a certain part of the model: measure the offset of the firing point, rotate by the matrix, fire shot from the players location + rotated offset.

Another good use is the third person camera. Here are the rough steps:
Pick the offset for the camera, say 5 units up, 20 units behind the player
Multiply this offset by the players rotation matrix
Set camera location=players location + rotated offset
Make the camera look directly at the player

Conclusion:
Its funny how a little bit of maths can make your game so much more interesting. When I first learned trigonometry, I learned it because I had to.
Once I started writing games, I found that all sorts of bits of math that I learned were actually really handy. In particular was trigonometry.

Happy coding
Mark

XML Serialisation of hierarchy in C#

Yesterday was a BAD class :-(
I had the students to go and research out how to use the build in XML serialisation functions in C#, and we were going to use them to to covert all our message classes into XML for sending over the network.
I went to class, we all started coding...

public class SomeData 
{ 
    public int a; 
    public float b; 
    public string c; 
} 

// create new object and populate myData data 
SomeData myData = new SomeData(); 
myData.a = 5; 
myData.b = 8.8f; 
myData.c = "MeString"; 

// Serialization - convert to XML 
XmlSerializer sendSerializer = new XmlSerializer(typeof(SomeData)); 
StreamWriter myWriter = new StreamWriter(@"savingXML.xml"); 
sendSerializer.Serialize(myWriter, myData); 
myWriter.Close(); 
 
// Deserialization - convert back to a structure 
XmlSerializer revSerializer = new XmlSerializer(typeof(SomeData)); 
FileStream myFileStream = new FileStream(@"savingXML.xml", FileMode.Open); 
myData = (SomeData)revSerializer.Deserialize(myFileStream); 

It all coming together so well until...
<Insert dramatic music here>
I went on with the second part which was to have multiple objects types being serialised.

This is when it all fell apart


The problem
Look back the previous code, do you see when the XmlSerializer is being created it needs a type. You put in the wrong type and it just throws an exception.  I tried using typeof(Object), I tried base classes, and all other things. Eventually I found a site which explained it indirectly.

How To Solve the issue
The XmlSerializer will accept a type and an array of types, and it accept any of the types specified.
So this works:
public class SomeDataA{...}
public class SomeDataB{...}
public class SomeDataC{...}


// create new object and populate myData data 
SomeDataA myDataA = new SomeDataA(); 
SomeDataB myDataB = new SomeDataB(); 
SomeDataC myDataC = new SomeDataC(); 

// Serialization - convert to XML 
XmlSerializer sendSerializer = new XmlSerializer(typeof(SomeDataA),new Type[]{typeof(SomeDataB),typeof(SomeDataC)}); 
StreamWriter myWriter = new StreamWriter(@"savingXML.xml"); 
sendSerializer.Serialize(myWriter, myDataA); 
sendSerializer.Serialize(myWriter, myDataB); 
sendSerializer.Serialize(myWriter, myDataC); 
myWriter.Close(); 
 
// and the same for Deserialization

It also means that I can now easily have a whole hierarchy provided I know all the classes.
public class Base{...}
public class Derived1: Base{...}
public class Derived2: Base{...}

// Deserialization - convert back to a structure 
XmlSerializer revSerializer = new XmlSerializer(typeof(Base),new Type[]{typeof(Derived1),typeof(Derived2)}); 
FileStream myFileStream = new FileStream(@"savingXML.xml", FileMode.Open); 
Base b = (Base)revSerializer.Deserialize(myFileStream); 
if (b is Derived1)
{
  Derived1 d1=(Derived1)b;
  // do stuff with d1
}
else if (b is Derived2)
{
  Derived2 d2=(Derived2)b;
  // do stuff with d2
}

Conclusion
In order to use the C# XmlSerializer, you need to have specify all possible classes which could be used. This is a bit of a bind, but know I know about the issue, I won't fall foul of it again
I'm sure the Java XmlSerializer doesn't have this funny issue. But its not the total show stopper, just an annoyance, and it messed up my class yesterday.
So next week, I need to be a bit better prepared..

Happy Coding:
Mark