Merge branch 'master' into wall-ground-portal-bug

This commit is contained in:
Weston 2023-03-27 16:12:01 -05:00 committed by GitHub
commit 199489f3f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 317 additions and 77 deletions

View file

@ -167,6 +167,7 @@ MODEL_LIST = assets/models/cube/cube.blend \
assets/models/props/autoportal_frame/autoportal_frame.blend \
assets/models/props/button.blend \
assets/models/props/door_01.blend \
assets/models/props/door_02.blend \
assets/models/props/combine_ball_catcher.blend \
assets/models/props/combine_ball_launcher.blend \
assets/models/props/cylinder_test.blend \
@ -193,6 +194,8 @@ ANIM_LIST = build/assets/models/pedestal_anim.o \
build/assets/models/props/box_dropper_anim.o \
build/assets/models/props/combine_ball_catcher_anim.o \
build/assets/models/props/combine_ball_launcher_anim.o \
build/assets/models/props/door_01_anim.o \
build/assets/models/props/door_02_anim.o \
build/assets/models/player/chell_anim.o \
build/assets/models/props/switch001_anim.o
@ -228,12 +231,15 @@ build/src/scene/ball_launcher.o: build/assets/models/props/combine_ball_launcher
build/src/scene/ball_catcher.o: build/assets/models/props/combine_ball_catcher.h build/assets/materials/static.h
build/src/scene/door.o: build/assets/models/props/door_01.h build/assets/models/props/door_02.h
build/assets/models/player/chell.h: assets/materials/chell.skm.yaml
build/assets/models/props/combine_ball_catcher.h: assets/materials/ball_catcher.skm.yaml
build/assets/models/props/combine_ball_launcher.h: assets/materials/ball_catcher.skm.yaml
ANIM_TEST_CHAMBERS = build/assets/test_chambers/test_chamber_03/test_chamber_03_anim.o \
build/assets/test_chambers/test_chamber_04/test_chamber_04_anim.o \
build/assets/test_chambers/test_chamber_06/test_chamber_06_anim.o

View file

@ -1,4 +1,5 @@
# Portal64
![](./assets/images/portal64_readme_logo.gif)
A demake of Portal for the Nintendo 64.
@ -106,13 +107,13 @@ Where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where Blender
- [ ] Portal not rendering recursively sometimes
- [ ] Correct elevator timing
- [ ] Presort portal gun polygon order
- [ ] Portal gun movement with player movement/shooting #19
- [ ] Camera shake
- [ ] Adding a menu to game #47
- [ ] Adding y-axis/x-axis inverting options #55
- [ ] Adding loading notice between levels #45
- [ ] Vertex lighting #39
- [ ] Multi controller support #23
- [x] Portal gun movement with player movement/shooting #19
## Current New Sounds TODO List
- [ ] Fast flying air whoosh sound
@ -130,8 +131,6 @@ Where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where Blender
- [ ] Two wall portals next to eachother can be used to clip any object out of any level by pushing it into corner, then dropping.
- [ ] Glass can be walked through from one side on multiple levels (0,1,4,...)
- [ ] Passing into a ceiling portal can sometimes mess with the player rotation
- [ ] Can shoot portals through decor objects
- [ ] Can shoot portals while holding an object
- [ ] Can shoot portals, and walk through signage
- [ ] Chell animation problem (fixed itself, investigate)
- [ ] Can place portals on ground after final fizzler on all levels
@ -140,3 +139,4 @@ Where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where Blender
- [ ] various visual glitches when running PAL on NTSC console #65
- [x] Any grabbable object can be clipped through level by wall/floor portals method.
- [x] Player can clip through any level by placing one portal on wall and another portal right next to it on ground. #13
- [x] Can shoot portals while holding an object

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

View file

@ -0,0 +1 @@
-alpha off -crop 128x256+251+0 -resize 32x64

View file

@ -342,6 +342,20 @@ materials:
color: ["SHADE", "0", "TEXEL0", "0"]
gDPSetTextureFilter: G_TF_BILERP
door_02:
gDPSetTile:
filename:
../../portal_pak_modified/materials/models/props/door_02.png
siz: G_IM_SIZ_16b
fmt: G_IM_FMT_RGBA
t:
mirror: true
gSPGeometryMode:
set: [G_LIGHTING, G_SHADE]
gDPSetCombineMode:
color: ["SHADE", "0", "TEXEL0", "0"]
gDPSetTextureFilter: G_TF_BILERP
plastic/plasticwall001a:
gDPSetPrimColor:
r: 230

Binary file not shown.

View file

