/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "simulation2/system/Component.h" #include "ICmpMotion.h" #include "ICmpPosition.h" #include "simulation2/MessageTypes.h" #include "graphics/Terrain.h" class CCmpMotionBall : public ICmpMotion { public: static void ClassInit(CComponentManager& componentManager) { componentManager.SubscribeToMessageType(MT_Update); } DEFAULT_COMPONENT_ALLOCATOR(MotionBall) // Current speed in metres per second float m_SpeedX, m_SpeedZ; static std::string GetSchema() { return ""; } virtual void Init(const CSimContext& UNUSED(context), const CParamNode& UNUSED(paramNode)) { m_SpeedX = 0; m_SpeedZ = 0; } virtual void Deinit(const CSimContext& UNUSED(context)) { } virtual void Serialize(ISerializer& serialize) { serialize.NumberFloat_Unbounded("speed x", m_SpeedX); serialize.NumberFloat_Unbounded("speed z", m_SpeedZ); } virtual void Deserialize(const CSimContext& context, const CParamNode& paramNode, IDeserializer& deserialize) { Init(context, paramNode); deserialize.NumberFloat_Unbounded("speed x", m_SpeedX); deserialize.NumberFloat_Unbounded("speed z", m_SpeedZ); } virtual void HandleMessage(const CSimContext& context, const CMessage& msg, bool UNUSED(global)) { switch (msg.GetType()) { case MT_Update: { fixed dt = static_cast (msg).turnLength; Move(context, dt); break; } } } void Move(const CSimContext& context, fixed dt); }; void CCmpMotionBall::Move(const CSimContext& context, fixed dt) { CmpPtr cmpPosition(context, GetEntityId()); if (cmpPosition.null()) return; // TODO: this is all FP-unsafe CFixedVector3D pos = cmpPosition->GetPosition(); float x = pos.X.ToFloat(); float z = pos.Z.ToFloat(); CVector3D normal; context.GetTerrain().CalcNormal(x / CELL_SIZE, z / CELL_SIZE, normal); // Flatten the vector, to get the downhill force float g = 10.f; CVector3D force(g * normal.X, 0.f, g * normal.Z); m_SpeedX += force.X; m_SpeedZ += force.Z; float drag = 0.5f; // fractional decay per second float dt_ = dt.ToFloat(); m_SpeedX *= pow(drag, dt_); m_SpeedZ *= pow(drag, dt_); cmpPosition->MoveTo(entity_pos_t::FromFloat(x + m_SpeedX * dt_), entity_pos_t::FromFloat(z + m_SpeedZ * dt_)); } REGISTER_COMPONENT_TYPE(MotionBall)