I've been lately working on a simple game using C++ and SFML latest version, but I had a problem which is that the collision detection is not that good, for example the player dies even if the enemy didn't touch him yet, but just near him. Here is the code of the player class with the move function and collision detection code AND the moves of the enemy class:
`class PlayerA : public CircleShape
{
public:
//Constructor:
PlayerA(float xposition, float yposition, float radius, float s)
{
setRadius(radius);
setFillColor(Color::Yellow);
setOutlineColor(Color(00,80,00));
setOutlineThickness(-2);
setPointCount(3);
setSpeed(s);
setPosition(xposition,yposition);
}
//Movements of the player:
void up()
{
move(0,-10*speed);
}
void down()
{
move(0,10*speed);
}
void right()
{
move(10*speed,0);
}
void left()
{
move(-10*speed,0);
}
void checkA(ObsA *obs1=NULL,ObsA *obs2=NULL, ObsA *obs3=NULL, ObsA *obs4=NULL, ObsA *obs5=NULL)
{
if(obs2==NULL)
{
if(getGlobalBounds().intersects(obs1->getGlobalBounds()))
{
relevel();
}
}
private:
float speed=0.00;
void obs()
{
if(speed > 0)
{
rotate(0.5*speed);
}
else
{
rotate(0.5*speed);
}
}
private:
float speed = 0.00;
void obs()
{
if(speed > 0)
{
rotate(0.5*speed);
}
else
{
rotate(0.5*speed);
}
}
private:
float speed = 0.00;
Is there something wrong with the code, how to fix the problem, thank you!
The intersects function just check if two rectangles intersect. If you want pixel perfect collision detection in SFML you have to write that yourself.
Basically, start with intersects, if it is true, then get the intersecting rectangle and check if any pixels therein from both original rectangles contains overlaping relevant pixels.
You can use this function to perform better collision detection.Its a basic one but works well
bool circleTest(const sf::Sprite &first, const sf::Sprite &second)
{
sf::Vector2f firstRect(first.getTextureRect().width, first.getTextureRect().height);
firstRect.x *= first.getScale().x;
firstRect.y *= first.getScale().y;
sf::Vector2f secondRect(second.getTextureRect().width, second.getTextureRect().height);
secondRect.x *= second.getScale().x;
secondRect.y *= second.getScale().y;
float r1 = (firstRect.x + firstRect.y) / 4;
float r2 = (secondRect.x + secondRect.y) / 4;
float xd = first.getPosition().x - second.getPosition().x;
float yd = first.getPosition().y - second.getPosition().y;
return std::sqrt(xd * xd + yd * yd) <= r1 + r2;
}
Are you using a circle? If I remember correctly, the circle will have a rectangle hitbox. If that is the case, then you may have collision between the invisible rectangle corners.
If you're using a circle, Perhaps change class to a square rectangle and see if collision works correctly. Or try testing collision directly on an x or y axis with your circles; i.e. having them moving in a straight line towards each other only changing 1 axis. (the edge of the circle will be the same as the edge of the rectangle at the left, right, top, and bottom sections).
If you're needing a better collision for circles, there may be one already built in SFML. But I don't think it would be too much to write your own logic using the radius of your two circles, the center of your two objects, and the angle hypotenuse between the centers.
edit based on Merlyn Morgan-Graham's comment.
Related
I'm writing a simple game engine and after a lot of rethinking/refactoring I settled with sort of a component based architecture (not strictly ECS, but it isn't inheritance based anymore either). So everything in my world is an entity, and each entity has got a bunch of components. Every system/subsystem in my game scans an entity for a series of components it's interested in, and performs some relevant computations.
So far so good. The engine basic architecture can be seen here:
Now, every entity that is collidable with has a collision component (along with position/movement/rigidbody components), so the physics system needs to get that component and use it to feed its collision detection algorithms, in order to generate contact data to be used to resolve the collision.
I'm stuck on the following issue: the collison detection algorithms deal with different geometries: boxes,spheres,planes and rays (as of now), but I don't want to have a spherecollisioncomponent and a boxcollisioncomponent, at least I don't want them to be unrelated but I'd like them to share some common base class.
class Sphere
{
public:
Sphere(float radius);
~Sphere();
float GetRadius() { return mRadius; }
private:
float mRadius;
};
class Box : public BoundingVolume
{
public:
Box(const XMFLOAT3 &halfSize);
~Box();
XMFLOAT3 const &GetHalfSize() const { return mHalfSize; }
private:
XMFLOAT3 mHalfSize;
};
Obviously each component has a different interface (boxes have halfsizes, spheres have a radius and so on), and the different collision detection functions deal very differently with each of them (box-box, box-sphere, sphere-sphere..).
void CollisionSystem::BoxAndBoxCollision(const Box &box1, const Box &box2)
{
// contact data
XMFLOAT3 contactPoint;
XMFLOAT3 contactNormal;
float minOverlap = 100.0f;
// get axes for SAT test
std::vector<XMFLOAT3> axes = GetSATAxes(box1, box2);
int axisIndex = 0;
int index = 0;
for (XMFLOAT3 axis : axes)
{
if (XMVectorGetX(XMVector3Length(XMLoadFloat3(&axis))) < 0.01f)
{
index++;
continue;
}
float overlap = PerformSAT(axis, box1, box2);
if (overlap < 0) // found separating axis - early out
return;
if (overlap < minOverlap)
{
minOverlap = overlap;
axisIndex = index;
}
index++;
}
// other collision detection/generation code.....
// store contact
mContacts.push_back(new Contact(box1->GetRigidBody(), box2->GetRigidBody(), contactPoint, contactNormal, minOverlap, coefficientOfRestitution));
}
So how can I solve this in an elegant and robust way?
While I found many problems that are similar too mine, none of the solutions solved my problem.
I've been experimenting with SDL2 in C++ (Visual C++) and the entity-component-system (ECS). But I just can't figure out the bug in my collision response.
So here it is: My player sometimes gets set back to its origin when it encounters something like a rock (a simple gray tile). But sometimes it goes right through and gets stuck or ends up on the other side.
I can only assume it has something to do with the data changed in between frames, so it isn't always caught. But for the life of me I can't figure it out.
Here is my rectangular detection method:
bool Collision::RectIntersect(const SDL_Rect& a, const SDL_Rect& b, SDL_Rect& intersect)
{
intersect = { 0, 0, 0, 0 };
int leftX = std::max(a.x, b.x);
int rightX = std::min(a.x + a.w, b.x + b.w);
int topY = std::max(a.y, b.y);
int bottomY = std::min(a.y + a.h, b.y + b.h);
if (leftX < rightX && topY < bottomY)
{
intersect = { leftX, topY, rightX - leftX, bottomY - topY };
return true;
}
return false;
}
Here is my snippet where my inputs are handled and subsequently any collision detections are resolved before the code actually moves anything:
void InputComponent::handleEvents(SDL_Event* e)
{
const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
if (e != nullptr)
{
/*
keyHeld: array of 4 for each direction (+/- x, +/- y (WASD))
hold value true, if pressed down, otherwise false
*/
if (keyboardState[SDL_SCANCODE_A])
{
keyHeld[0] = true;
}
else
{
keyHeld[0] = false;
}
if (keyboardState[SDL_SCANCODE_D])
{
keyHeld[1] = true;
}
else
{
keyHeld[1] = false;
}
if (keyboardState[SDL_SCANCODE_W])
{
keyHeld[2] = true;
}
else
{
keyHeld[2] = false;
}
if (keyboardState[SDL_SCANCODE_S])
{
keyHeld[3] = true;
}
else
{
keyHeld[3] = false;
}
}
/*
tmpVel: Vector to store the assumed velocity in x- and y-direction
*/
Vector2D tmpVel(0.0f, 0.0f);
// left and right (A and D)
if (keyHeld[0] && !keyHeld[1]) // left
{
tmpVel.x = -1.0f;
}
else if (!keyHeld[0] && keyHeld[1]) // right
{
tmpVel.x = 1.0f;
}
else
{
tmpVel.x = 0.0f; // left and right cancel each other out
}
// up and down (W and S)
if (keyHeld[2] && !keyHeld[3]) // up
{
tmpVel.y = -1.0f;
}
else if (!keyHeld[2] && keyHeld[3]) // down
{
tmpVel.y = 1.0f;
}
else
{
tmpVel.y = 0.0f; // up and down cancel each other out
}
/*
check for collision with presumed direction according to tmpVel
*/
SDL_Rect intersection;
// get current player position
SDL_Rect movedPlayer = entity->getComponent<CollisionComponent>().getCollider();
// add trajectory of theoretical movement
movedPlayer.x += static_cast<int>(tmpVel.x * vel_->getSpeed());
movedPlayer.y += static_cast<int>(tmpVel.y * vel_->getSpeed());
bool hasCollided = false;
// collect all collidable objects
for (auto& c : manager_->getGroup(GroupLabel::GR_COLLIDERS))
{
// check player against each collidable tile
//if (SDL_IntersectRect(&movedPlayer, &c->getComponent<CollisionComponent>().getCollider(), &intersection))
if (Collision::RectIntersect(movedPlayer, c->getComponent<CollisionComponent>().getCollider(), intersection))
{
// collision on x-axis
if (intersection.w > 0)
{
// set velocity on x-axis to 0
vel_->setVelocityX(0.0f);
// reset player position back according to width of intersected rectangle
pos_->setPosX(pos_->getPos().x + (static_cast<float>(intersection.w) * (-tmpVel.x)));
}
// collision on y-axis
if (intersection.h > 0)
{
// set velocity on y-axis to 0
vel_->setVelocityY(0.0f);
// reset player position back according to height of intersected rectangle
pos_->setPosY(pos_->getPos().y + (static_cast<float>(intersection.h) * (-tmpVel.y)));
}
hasCollided = true;
}
}
if (!hasCollided)
{
vel_->setVelocity(tmpVel);
}
}
Can anybody put me in the right direction?
What happens when the right edge of the player exactly equals the left edge of the rock? It looks like the collision is not detected, since the test is for (leftX < rightX). So the velocity is updated and the player is moved by the velocity. (It's odd that you simply update the velocity and later move the player instead of just moving them to the new already calculated position.) If you change the check to (leftX <= rightX), does the problem persist?
As far as I can see there are two things wrong with your collision detection. The first is that you're testing (leftX < rightX && topY < bottomY) when you should be testing (leftX <= rightX && topY <= bottomY). If you fix this your code will work in most situations.
The second problem you've got, which may not become apparent straight away, is that your are performing collision detection for discreet points in time. If your player has a large enough velocity vector you may end up with this situation:
Update 1: Player is in front of wall travelling towards it. AABB test shows no collision.
Update 2: Player is behind wall travelling away from it. AABB test shows no collision.
Your AABB test is correct and yet the player has passed through the wall. The naive approach to fixing this is to test more often (update 1.5 may have shown a collision), or to limit player velocity. Both approaches will require a lot of fine tuning especially if you're dealing with objects that can move at different speeds and walls with differing thickness.
A more robust approach is to take account of velocity in your test. Since you know the velocity of your AABB you can project this shape along its velocity vector. If you do this for both AABBs you'll end up with two elongated shapes which you can test against each other. If they overlap then you know that their paths cross and that there may be a collision.
Of course, knowing that there might be a collision is not hugely helpful. The problem is one AABB may be moving very slowly and the other very quickly so even though they both pass through the same space (their elongated shapes intersect) they don't pass through it at the same time.
Figuring out whether they both pass through the same space at the same time is hard, so instead we cheat. If you subtract the velocity of B from the velocity of A and then use this modified velocity to project the elongated shape of A, you can effectively treat B as a stationary object and still get the correct result. Knowing this, your test is now "does B overlap the elongated shape of A?". This is just a simple AABB vs Ngon problem.
While the above will give you a boolean as to whether two moving AABBs collide it will not tell you when they collide which is also useful for calculating things like rebounds.
I would very much recommend the book Real Time Collision Detection by Christer Ericson which is pretty much the go to book on collision detection for any aspiring game developer.
The following is a code snippet from the CD-ROM which accompanies the book. It tests a moving AABB against another moving AABB and also provides a time of first contact.
// Intersect AABBs ‘a’ and ‘b’ moving with constant velocities va and vb.
// On intersection, return time of first and last contact in tfirst and tlast
int IntersectMovingAABBAABB(AABB a, AABB b, Vector va, Vector vb, float &tfirst, float &tlast)
{
// Exit early if ‘a’ and ‘b’ initially overlapping
if (TestAABBAABB(a, b)) {
tfirst = tlast = 0.0f;
return 1;
}
// Use relative velocity; effectively treating ’a’ as stationary
Vector v = vb - va;
// Initialize times of first and last contact
tfirst = 0.0f;
tlast = 1.0f;
// For each axis, determine times of first and last contact, if any
for (int i = 0; i < 3; i++) {
if (v[i] < 0.0f) {
if (b.max[i] < a.min[i]) return 0;
// Nonintersecting and moving apart
if (a.max[i] < b.min[i]) tfirst = Max((a.max[i] - b.min[i]) / v[i], tfirst);
if (b.max[i] > a.min[i]) tlast = Min((a.min[i] - b.max[i]) / v[i], tlast);
}
if (v[i] > 0.0f) {
if (b.min[i] > a.max[i]) return 0;
// Nonintersecting and moving apart
if (b.max[i] < a.min[i]) tfirst = Max((a.min[i] - b.max[i]) / v[i], tfirst);
if (a.max[i] > b.min[i]) tlast = Min((a.max[i] - b.min[i]) / v[i], tlast);
}
// No overlap possible if time of first contact occurs after time of last contact
if (tfirst > tlast) return 0;
}
return 1;
}
The following attribution is required by Elsevier's Software License Agreement:
“from Real-Time Collision Detection by Christer Ericson, published by Morgan Kaufmann Publishers, © 2005 Elsevier Inc”
I'm having trouble with implementing gravity on objects.
I have a bunch of circle objects that I'm drawing using OpenGL. I'm using delta-x and delta-y to move the circles (balls). I'm trying to add a gravitational constant to the y coordinate each frame so it simulates being pulled downward, but I'm not sure exactly how to do that.
Here's the relevant code:
class Ball
{
public:
double x;
double y;
double radius;
double deltaX;
double deltaY;
};
std::vector<Ball> gAllBalls; // a vector of balls with random positions and delta-values
double gGravity = ?; // gravitational constant - I know it's 92 m/s^s, but I don't know how to apply that to deltaX and deltaY
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
for (auto &thisBall : gAllBalls)
{
// draw
glColor3d(thisBall.red, thisBall.green, thisBall.blue);
DrawCircle(thisBall.x, thisBall.y, thisBall.radius);
// gravity - not working
if (thisBall.y + thisBall.radius < gScreenHeight - gGravity)
{
thisBall.y += gGravity;
}
// wall bouncing
if (thisBall.y + thisBall.radius + thisBall.deltaY >= gScreenHeight) // up
{
thisBall.deltaY = -thisBall.deltaY;
}
if (thisBall.y + thisBall.deltaY - thisBall.radius < 0) // down
{
thisBall.deltaY = -thisBall.deltaY;
}
if (thisBall.x + thisBall.deltaX - thisBall.radius < 0) // left
{
thisBall.deltaX = -thisBall.deltaX;
}
if (thisBall.x + thisBall.radius + thisBall.deltaX >= gScreenWidth) // right
{
thisBall.deltaX = -thisBall.deltaX;
}
// move
thisBall.x += thisBall.deltaX;
thisBall.y += thisBall.deltaY;
}
glutSwapBuffers();
glutPostRedisplay();
}
A big problem I'm having is that I don't know how to calculate the gravity, since I'm using deltaX and deltaY instead of having separate speed and distance variables to calculate 92 m/s^2. However, no matter what I set the gravity to, the balls don't behave like they should - regardless of gravity strength, so there has to be something else wrong, but I don't know what.
I think the problem here is the physics, rather than the programming technique.
In your case, I would change the 'delta' members of your Ball class to 'speed', since they are a unit of distance that change the position of your object per cycle (time), however this is just a suggestion to make it easier to visualize...
class Ball
{
public:
double x;
double y;
double radius;
double speedX;
double speedY;
};
In second place, I in your code, you are changing the 'y' member, rather than the speed, and since gravity changes speed, hence the problem.
Try doing that, and for debugging purposes, I would try with punctual objects (no radius, just plain (x,y) coordinates).
So, to conclude, I would simply change your gravity code to the following:
// gravity - 'fixed'
if (thisBall.y + thisBall.radius < gScreenHeight - gGravity)
{
thisBall.speedY -= gGravity; //notice the '-'
}
The value of gravity should be absolute and positive, so as to keep things as simple as posible. If you try this, you should have an ideal simple physics simulator, with a ball of constant speedX (only changing its direction, not magnitude).
Please try this, and let me know how it went, good luck, keep it up =)
I'm Using OpenGL/C++ to create a game.
One aspect of this game that I'm working on is having a character that shoots a projectile the way said character is facing. To do this I have a 'player' and a 'projectile'.
I pass to the projectile the characters x and y co-ordinates, the angle the player is facing. From this I want to shoot the projectile in that direction.
In my draw I am currently using glTranslate with the characters x and y and rotating the projectile on the way the character is facing. This moves my projectile to the way the player is facing.
glTranslatef(this->m_X, this->m_Y, 0);
glRotatef(angle, 0, 0, 1);
This is where i'm stuck, I can move the projectile position by incrementing/decrementing the X and Y values in the translate. But what I'm trying to ask is how can I move the projectile along the line the player is facing.
Thanks for the help!
You can use polar vectors for these calculations.
http://mathworld.wolfram.com/PolarVector.html
A polar vector will allow you to make several calculations that would normally be complicated and convoluted in a simple way. Using their applied mathematics your request won't be an issue.
Here's an implementation of mine of polar vectors.
The header file:
#include <cmath>
//Using SFML Vector2 class, making a similar class is easy.
//Check this URL: http://www.sfml-dev.org/documentation/2.3.2/classsf_1_1Vector2.php
class PolarVector
{
public:
float r;
float t; ///Angle stored in degrees.
PolarVector();
PolarVector(float radius, float angle);
PolarVector(const sf::Vector2f V2); ///Conversion constructor.
sf::Vector2f TurnToRectangular() const;
};
PolarVector TurnToPolar(const sf::Vector2f point);
float getConvertedRadius(const sf::Vector2f point);
float getConvertedAngle(sf::Vector2f point);
bool operator ==(const PolarVector& left, const PolarVector& right);
bool operator !=(const PolarVector& left, const PolarVector& right);
And the source file:
#include "PolarVector.hpp"
PolarVector::PolarVector()
:r(0.f)
,t(0.f)
{}
PolarVector::PolarVector(float radius, float angle)
:r(radius)
,t(angle)
{}
PolarVector::PolarVector(const sf::Vector2f V2)
:r(getConvertedRadius(V2))
,t(getConvertedAngle(V2))
{}
sf::Vector2f PolarVector::TurnToRectangular() const
{ return sf::Vector2f(static_cast<float>(r* std::cos(t)), static_cast<float>(r* std::sin(t))); }
PolarVector TurnToPolar(const sf::Vector2f point)
{
PolarVector PV;
PV.r = getConvertedAngle(point);
PV.t = getConvertedRadius(point);
return PV;
}
float getConvertedRadius(const sf::Vector2f point)
{ return std::sqrt((point.x * point.x) + (point.y * point.y) ); }
float getConvertedAngle(const sf::Vector2f point)
{ return std::atan2(point.y, point.x); }
bool operator ==(const PolarVector& left, const PolarVector& right)
{
float diffR = left.r - right.r;
float diffA = left.t - right.t;
return ((diffR <= EPSILON) && (diffA <= EPSILON));
}
bool operator !=(const PolarVector& left, const PolarVector& right)
{
float diffR = left.r - right.r;
float diffA = left.t - right.t;
return !((diffR <= EPSILON) && (diffA <= EPSILON));
}
The reason why I suggest this is because you can do the following.
Let's say you have a 2 dimensional vector:
sf::Vector2f character(0.f, 0.f); //Origin point. First parameter is X, second is Y
float angleCharFacesAt = 0.698132; //40 degrees in radians. C++ Trigonometry uses Radians. std::cos, std::sin and std::atan2 are used internally.
For the first object or character. You want the other object to have the same angle, but a different position.
Let's say the other object has a position above it:
sf::Vector2f object(0.f, 10.f); //Above the origin point.
float angleObjectFacesAt = 0.f; //0 degrees.
So all you need to do is rotate it using a polar vector:
PolarVector PV = TurnToPolar(object); //Use this for calculations.
PV.t += angleCharFacesAt; //t is the angle parameter of the polar vector.
object = PV.TurnToRectangular(object);
By doing this you will get the rotated position of the object.
The distance between one object and the other will always be the r (Radius) value of the polar vector. So you could make the distance longer or shorter by doing this:
PolarVector PV = TurnToPolar(object); //Use this for calculations.
PV.r += 10; //Increase the radius to increase the distance between the objects.
object = PV.TurnToRectangular(object);
You should try to understand the rotation matrix and polar math to be able to achieve more things with this, but with this code it is possible. You should also put all this code in a class, but first play with it until you understand it well.
Sorry for the lengthy answer, but this is a topic that isn't very easy to explain without delving into linear algebra. The classes are for actual code manageability (I use these in my own game), but you can reproduce the same effects with the calculations only.
I personally prefer Polar Vectors over using the rotation matrix due to their usefulness in more than just rotating an object. But here's a link to understanding the rotation matrix better: https://en.wikipedia.org/wiki/Rotation_matrix
After you've done the transformation with the polar vector, you can just glTranslate to the final position given by the polar vector. You have to make sure that you rotate around the origin you are using. Otherwise rotation might not occur as you desire to use it.
Hey so i've made a 'body' class, which inherits from sf::drawable in SFML that holds shapes together so i can form more complicated shapes and figures. I found i had to do a few updates on each individual member shape at render time, based on what's happened to the body over-all since last render.
This included:
Rotation
Translations
Scaling
I thought i would have to manually write the code to factor in these changes that could have occured to the overall body, so the shape positions turned out right. However when coding the Rotation part, i found after writing the manual code that even though i made Bodies Render() function only iterate through and render each shape without changing them, they somehow came out with the right orientation anyway. HOW CAN THIS BE?
I commented out the code i wrote and apparently didn't need, and i use the Draw() function to render. Please explain to me my own code! (God i feel retarded).
here's the class:
class Body : public sf::Drawable{
public:
Body(const sf::Vector2f& Position = sf::Vector2f(0, 0), const sf::Vector2f& Scale = sf::Vector2f(1, 1), float Rotation = 0.f, const sf::Color& Col = sf::Color(255, 255, 255, 255)){
SetPosition(Position);
SetScale(Scale);
SetRotation(Rotation);
SetColor(Col);
RotVal=0;};
////////////////// Drawable Functions ////////////////////
void SetX(float X){
MoveVal.x += X - GetPosition().x;
Drawable::SetX(X);};
void SetY(float Y){
MoveVal.y += Y - GetPosition().y;
Drawable::SetY(Y);};
void SetRotation(float Rotation){
RotVal+= Rotation-GetRotation();
Drawable::SetRotation(Rotation);};
////////////////////////////////////////////////////////////
bool AddShape(sf::Shape& S){
Shapes.push_back(S); return true;};
bool AddSprite(sf::Sprite& S){
Sprites.push_back(S); return true;};
void Draw(sf::RenderTarget& target){
for(unsigned short I=0; I<Shapes.size(); I++){
//Body offset
Shapes[I].SetPosition(
Shapes[I].GetPosition().x + MoveVal.x,
Shapes[I].GetPosition().y + MoveVal.y);
// Aparrently Body shapes rotate on their own...
//WWTFFFF>>>>??????????
//Body Rotation
//float px= GetPosition().x,
// py= GetPosition().y,
// x= Shapes[I].GetPosition().x,
// y= Shapes[I].GetPosition().y,
// rot= ConvToRad(RotVal);
/*Shapes[I].SetPosition(
px + ((x-px)*cos(rot)) - ((y-py)*sin(rot)),
py - ((x-px)*sin(rot)) + ((y-py)*cos(rot)));*/ //TODO: put this in a math header
//Shapes[I].Rotate(RotVal);
}
target.Draw(*this); // draws each individual shape
//Reset all the Change Values
RotVal=0;
MoveVal.x=0;
MoveVal.y=0;
};
private:
sf::Vector2f MoveVal;
float RotVal;
std::vector<sf::Shape> Shapes;
std::vector<sf::Sprite> Sprites;
virtual void Render(sf::RenderTarget& target) const{
for(unsigned short I=0; I<Shapes.size(); I++){
target.Draw(Shapes[I]);}
for(unsigned short I=0; I<Sprites.size(); I++){
target.Draw(Sprites[I]);}
};
};
My guess was confirmed by the SFML source code.
When you call target.Draw(*this) it eventually calls Drawable::Draw(RenderTarget& Target) const, which sets up a render matrix which has the rotation that you gave it with the Drawable::SetRotation call. Your virtual Render function is then called, with that rotation environment set up. This means that your body-parts get rotated.
Have a look at the source yourself to get a better understanding. (;