@ -1 +1 @@
-m assets/materials/static.skm.yaml -m assets/materials/objects.skm.yaml --default-material door_01
-m assets/materials/static.skm.yaml -m assets/materials/objects.skm.yaml --default-material door_01 --fps 24

Binary file not shown.

View file

@ -0,0 +1 @@
-m assets/materials/static.skm.yaml -m assets/materials/objects.skm.yaml --default-material door_02

View file

@ -79,15 +79,20 @@ struct FrameData {
template <typename T>
void findStartValue(const T* keys, unsigned keyCount, double at, unsigned& startValue, double& lerp) {
lerp = 0.0f;
for (startValue = 0; startValue < keyCount; ++startValue) {
if (keys[startValue].mTime >= at) {
if (keys[startValue].mTime == at) {
lerp = 0.0f;
break;
} else if (keys[startValue].mTime > at) {
if (startValue == 0) {
lerp = 0.0f;
} else {
--startValue;
double deltaTime = keys[startValue + 1].mTime - keys[startValue].mTime;
if (deltaTime == 1.0) {
if (deltaTime == 0.0) {
lerp = 0.0f;
} else {
lerp = (at - keys[startValue].mTime) / deltaTime;
@ -151,7 +156,7 @@ aiQuaternion evaluateQuaternionAt(const aiQuatKey* keys, unsigned keyCount, doub
}
void generateanimationV2(const aiAnimation& animation, BoneHierarchy& bones, CFileDefinition& fileDef, const DisplayListSettings& settings) {
int nFrames = ceil(animation.mDuration * settings.mTicksPerSecond / animation.mTicksPerSecond);
int nFrames = ceil(animation.mDuration * settings.mTicksPerSecond / animation.mTicksPerSecond) + 1;
std::vector<std::vector<FrameData>> allFrameData(nFrames);

View file

@ -140,11 +140,17 @@ struct Location {
short roomIndex;
};
enum DoorType {
DoorType01,
DoorType02,
};
struct DoorDefinition {
struct Vector3 location;
struct Quaternion rotation;
short doorwayIndex;
short signalIndex;
short doorType;
};
struct ButtonDefinition {

View file

@ -161,7 +161,7 @@ static void gameProc(void* arg) {
contactSolverInit(&gContactSolver);
portalSurfaceCleanupQueueInit();
savefileNew();
levelLoad(6);
levelLoad(2);
cutsceneRunnerReset();
controllersInit();
initAudio(fps);

View file

@ -322,7 +322,7 @@ void contactSolverIterateConstraints(struct ContactSolver* contactSolver) {
struct PointConstraint* prev = NULL;
while (curr) {
if (!pointConstraintMoveToPoint(curr->object, &curr->targetPos, curr->maxPosImpulse)) {
if (!pointConstraintMoveToPoint(curr->object, &curr->targetPos, curr->maxPosImpulse, curr->teleportOnBreak, curr->movementScaleFactor)) {
struct PointConstraint* next = curr->nextConstraint;
if (prev) {

View file

@ -4,13 +4,18 @@
#define BREAK_CONSTRAINT_DISTANCE 2.0f
int pointConstraintMoveToPoint(struct CollisionObject* object, struct Vector3* worldPoint, float maxImpulse) {
int pointConstraintMoveToPoint(struct CollisionObject* object, struct Vector3* worldPoint, float maxImpulse, int teleportOnBreak, float movementScaleFactor) {
struct RigidBody* rigidBody = object->body;
struct Vector3 targetVelocity;
vector3Sub(worldPoint, &rigidBody->transform.position, &targetVelocity);
if (vector3MagSqrd(&targetVelocity) > BREAK_CONSTRAINT_DISTANCE * BREAK_CONSTRAINT_DISTANCE) {
if (teleportOnBreak){
object->body->transform.position = *worldPoint;
return 1;
}
return 0;
}
@ -39,8 +44,10 @@ int pointConstraintMoveToPoint(struct CollisionObject* object, struct Vector3* w
struct Vector3 delta;
vector3Sub(&targetVelocity, &rigidBody->velocity, &delta);
float deltaSqrd = vector3MagSqrd(&delta);
if (deltaSqrd < maxImpulse * maxImpulse) {
vector3Scale(&targetVelocity, &targetVelocity, movementScaleFactor);
rigidBody->velocity = targetVelocity;
} else {
vector3AddScaled(&rigidBody->velocity, &delta, maxImpulse / sqrtf(deltaSqrd), &rigidBody->velocity);
@ -74,13 +81,15 @@ void pointConstraintRotateTo(struct RigidBody* rigidBody, struct Quaternion* wor
}
}
void pointConstraintInit(struct PointConstraint* constraint, struct CollisionObject* object, float maxPosImpulse, float maxRotImpulse) {
void pointConstraintInit(struct PointConstraint* constraint, struct CollisionObject* object, float maxPosImpulse, float maxRotImpulse, int teleportOnBreak, float movementScaleFactor) {
constraint->nextConstraint = NULL;
constraint->object = object;
constraint->targetPos = object->body->transform.position;
constraint->targetRot = object->body->transform.rotation;
constraint->maxPosImpulse = maxPosImpulse;
constraint->maxRotImpulse = maxRotImpulse;
constraint->teleportOnBreak = teleportOnBreak;
constraint->movementScaleFactor = movementScaleFactor;
}
void pointConstraintUpdateTarget(struct PointConstraint* constraint, struct Vector3* worldPoint, struct Quaternion* worldRotation) {

View file

@ -11,12 +11,14 @@ struct PointConstraint {
struct Quaternion targetRot;
float maxPosImpulse;
float maxRotImpulse;
int teleportOnBreak;
float movementScaleFactor;
};
void pointConstraintInit(struct PointConstraint* constraint, struct CollisionObject* object, float maxPosImpulse, float maxRotImpulse);
void pointConstraintInit(struct PointConstraint* constraint, struct CollisionObject* object, float maxPosImpulse, float maxRotImpulse, int teleportOnBreak, float movementScaleFactor);
void pointConstraintUpdateTarget(struct PointConstraint* constraint, struct Vector3* worldPoint, struct Quaternion* worldRotation);
int pointConstraintMoveToPoint(struct CollisionObject* object, struct Vector3* worldPoint, float maxImpulse);
int pointConstraintMoveToPoint(struct CollisionObject* object, struct Vector3* worldPoint, float maxImpulse, int teleportOnBreak, float movementScaleFactor);
void pointConstraintRotateTo(struct RigidBody* rigidBody, struct Quaternion* worldRotation, float maxImpulse);
#endif

View file

@ -32,6 +32,12 @@
struct Vector3 gGrabDistance = {0.0f, 0.0f, -1.5f};
struct Vector3 gCameraOffset = {0.0f, 0.0f, 0.0f};
struct Vector3 gPortalGunOffset = {0.150957, -0.153587, -0.355};
struct Vector3 gPortalGunShootOffset = {0.150957, -0.153587, 0.1};
struct Vector3 gPortalGunForward = {0.1f, -0.1f, 1.0f};
struct Vector3 gPortalGunShootForward = {0.1f, -0.25f, 1.0f};
struct Vector3 gPortalGunUp = {0.0f, 1.0f, 0.0f};
struct Vector2 gPlayerColliderEdgeVectors[] = {
{0.0f, 1.0f},
{0.707f, 0.707f},
@ -115,8 +121,11 @@ void playerRender(void* data, struct DynamicRenderDataList* renderList, struct R
);
}
void playerInit(struct Player* player, struct Location* startLocation, struct Vector3* velocity) {
void playerInit(struct Player* player, struct Location* startLocation, struct Vector3* velocity, struct CollisionObject* portalGunObject) {
collisionObjectInit(&player->collisionObject, &gPlayerColliderData, &player->body, 1.0f, PLAYER_COLLISION_LAYERS);
// rigidBodyMarkKinematic(&player->body);
player->body.flags |= RigidBodyIsKinematic | RigidBodyIsPlayer;
collisionSceneAddDynamicObject(&player->collisionObject);
@ -130,6 +139,7 @@ void playerInit(struct Player* player, struct Location* startLocation, struct Ve
player->body.velocity = *velocity;
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
player->grabConstraint.object = NULL;
player->gunConstraint.object = NULL;
player->pitchVelocity = 0.0f;
player->yawVelocity = 0.0f;
player->flags = 0;
@ -162,6 +172,9 @@ void playerInit(struct Player* player, struct Location* startLocation, struct Ve
collisionObjectUpdateBB(&player->collisionObject);
dynamicSceneSetRoomFlags(player->dynamicId, ROOM_FLAG_FROM_INDEX(player->body.currentRoom));
pointConstraintInit(&player->gunConstraint, portalGunObject, 20.0f, 2.5f, 1, 0.9f);
contactSolverAddPointConstraint(&gContactSolver, &player->gunConstraint);
}
#define PLAYER_SPEED (150.0f / 64.0f)
@ -226,13 +239,13 @@ void playerApplyPortalGrab(struct Player* player, int portalIndex) {
void playerSetGrabbing(struct Player* player, struct CollisionObject* grabbing) {
if (grabbing && !player->grabConstraint.object) {
pointConstraintInit(&player->grabConstraint, grabbing, 8.0f, 5.0f);
pointConstraintInit(&player->grabConstraint, grabbing, 8.0f, 5.0f, 0, 1.0f);
contactSolverAddPointConstraint(&gContactSolver, &player->grabConstraint);
} else if (!grabbing && player->grabConstraint.object) {
player->grabConstraint.object = NULL;
contactSolverRemovePointConstraint(&gContactSolver, &player->grabConstraint);
} else if (grabbing != player->grabConstraint.object) {
pointConstraintInit(&player->grabConstraint, grabbing, 8.0f, 5.0f);
pointConstraintInit(&player->grabConstraint, grabbing, 8.0f, 5.0f, 0, 1.0f);
}
}
@ -371,6 +384,33 @@ void playerUpdateGrabbedObject(struct Player* player) {
}
}
void playerUpdateGunObject(struct Player* player) {
struct Vector3 forward;
struct Vector3 offset;
if (player->flags & PlayerJustShotPortalGun){
player->flags &= ~PlayerJustShotPortalGun;
forward = gPortalGunShootForward;
offset = gPortalGunShootOffset;
}
else{
forward = gPortalGunForward;
offset = gPortalGunOffset;
}
struct Quaternion relativeRotation;
quatLook(&forward, &gPortalGunUp, &relativeRotation);
quatMultiply(&player->lookTransform.rotation, &relativeRotation, &player->gunConstraint.object->body->transform.rotation);
struct Vector3 gunPoint;
struct Vector3 temp_gun_dist = offset;
transformPoint(&player->lookTransform, &temp_gun_dist, &gunPoint);
pointConstraintUpdateTarget(&player->gunConstraint, &gunPoint, &player->gunConstraint.object->body->transform.rotation);
}
#define DEADZONE_SIZE 5
#define MAX_JOYSTICK_RANGE 80
@ -725,6 +765,7 @@ void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
cameraTransform->rotation = player->lookTransform.rotation;
cameraTransform->position = player->lookTransform.position;
playerUpdateGrabbedObject(player);
playerUpdateGunObject(player);
collisionObjectUpdateBB(&player->collisionObject);

View file

@ -27,6 +27,7 @@ enum PlayerFlags {
PlayerJustLanded = (1 << 8),
PlayerJustSelect = (1 << 9),
PlayerJustDeniedSelect = (1 << 10),
PlayerJustShotPortalGun = (1 << 11),
};
struct Player {
@ -38,6 +39,7 @@ struct Player {
short grabbingThroughPortal;
short dynamicId;
struct PointConstraint grabConstraint;
struct PointConstraint gunConstraint;
float pitchVelocity;
float yawVelocity;
enum PlayerFlags flags;
@ -49,7 +51,7 @@ struct Player {
int currentFoot; //left=0, right=1
};
void playerInit(struct Player* player, struct Location* startLocation, struct Vector3* velocity);
void playerInit(struct Player* player, struct Location* startLocation, struct Vector3* velocity, struct CollisionObject* portalGunObject);
void playerUpdate(struct Player* player, struct Transform* cameraTransform);
void playerGetMoveBasis(struct Transform* transform, struct Vector3* forward, struct Vector3* right);

View file

@ -11,6 +11,7 @@
#include "../physics/collision_scene.h"
#include "../build/assets/models/props/door_01.h"
#include "../build/assets/models/props/door_02.h"
#define OPEN_VELOCITY 8.0f
@ -28,6 +29,25 @@ struct ColliderTypeData gDoorCollider = {
&gCollisionBoxCallbacks,
};
struct DoorTypeDefinition gDoorTypeDefinitions[] = {
[DoorType01] = {
&props_door_01_armature,
&props_door_01_model_gfx[0],
&props_door_01_Armature_open_clip,
&props_door_01_Armature_close_clip,
-1,
1.0f,
},
[DoorType02] = {
&props_door_02_armature,
&props_door_02_model_gfx[0],
&props_door_02_Armature_open_clip,
&props_door_02_Armature_close_clip,
PROPS_DOOR_02_DOOR_BONE,
3.0f,
},
};
void doorRender(void* data, struct DynamicRenderDataList* renderList, struct RenderState* renderState) {
struct Door* door = (struct Door*)data;
Mtx* matrix = renderStateRequestMatrices(renderState, 1);
@ -43,18 +63,13 @@ void doorRender(void* data, struct DynamicRenderDataList* renderList, struct Ren
transformToMatrixL(&originalTransform, matrix, SCENE_SCALE);
props_door_01_default_bones[PROPS_DOOR_01_DOORL_BONE].position.x = door->openAmount * -0.625f * SCENE_SCALE;
props_door_01_default_bones[PROPS_DOOR_01_DOORR_BONE].position.x = door->openAmount * 0.625f * SCENE_SCALE;
Mtx* armature = renderStateRequestMatrices(renderState, PROPS_DOOR_01_DEFAULT_BONES_COUNT);
Mtx* armature = renderStateRequestMatrices(renderState, door->armature.numberOfBones);
if (!armature) {
return;
}
transformToMatrixL(&props_door_01_default_bones[PROPS_DOOR_01_FRAME_BONE], &armature[PROPS_DOOR_01_FRAME_BONE], 1.0f);
transformToMatrixL(&props_door_01_default_bones[PROPS_DOOR_01_DOORL_BONE], &armature[PROPS_DOOR_01_DOORL_BONE], 1.0f);
transformToMatrixL(&props_door_01_default_bones[PROPS_DOOR_01_DOORR_BONE], &armature[PROPS_DOOR_01_DOORR_BONE], 1.0f);
skCalculateTransforms(&door->armature, armature);
dynamicRenderListAddData(renderList, door_01_gfx, matrix, door_01_material_index, &door->rigidBody.transform.position, armature);
}
@ -64,6 +79,11 @@ void doorInit(struct Door* door, struct DoorDefinition* doorDefinition, struct W
rigidBodyMarkKinematic(&door->rigidBody);
collisionSceneAddDynamicObject(&door->collisionObject);
struct DoorTypeDefinition* typeDefinition = &gDoorTypeDefinitions[doorDefinition->doorType];
skArmatureInit(&door->armature, typeDefinition->armature);
skAnimatorInit(&door->animator, typeDefinition->armature->numberOfBones);
door->rigidBody.transform.position = doorDefinition->location;
door->rigidBody.transform.position.y += 1.0f;
door->rigidBody.transform.rotation = doorDefinition->rotation;
@ -73,7 +93,6 @@ void doorInit(struct Door* door, struct DoorDefinition* doorDefinition, struct W
door->dynamicId = dynamicSceneAdd(door, doorRender, &door->rigidBody.transform.position, 1.7f);
door->signalIndex = doorDefinition->signalIndex;
door->openAmount = 0.0f;
if (doorDefinition->doorwayIndex >= 0 && doorDefinition->doorwayIndex < world->doorwayCount) {
door->forDoorway = &world->doorways[doorDefinition->doorwayIndex];
@ -89,31 +108,46 @@ void doorInit(struct Door* door, struct DoorDefinition* doorDefinition, struct W
}
void doorUpdate(struct Door* door) {
float targetOpenAmount = signalsRead(door->signalIndex) ? 1.0f : 0.0f;
door->openAmount = mathfMoveTowards(door->openAmount, targetOpenAmount, OPEN_VELOCITY * FIXED_DELTA_TIME);
struct DoorTypeDefinition* typeDefinition = &gDoorTypeDefinitions[door->doorDefinition->doorType];
int signal = signalsRead(door->signalIndex);
skAnimatorUpdate(&door->animator, door->armature.pose, FIXED_DELTA_TIME);
int isOpen = (door->flags & DoorFlagsIsOpen) != 0;
if (isOpen != signal) {
if (!skAnimatorIsRunning(&door->animator)) {
if (signal) {
skAnimatorRunClip(&door->animator, typeDefinition->openClip, 0.0f, 0);
} else {
skAnimatorRunClip(&door->animator, typeDefinition->closeClip, 0.0f, 0);
}
soundPlayerPlay(soundsDoor, 3.0f, 0.5f, &door->rigidBody.transform.position, &gZeroVec);
}
if (signal) {
door->flags |= DoorFlagsIsOpen;
} else {
door->flags &= ~DoorFlagsIsOpen;
}
}
int isDoorwayOpen = skAnimatorIsRunning(&door->animator) || isOpen;
if (door->forDoorway) {
if (door->openAmount == 0.0f) {
door->forDoorway->flags &= ~DoorwayFlagsOpen;
} else {
if (isDoorwayOpen) {
door->forDoorway->flags |= DoorwayFlagsOpen;
} else {
door->forDoorway->flags &= ~DoorwayFlagsOpen;
}
}
if (door->openAmount == 0.0f) {
door->collisionObject.collisionLayers = COLLISION_LAYERS_TANGIBLE|COLLISION_LAYERS_STATIC;
door->flags &= ~DoorFlagsJustOpened;
if (!(door->flags & DoorFlagsJustClosed)){
soundPlayerPlay(soundsDoor, 3.0f, 0.5f, &door->rigidBody.transform.position, &gZeroVec);
door->flags |= DoorFlagsJustClosed;
}
if (typeDefinition->colliderBoneIndex == -1) {
door->collisionObject.collisionLayers = isDoorwayOpen ? 0 : (COLLISION_LAYERS_TANGIBLE | COLLISION_LAYERS_STATIC);
} else {
door->flags &= ~DoorFlagsJustClosed;
if (!(door->flags & DoorFlagsJustOpened)){
soundPlayerPlay(soundsDoor, 3.0f, 0.5f, &door->rigidBody.transform.position, &gZeroVec);
door->flags |= DoorFlagsJustOpened;
}
door->collisionObject.collisionLayers = 0;
door->rigidBody.transform.position.y =
door->doorDefinition->location.y +
door->armature.pose[typeDefinition->colliderBoneIndex].position.y * (1.0f / SCENE_SCALE);
}
}

View file

@ -5,20 +5,32 @@
#include "../levels/level_definition.h"
#include "../audio/soundplayer.h"
#include "../audio/clips.h"
#include "../sk64/skelatool_animator.h"
#include "../sk64/skelatool_armature.h"
enum DoorFlags {
DoorFlagsJustClosed = (1 << 0),
DoorFlagsJustOpened = (1 << 1),
DoorFlagsIsOpen = (1 << 0),
};
struct DoorTypeDefinition {
struct SKArmatureDefinition* armature;
Gfx* model;
struct SKAnimationClip* openClip;
struct SKAnimationClip* closeClip;
short colliderBoneIndex;
float closeSpeed;
};
struct Door {
struct CollisionObject collisionObject;
struct RigidBody rigidBody;
struct SKAnimator animator;
struct SKArmature armature;
struct Doorway* forDoorway;
struct DoorDefinition* doorDefinition;
short dynamicId;
short signalIndex;
float openAmount;
short flags;
};

78
src/scene/portal_gun.c Normal file
View file

@ -0,0 +1,78 @@
#include "portal_gun.h"
#include "../physics/collision_scene.h"
#include "../physics/collision_cylinder.h"
#include "models/models.h"
struct Vector2 gGunColliderEdgeVectors[] = {
{0.0f, 1.0f},
{0.707f, 0.707f},
{1.0f, 0.0f},
{0.707f, -0.707f},
};
struct CollisionQuad gGunColliderFaces[8];
struct CollisionCylinder gGunCollider = {
0.05f,
0.1f,
gGunColliderEdgeVectors,
sizeof(gGunColliderEdgeVectors) / sizeof(*gGunColliderEdgeVectors),
gGunColliderFaces,
};
struct ColliderTypeData gGunColliderData = {
CollisionShapeTypeCylinder,
&gGunCollider,
0.0f,
0.6f,
&gCollisionCylinderCallbacks,
};
void portalGunInit(struct PortalGun* portalGun, struct Transform* at){
collisionObjectInit(&portalGun->collisionObject, &gGunColliderData, &portalGun->rigidBody, 1.0f, 0);
collisionSceneAddDynamicObject(&portalGun->collisionObject);
portalGun->rigidBody.transform = *at;
portalGun->rigidBody.transform.scale = gOneVec;
portalGun->rigidBody.currentRoom = 0;
portalGun->rigidBody.velocity = gZeroVec;
portalGun->rigidBody.angularVelocity = gZeroVec;
portalGun->dynamicId = dynamicSceneAdd(portalGun, portalGunDummyRender, &portalGun->rigidBody.transform.position, 0.05f);
portalGun->portalGunVisible = 0;
collisionObjectUpdateBB(&portalGun->collisionObject);
dynamicSceneSetRoomFlags(portalGun->dynamicId, ROOM_FLAG_FROM_INDEX(portalGun->rigidBody.currentRoom));
}
void portalGunDummyRender(void* data, struct DynamicRenderDataList* renderList, struct RenderState* renderState){
return;
}
void portalGunRenderReal(struct PortalGun* portalGun, struct RenderState* renderState){
if (portalGun->portalGunVisible){
portalGun->rigidBody.transform.scale = gOneVec;
Mtx* matrix = renderStateRequestMatrices(renderState, 1);
if (!matrix) {
return;
}
transformToMatrixL(&portalGun->rigidBody.transform, matrix, SCENE_SCALE);
gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL);
gSPDisplayList(renderState->dl++, v_portal_gun_gfx);
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
}
}
void portalGunUpdate(struct PortalGun* portalGun, struct Player* player){
if (player->flags & (PlayerHasFirstPortalGun | PlayerHasSecondPortalGun)){
portalGun->portalGunVisible = 1;
}
else{
portalGun->portalGunVisible = 0;
}
dynamicSceneSetRoomFlags(portalGun->dynamicId, ROOM_FLAG_FROM_INDEX(portalGun->rigidBody.currentRoom));
}

24
src/scene/portal_gun.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef __PORTAL_GUN_H__
#define __PORTAL_GUN_H__
#include "../physics/collision_object.h"
#include "../math/transform.h"
#include "../graphics/renderstate.h"
#include "../physics/rigid_body.h"
#include "../physics/collision_object.h"
#include "../scene/dynamic_scene.h"
#include "../player/player.h"
struct PortalGun {
struct CollisionObject collisionObject;
struct RigidBody rigidBody;
int portalGunVisible;
short dynamicId;
};
void portalGunInit(struct PortalGun* portalGun, struct Transform* at);
void portalGunDummyRender(void* data, struct DynamicRenderDataList* renderList, struct RenderState* renderState);
void portalGunUpdate(struct PortalGun* portalGun, struct Player* player);
void portalGunRenderReal(struct PortalGun* portalGun, struct RenderState* renderState);
#endif

View file

@ -31,10 +31,6 @@
#include "signals.h"
#include "render_plan.h"
struct Vector3 gPortalGunOffset = {0.120957, -0.113587, -0.20916};
struct Vector3 gPortalGunForward = {0.1f, -0.1f, 1.0f};
struct Vector3 gPortalGunUp = {0.0f, 1.0f, 0.0f};
Lights1 gSceneLights = gdSPDefLights1(128, 128, 128, 128, 128, 128, 0, 127, 0);
#define LEVEL_INDEX_WITH_GUN_0 2
@ -78,7 +74,9 @@ void sceneInit(struct Scene* scene) {
transformConcat(&startLocation->transform, levelRelativeTransform(), &combinedLocation.transform);
quatMultVector(&startLocation->transform.rotation, levelRelativeVelocity(), &startVelocity);
playerInit(&scene->player, &combinedLocation, &startVelocity);
portalGunInit(&scene->portalGun, &combinedLocation.transform);
playerInit(&scene->player, &combinedLocation, &startVelocity, &scene->portalGun.collisionObject);
sceneUpdateListeners(scene);
if (gCurrentLevelIndex >= LEVEL_INDEX_WITH_GUN_0) {
@ -205,26 +203,6 @@ void sceneRenderPerformanceMetrics(struct Scene* scene, struct RenderState* rend
gDPPipeSync(renderState->dl++);
}
void sceneRenderPortalGun(struct Scene* scene, struct RenderState* renderState) {
struct Transform gunTransform;
transformPoint(&scene->player.lookTransform, &gPortalGunOffset, &gunTransform.position);
struct Quaternion relativeRotation;
quatLook(&gPortalGunForward, &gPortalGunUp, &relativeRotation);
quatMultiply(&scene->player.lookTransform.rotation, &relativeRotation, &gunTransform.rotation);
gunTransform.scale = gOneVec;
Mtx* matrix = renderStateRequestMatrices(renderState, 1);
if (!matrix) {
return;
}
transformToMatrixL(&gunTransform, matrix, SCENE_SCALE);
gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL);
gSPDisplayList(renderState->dl++, v_portal_gun_gfx);
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
}
LookAt gLookAt = gdSPDefLookAt(127, 0, 0, 0, 127, 0);
void sceneRender(struct Scene* scene, struct RenderState* renderState, struct GraphicsTask* task) {
@ -247,9 +225,7 @@ void sceneRender(struct Scene* scene, struct RenderState* renderState, struct Gr
renderPlanBuild(&renderPlan, scene, renderState);
renderPlanExecute(&renderPlan, scene, staticMatrices, renderState);
if (scene->player.flags & (PlayerHasFirstPortalGun | PlayerHasSecondPortalGun)) {
sceneRenderPortalGun(scene, renderState);
}
portalGunRenderReal(&scene->portalGun, renderState);
gDPPipeSync(renderState->dl++);
gDPSetRenderMode(renderState->dl++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
@ -279,18 +255,24 @@ void sceneCheckPortals(struct Scene* scene) {
quatMultVector(&scene->player.lookTransform.rotation, &raycastRay.dir, &raycastRay.dir);
quatMultVector(&scene->player.lookTransform.rotation, &gUp, &playerUp);
if (controllerGetButtonDown(0, Z_TRIG) && (scene->player.flags & PlayerHasSecondPortalGun)) {
if (controllerGetButtonDown(0, Z_TRIG) && (scene->player.flags & PlayerHasSecondPortalGun) && !playerIsGrabbing(&scene->player)) {
sceneFirePortal(scene, &raycastRay, &playerUp, 0, scene->player.body.currentRoom, 1, 0);
scene->player.flags |= PlayerJustShotPortalGun;
scene->last_portal_indx_shot=0;
soundPlayerPlay(soundsPortalgunShoot[0], 1.0f, 1.0f, NULL, NULL);
}
if (controllerGetButtonDown(0, R_TRIG | L_TRIG) && (scene->player.flags & PlayerHasFirstPortalGun)) {
if (controllerGetButtonDown(0, R_TRIG | L_TRIG) && (scene->player.flags & PlayerHasFirstPortalGun) && !playerIsGrabbing(&scene->player)) {
sceneFirePortal(scene, &raycastRay, &playerUp, 1, scene->player.body.currentRoom, 1, 0);
scene->player.flags |= PlayerJustShotPortalGun;
scene->last_portal_indx_shot=1;
soundPlayerPlay(soundsPortalgunShoot[1], 1.0f, 1.0f, NULL, NULL);
}
if (controllerGetButtonDown(0, R_TRIG | L_TRIG | Z_TRIG) && playerIsGrabbing(&scene->player)){
playerSetGrabbing(&scene->player, NULL);
}
scene->looked_wall_portalable_0 = 0;
scene->looked_wall_portalable_1 = 0;
@ -323,6 +305,7 @@ void sceneCheckPortals(struct Scene* scene) {
if (scene->player.flags & PlayerHasFirstPortalGun){
if (sceneFirePortal(scene, &raycastRay, &playerUp, 0, scene->player.body.currentRoom, 1, 1)){
scene->looked_wall_portalable_0 = 1;
}
if (sceneFirePortal(scene, &raycastRay, &playerUp, 1, scene->player.body.currentRoom, 1, 1)){
@ -449,6 +432,7 @@ void sceneUpdate(struct Scene* scene) {
signalsReset();
portalGunUpdate(&scene->portalGun, &scene->player);
playerUpdate(&scene->player, &scene->camera.transform);
sceneUpdateListeners(scene);
sceneCheckPortals(scene);
@ -524,6 +508,14 @@ void sceneUpdate(struct Scene* scene) {
&gZeroVec,
scene->elevators[teleportTo].roomIndex
);
rigidBodyTeleport(
&scene->portalGun.rigidBody,
&scene->elevators[i].rigidBody.transform,
&scene->elevators[teleportTo].rigidBody.transform,
&gZeroVec,
&gZeroVec,
scene->elevators[teleportTo].roomIndex
);
checkpointSave(&gScene);
sceneClosePortal(&gScene, 0);
sceneClosePortal(&gScene, 1);

View file

@ -20,10 +20,12 @@
#include "switch.h"
#include "ball_launcher.h"
#include "ball_catcher.h"
#include "portal_gun.h"
struct Scene {
struct Camera camera;
struct Player player;
struct PortalGun portalGun;
struct Portal portals[2];
struct Button* buttons;
struct DecorObject** decor;

View file

@ -4,6 +4,8 @@
#define SK_ANIMATION_EVENT_END 0xFFFF
#define SK_ANIMATION_EVENT_START 0xFFFE
#define SK_ANIMATION_CLIP_DURATION(clip) ((clip)->nFrames / (clip)->fps)
struct SKU16Vector3 {
short x;
short y;

View file

@ -60,6 +60,14 @@ sk_definition_writer.add_header('"decor/decor_object_list.h"')
local doors = {}
local function parse_door_type(name)
if name == '02' then
return sk_definition_writer.raw('DoorType02')
end
return sk_definition_writer.raw('DoorType01')
end
for _, door in pairs(sk_scene.nodes_for_type('@door')) do
local position, rotation = door.node.full_transformation:decompose()
@ -68,6 +76,7 @@ for _, door in pairs(sk_scene.nodes_for_type('@door')) do
rotation,
world.find_coplanar_doorway(position) - 1,
signals.signal_index_for_name(door.arguments[1] or ''),
parse_door_type(door.arguments[2])
})
end