Changes to player, and mesh renderer INCOMPLETE
This commit is contained in:
301
Player.cpp
301
Player.cpp
@@ -1,50 +1,120 @@
|
||||
#include "Player.h"
|
||||
#include "Camera.h"
|
||||
#include "LevelMap.h"
|
||||
#include "PlayerInputComponent.h"
|
||||
#include <iostream>
|
||||
|
||||
Player::Player(glm::vec3 Position, glm::vec3 Rotation)
|
||||
: GameObject(Position, Rotation, glm::vec3(1.0f, 1.0f, 1.0f)),
|
||||
PlayerCamera(new Camera(glm::vec3(0.0f, 1.0f, 0.0f)))
|
||||
Player::Player(glm::vec3 position, glm::vec3 rotation, std::vector<Sector>& sectors, GLFWwindow* Window)
|
||||
: GameObject(position, rotation, glm::vec3(1.0f, 1.0f, 1.0f)),
|
||||
PlayerCamera(std::make_unique<Camera>(Window)),
|
||||
cPlayerInput(std::make_unique<PlayerInputComponent>(Window, *this)),
|
||||
LevelSectors(sectors),
|
||||
CurrentSector(§ors[0])
|
||||
{
|
||||
|
||||
PlayerCamera->Position = Position + PlayerCamera->CameraOffset;
|
||||
PlayerCamera->WorldUp = this->WorldUp;
|
||||
std::cout << "{" << Position.x << ", " << Position.y << ", " << Position.z << "}" << std::endl;
|
||||
std::cout << "{" << PlayerCamera->Position.x << ", " << PlayerCamera->Position.y << ", " << PlayerCamera->Position.z << "}" << std::endl;
|
||||
PlayerCamera->SetOffset(glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
PlayerCamera->MoveCamera(Position);
|
||||
PlayerCamera->Rotation = Rotation;
|
||||
}
|
||||
|
||||
void Player::Update()
|
||||
void Player::Update(float DeltaTime)
|
||||
{
|
||||
GameObject::Update(DeltaTime);
|
||||
cPlayerInput->Update(DeltaTime);
|
||||
|
||||
if (bJumping)
|
||||
{
|
||||
Position.y += JumpVelocity * DeltaTime;
|
||||
JumpVelocity -= GRAVITY * DeltaTime;
|
||||
|
||||
if (Position.y <= CurrentSector->floor_height)
|
||||
{
|
||||
JumpVelocity = 0.0f;
|
||||
Position.y = CurrentSector->floor_height;
|
||||
bJumping = false;
|
||||
std::cout << "STOP JUMPING" << std::endl;
|
||||
}
|
||||
}
|
||||
else if (Position.y > CurrentSector->floor_height)
|
||||
{
|
||||
Position.y -= GRAVITY * DeltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
Position.y = CurrentSector->floor_height;
|
||||
bJumping = false;
|
||||
}
|
||||
|
||||
PlayerCamera->MoveCamera(Position);
|
||||
}
|
||||
|
||||
void Player::ProcessKeyboard(EInputDirection Direction, float Delta)
|
||||
void Player::Move(EInputDirection Direction, float Delta)
|
||||
{
|
||||
float Velocity = bIsRunning ? RunSpeed : WalkSpeed;
|
||||
Velocity = Velocity * Delta;
|
||||
glm::vec3 newPosition = Position;
|
||||
if (Direction == FORWARD)
|
||||
Position += Front * Velocity;
|
||||
newPosition += Front * Velocity;
|
||||
if (Direction == BACKWARD)
|
||||
Position -= Front * Velocity;
|
||||
newPosition -= Front * Velocity;
|
||||
if (Direction == LEFT)
|
||||
Position -= Right * Velocity;
|
||||
newPosition -= Right * Velocity;
|
||||
if (Direction == RIGHT)
|
||||
Position += Right * Velocity;
|
||||
newPosition += Right * Velocity;
|
||||
|
||||
PlayerCamera->Position = Position + PlayerCamera->CameraOffset;
|
||||
PlayerCamera->WorldUp = this->WorldUp;
|
||||
if (!CrossingWall(newPosition))
|
||||
{
|
||||
Position = newPosition;
|
||||
}
|
||||
|
||||
for (Sector& Sector : LevelSectors)
|
||||
{
|
||||
glm::vec2 playerPoint = { Position.x, Position.z };
|
||||
if (PointInPolygon(playerPoint, Sector.walls))
|
||||
{
|
||||
/*if (!bJumping)
|
||||
Position.y = Sector.floor_height;*/
|
||||
if (CurrentSector != &Sector)
|
||||
{
|
||||
std::cout << "Updating CurrentSector ("
|
||||
<< (CurrentSector ? CurrentSector->index : -1)
|
||||
<< ") to Sector (" << Sector.index << ")" << std::endl;
|
||||
CurrentSector = &Sector;
|
||||
}
|
||||
break;
|
||||
// TO DO: Pretty sure this limits me for sectors that contain sectors, i.e. if I want multiple floor/ceiling heights within a sector it will have to be made of multiple sectors
|
||||
//std::cout << "Player in: " << sector.index << " | Player Y: " << sector.floor_height << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::ProcessMouseMovement(float XOffset, float YOffset, GLboolean bConstrainPitch)
|
||||
void Player::Jump()
|
||||
{
|
||||
XOffset *= MOUSE_SENSITIVITY;
|
||||
YOffset *= MOUSE_SENSITIVITY;
|
||||
if (bJumping) return;
|
||||
|
||||
Yaw += XOffset;
|
||||
PlayerCamera->Yaw = Yaw;
|
||||
//std::cout << "JUMP!" << std::endl;
|
||||
bJumping = true;
|
||||
JumpVelocity = JumpForce;
|
||||
}
|
||||
|
||||
PlayerCamera->ProcessMouseMovement(XOffset, YOffset);
|
||||
UpdatePlayerVectors();
|
||||
void Player::Sprint()
|
||||
{
|
||||
bIsRunning = true;
|
||||
}
|
||||
|
||||
void Player::StopSprint()
|
||||
{
|
||||
bIsRunning = false;
|
||||
}
|
||||
|
||||
void Player::Look(float Yaw, float Pitch, GLboolean bConstrainPitch)
|
||||
{
|
||||
Yaw *= MOUSE_SENSITIVITY;
|
||||
Pitch *= MOUSE_SENSITIVITY;
|
||||
|
||||
Rotation.y += Yaw;
|
||||
|
||||
PlayerCamera->RotateCamera(Yaw, Pitch);
|
||||
UpdateVectors();
|
||||
}
|
||||
|
||||
glm::mat4 Player::GetViewMatrix() const
|
||||
@@ -52,13 +122,182 @@ glm::mat4 Player::GetViewMatrix() const
|
||||
return PlayerCamera->GetViewMatrix();
|
||||
}
|
||||
|
||||
void Player::UpdatePlayerVectors()
|
||||
bool Player::CrossingWall(glm::vec3 NewPosition)
|
||||
{
|
||||
glm::vec3 UpdatedFront;
|
||||
UpdatedFront.x = cos(glm::radians(Yaw)) * cos(0);
|
||||
UpdatedFront.y = sin(0);
|
||||
UpdatedFront.z = sin(glm::radians(Yaw)) * cos(0);
|
||||
Front = glm::normalize(UpdatedFront);
|
||||
Right = glm::normalize(glm::cross(Front, WorldUp));
|
||||
Up = glm::normalize(glm::cross(Right, Front));
|
||||
// Convert 3D positions to 2D (XZ plane) for wall collision
|
||||
glm::vec2 CurrentPosition = glm::vec2(Position.x, Position.z);
|
||||
glm::vec2 NextPosition = glm::vec2(NewPosition.x, NewPosition.z);
|
||||
|
||||
//bool bCrossed = false;
|
||||
|
||||
// Check each wall in the sector
|
||||
for (const Wall& Wall : CurrentSector->walls)
|
||||
{
|
||||
glm::vec2 WallStart = Wall.a;
|
||||
glm::vec2 WallEnd = Wall.b;
|
||||
|
||||
// Check if movement line segment intersects with wall line segment
|
||||
if (LineSegmentsIntersect(CurrentPosition, NextPosition, WallStart, WallEnd))
|
||||
{
|
||||
if (Wall.portal == 0)
|
||||
{
|
||||
return true; // Collision detected
|
||||
}
|
||||
else if (CanFitInNextSector(LevelSectors[Wall.portal-1]))// check if valid portal (floor height < player y and floor and ceiling tall enough for player)
|
||||
{
|
||||
CurrentSector = &LevelSectors[Wall.portal - 1];
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//return true; // Collision detected
|
||||
}
|
||||
}
|
||||
|
||||
//if (bCrossed) return bCrossed; // breakout early, attempting to move through wall
|
||||
|
||||
// Check outward facing sectors to ensure not moving into pillars
|
||||
for (const Sector& Sector : LevelSectors)
|
||||
{
|
||||
if (!Sector.outward_facing)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check each wall in the sector
|
||||
for (const Wall& Wall : Sector.walls)
|
||||
{
|
||||
glm::vec2 WallStart = Wall.a;
|
||||
glm::vec2 WallEnd = Wall.b;
|
||||
|
||||
// Check if movement line segment intersects with wall line segment
|
||||
if (LineSegmentsIntersect(CurrentPosition, NextPosition, WallStart, WallEnd))
|
||||
{
|
||||
//if (Wall.portal != 0)
|
||||
//{
|
||||
// return false; // Collision but to another sector
|
||||
//}
|
||||
return true; // Collision detected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false; // No collisions detected
|
||||
}
|
||||
|
||||
bool Player::LineSegmentsIntersect(const glm::vec2& StartPosition, const glm::vec2& EndPosition, const glm::vec2& WallPointA, const glm::vec2& WallPointB)
|
||||
{
|
||||
// Implementation of the cross product test for line segment intersection
|
||||
auto cross = [](const glm::vec2& a, const glm::vec2& b) {
|
||||
return a.x * b.y - a.y * b.x;
|
||||
};
|
||||
|
||||
glm::vec2 PlayerNormal = EndPosition - StartPosition;
|
||||
glm::vec2 WallNormal = WallPointB - WallPointA;
|
||||
glm::vec2 WallToPlayerNormal = WallPointA - StartPosition;
|
||||
|
||||
float PlayerWallCross = cross(PlayerNormal, WallNormal);
|
||||
|
||||
// If lines are not parallel
|
||||
if (std::abs(PlayerWallCross) >= std::numeric_limits<float>::epsilon())
|
||||
{
|
||||
float t = cross(WallToPlayerNormal, PlayerNormal) / PlayerWallCross;
|
||||
float u = cross(WallToPlayerNormal, WallNormal) / PlayerWallCross;
|
||||
|
||||
// If intersection point is on both segments
|
||||
if ((t >= 0 && t <= 1) && (u >= 0 && u <= 1))
|
||||
return true;
|
||||
}
|
||||
|
||||
// If no intersection, check distance from EndPosition to wall segment
|
||||
return PointToLineSegmentDistance(EndPosition, WallPointA, WallPointB) <= 1.0f;
|
||||
}
|
||||
|
||||
float Player::PointToLineSegmentDistance(const glm::vec2& point, const glm::vec2& segA, const glm::vec2& segB)
|
||||
{
|
||||
glm::vec2 segVec = segB - segA;
|
||||
float segLengthSquared = glm::dot(segVec, segVec);
|
||||
|
||||
// If segment is actually a point
|
||||
if (segLengthSquared < std::numeric_limits<float>::epsilon())
|
||||
return glm::distance(point, segA);
|
||||
|
||||
// Project point onto the segment
|
||||
float t = glm::dot(point - segA, segVec) / segLengthSquared;
|
||||
t = glm::clamp(t, 0.0f, 1.0f);
|
||||
|
||||
glm::vec2 projection = segA + t * segVec;
|
||||
return glm::distance(point, projection);
|
||||
}
|
||||
|
||||
|
||||
// Checking if a point is inside a polygon
|
||||
bool Player::PointInPolygon(glm::vec2 point, std::vector<Wall> polygon)
|
||||
{
|
||||
int num_vertices = polygon.size();
|
||||
double x = point.x, y = point.y;
|
||||
bool inside = false;
|
||||
|
||||
// Store the first point in the polygon and initialize
|
||||
// the second point
|
||||
glm::vec2 p1 = polygon[0].a, p2;
|
||||
|
||||
// Loop through each edge in the polygon
|
||||
for (int i = 1; i <= num_vertices; i++) {
|
||||
// Get the next point in the polygon
|
||||
p2 = polygon[i % num_vertices].a;
|
||||
|
||||
// Check if the point is above the minimum y
|
||||
// coordinate of the edge
|
||||
if (y > std::min(p1.y, p2.y)) {
|
||||
// Check if the point is below the maximum y
|
||||
// coordinate of the edge
|
||||
if (y <= std::max(p1.y, p2.y)) {
|
||||
// Check if the point is to the left of the
|
||||
// maximum x coordinate of the edge
|
||||
if (x <= std::max(p1.x, p2.x)) {
|
||||
// Calculate the x-intersection of the
|
||||
// line connecting the point to the edge
|
||||
double x_intersection
|
||||
= (y - p1.y) * (p2.x - p1.x)
|
||||
/ (p2.y - p1.y)
|
||||
+ p1.x;
|
||||
|
||||
// Check if the point is on the same
|
||||
// line as the edge or to the left of
|
||||
// the x-intersection
|
||||
if (p1.x == p2.x
|
||||
|| x <= x_intersection) {
|
||||
// Flip the inside flag
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the current point as the first point for
|
||||
// the next iteration
|
||||
p1 = p2;
|
||||
}
|
||||
|
||||
// Return the value of the inside flag
|
||||
return inside;
|
||||
}
|
||||
|
||||
bool Player::CanFitInNextSector(Sector Sector)
|
||||
{
|
||||
std::cout << "Checking sector " << Sector.index << " | Floor height : " << Sector.floor_height << " | Player Y : " << Position.y << " | Sector height : " << Sector.ceiling_height - Sector.floor_height << std::endl;
|
||||
if (Position.y < Sector.floor_height - STEP_HEIGHT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Sector.ceiling_height - Sector.floor_height < PLAYER_HEIGHT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user