| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- #include "Vehicle.h"
- #include <Urho3D/Core/Context.h>
- #include <Urho3D/Graphics/DebugRenderer.h>
- #include <Urho3D/Graphics/DecalSet.h>
- #include <Urho3D/Graphics/Material.h>
- #include <Urho3D/Graphics/Model.h>
- #include <Urho3D/Graphics/ParticleEffect.h>
- #include <Urho3D/Graphics/ParticleEmitter.h>
- #include <Urho3D/Graphics/StaticModel.h>
- #include <Urho3D/IO/Log.h>
- #include <Urho3D/Physics/CollisionShape.h>
- #include <Urho3D/Physics/Constraint.h>
- #include <Urho3D/Physics/PhysicsEvents.h>
- #include <Urho3D/Physics/PhysicsUtils.h>
- #include <Urho3D/Physics/PhysicsWorld.h>
- #include <Urho3D/Physics/RaycastVehicle.h>
- #include <Urho3D/Physics/RigidBody.h>
- #include <Urho3D/Resource/ResourceCache.h>
- #include <Urho3D/Scene/Scene.h>
- #include <Urho3D/Urho3D.h>
- using namespace Urho3D;
- const float CHASSIS_WIDTH = 2.6f;
- const float WHEEL_WIDTH = 0.4f;
- void Vehicle::RegisterObject(Context* context)
- {
- context->RegisterFactory<Vehicle>();
- URHO3D_ATTRIBUTE("Steering", float, steering_, 0.0f, AM_DEFAULT);
- URHO3D_ATTRIBUTE("Controls Yaw", float, controls_.yaw_, 0.0f, AM_DEFAULT);
- URHO3D_ATTRIBUTE("Controls Pitch", float, controls_.pitch_, 0.0f, AM_DEFAULT);
- }
- Vehicle::Vehicle(Urho3D::Context* context)
- : LogicComponent(context),
- steering_(0.0f)
- {
- SetUpdateEventMask(USE_FIXEDUPDATE | USE_POSTUPDATE);
- engineForce_ = 0.0f;
- brakingForce_ = 50.0f;
- vehicleSteering_ = 0.0f;
- maxEngineForce_ = 2500.0f;
- wheelRadius_ = 0.5f;
- suspensionRestLength_ = 0.6f;
- wheelWidth_ = 0.4f;
- suspensionStiffness_ = 14.0f;
- suspensionDamping_ = 2.0f;
- suspensionCompression_ = 4.0f;
- wheelFriction_ = 1000.0f;
- rollInfluence_ = 0.12f;
- emittersCreated = false;
- }
- Vehicle::~Vehicle()
- {
- }
- void Vehicle::Init()
- {
- RaycastVehicle* vehicle = node_->CreateComponent<RaycastVehicle>();
- vehicle->Init();
- RigidBody* hullBody = node_->GetComponent<RigidBody>();
- hullBody->SetMass(800.0f);
- hullBody->SetLinearDamping(0.2f); // Some air resistance
- hullBody->SetAngularDamping(0.5f);
- hullBody->SetCollisionLayer(1);
- // This function is called only from the main program when initially creating the vehicle, not on scene load
- ResourceCache* cache = GetSubsystem<ResourceCache>();
- StaticModel* hullObject = node_->CreateComponent<StaticModel>();
- // Setting-up collision shape
- CollisionShape* hullColShape = node_->CreateComponent<CollisionShape>();
- Vector3 v3BoxExtents = Vector3::ONE;
- hullColShape->SetBox(v3BoxExtents);
- node_->SetScale(Vector3(2.3f, 1.0f, 4.0f));
- hullObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
- hullObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
- hullObject->SetCastShadows(true);
- float connectionHeight = -0.4f;
- bool isFrontWheel = true;
- Vector3 wheelDirection(0, -1, 0);
- Vector3 wheelAxle(-1, 0, 0);
- // We use not scaled coordinates here as everything will be scaled.
- // Wheels are on bottom at edges of the chassis
- // Note we don't set wheel nodes as children of hull (while we could) to avoid scaling to affect them.
- float wheelX = CHASSIS_WIDTH / 2.0f - wheelWidth_;
- // Front left
- connectionPoints_[0] = Vector3(-wheelX, connectionHeight, 2.5f - GetWheelRadius() * 2.0f);
- // Front right
- connectionPoints_[1] = Vector3(wheelX, connectionHeight, 2.5f - GetWheelRadius() * 2.0f);
- // Back left
- connectionPoints_[2] = Vector3(-wheelX, connectionHeight, -2.5f + GetWheelRadius() * 2.0f);
- // Back right
- connectionPoints_[3] = Vector3(wheelX, connectionHeight, -2.5f + GetWheelRadius() * 2.0f);
- const Color LtBrown(0.972f, 0.780f, 0.412f);
- for (int id = 0; id < sizeof(connectionPoints_) / sizeof(connectionPoints_[0]); id++)
- {
- Node* wheelNode = GetScene()->CreateChild();
- Vector3 connectionPoint = connectionPoints_[id];
- // Front wheels are at front (z > 0)
- // back wheels are at z < 0
- // Setting rotation according to wheel position
- bool isFrontWheel = connectionPoints_[id].z_ > 0.0f;
- wheelNode->SetRotation(connectionPoint.x_ >= 0.0 ? Quaternion(0.0f, 0.0f, -90.0f) : Quaternion(0.0f, 0.0f, 90.0f));
- wheelNode->SetWorldPosition(node_->GetWorldPosition() + node_->GetWorldRotation() * connectionPoints_[id]);
- vehicle->AddWheel(wheelNode, wheelDirection, wheelAxle, suspensionRestLength_, wheelRadius_, isFrontWheel);
- vehicle->SetWheelSuspensionStiffness(id, suspensionStiffness_);
- vehicle->SetWheelDampingRelaxation(id, suspensionDamping_);
- vehicle->SetWheelDampingCompression(id, suspensionCompression_);
- vehicle->SetWheelFrictionSlip(id, wheelFriction_);
- vehicle->SetWheelRollInfluence(id, rollInfluence_);
- wheelNode->SetScale(Vector3(1.0f, 0.65f, 1.0f));
- StaticModel* pWheel = wheelNode->CreateComponent<StaticModel>();
- pWheel->SetModel(cache->GetResource<Model>("Models/Cylinder.mdl"));
- pWheel->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
- pWheel->SetCastShadows(true);
- CreateEmitter(connectionPoints_[id]);
- }
- emittersCreated = true;
- vehicle->ResetWheels();
- }
- void Vehicle::CreateEmitter(Vector3 place)
- {
- ResourceCache* cache = GetSubsystem<ResourceCache>();
- Node* emitter = GetScene()->CreateChild();
- emitter->SetWorldPosition(node_->GetWorldPosition() + node_->GetWorldRotation() * place + Vector3(0, -wheelRadius_, 0));
- ParticleEmitter* particleEmitter = emitter->CreateComponent<ParticleEmitter>();
- particleEmitter->SetEffect(cache->GetResource<ParticleEffect>("Particle/Dust.xml"));
- particleEmitter->SetEmitting(false);
- particleEmitterNodeList_.Push(emitter);
- emitter->SetTemporary(true);
- }
- /// Applying attributes
- void Vehicle::ApplyAttributes()
- {
- RaycastVehicle* vehicle = node_->GetOrCreateComponent<RaycastVehicle>();
- if (emittersCreated)
- return;
- for (int i = 0; i < 4; i++)
- {
- CreateEmitter(connectionPoints_[i]);
- }
- emittersCreated = true;
- }
- void Vehicle::FixedUpdate(float timeStep)
- {
- float newSteering = 0.0f;
- float accelerator = 0.0f;
- bool brake = false;
- RaycastVehicle* vehicle = node_->GetComponent<RaycastVehicle>();
- // Read controls
- if (controls_.buttons_ & CTRL_LEFT)
- {
- newSteering = -1.0f;
- }
- if (controls_.buttons_ & CTRL_RIGHT)
- {
- newSteering = 1.0f;
- }
- if (controls_.buttons_ & CTRL_FORWARD)
- {
- accelerator = 1.0f;
- }
- if (controls_.buttons_ & CTRL_BACK)
- {
- accelerator = -0.5f;
- }
- if (controls_.buttons_ & CTRL_BRAKE)
- {
- brake = true;
- }
- // When steering, wake up the wheel rigidbodies so that their orientation is updated
- if (newSteering != 0.0f)
- {
- SetSteering(GetSteering() * 0.95f + newSteering * 0.05f);
- }
- else
- {
- SetSteering(GetSteering() * 0.8f + newSteering * 0.2f);
- }
- // Set front wheel angles
- vehicleSteering_ = steering_;
- int wheelIndex = 0;
- vehicle->SetSteeringValue(wheelIndex, vehicleSteering_);
- wheelIndex = 1;
- vehicle->SetSteeringValue(wheelIndex, vehicleSteering_);
- // apply forces
- engineForce_ = maxEngineForce_ * accelerator;
- // 2x wheel drive
- vehicle->SetEngineForce(2, engineForce_);
- vehicle->SetEngineForce(3, engineForce_);
- for (int i = 0; i < vehicle->GetNumWheels(); i++)
- {
- if (brake)
- {
- vehicle->SetBrake(i, brakingForce_);
- }
- else
- {
- vehicle->SetBrake(i, 0.0f);
- }
- }
- }
- void Vehicle::PostUpdate(float timeStep)
- {
- RaycastVehicle* vehicle = node_->GetComponent<RaycastVehicle>();
- RigidBody* vehicleBody = node_->GetComponent<RigidBody>();
- Vector3 velocity = vehicleBody->GetLinearVelocity();
- Vector3 accel = (velocity - prevVelocity_) / timeStep;
- float planeAccel = Vector3(accel.x_, 0.0f, accel.z_).Length();
- for (int i = 0; i < vehicle->GetNumWheels(); i++)
- {
- Node* emitter = particleEmitterNodeList_[i];
- ParticleEmitter* particleEmitter = emitter->GetComponent<ParticleEmitter>();
- if (vehicle->WheelIsGrounded(i) && (vehicle->GetWheelSkidInfoCumulative(i) < 0.9f || vehicle->GetBrake(i) > 2.0f ||
- planeAccel > 15.0f))
- {
- particleEmitterNodeList_[i]->SetWorldPosition(vehicle->GetContactPosition(i));
- if (!particleEmitter->IsEmitting())
- {
- particleEmitter->SetEmitting(true);
- }
- URHO3D_LOGDEBUG("GetWheelSkidInfoCumulative() = " +
- String(vehicle->GetWheelSkidInfoCumulative(i)) + " " +
- String(vehicle->GetMaxSideSlipSpeed()));
- /* TODO: Add skid marks here */
- }
- else if (particleEmitter->IsEmitting())
- {
- particleEmitter->SetEmitting(false);
- }
- }
- prevVelocity_ = velocity;
- }
|