1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-25 11:52:40 +01:00

Initial chase scene implementation, opening cutscene chase works

This commit is contained in:
Daniel Evans 2016-04-13 01:47:19 +01:00
parent 14c33024b7
commit 46621093f9
6 changed files with 260 additions and 3 deletions

View File

@ -0,0 +1,57 @@
#ifndef _CHASE_HPP_
#define _CHASE_HPP_
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <string>
#include <vector>
#include <map>
class GameObject;
struct ChaseKeyframe
{
glm::vec3 velocity;
int steeringAngle;
int acceleratorPower;
int brakePower;
bool handbrake;
glm::vec3 position;
glm::quat rotation;
static bool load(const std::string& filePath, std::vector<ChaseKeyframe>& frames);
};
/**
* @brief The ChaseCoordinator class handles loading and playing a chase
*
* It reads in ChaseKeyframes for a set of objects, and replays them
* over time.
*/
class ChaseCoordinator
{
public:
ChaseCoordinator()
: chaseTime(-1.f)
{ }
bool addChaseVehicle(GameObject* vehicle, int index, const std::string& pathFile);
GameObject* getChaseVehicle(int index);
void removeChaseVehicle(int index);
void start();
void update(float dt);
void cleanup();
private:
float chaseTime;
struct ChaseObject {
std::vector<ChaseKeyframe> keyframes;
GameObject* object;
};
std::map<int, ChaseObject> chaseVehicles;
};
#endif

View File

