Added vehicle sample.
This commit is contained in:
parent
04b00263b0
commit
26901cdc4c
@ -1,3 +1,25 @@
|
||||
//
|
||||
// Copyright (c) 2008-2013 the Urho3D project.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#include "AnimationController.h"
|
||||
#include "Character.h"
|
||||
#include "MemoryBuffer.h"
|
||||
@ -17,9 +39,12 @@ Character::Character(Context* context) :
|
||||
|
||||
void Character::OnNodeSet(Node* node)
|
||||
{
|
||||
// Component has been inserted into its scene node. Subscribe to events now
|
||||
SubscribeToEvent(node, E_NODECOLLISION, HANDLER(Character, HandleNodeCollision));
|
||||
SubscribeToEvent(GetScene()->GetComponent<PhysicsWorld>(), E_PHYSICSPRESTEP, HANDLER(Character, HandleFixedUpdate));
|
||||
if (node)
|
||||
{
|
||||
// Component has been inserted into its scene node. Subscribe to events now
|
||||
SubscribeToEvent(node, E_NODECOLLISION, HANDLER(Character, HandleNodeCollision));
|
||||
SubscribeToEvent(GetScene()->GetComponent<PhysicsWorld>(), E_PHYSICSPRESTEP, HANDLER(Character, HandleFixedUpdate));
|
||||
}
|
||||
}
|
||||
|
||||
void Character::HandleNodeCollision(StringHash eventType, VariantMap& eventData)
|
||||
@ -71,9 +96,9 @@ void Character::HandleFixedUpdate(StringHash eventType, VariantMap& eventData)
|
||||
// Velocity on the XZ plane
|
||||
Vector3 planeVelocity(velocity.x_, 0.0f, velocity.z_);
|
||||
|
||||
if (controls_.IsDown(CTRL_UP))
|
||||
if (controls_.IsDown(CTRL_FORWARD))
|
||||
moveDir += Vector3::FORWARD;
|
||||
if (controls_.IsDown(CTRL_DOWN))
|
||||
if (controls_.IsDown(CTRL_BACK))
|
||||
moveDir += Vector3::BACK;
|
||||
if (controls_.IsDown(CTRL_LEFT))
|
||||
moveDir += Vector3::LEFT;
|
||||
|
@ -27,13 +27,11 @@
|
||||
|
||||
using namespace Urho3D;
|
||||
|
||||
const int CTRL_UP = 1;
|
||||
const int CTRL_DOWN = 2;
|
||||
const int CTRL_FORWARD = 1;
|
||||
const int CTRL_BACK = 2;
|
||||
const int CTRL_LEFT = 4;
|
||||
const int CTRL_RIGHT = 8;
|
||||
const int CTRL_FIRE = 16;
|
||||
const int CTRL_JUMP = 32;
|
||||
const int CTRL_ALL = 63;
|
||||
const int CTRL_JUMP = 16;
|
||||
|
||||
const float MOVE_FORCE = 0.8f;
|
||||
const float INAIR_MOVE_FORCE = 0.02f;
|
||||
@ -54,13 +52,15 @@ public:
|
||||
/// Handle node being assigned.
|
||||
virtual void OnNodeSet(Node* node);
|
||||
|
||||
/// Movement controls.
|
||||
Controls controls_;
|
||||
|
||||
private:
|
||||
/// Handle physics collision event.
|
||||
void HandleNodeCollision(StringHash eventType, VariantMap& eventData);
|
||||
/// Handle physics world update event.
|
||||
void HandleFixedUpdate(StringHash eventType, VariantMap& eventData);
|
||||
|
||||
/// Movement controls.
|
||||
Controls controls_;
|
||||
/// Grounded flag for movement.
|
||||
bool onGround_;
|
||||
/// Jump flag.
|
||||
|
@ -1,3 +1,25 @@
|
||||
//
|
||||
// Copyright (c) 2008-2013 the Urho3D project.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#include "AnimatedModel.h"
|
||||
#include "AnimationController.h"
|
||||
#include "Camera.h"
|
||||
@ -71,6 +93,7 @@ void CharacterDemo::CreateScene()
|
||||
// Create camera and define viewport. Camera does not necessarily have to belong to the scene
|
||||
cameraNode_ = new Node(context_);
|
||||
Camera* camera = cameraNode_->CreateComponent<Camera>();
|
||||
camera->SetFarClip(300.0f);
|
||||
GetSubsystem<Renderer>()->SetViewport(0, new Viewport(context_, scene_, camera));
|
||||
|
||||
// Create static scene content. First create a zone for ambient lighting and fog control
|
||||
@ -230,8 +253,8 @@ void CharacterDemo::HandleUpdate(StringHash eventType, VariantMap& eventData)
|
||||
// Get movement controls and assign them to the character logic component. If UI has a focused element, clear controls
|
||||
if (!ui->GetFocusElement())
|
||||
{
|
||||
character_->controls_.Set(CTRL_UP, input->GetKeyDown('W'));
|
||||
character_->controls_.Set(CTRL_DOWN, input->GetKeyDown('S'));
|
||||
character_->controls_.Set(CTRL_FORWARD, input->GetKeyDown('W'));
|
||||
character_->controls_.Set(CTRL_BACK, input->GetKeyDown('S'));
|
||||
character_->controls_.Set(CTRL_LEFT, input->GetKeyDown('A'));
|
||||
character_->controls_.Set(CTRL_RIGHT, input->GetKeyDown('D'));
|
||||
character_->controls_.Set(CTRL_JUMP, input->GetKeyDown(KEY_SPACE));
|
||||
@ -247,7 +270,7 @@ void CharacterDemo::HandleUpdate(StringHash eventType, VariantMap& eventData)
|
||||
firstPerson_ = !firstPerson_;
|
||||
}
|
||||
else
|
||||
character_->controls_.Set(CTRL_UP | CTRL_DOWN | CTRL_LEFT | CTRL_RIGHT | CTRL_JUMP, false);
|
||||
character_->controls_.Set(CTRL_FORWARD | CTRL_BACK | CTRL_LEFT | CTRL_RIGHT | CTRL_JUMP, false);
|
||||
|
||||
// Set rotation already here so that it's updated every rendering frame instead of every physics frame
|
||||
character_->GetNode()->SetRotation(Quaternion(character_->controls_.yaw_, Vector3::UP));
|
||||
|
@ -33,12 +33,12 @@ namespace Urho3D
|
||||
using namespace Urho3D;
|
||||
|
||||
class Character;
|
||||
|
||||
/// Moving character example.
|
||||
/// This sample demonstrates:
|
||||
/// - Controlling a humanoid character through physics;
|
||||
/// - Driving animations using the AnimationController component;
|
||||
/// - Implementing 1st and 3rd person cameras, using raycasts to avoid the 3rd person camera
|
||||
|
||||
/// Moving character example.
|
||||
/// This sample demonstrates:
|
||||
/// - Controlling a humanoid character through physics;
|
||||
/// - Driving animations using the AnimationController component;
|
||||
/// - Implementing 1st and 3rd person cameras, using raycasts to avoid the 3rd person camera
|
||||
/// clipping into scenery
|
||||
class CharacterDemo : public Sample
|
||||
{
|
||||
@ -56,7 +56,7 @@ private:
|
||||
void CreateScene();
|
||||
/// Create controllable character.
|
||||
void CreateCharacter();
|
||||
/// Construct an instruction text to the UI.
|
||||
/// Construct an instruction text to the UI.
|
||||
void CreateInstructions();
|
||||
/// Subscribe to necessary events.
|
||||
void SubscribeToEvents();
|
||||
@ -69,7 +69,7 @@ private:
|
||||
SharedPtr<Scene> scene_;
|
||||
/// Camera scene node.
|
||||
SharedPtr<Node> cameraNode_;
|
||||
/// The controllable character.
|
||||
/// The controllable character component.
|
||||
WeakPtr<Character> character_;
|
||||
/// First person camera flag.
|
||||
bool firstPerson_;
|
||||
|
32
Source/Samples/19_VehicleDemo/CMakeLists.txt
Normal file
32
Source/Samples/19_VehicleDemo/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
||||
#
|
||||
# Copyright (c) 2008-2013 the Urho3D project.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
|
||||
# Define target name
|
||||
set (TARGET_NAME 19_VehicleDemo)
|
||||
|
||||
# Define source files
|
||||
file (GLOB CPP_FILES *.cpp)
|
||||
file (GLOB H_FILES *.h)
|
||||
set (SOURCE_FILES ${CPP_FILES} ${H_FILES} ${COMMON_SAMPLE_H_FILES})
|
||||
|
||||
# Setup target with resource copying
|
||||
setup_main_executable ()
|
161
Source/Samples/19_VehicleDemo/Vehicle.cpp
Normal file
161
Source/Samples/19_VehicleDemo/Vehicle.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
//
|
||||
// Copyright (c) 2008-2013 the Urho3D project.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#include "CollisionShape.h"
|
||||
#include "Constraint.h"
|
||||
#include "Material.h"
|
||||
#include "Model.h"
|
||||
#include "PhysicsEvents.h"
|
||||
#include "PhysicsWorld.h"
|
||||
#include "ResourceCache.h"
|
||||
#include "RigidBody.h"
|
||||
#include "Scene.h"
|
||||
#include "StaticModel.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
Vehicle::Vehicle(Context* context) :
|
||||
Component(context),
|
||||
steering_(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
void Vehicle::OnNodeSet(Node* node)
|
||||
{
|
||||
if (node)
|
||||
SubscribeToEvent(GetScene()->GetComponent<PhysicsWorld>(), E_PHYSICSPRESTEP, HANDLER(Vehicle, HandleFixedUpdate));
|
||||
}
|
||||
|
||||
void Vehicle::Init()
|
||||
{
|
||||
ResourceCache* cache = GetSubsystem<ResourceCache>();
|
||||
|
||||
StaticModel* hullObject = node_->CreateComponent<StaticModel>();
|
||||
hullBody_ = node_->CreateComponent<RigidBody>();
|
||||
CollisionShape* hullShape = node_->CreateComponent<CollisionShape>();
|
||||
|
||||
node_->SetScale(Vector3(1.5f, 1.0f, 3.0f));
|
||||
hullObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
|
||||
hullObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
|
||||
hullObject->SetCastShadows(true);
|
||||
hullShape->SetBox(Vector3::ONE);
|
||||
hullBody_->SetMass(4.0f);
|
||||
hullBody_->SetLinearDamping(0.2f); // Some air resistance
|
||||
hullBody_->SetAngularDamping(0.5f);
|
||||
hullBody_->SetCollisionLayer(1);
|
||||
|
||||
frontLeft_ = InitWheel("FrontLeft", Vector3(-0.6f, -0.4f, 0.3f));
|
||||
frontRight_ = InitWheel("FrontRight", Vector3(0.6f, -0.4f, 0.3f));
|
||||
rearLeft_ = InitWheel("RearLeft", Vector3(-0.6f, -0.4f, -0.3f));
|
||||
rearRight_ = InitWheel("RearRight", Vector3(0.6f, -0.4f, -0.3f));
|
||||
|
||||
frontLeftAxis_ = frontLeft_->GetComponent<Constraint>();
|
||||
frontRightAxis_ = frontRight_->GetComponent<Constraint>();
|
||||
frontLeftBody_ = frontLeft_->GetComponent<RigidBody>();
|
||||
frontRightBody_ = frontRight_->GetComponent<RigidBody>();
|
||||
rearLeftBody_ = rearLeft_->GetComponent<RigidBody>();
|
||||
rearRightBody_ = rearRight_->GetComponent<RigidBody>();
|
||||
}
|
||||
|
||||
Node* Vehicle::InitWheel(const String& name, const Vector3& offset)
|
||||
{
|
||||
ResourceCache* cache = GetSubsystem<ResourceCache>();
|
||||
|
||||
// Note: do not parent the wheel to the hull scene node. Instead create it on the root level and let the physics
|
||||
// constraint keep it together
|
||||
Node* wheelNode = GetScene()->CreateChild(name);
|
||||
wheelNode->SetPosition(node_->LocalToWorld(offset));
|
||||
wheelNode->SetRotation(node_->GetWorldRotation() * (offset.x_ >= 0.0 ? Quaternion(0.0f, 0.0f, -90.0f) :
|
||||
Quaternion(0.0f, 0.0f, 90.0f)));
|
||||
wheelNode->SetScale(Vector3(0.8f, 0.5f, 0.8f));
|
||||
|
||||
StaticModel* wheelObject = wheelNode->CreateComponent<StaticModel>();
|
||||
RigidBody* wheelBody = wheelNode->CreateComponent<RigidBody>();
|
||||
CollisionShape* wheelShape = wheelNode->CreateComponent<CollisionShape>();
|
||||
Constraint* wheelConstraint = wheelNode->CreateComponent<Constraint>();
|
||||
|
||||
wheelObject->SetModel(cache->GetResource<Model>("Models/Cylinder.mdl"));
|
||||
wheelObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
|
||||
wheelObject->SetCastShadows(true);
|
||||
wheelShape->SetSphere(1.0f);
|
||||
wheelBody->SetFriction(1.0f);
|
||||
wheelBody->SetMass(1.0f);
|
||||
wheelBody->SetLinearDamping(0.2f); // Some air resistance
|
||||
wheelBody->SetAngularDamping(0.75f); // Could also use rolling friction
|
||||
wheelBody->SetCollisionLayer(1);
|
||||
wheelConstraint->SetConstraintType(CONSTRAINT_HINGE);
|
||||
wheelConstraint->SetOtherBody(GetComponent<RigidBody>()); // Connect to the hull body
|
||||
wheelConstraint->SetWorldPosition(wheelNode->GetWorldPosition()); // Set constraint's both ends at wheel's location
|
||||
wheelConstraint->SetAxis(Vector3::UP); // Wheel rotates around its local Y-axis
|
||||
wheelConstraint->SetOtherAxis(offset.x_ >= 0.0 ? Vector3::RIGHT : Vector3::LEFT); // Wheel's hull axis points either left or right
|
||||
wheelConstraint->SetLowLimit(Vector2(-180.0f, 0.0f)); // Let the wheel rotate freely around the axis
|
||||
wheelConstraint->SetHighLimit(Vector2(180.0f, 0.0f));
|
||||
wheelConstraint->SetDisableCollision(true); // Let the wheel intersect the vehicle hull
|
||||
|
||||
return wheelNode;
|
||||
}
|
||||
|
||||
void Vehicle::HandleFixedUpdate(StringHash eventType, VariantMap& eventData)
|
||||
{
|
||||
float newSteering = 0.0f;
|
||||
float accelerator = 0.0f;
|
||||
|
||||
// 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;
|
||||
|
||||
// When steering, wake up the wheel rigidbodies so that their orientation is updated
|
||||
if (newSteering != 0.0f)
|
||||
{
|
||||
frontLeftBody_->Activate();
|
||||
frontRightBody_->Activate();
|
||||
steering_ = steering_ * 0.95f + newSteering * 0.05f;
|
||||
}
|
||||
else
|
||||
steering_ = steering_ * 0.8f + newSteering * 0.2f;
|
||||
|
||||
// Set front wheel angles
|
||||
Quaternion steeringRot(0, steering_ * MAX_WHEEL_ANGLE, 0);
|
||||
frontLeftAxis_->SetOtherAxis(steeringRot * Vector3::LEFT);
|
||||
frontRightAxis_->SetOtherAxis(steeringRot * Vector3::RIGHT);
|
||||
|
||||
Quaternion hullRot = hullBody_->GetRotation();
|
||||
if (accelerator != 0.0f)
|
||||
{
|
||||
// Torques are applied in world space, so need to take the vehicle & wheel rotation into account
|
||||
Vector3 torqueVec = Vector3(ENGINE_POWER * accelerator, 0.0f, 0.0f);
|
||||
|
||||
frontLeftBody_->ApplyTorque(hullRot * steeringRot * torqueVec);
|
||||
frontRightBody_->ApplyTorque(hullRot * steeringRot * torqueVec);
|
||||
rearLeftBody_->ApplyTorque(hullRot * torqueVec);
|
||||
rearRightBody_->ApplyTorque(hullRot * torqueVec);
|
||||
}
|
||||
|
||||
// Apply downforce proportional to velocity
|
||||
Vector3 localVelocity = hullRot.Inverse() * hullBody_->GetLinearVelocity();
|
||||
hullBody_->ApplyForce(hullRot * Vector3::DOWN * Abs(localVelocity.z_) * DOWN_FORCE);
|
||||
}
|
90
Source/Samples/19_VehicleDemo/Vehicle.h
Normal file
90
Source/Samples/19_VehicleDemo/Vehicle.h
Normal file
@ -0,0 +1,90 @@
|
||||
//
|
||||
// Copyright (c) 2008-2013 the Urho3D project.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Component.h"
|
||||
#include "Controls.h"
|
||||
|
||||
namespace Urho3D
|
||||
{
|
||||
class Constraint;
|
||||
class Node;
|
||||
class RigidBody;
|
||||
}
|
||||
|
||||
using namespace Urho3D;
|
||||
|
||||
const int CTRL_FORWARD = 1;
|
||||
const int CTRL_BACK = 2;
|
||||
const int CTRL_LEFT = 4;
|
||||
const int CTRL_RIGHT = 8;
|
||||
|
||||
const float YAW_SENSITIVITY = 0.1f;
|
||||
const float ENGINE_POWER = 10.0f;
|
||||
const float DOWN_FORCE = 10.0f;
|
||||
const float MAX_WHEEL_ANGLE = 22.5f;
|
||||
|
||||
/// Vehicle component, responsible for physical movement according to controls.
|
||||
class Vehicle : public Component
|
||||
{
|
||||
OBJECT(Vehicle)
|
||||
|
||||
public:
|
||||
/// Construct.
|
||||
Vehicle(Context* context);
|
||||
|
||||
/// Handle node being assigned.
|
||||
virtual void OnNodeSet(Node* node);
|
||||
|
||||
/// Initialize the vehicle. Create rendering and physics components.
|
||||
void Init();
|
||||
|
||||
/// Movement controls.
|
||||
Controls controls_;
|
||||
|
||||
private:
|
||||
/// Initialize a wheel and return its scene node.
|
||||
Node* InitWheel(const String& name, const Vector3& offset);
|
||||
/// Handle physics world update event.
|
||||
void HandleFixedUpdate(StringHash eventType, VariantMap& eventData);
|
||||
|
||||
// Wheel scene nodes.
|
||||
WeakPtr<Node> frontLeft_;
|
||||
WeakPtr<Node> frontRight_;
|
||||
WeakPtr<Node> rearLeft_;
|
||||
WeakPtr<Node> rearRight_;
|
||||
|
||||
// Steering axle constraints.
|
||||
WeakPtr<Constraint> frontLeftAxis_;
|
||||
WeakPtr<Constraint> frontRightAxis_;
|
||||
|
||||
// Hull and wheel rigid bodies.
|
||||
WeakPtr<RigidBody> hullBody_;
|
||||
WeakPtr<RigidBody> frontLeftBody_;
|
||||
WeakPtr<RigidBody> frontRightBody_;
|
||||
WeakPtr<RigidBody> rearLeftBody_;
|
||||
WeakPtr<RigidBody> rearRightBody_;
|
||||
|
||||
/// Current left/right steering amount (-1 to 1.)
|
||||
float steering_;
|
||||
};
|
251
Source/Samples/19_VehicleDemo/VehicleDemo.cpp
Normal file
251
Source/Samples/19_VehicleDemo/VehicleDemo.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
//
|
||||
// Copyright (c) 2008-2013 the Urho3D project.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#include "Camera.h"
|
||||
#include "CollisionShape.h"
|
||||
#include "Constraint.h"
|
||||
#include "CoreEvents.h"
|
||||
#include "Engine.h"
|
||||
#include "Font.h"
|
||||
#include "Input.h"
|
||||
#include "Light.h"
|
||||
#include "Material.h"
|
||||
#include "Model.h"
|
||||
#include "Octree.h"
|
||||
#include "PhysicsWorld.h"
|
||||
#include "ProcessUtils.h"
|
||||
#include "Renderer.h"
|
||||
#include "RigidBody.h"
|
||||
#include "ResourceCache.h"
|
||||
#include "Scene.h"
|
||||
#include "StaticModel.h"
|
||||
#include "Terrain.h"
|
||||
#include "Text.h"
|
||||
#include "UI.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Zone.h"
|
||||
|
||||
#include "VehicleDemo.h"
|
||||
|
||||
#include "DebugNew.h"
|
||||
|
||||
const float CAMERA_MIN_DIST = 3.0f;
|
||||
const float CAMERA_MAX_DIST = 8.0f;
|
||||
|
||||
DEFINE_APPLICATION_MAIN(VehicleDemo)
|
||||
|
||||
VehicleDemo::VehicleDemo(Context* context) :
|
||||
Sample(context)
|
||||
{
|
||||
// Register factory for the Vehicle component so it can be created via CreateComponent
|
||||
context_->RegisterFactory<Vehicle>();
|
||||
}
|
||||
|
||||
void VehicleDemo::Start()
|
||||
{
|
||||
// Execute base class startup
|
||||
Sample::Start();
|
||||
|
||||
// Create static scene content
|
||||
CreateScene();
|
||||
|
||||
// Create the controllable vehicle
|
||||
CreateVehicle();
|
||||
|
||||
// Create the UI content
|
||||
CreateInstructions();
|
||||
|
||||
// Subscribe to necessary events
|
||||
SubscribeToEvents();
|
||||
}
|
||||
|
||||
void VehicleDemo::CreateScene()
|
||||
{
|
||||
ResourceCache* cache = GetSubsystem<ResourceCache>();
|
||||
|
||||
scene_ = new Scene(context_);
|
||||
|
||||
// Create scene subsystem components
|
||||
scene_->CreateComponent<Octree>();
|
||||
scene_->CreateComponent<PhysicsWorld>();
|
||||
|
||||
// Create camera and define viewport. Camera does not necessarily have to belong to the scene
|
||||
cameraNode_ = new Node(context_);
|
||||
Camera* camera = cameraNode_->CreateComponent<Camera>();
|
||||
camera->SetFarClip(500.0f);
|
||||
GetSubsystem<Renderer>()->SetViewport(0, new Viewport(context_, scene_, camera));
|
||||
|
||||
// Create static scene content. First create a zone for ambient lighting and fog control
|
||||
Node* zoneNode = scene_->CreateChild("Zone");
|
||||
Zone* zone = zoneNode->CreateComponent<Zone>();
|
||||
zone->SetAmbientColor(Color(0.15f, 0.15f, 0.15f));
|
||||
zone->SetFogColor(Color(0.5f, 0.5f, 0.7f));
|
||||
zone->SetFogStart(300.0f);
|
||||
zone->SetFogEnd(500.0f);
|
||||
zone->SetBoundingBox(BoundingBox(-2000.0f, 2000.0f));
|
||||
|
||||
// Create a directional light with cascaded shadow mapping
|
||||
Node* lightNode = scene_->CreateChild("DirectionalLight");
|
||||
lightNode->SetDirection(Vector3(0.3f, -0.5f, 0.425f));
|
||||
Light* light = lightNode->CreateComponent<Light>();
|
||||
light->SetLightType(LIGHT_DIRECTIONAL);
|
||||
light->SetCastShadows(true);
|
||||
light->SetShadowBias(BiasParameters(0.0001f, 0.5f));
|
||||
light->SetShadowCascade(CascadeParameters(10.0f, 50.0f, 200.0f, 0.0f, 0.8f));
|
||||
light->SetSpecularIntensity(0.5f);
|
||||
|
||||
// Create heightmap terrain with collision
|
||||
Node* terrainNode = scene_->CreateChild("Terrain");
|
||||
terrainNode->SetPosition(Vector3::ZERO);
|
||||
Terrain* terrain = terrainNode->CreateComponent<Terrain>();
|
||||
terrain->SetPatchSize(64);
|
||||
terrain->SetSpacing(Vector3(2.0f, 0.1f, 2.0f)); // Spacing between vertices and vertical resolution of the height map
|
||||
terrain->SetSmoothing(true);
|
||||
terrain->SetHeightMap(cache->GetResource<Image>("Textures/HeightMap.png"));
|
||||
terrain->SetMaterial(cache->GetResource<Material>("Materials/Terrain.xml"));
|
||||
// The terrain consists of large triangles, which fits well for occlusion rendering, as a hill can occlude all
|
||||
// terrain patches and other objects behind it
|
||||
terrain->SetOccluder(true);
|
||||
|
||||
RigidBody* body = terrainNode->CreateComponent<RigidBody>();
|
||||
body->SetCollisionLayer(2); // Use layer bitmask 2 for static geometry
|
||||
CollisionShape* shape = terrainNode->CreateComponent<CollisionShape>();
|
||||
shape->SetTerrain();
|
||||
|
||||
// Create 1000 mushrooms in the terrain. Always face outward along the terrain normal
|
||||
const unsigned NUM_MUSHROOMS = 1000;
|
||||
for (unsigned i = 0; i < NUM_MUSHROOMS; ++i)
|
||||
{
|
||||
Node* objectNode = scene_->CreateChild("Mushroom");
|
||||
Vector3 position(Random(2000.0f) - 1000.0f, 0.0f, Random(2000.0f) - 1000.0f);
|
||||
position.y_ = terrain->GetHeight(position) - 0.1f;
|
||||
objectNode->SetPosition(position);
|
||||
// Create a rotation quaternion from up vector to terrain normal
|
||||
objectNode->SetRotation(Quaternion(Vector3::UP, terrain->GetNormal(position)));
|
||||
objectNode->SetScale(3.0f);
|
||||
StaticModel* object = objectNode->CreateComponent<StaticModel>();
|
||||
object->SetModel(cache->GetResource<Model>("Models/Mushroom.mdl"));
|
||||
object->SetMaterial(cache->GetResource<Material>("Materials/Mushroom.xml"));
|
||||
object->SetCastShadows(true);
|
||||
|
||||
RigidBody* body = objectNode->CreateComponent<RigidBody>();
|
||||
body->SetCollisionLayer(2);
|
||||
CollisionShape* shape = objectNode->CreateComponent<CollisionShape>();
|
||||
shape->SetTriangleMesh(object->GetModel(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void VehicleDemo::CreateVehicle()
|
||||
{
|
||||
ResourceCache* cache = GetSubsystem<ResourceCache>();
|
||||
|
||||
Node* vehicleNode = scene_->CreateChild("Vehicle");
|
||||
vehicleNode->SetPosition(Vector3(0.0f, 5.0f, 0.0f));
|
||||
|
||||
// Create the vehicle logic component
|
||||
vehicle_ = vehicleNode->CreateComponent<Vehicle>();
|
||||
// Create the rendering and physics components
|
||||
vehicle_->Init();
|
||||
}
|
||||
|
||||
void VehicleDemo::CreateInstructions()
|
||||
{
|
||||
ResourceCache* cache = GetSubsystem<ResourceCache>();
|
||||
UI* ui = GetSubsystem<UI>();
|
||||
|
||||
// Construct new Text object, set string to display and font to use
|
||||
Text* instructionText = ui->GetRoot()->CreateChild<Text>();
|
||||
instructionText->SetText(
|
||||
"Use WASD keys to drive, mouse to rotate camera"
|
||||
);
|
||||
instructionText->SetFont(cache->GetResource<Font>("Fonts/Anonymous Pro.ttf"), 15);
|
||||
|
||||
// Position the text relative to the screen center
|
||||
instructionText->SetHorizontalAlignment(HA_CENTER);
|
||||
instructionText->SetVerticalAlignment(VA_CENTER);
|
||||
instructionText->SetPosition(0, ui->GetRoot()->GetHeight() / 4);
|
||||
}
|
||||
|
||||
void VehicleDemo::SubscribeToEvents()
|
||||
{
|
||||
// Subscribe to Update event for setting the character controls before physics simulation
|
||||
SubscribeToEvent(E_UPDATE, HANDLER(VehicleDemo, HandleUpdate));
|
||||
|
||||
// Subscribe to PostUpdate event for updating the camera position after physics simulation
|
||||
SubscribeToEvent(E_POSTUPDATE, HANDLER(VehicleDemo, HandlePostUpdate));
|
||||
}
|
||||
|
||||
void VehicleDemo::HandleUpdate(StringHash eventType, VariantMap& eventData)
|
||||
{
|
||||
using namespace Update;
|
||||
|
||||
float timeStep = eventData[P_TIMESTEP].GetFloat();
|
||||
Input* input = GetSubsystem<Input>();
|
||||
|
||||
if (vehicle_)
|
||||
{
|
||||
UI* ui = GetSubsystem<UI>();
|
||||
|
||||
// Get movement controls and assign them to the vehicle component. If UI has a focused element, clear controls
|
||||
if (!ui->GetFocusElement())
|
||||
{
|
||||
vehicle_->controls_.Set(CTRL_FORWARD, input->GetKeyDown('W'));
|
||||
vehicle_->controls_.Set(CTRL_BACK, input->GetKeyDown('S'));
|
||||
vehicle_->controls_.Set(CTRL_LEFT, input->GetKeyDown('A'));
|
||||
vehicle_->controls_.Set(CTRL_RIGHT, input->GetKeyDown('D'));
|
||||
|
||||
// Add yaw & pitch from the mouse motion. Used only for the camera, does not affect motion
|
||||
vehicle_->controls_.yaw_ += (float)input->GetMouseMoveX() * YAW_SENSITIVITY;
|
||||
vehicle_->controls_.pitch_ += (float)input->GetMouseMoveY() * YAW_SENSITIVITY;
|
||||
// Limit pitch
|
||||
vehicle_->controls_.pitch_ = Clamp(vehicle_->controls_.pitch_, 1.0f, 80.0f);
|
||||
}
|
||||
else
|
||||
vehicle_->controls_.Set(CTRL_FORWARD | CTRL_BACK | CTRL_LEFT | CTRL_RIGHT, false);
|
||||
}
|
||||
}
|
||||
|
||||
void VehicleDemo::HandlePostUpdate(StringHash eventType, VariantMap& eventData)
|
||||
{
|
||||
if (!vehicle_)
|
||||
return;
|
||||
|
||||
Node* vehicleNode = vehicle_->GetNode();
|
||||
|
||||
// Get camera lookat dir from vehicle yaw + camera yaw and camera pitch. Do not apply vehicle's pitch
|
||||
// angle, because it changes abruptly when going over bumps in the terrain
|
||||
Quaternion rot = Quaternion(0.0f, vehicleNode->GetRotation().YawAngle() + vehicle_->controls_.yaw_, 0.0f);
|
||||
Quaternion dir = rot * Quaternion(vehicle_->controls_.pitch_, Vector3::RIGHT);
|
||||
Vector3 aimPoint = vehicleNode->GetPosition() + rot * Vector3(0.0f, 1.7f, 0.0f);
|
||||
|
||||
// Collide camera ray with static physics objects (layer bitmask 2) to ensure we see the vehicle properly
|
||||
Vector3 rayDir = dir * Vector3::BACK;
|
||||
float rayDistance = CAMERA_MAX_DIST;
|
||||
PhysicsRaycastResult result;
|
||||
scene_->GetComponent<PhysicsWorld>()->RaycastSingle(result, Ray(aimPoint, rayDir), rayDistance, 2);
|
||||
if (result.body_)
|
||||
rayDistance = Min(rayDistance, result.distance_);
|
||||
rayDistance = Clamp(rayDistance, CAMERA_MIN_DIST, CAMERA_MAX_DIST);
|
||||
|
||||
cameraNode_->SetPosition(aimPoint + rayDir * rayDistance);
|
||||
cameraNode_->SetRotation(dir);
|
||||
}
|
72
Source/Samples/19_VehicleDemo/VehicleDemo.h
Normal file
72
Source/Samples/19_VehicleDemo/VehicleDemo.h
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// Copyright (c) 2008-2013 the Urho3D project.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Sample.h"
|
||||
|
||||
namespace Urho3D
|
||||
{
|
||||
class Node;
|
||||
class Scene;
|
||||
}
|
||||
|
||||
using namespace Urho3D;
|
||||
|
||||
class Vehicle;
|
||||
|
||||
/// Vehicle example.
|
||||
/// This sample demonstrates:
|
||||
/// - Creating a heightmap terrain with collision;
|
||||
/// - Constructing a physical vehicle with rigid bodies for the hull and the wheels, joined with constraints;
|
||||
class VehicleDemo : public Sample
|
||||
{
|
||||
OBJECT(VehicleDemo);
|
||||
|
||||
public:
|
||||
/// Construct.
|
||||
VehicleDemo(Context* context);
|
||||
|
||||
/// Setup after engine initialization and before running the main loop.
|
||||
virtual void Start();
|
||||
|
||||
private:
|
||||
/// Create static scene content.
|
||||
void CreateScene();
|
||||
/// Create the vehicle.
|
||||
void CreateVehicle();
|
||||
/// Construct an instruction text to the UI.
|
||||
void CreateInstructions();
|
||||
/// Subscribe to necessary events.
|
||||
void SubscribeToEvents();
|
||||
/// Handle application update. Set controls to vehicle.
|
||||
void HandleUpdate(StringHash eventType, VariantMap& eventData);
|
||||
/// Handle application post-update. Update camera position after vehicle has moved.
|
||||
void HandlePostUpdate(StringHash eventType, VariantMap& eventData);
|
||||
|
||||
/// Scene.
|
||||
SharedPtr<Scene> scene_;
|
||||
/// Camera scene node.
|
||||
SharedPtr<Node> cameraNode_;
|
||||
/// The controllable vehicle component.
|
||||
WeakPtr<Vehicle> vehicle_;
|
||||
};
|
@ -59,4 +59,5 @@ add_subdirectory (14_SoundEffects)
|
||||
add_subdirectory (15_Navigation)
|
||||
add_subdirectory (16_Chat)
|
||||
add_subdirectory (17_SceneReplication)
|
||||
add_subdirectory (18_CharacterDemo)
|
||||
add_subdirectory (18_CharacterDemo)
|
||||
add_subdirectory (19_VehicleDemo)
|
Loading…
Reference in New Issue
Block a user