Revamped collision system
This commit is contained in:
@@ -178,7 +178,6 @@ void psxsplash::SceneManager::InitializeScene(uint8_t* splashpackData, LoadingSc
|
||||
SPLASHPACKCollider* collider = sceneSetup.colliders[i];
|
||||
if (collider == nullptr) continue;
|
||||
|
||||
// Convert fixed-point values from binary format to AABB
|
||||
AABB bounds;
|
||||
bounds.min.x.value = collider->minX;
|
||||
bounds.min.y.value = collider->minY;
|
||||
@@ -187,10 +186,8 @@ void psxsplash::SceneManager::InitializeScene(uint8_t* splashpackData, LoadingSc
|
||||
bounds.max.y.value = collider->maxY;
|
||||
bounds.max.z.value = collider->maxZ;
|
||||
|
||||
// Convert collision type
|
||||
CollisionType type = static_cast<CollisionType>(collider->collisionType);
|
||||
|
||||
// Register with collision system
|
||||
m_collisionSystem.registerCollider(
|
||||
collider->gameObjectIndex,
|
||||
bounds,
|
||||
@@ -199,6 +196,22 @@ void psxsplash::SceneManager::InitializeScene(uint8_t* splashpackData, LoadingSc
|
||||
);
|
||||
}
|
||||
|
||||
// Register trigger boxes from splashpack data
|
||||
for (size_t i = 0; i < sceneSetup.triggerBoxes.size(); i++) {
|
||||
SPLASHPACKTriggerBox* tb = sceneSetup.triggerBoxes[i];
|
||||
if (tb == nullptr) continue;
|
||||
|
||||
AABB bounds;
|
||||
bounds.min.x.value = tb->minX;
|
||||
bounds.min.y.value = tb->minY;
|
||||
bounds.min.z.value = tb->minZ;
|
||||
bounds.max.x.value = tb->maxX;
|
||||
bounds.max.y.value = tb->maxY;
|
||||
bounds.max.z.value = tb->maxZ;
|
||||
|
||||
m_collisionSystem.registerTriggerBox(bounds, tb->luaFileIndex);
|
||||
}
|
||||
|
||||
// Load Lua files - order is important here. We need
|
||||
// to load the Lua files before we register the game objects,
|
||||
// as the game objects may reference Lua files by index.
|
||||
@@ -289,21 +302,44 @@ void psxsplash::SceneManager::GameTick(psyqo::GPU &gpu) {
|
||||
|
||||
// Collision detection
|
||||
uint32_t collisionStart = gpu.now();
|
||||
int collisionCount = m_collisionSystem.detectCollisions();
|
||||
|
||||
// Process solid collisions - call OnCollision on BOTH objects
|
||||
const CollisionResult* results = m_collisionSystem.getResults();
|
||||
for (int i = 0; i < collisionCount; i++) {
|
||||
auto* objA = getGameObject(results[i].objectA);
|
||||
auto* objB = getGameObject(results[i].objectB);
|
||||
if (objA && objB) {
|
||||
L.OnCollision(objA, objB);
|
||||
L.OnCollision(objB, objA); // Call on both objects
|
||||
// Build player AABB from position + radius/height
|
||||
AABB playerAABB;
|
||||
{
|
||||
psyqo::FixedPoint<12> r;
|
||||
r.value = m_playerRadius;
|
||||
psyqo::FixedPoint<12> px = static_cast<psyqo::FixedPoint<12>>(m_playerPosition.x);
|
||||
psyqo::FixedPoint<12> py = static_cast<psyqo::FixedPoint<12>>(m_playerPosition.y);
|
||||
psyqo::FixedPoint<12> pz = static_cast<psyqo::FixedPoint<12>>(m_playerPosition.z);
|
||||
psyqo::FixedPoint<12> h = static_cast<psyqo::FixedPoint<12>>(m_playerHeight);
|
||||
playerAABB.min = psyqo::Vec3{px - r, py - h, pz - r};
|
||||
playerAABB.max = psyqo::Vec3{px + r, py, pz + r};
|
||||
}
|
||||
|
||||
psyqo::Vec3 pushBack;
|
||||
int collisionCount = m_collisionSystem.detectCollisions(playerAABB, pushBack);
|
||||
|
||||
// Apply push-back to player position
|
||||
{
|
||||
psyqo::FixedPoint<12> zero;
|
||||
if (pushBack.x != zero || pushBack.z != zero) {
|
||||
m_playerPosition.x = m_playerPosition.x + pushBack.x;
|
||||
m_playerPosition.z = m_playerPosition.z + pushBack.z;
|
||||
}
|
||||
}
|
||||
|
||||
// Process trigger events (enter/stay/exit)
|
||||
m_collisionSystem.processTriggerEvents(*this);
|
||||
// Fire onCollideWithPlayer Lua events on collided objects
|
||||
const CollisionResult* results = m_collisionSystem.getResults();
|
||||
for (int i = 0; i < collisionCount; i++) {
|
||||
if (results[i].objectA != 0xFFFF) continue;
|
||||
auto* obj = getGameObject(results[i].objectB);
|
||||
if (obj) {
|
||||
L.OnCollideWithPlayer(obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Process trigger boxes (enter/exit)
|
||||
m_collisionSystem.detectTriggers(playerAABB, *this);
|
||||
|
||||
gpu.pumpCallbacks();
|
||||
uint32_t collisionEnd = gpu.now();
|
||||
@@ -489,29 +525,14 @@ void psxsplash::SceneManager::GameTick(psyqo::GPU &gpu) {
|
||||
processPendingSceneLoad();
|
||||
}
|
||||
|
||||
// Trigger event callbacks
|
||||
void psxsplash::SceneManager::fireTriggerEnter(uint16_t triggerObjIdx, uint16_t otherObjIdx) {
|
||||
auto* trigger = getGameObject(triggerObjIdx);
|
||||
auto* other = getGameObject(otherObjIdx);
|
||||
if (trigger && other) {
|
||||
L.OnTriggerEnter(trigger, other);
|
||||
}
|
||||
void psxsplash::SceneManager::fireTriggerEnter(int16_t luaFileIndex, uint16_t triggerIndex) {
|
||||
if (luaFileIndex < 0) return;
|
||||
L.OnTriggerEnterScript(luaFileIndex, triggerIndex);
|
||||
}
|
||||
|
||||
void psxsplash::SceneManager::fireTriggerStay(uint16_t triggerObjIdx, uint16_t otherObjIdx) {
|
||||
auto* trigger = getGameObject(triggerObjIdx);
|
||||
auto* other = getGameObject(otherObjIdx);
|
||||
if (trigger && other) {
|
||||
L.OnTriggerStay(trigger, other);
|
||||
}
|
||||
}
|
||||
|
||||
void psxsplash::SceneManager::fireTriggerExit(uint16_t triggerObjIdx, uint16_t otherObjIdx) {
|
||||
auto* trigger = getGameObject(triggerObjIdx);
|
||||
auto* other = getGameObject(otherObjIdx);
|
||||
if (trigger && other) {
|
||||
L.OnTriggerExit(trigger, other);
|
||||
}
|
||||
void psxsplash::SceneManager::fireTriggerExit(int16_t luaFileIndex, uint16_t triggerIndex) {
|
||||
if (luaFileIndex < 0) return;
|
||||
L.OnTriggerExitScript(luaFileIndex, triggerIndex);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -746,8 +767,12 @@ void psxsplash::SceneManager::shrinkBuffer() {
|
||||
if (m_liveDataSize == 0 || m_currentSceneData == nullptr) return;
|
||||
|
||||
uint8_t* oldBase = m_currentSceneData;
|
||||
uint8_t* newBase = new uint8_t[m_liveDataSize];
|
||||
if (!newBase) return;
|
||||
// Allocate the shrunk buffer. The volatile cast prevents the compiler
|
||||
// from assuming operator new never returns NULL (it does with
|
||||
// -fno-exceptions), which would let it optimize away the null check.
|
||||
uint8_t* volatile newBaseV = new uint8_t[m_liveDataSize];
|
||||
uint8_t* newBase = newBaseV;
|
||||
if (!newBase) return; // Heap exhausted — keep the full buffer
|
||||
__builtin_memcpy(newBase, oldBase, m_liveDataSize);
|
||||
|
||||
intptr_t delta = reinterpret_cast<intptr_t>(newBase) - reinterpret_cast<intptr_t>(oldBase);
|
||||
|
||||
Reference in New Issue
Block a user