A rough PhysicsComponent

After refactoring the Sprite and turning it into a SpriteComponent I thought the next most obvious candidate for my new component system was a PhysicsComponent that will be responsible for moving the GameObject.

Basically I had a look at my existing player class and decided that there was quite a bit of code related to the movement of the sprite itself. So I decided to pull all that out and move it into my new PhysicsComponent. My PhysicComponent currently looks like this:

class PhysicsComponent : public Component {
public:
 PhysicsComponent();
 PhysicsComponent(const glm::vec3 a_position, const float a_fRotationSpeed, 
                  const float a_fRotationAngle = 0);
 void AddForce(const glm::vec2 a_force) { m_acceleration += a_force; }
 void AddRotation(const float a_fRotation) 
                  { m_fRotationAngle += a_fRotation; }
 glm::vec3 GetPosition() const { return m_position; }
 float GetRotation() const { return m_fRotationAngle; }
 void Update(const double a_dDeltaTime);

private:
 glm::vec3 m_position;
 float m_fRotationAngle;

 glm::vec2 m_velocity;
 glm::vec2 m_acceleration;
 float m_fRotationSpeed;

 static const float m_fFrictionValue;
};

Basically I want to store and manipulate the position and rotation of a GameObject – so I’ve provided getters for these values since other components will need to work with them (so far just my SpriteComponent).

Something I probably knew already, but had forgotten, is that static const class members must be initialised outside of the class declaration, and also outside of any member functions. So at the top of PhysicsComponent.cpp I have the line:

const float PhysicsComponent::m_fFrictionValue = 0.97;

Though really the friction shouldn’t be the same for all objects, so I guess I might turn this into a regular const in my next coding session.

All the interesting code is really inside the Update function – it’s basically a straight conversion from what I had in the Player Update function.

void PhysicsComponent::Update(const double a_dDelaTime)
{
 m_velocity.x += m_acceleration.x * a_dDelaTime;
 m_velocity.y += m_acceleration.y * a_dDelaTime;

 glm::vec4 rotationVector = glm::rotate(glm::mat4(1), 
                            m_fRotationAngle + 90, glm::vec3(0, 0, 1)) 
                            * glm::vec4(m_fRotationSpeed, 0, 0, 1);

 m_position.x += m_velocity.x * a_dDelaTime * rotationVector.x;
 m_position.y += m_velocity.y * a_dDelaTime * rotationVector.y;

 m_velocity *= m_fFrictionValue;

 m_acceleration.x = 0;
 m_acceleration.y = 0;
}

Here I’m just calculating the velocity based on any forces that had been added since the last update (I kind of like this approach, means I can apply multiple forces and just add to the acceleration in a frame). Then calculating the rotation (perhaps I should cache this vector and only calculate this if the rotation actually changes? Right now I’m doing it every frame..) and using these two results to calculate my current position. I also adjust the velocity down a bit to simulate friction (though there probably isn’t friction in space).

Lastly I set the acceleration to 0. This feels a bit hacky since I don’t really think acceleration works like this. But it works well for the moment.

Since the PhysicsComponent needs the delta time in the Update function then I needed to add it as an argument in the Update function of the base class. Which made me realise that the SpriteComponent Update function was incorrect. I was passing in position, rotation and scale, which meant it wasn’t actually overwriting the base Update and attempts at polymorphism wouldn’t work. So I decided to go back to having the position, rotation and scale as members of the SpriteComponent – and public ones at that, since they need to be set externally after object creation (more on this shortly). This meant I could fix the parameters of the Update function so they matched the base class.

I also realised I had not written a constructor for my Component class – so I had no way of setting the ComponentType. Once this was fixed I could set the type properly from SpriteComponent and PhysicsComponent.

Once finished with all this I decided to try and put some of this together into my PlayerObject. This is the result so far:

void PlayerObject::Update(const double a_dDeltaTime)
{
 GameObject::Update(a_dDeltaTime);

 GLFWwindow* currentContext = glfwGetCurrentContext();
 PhysicsComponent* physicsComponent = 
          dynamic_cast<PhysicsComponent*>(GameObject::GetComponent(PHYSICS));
 if (physicsComponent != nullptr) {
     if (glfwGetKey(currentContext, 'W')) {
         physicsComponent->AddForce(glm::vec2(150, 150));
     }

     if (glfwGetKey(currentContext, 'A')) {
         physicsComponent->AddRotation(3);
     }

     if (glfwGetKey(currentContext, 'D')) {
         physicsComponent->AddRotation(-3);
     }
 }

 SpriteComponent* spriteComponent = 
          dynamic_cast<SpriteComponent*>(GameObject::GetComponent(SPRITE));
 if (spriteComponent != nullptr) {
     if (physicsComponent != nullptr) {
         spriteComponent->m_position = physicsComponent->GetPosition();
         spriteComponent->m_fRotationAngle = physicsComponent->GetRotation();
     }
     spriteComponent->Draw();
 }
}

A few observations – I dislike the way I’m currently accessing each of these components. However as I mentioned in my previous post, I’m planning on fixing the component system up a bit so that there are shared arrays of components in the Screen and the GameObjects will just contain references to them (either pointers or indices). So I will leave this alone for the moment.

Also – I really don’t like having to set the position and rotation of the Sprite like this. I feel like the Sprite and Physics components will have to work together like this in a number of objects, so I’m going to have to repeat this code. Which is a warning sign that it can probably be done in a different way. I’m just not sure how – though I am going to add this to my list of planned refactors/changes.

OK, that’s all for now. Please let me know what you think, or ask me a question if you don’t understand my logic or a piece of code.

Advertisements

One thought on “A rough PhysicsComponent

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s