Added 3rd person view
This commit is contained in:
parent
57789eed24
commit
0d7d430909
@ -72,6 +72,23 @@ void Character::setPathPlanner(PathPlanner planner) {
|
||||
pathPlanner = std::move(planner);
|
||||
}
|
||||
|
||||
void Character::clearPath() {
|
||||
walkTarget = position;
|
||||
requestedWalkTarget = position;
|
||||
pathWaypoints.clear();
|
||||
currentWaypointIndex = 0;
|
||||
onArrivedCallback = nullptr;
|
||||
}
|
||||
|
||||
void Character::setDirectWalkTarget(const Eigen::Vector3f& target) {
|
||||
Eigen::Vector3f normalized(target.x(), 0.f, target.z());
|
||||
walkTarget = normalized;
|
||||
requestedWalkTarget = normalized;
|
||||
pathWaypoints.clear();
|
||||
currentWaypointIndex = 0;
|
||||
onArrivedCallback = nullptr;
|
||||
}
|
||||
|
||||
AnimationState Character::resolveActiveState() const {
|
||||
|
||||
if (animations.count(currentState)) return currentState;
|
||||
|
||||
@ -42,6 +42,8 @@ public:
|
||||
std::function<void()> onArrived = nullptr);
|
||||
|
||||
void setPathPlanner(PathPlanner planner);
|
||||
void clearPath();
|
||||
void setDirectWalkTarget(const Eigen::Vector3f& target);
|
||||
void draw(Renderer& renderer);
|
||||
void drawShadowDepth(Renderer& renderer);
|
||||
void drawWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
|
||||
@ -49,6 +51,7 @@ public:
|
||||
// Public: read by Game for camera tracking and ray-cast origin
|
||||
Eigen::Vector3f position = Eigen::Vector3f(0.f, 0.f, 0.f);
|
||||
float facingAngle = 0.0f;
|
||||
float targetFacingAngle = 0.0f;
|
||||
|
||||
// Per-character tuning — set after construction, before first update
|
||||
float walkSpeed = 3.0f;
|
||||
@ -89,7 +92,6 @@ private:
|
||||
std::vector<Eigen::Vector3f> pathWaypoints;
|
||||
size_t currentWaypointIndex = 0;
|
||||
PathPlanner pathPlanner;
|
||||
float targetFacingAngle = 0.0f;
|
||||
std::function<void()> onArrivedCallback;
|
||||
|
||||
static constexpr float WALK_THRESHOLD = 0.05f;
|
||||
|
||||
@ -15,7 +15,7 @@ namespace ZL {
|
||||
using std::max;
|
||||
#endif
|
||||
|
||||
constexpr float DEFAULT_ZOOM = 36.f;
|
||||
constexpr float DEFAULT_ZOOM = 4.f;
|
||||
|
||||
class Environment {
|
||||
public:
|
||||
|
||||
13
src/Game.cpp
13
src/Game.cpp
@ -144,7 +144,7 @@ namespace ZL
|
||||
|
||||
std::cout << "Load resurces step 4" << std::endl;
|
||||
|
||||
currentLocation = std::make_unique<Location>(renderer, inventory);
|
||||
currentLocation = std::make_unique<Location>(renderer, inventory, "forest");
|
||||
|
||||
currentLocation->setup();
|
||||
|
||||
@ -374,6 +374,13 @@ namespace ZL
|
||||
//space.clearTextRendererCache();
|
||||
}
|
||||
|
||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
}
|
||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_AC_BACK) {
|
||||
Environment::exitGameLoop = true;
|
||||
@ -468,7 +475,7 @@ namespace ZL
|
||||
handleMotion(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
|
||||
if (currentLocation)
|
||||
{
|
||||
currentLocation->handleMotion(ZL::UiManager::MOUSE_FINGER_ID, event.motion.x, event.motion.y, mx, my);
|
||||
currentLocation->handleMotion(ZL::UiManager::MOUSE_FINGER_ID, event.motion.xrel, event.motion.yrel, mx, my);
|
||||
}
|
||||
}
|
||||
|
||||
@ -532,6 +539,7 @@ namespace ZL
|
||||
case SDLK_a:
|
||||
case SDLK_d:
|
||||
case SDLK_u:
|
||||
case SDLK_i:
|
||||
if (currentLocation) currentLocation->handleKeyDown(event.key.keysym.sym);
|
||||
break;
|
||||
|
||||
@ -568,6 +576,7 @@ namespace ZL
|
||||
case SDLK_s:
|
||||
case SDLK_a:
|
||||
case SDLK_d:
|
||||
case SDLK_i:
|
||||
if (currentLocation) currentLocation->handleKeyUp(event.key.keysym.sym);
|
||||
break;
|
||||
default: break;
|
||||
|
||||
149
src/Location.cpp
149
src/Location.cpp
@ -32,6 +32,9 @@ namespace ZL
|
||||
|
||||
void Location::setup()
|
||||
{
|
||||
|
||||
carPosition = { 5.4005, 0, -3.811283 };
|
||||
|
||||
auto playerTexture0 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/male_packed0_diffuse.png", CONST_ZIP_FILE));
|
||||
auto playerTexture1 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/male_packed1_diffuse.png", CONST_ZIP_FILE));
|
||||
auto playerTexture2 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/male_packed2_diffuse.png", CONST_ZIP_FILE));
|
||||
@ -95,8 +98,8 @@ void Location::setup()
|
||||
salesperson->walkSpeed = 3.0f;
|
||||
salesperson->rotationSpeed = 8.0f;
|
||||
salesperson->modelScale = 0.01f;
|
||||
salesperson->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
||||
salesperson->position = Vector3f{ 10, -0, -10 };
|
||||
salesperson->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(0, Eigen::Vector3f::UnitY()));
|
||||
salesperson->position = Vector3f{ -8.31099, -0, -3.56868 };
|
||||
salesperson->setTarget(salesperson->position);
|
||||
|
||||
auto policeTexture0 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/police_packed0_diffuse.png", CONST_ZIP_FILE));
|
||||
@ -280,39 +283,12 @@ void Location::setup()
|
||||
carWheelMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
carWheelMesh.RefreshVBO();
|
||||
|
||||
/*
|
||||
auto girlfriendTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/female_packed0_diffuse.png", CONST_ZIP_FILE));
|
||||
girlfriend = std::make_unique<Character>();
|
||||
girlfriend->loadAnimation(AnimationState::STAND, "resources/e/woman_stand_idle001.txt", CONST_ZIP_FILE);
|
||||
girlfriend->loadAnimation(AnimationState::WALK, "resources/e/woman_run001.txt", CONST_ZIP_FILE);
|
||||
girlfriend->setTexture(girlfriendTexture);
|
||||
girlfriend->walkSpeed = 3.0f;
|
||||
girlfriend->rotationSpeed = 8.0f;
|
||||
girlfriend->modelScale = 0.01f;
|
||||
girlfriend->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
||||
girlfriend->position = Vector3f{ -10, -0, -10 };
|
||||
girlfriend->setTarget(girlfriend->position);*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Location::setupNavigation()
|
||||
{
|
||||
|
||||
std::vector<PathFinder::ObstacleMesh> obstacles;
|
||||
/*obstacles.reserve(gameObjects.size() + interactiveObjects.size());
|
||||
|
||||
for (const auto& item : gameObjects) {
|
||||
const LoadedGameObject& gameObj = item.second;
|
||||
obstacles.push_back({ &gameObj.mesh.data, Eigen::Vector3f::Zero() });
|
||||
}
|
||||
|
||||
for (const InteractiveObject& intObj : interactiveObjects) {
|
||||
if (!intObj.isActive) {
|
||||
continue;
|
||||
}
|
||||
obstacles.push_back({ &intObj.mesh.data, intObj.position });
|
||||
}*/
|
||||
|
||||
if (locationId == "forest") {
|
||||
navigation.build(obstacles, "resources/config2/navigation2.json", CONST_ZIP_FILE);
|
||||
@ -496,12 +472,13 @@ void Location::setup()
|
||||
|
||||
renderer.LoadIdentity();
|
||||
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||
//renderer.TranslateMatrix({ 0, -6.f, 0 });
|
||||
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
Eigen::Vector3f camTarget = inCar ? carPosition : (player ? player->position : Eigen::Vector3f::Zero());
|
||||
renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() });
|
||||
renderer.TranslateMatrix({ 0, -1.3f, 0 });
|
||||
|
||||
|
||||
if (roomMesh.data.PositionData.size() > 0)
|
||||
{
|
||||
@ -581,8 +558,8 @@ void Location::setup()
|
||||
for (auto& npc : npcs) npc->draw(renderer);
|
||||
|
||||
//#ifdef SHOW_PATH
|
||||
drawDebugNavigation();
|
||||
drawDebugForbidden();
|
||||
//drawDebugNavigation();
|
||||
//drawDebugForbidden();
|
||||
//#endif
|
||||
|
||||
renderer.PopMatrix();
|
||||
@ -777,9 +754,52 @@ void Location::setup()
|
||||
return navigation.setAreaAvailable(areaName, available);
|
||||
}
|
||||
|
||||
bool Location::isCarFootprintWalkable(const Eigen::Vector3f& center, float rotation) const
|
||||
{
|
||||
if (!navigation.isReady()) return true;
|
||||
|
||||
constexpr float carLength = 7.3f;
|
||||
constexpr float carWidth = 2.8f;
|
||||
constexpr float sampleSpacing = 0.35f;
|
||||
|
||||
const float halfLength = carLength * 0.5f;
|
||||
const float halfWidth = carWidth * 0.5f;
|
||||
const int longSteps = max(1, static_cast<int>(std::ceil(carLength / sampleSpacing)));
|
||||
const int widthSteps = max(1, static_cast<int>(std::ceil(carWidth / sampleSpacing)));
|
||||
|
||||
const Eigen::Vector3f forward(-std::sin(rotation), 0.f, -std::cos(rotation));
|
||||
const Eigen::Vector3f right(std::cos(rotation), 0.f, -std::sin(rotation));
|
||||
|
||||
for (int i = 0; i <= longSteps; ++i) {
|
||||
const float fl = (static_cast<float>(i) / static_cast<float>(longSteps)) * 2.0f - 1.0f;
|
||||
const Eigen::Vector3f lineOffset = forward * (fl * halfLength);
|
||||
for (int j = 0; j <= widthSteps; ++j) {
|
||||
const float fw = (static_cast<float>(j) / static_cast<float>(widthSteps)) * 2.0f - 1.0f;
|
||||
const Eigen::Vector3f sample = center + lineOffset + right * (fw * halfWidth);
|
||||
if (!navigation.isWalkable(sample)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Location::update(int64_t delta)
|
||||
{
|
||||
const Eigen::Vector3f playerPosBefore = player ? player->position : Eigen::Vector3f::Zero();
|
||||
|
||||
if (player) {
|
||||
if (!inCar) {
|
||||
player->targetFacingAngle = cameraAzimuth;
|
||||
if (keyForward) {
|
||||
player->attackTarget = nullptr;
|
||||
Eigen::Vector3f forward(std::sin(cameraAzimuth), 0.f, -std::cos(cameraAzimuth));
|
||||
player->setDirectWalkTarget(player->position + forward * 5.0f);
|
||||
} else if (wasKeyForward) {
|
||||
player->clearPath();
|
||||
}
|
||||
wasKeyForward = keyForward;
|
||||
}
|
||||
player->update(delta);
|
||||
dialogueSystem.update(static_cast<int>(delta), player->position);
|
||||
if (!roofObjectKey.empty()) {
|
||||
@ -824,25 +844,55 @@ void Location::setup()
|
||||
|
||||
carVelocity = max(-carMaxReverseSpeed, min(carMaxSpeed, carVelocity));
|
||||
|
||||
const float oldRotation = carRotation;
|
||||
if (std::abs(carVelocity) > 0.01f) {
|
||||
float speedFactor = carVelocity / carMaxSpeed;
|
||||
if (keyLeft) carRotation += carTurnRate * dt * speedFactor;
|
||||
if (keyRight) carRotation -= carTurnRate * dt * speedFactor;
|
||||
}
|
||||
if (navigation.isReady() && !isCarFootprintWalkable(carPosition, carRotation)) {
|
||||
carRotation = oldRotation;
|
||||
}
|
||||
|
||||
float targetSteer = (keyLeft ? 1.f : 0.f) - (keyRight ? 1.f : 0.f);
|
||||
targetSteer *= carMaxSteerAngle;
|
||||
float steerLerp = min(1.f, dt * 8.f);
|
||||
carSteeringAngle += (targetSteer - carSteeringAngle) * steerLerp;
|
||||
|
||||
Eigen::Vector3f forward(-std::sin(carRotation), 0.f, -std::cos(carRotation));
|
||||
carPosition += forward * carVelocity * dt;
|
||||
const Eigen::Vector3f forward(-std::sin(carRotation), 0.f, -std::cos(carRotation));
|
||||
const Eigen::Vector3f totalDelta = forward * carVelocity * dt;
|
||||
const float totalDist = totalDelta.norm();
|
||||
const float maxSubstep = 0.2f;
|
||||
const int substeps = max(1, static_cast<int>(std::ceil(totalDist / maxSubstep)));
|
||||
const Eigen::Vector3f stepDelta = totalDelta / static_cast<float>(substeps);
|
||||
for (int s = 0; s < substeps; ++s) {
|
||||
Eigen::Vector3f candidate = carPosition + stepDelta;
|
||||
if (navigation.isReady() && !isCarFootprintWalkable(candidate, carRotation)) {
|
||||
carVelocity = 0.f;
|
||||
break;
|
||||
}
|
||||
carPosition = candidate;
|
||||
}
|
||||
|
||||
if (player) {
|
||||
player->position = carPosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (player && !inCar && navigation.isReady() && !navigation.isWalkable(player->position)) {
|
||||
const Eigen::Vector3f slideX(player->position.x(), playerPosBefore.y(), playerPosBefore.z());
|
||||
const Eigen::Vector3f slideZ(playerPosBefore.x(), playerPosBefore.y(), player->position.z());
|
||||
Eigen::Vector3f resolved;
|
||||
if (navigation.isWalkable(slideX)) {
|
||||
resolved = slideX;
|
||||
} else if (navigation.isWalkable(slideZ)) {
|
||||
resolved = slideZ;
|
||||
} else {
|
||||
resolved = playerPosBefore;
|
||||
}
|
||||
player->position = resolved;
|
||||
}
|
||||
|
||||
// Check if player reached target interactive object
|
||||
if (targetInteractiveObject && player) {
|
||||
float distToObject = (player->position - targetInteractiveObject->position).norm();
|
||||
@ -915,9 +965,14 @@ void Location::setup()
|
||||
std::cout << "[CLICK] Player position: (" << player->position.x() << ", "
|
||||
<< player->position.y() << ", " << player->position.z() << ")" << std::endl;
|
||||
|
||||
float distance = (player->position - clickedObject->position).norm();
|
||||
|
||||
if (distance < 5.0)
|
||||
{
|
||||
targetInteractiveObject = clickedObject;
|
||||
player->setTarget(clickedObject->position);
|
||||
std::cout << "[CLICK] Player moving to object..." << std::endl;
|
||||
}
|
||||
//player->setTarget(clickedObject->position);
|
||||
//std::cout << "[CLICK] Player moving to object..." << std::endl;
|
||||
}
|
||||
else {
|
||||
|
||||
@ -949,6 +1004,7 @@ void Location::setup()
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
else if (rayDir.y() < -0.001f && player) {
|
||||
// Otherwise, unproject click to ground plane for Viola's walk target
|
||||
float t = -camPos.y() / rayDir.y();
|
||||
@ -959,7 +1015,7 @@ void Location::setup()
|
||||
{
|
||||
player->setTarget(Eigen::Vector3f(hit.x(), 0.f, hit.z()));
|
||||
}
|
||||
}
|
||||
}*/
|
||||
else {
|
||||
std::cout << "[CLICK] No valid target found" << std::endl;
|
||||
}
|
||||
@ -970,30 +1026,25 @@ void Location::setup()
|
||||
{
|
||||
|
||||
}
|
||||
void Location::handleMotion(int64_t fingerId, int eventX, int eventY, int mx, int my)
|
||||
void Location::handleMotion(int64_t fingerId, int dx, int dy, int mx, int my)
|
||||
{
|
||||
if (dialogueSystem.blocksGameplayInput()) {
|
||||
dialogueSystem.handlePointerMoved(
|
||||
static_cast<float>(mx),
|
||||
Environment::projectionHeight - static_cast<float>(my)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rightMouseDown) {
|
||||
int dx = eventX - lastMouseX;
|
||||
int dy = eventY - lastMouseY;
|
||||
lastMouseX = eventX;
|
||||
lastMouseY = eventY;
|
||||
|
||||
const float sensitivity = 0.005f;
|
||||
const float inclinationSign = invertCameraY ? -1.0f : 1.0f;
|
||||
cameraAzimuth += dx * sensitivity;
|
||||
cameraInclination += dy * sensitivity;
|
||||
cameraInclination += inclinationSign * dy * sensitivity;
|
||||
|
||||
const float minInclination = M_PI * 30.f / 180.f;
|
||||
const float minInclination = M_PI * 10.f / 180.f;
|
||||
const float maxInclination = M_PI * 0.5f;
|
||||
cameraInclination = max(minInclination, min(maxInclination, cameraInclination));
|
||||
}
|
||||
}
|
||||
|
||||
void Location::handleKeyDown(int sdlKey)
|
||||
{
|
||||
@ -1002,8 +1053,10 @@ void Location::setup()
|
||||
case SDLK_s: keyBackward = true; break;
|
||||
case SDLK_a: keyLeft = true; break;
|
||||
case SDLK_d: keyRight = true; break;
|
||||
case SDLK_i: invertCameraY = !invertCameraY; break;
|
||||
case SDLK_u:
|
||||
girlfriend->setTarget(player->position);
|
||||
std::cout << player->position << std::endl;
|
||||
//girlfriend->setTarget(player->position);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
@ -85,6 +85,9 @@ namespace ZL
|
||||
bool rightMouseDown = false;
|
||||
int lastMouseX = 0;
|
||||
int lastMouseY = 0;
|
||||
bool mouseInitialized = false;
|
||||
bool wasKeyForward = false;
|
||||
bool invertCameraY = false;
|
||||
|
||||
|
||||
void setup();
|
||||
@ -102,7 +105,7 @@ namespace ZL
|
||||
|
||||
void handleDown(int64_t fingerId, int eventX, int eventY, int mx, int my);
|
||||
void handleUp(int64_t fingerId, int mx, int my);
|
||||
void handleMotion(int64_t fingerId, int eventX, int eventY, int mx, int my);
|
||||
void handleMotion(int64_t fingerId, int dx, int dy, int mx, int my);
|
||||
void handleKeyDown(int sdlKey);
|
||||
void handleKeyUp(int sdlKey);
|
||||
|
||||
@ -122,6 +125,8 @@ namespace ZL
|
||||
std::string roofObjectKey;
|
||||
bool roofVisible = true;
|
||||
std::vector<Eigen::AlignedBox<float, 2>> roofHideZones;
|
||||
|
||||
bool isCarFootprintWalkable(const Eigen::Vector3f& center, float rotation) const;
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
Loading…
Reference in New Issue
Block a user