@ -27,6 +27,8 @@ class VehicleObject;
class InventoryItem;
struct WeaponScan;
#include <data/Chase.hpp>
#include <glm/glm.hpp>
#include <btBulletDynamicsCommon.h>
@ -167,6 +169,11 @@ public:
*/
SoundManager sound;
/**
* Chase state
*/
ChaseCoordinator chase;
/**
* Each object type is allocated from a pool. This object helps manage
* the individual pools.

127
rwengine/src/data/Chase.cpp Normal file
View File

@ -0,0 +1,127 @@
#include "data/Chase.hpp"
#include <fstream>
#include <cstdint>
#include <rw/defines.hpp>
#include <objects/GameObject.hpp>
#include <engine/GameWorld.hpp>
#define KEYFRAMES_PER_SECOND 30
bool ChaseKeyframe::load(const std::string &filePath, std::vector<ChaseKeyframe> &frames)
{
std::ifstream chaseFile(filePath, std::ios_base::binary);
RW_CHECK(chaseFile.is_open(), "Failed to open chase file");
if (!chaseFile.is_open()) {
return false;
}
chaseFile.seekg(0, std::ios_base::end);
size_t fileLength = chaseFile.tellg();
chaseFile.seekg(0);
struct ChaseEntryRecord {
int16_t velocity[3];
int8_t right[3];
int8_t up[3];
uint8_t steering;
uint8_t driving;
uint8_t braking;
uint8_t handbrake;
glm::vec3 position;
};
static_assert(sizeof(ChaseEntryRecord) == 28, "ChaseEntryRecord is not 28 bytes");
RW_CHECK(fileLength % sizeof(ChaseEntryRecord) == 0, "File is not a mulitple of 28 byte");
size_t recordCount = fileLength / sizeof(ChaseEntryRecord);
for (size_t i = 0; i < recordCount; ++i)
{
ChaseEntryRecord rec;
chaseFile.read((char*)&rec, sizeof(ChaseEntryRecord));
glm::vec3 velocity {
rec.velocity[0]/16383.5f,
rec.velocity[1]/16383.5f,
rec.velocity[2]/16383.5f,
};
glm::vec3 right{
rec.right[0]/127.5f,
rec.right[1]/127.5f,
rec.right[2]/127.5f,
};
glm::vec3 up{
rec.up[0]/127.5f,
rec.up[1]/127.5f,
rec.up[2]/127.5f,
};
glm::mat3 rotation(right, up, glm::cross(right, up));
frames.push_back({
velocity,
rec.steering,
rec.driving,
rec.braking,
!!rec.handbrake,
rec.position,
glm::quat_cast(rotation)
});
}
return true;
}
bool ChaseCoordinator::addChaseVehicle(GameObject *vehicle, int index, const std::string &pathFile)
{
std::vector <ChaseKeyframe> keyframes;
bool result = ChaseKeyframe::load(pathFile, keyframes);
RW_CHECK(result, "Failed to load chase keyframes: " + pathFile);
chaseVehicles[index] = {keyframes, vehicle};
return result;
}
GameObject*ChaseCoordinator::getChaseVehicle(int index)
{
return chaseVehicles.at(index).object;
}
void ChaseCoordinator::removeChaseVehicle(int index)
{
auto it = chaseVehicles.find(index);
RW_CHECK(it != chaseVehicles.end(), "Vehicle not in chase");
if (it != chaseVehicles.end())
{
chaseVehicles.erase(it);
}
}
void ChaseCoordinator::start()
{
chaseTime = 0.f;
}
void ChaseCoordinator::update(float dt)
{
chaseTime += dt;
size_t frameNum = chaseTime * KEYFRAMES_PER_SECOND;
for(auto& it : chaseVehicles)
{
RW_CHECK(frameNum < it.second.keyframes.size(), "Vehicle out of chase keyframes");
if (frameNum >= it.second.keyframes.size()) continue;
const ChaseKeyframe& kf = it.second.keyframes[frameNum];
it.second.object->setPosition(kf.position);
it.second.object->setRotation(kf.rotation);
}
}
void ChaseCoordinator::cleanup()
{
for(auto& it : chaseVehicles)
{
it.second.object->engine->destroyObject(it.second.object);
}
chaseVehicles.clear();
}

View File

@ -701,6 +701,45 @@ void game_set_character_model(const ScriptArguments& args)
}
}
void game_start_chase_scene(const ScriptArguments& args)
{
// Hardcoded list of vehicles, put this somewhere else.
#define CHASE_VEHICLE(model, x, y, z, hdg, c1, c2, path) \
{ \
auto vehicle0 = args.getWorld()->createVehicle( \
model, \
glm::vec3(x, y, z), \
glm::angleAxis(glm::radians(hdg), glm::vec3(0.f, 0.f, 1.f))); \
vehicle0->setPrimaryColour(c1);\
vehicle0->setSecondaryColour(c2);\
args.getWorld()->chase.addChaseVehicle(vehicle0, path,\
args.getWorld()->data->getDataPath()+"/data/paths/CHASE" #path ".DAT");\
}
CHASE_VEHICLE(116, 273.5422f, -1167.1907f, 24.9906f, 64.f, 2, 1, 0);
CHASE_VEHICLE(117, 231.1783f, -1388.832f, 25.9782f, 90.0f, 2, 1, 1);
CHASE_VEHICLE(130, -28.9762f, -1031.3367f, 25.9781f, 242.0f, 1, 75, 2);
CHASE_VEHICLE(96, 114.1564f, -796.6938f, 24.9782f, 180.0f, 0, 0, 3);
CHASE_VEHICLE(110, 184.3156f, -1473.251f, 25.9782f, 0.0f, 6, 6, 4);
CHASE_VEHICLE(105, 173.8868f, -1377.6514f, 25.9782f, 0.0f, 4, 5, 6);
CHASE_VEHICLE(92, 102.5946f, -943.9363f, 25.9781f, 270.0f, 53,53, 7);
CHASE_VEHICLE(105, 177.7157f, -862.1865f, 25.9782f, 155.0f, 41, 1, 10);
CHASE_VEHICLE(92, 170.5698f, -889.0236f, 25.9782f, 154.0f, 10, 10,11);
CHASE_VEHICLE(111, 402.6081f, -917.4963f, 37.381f, 90.0f, 34, 1, 14);
CHASE_VEHICLE(110, -33.4962f, -938.4563f, 25.9781f, 266.0f, 6, 6, 16);
CHASE_VEHICLE(111, 49.3631f, -987.605f, 25.9781f, 0.0f, 51, 1, 18);
CHASE_VEHICLE(110, 179.0049f, -1154.6686f, 25.9781f, 0.0f, 6, 76, 19);
args.getWorld()->chase.start();
}
void game_stop_chase_scene(const ScriptArguments& args)
{
// Clean up remaining vehicles
args.getWorld()->chase.cleanup();
}
bool game_collision_loaded(const ScriptArguments& args)
{
// The paramter to this is actually the island number.
@ -836,6 +875,16 @@ void game_set_rampages(const ScriptArguments& args)
args.getWorld()->state->gameStats.totalRampages = args[0].integer;
}
void game_remove_chase_car(const ScriptArguments& args)
{
int chaseCar = args[0].integer;
GameObject* car = args.getWorld()->chase.getChaseVehicle(chaseCar);
RW_CHECK(car != nullptr, "Tried to remove null car from chase");
if (car == nullptr) return;
args.getWorld()->chase.removeChaseVehicle(chaseCar);
args.getWorld()->destroyObject(car);
}
void game_set_near_clip(const ScriptArguments& args)
{
args.getWorld()->state->cameraNear = args[0].real;
@ -1051,8 +1100,8 @@ GameModule::GameModule()
bindFunction(0x0352, game_set_character_model, 2, "Set Character Model" );
bindUnimplemented( 0x0353, game_refresh_character_model, 1, "Refresh Actor Model" );
bindUnimplemented( 0x0354, game_start_chase, 1, "Start Chase Scene" );
bindUnimplemented( 0x0355, game_stop_chase, 0, "Stop Chase Scene" );
bindFunction( 0x0354, game_start_chase_scene, 1, "Start Chase Scene" );
bindFunction( 0x0355, game_stop_chase_scene, 0, "Stop Chase Scene" );
bindUnimplemented( 0x0373, game_camera_behind_player, 0, "Set Camera Behind Player" );
bindUnimplemented( 0x0374, game_set_motion_blur, 1, "Set Motion Blur" );
@ -1125,7 +1174,7 @@ GameModule::GameModule()
bindFunction(0x0408, game_set_rampages, 1, "Set Total Rampage Missions" );
bindUnimplemented( 0x0409, game_explode_rc_buggy, 0, "Blow up RC buggy" );
bindUnimplemented( 0x040A, game_remove_chase_car, 1, "Remove Chase Car" );
bindFunction( 0x040A, game_remove_chase_car, 1, "Remove Chase Car" );
bindUnimplemented( 0x0418, game_set_object_ontop, 2, "Set Object Draw Ontop" );

View File

@ -0,0 +1,15 @@
#include <boost/test/unit_test.hpp>
#include "test_globals.hpp"
#include <data/Chase.hpp>
BOOST_AUTO_TEST_SUITE(ChaseTests)
BOOST_AUTO_TEST_CASE(test_load_keyframes)
{
std::vector<ChaseKeyframe> keyframes;
BOOST_REQUIRE(ChaseKeyframe::load(Global::getGamePath() + "/data/paths/CHASE0.DAT", keyframes));
BOOST_REQUIRE(keyframes.size() == 5400);
BOOST_CHECK_CLOSE(keyframes[0].position.x, 273.5422, 0.1);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -356,6 +356,8 @@ void RWGame::tick(float dt)
world->_work->update();
State* currState = StateManager::get().states.back();
world->chase.update(dt);
static float clockAccumulator = 0.f;
if ( currState->shouldWorldUpdate() ) {