Work on controls settings

This commit is contained in:
James Lambert 2023-05-12 08:21:47 -06:00
parent 2a0969abd0
commit 0602f6c30e
8 changed files with 213 additions and 21 deletions

View file

@ -257,7 +257,7 @@ build/src/menu/landing_menu.o: build/assets/materials/ui.h build/src/audio/clips
build/src/menu/options_menu.o: build/assets/materials/ui.h
build/src/menu/joystick_options.o: build/assets/materials/ui.h
build/src/menu/joystick_options.o: build/assets/materials/ui.h build/src/audio/clips.h
build/src/menu/controls.o: build/assets/materials/ui.h build/src/audio/clips.h

View file

@ -2,20 +2,71 @@
#include "../controls/controller.h"
#include "../font/dejavusans.h"
#include "../audio/soundplayer.h"
#include "../savefile/savefile.h"
#include "../build/assets/materials/ui.h"
#include "../build/src/audio/clips.h"
#define JOYSTICK_Y 54
#define JOYSTICK_WIDTH 252
#define JOYSTICK_HEIGHT 124
#define SCROLL_TICKS 9
#define SCROLL_INTERVALS (SCROLL_TICKS - 1)
#define JOYSTICK_X ((SCREEN_WD - JOYSTICK_WIDTH) / 2)
void joystickOptionsInit(struct JoystickOptions* joystickOptions) {
joystickOptions->selectedItem = 0;
joystickOptions->selectedItem = JoystickOptionInvert;
joystickOptions->invertControls = menuBuildCheckbox(&gDejaVuSansFont, "Invert Camera", JOYSTICK_X + 8, JOYSTICK_Y + 8);
joystickOptions->lookSensitivity = menuBuildSlider(JOYSTICK_X + 8, JOYSTICK_Y + 20, 80, 8, 13);
joystickOptions->lookSensitivityText = menuBuildText(&gDejaVuSansFont, "Look Sensitivity", JOYSTICK_X + 8, JOYSTICK_Y + 28);
joystickOptions->lookSensitivity = menuBuildSlider(JOYSTICK_X + 120, JOYSTICK_Y + 28, 120, SCROLL_TICKS);
joystickOptions->lookAccelerationText = menuBuildText(&gDejaVuSansFont, "Look Acceleration", JOYSTICK_X + 8, JOYSTICK_Y + 48);
joystickOptions->lookAcceleration = menuBuildSlider(JOYSTICK_X + 120, JOYSTICK_Y + 48, 120, SCROLL_TICKS);
joystickOptions->invertControls.checked = (gSaveData.controls.flags & ControlSaveFlagsInvert) != 0;
joystickOptions->lookSensitivity.value = (float)gSaveData.controls.sensitivity / 0xFFFF;
joystickOptions->lookAcceleration.value = (float)gSaveData.controls.acceleration / 0xFFFF;
}
#define FULL_SCROLL_TIME 2.0f
#define SCROLL_MULTIPLIER (int)(0xFFFF * FIXED_DELTA_TIME / (80 * FULL_SCROLL_TIME))
#define SCROLL_CHUNK_SIZE (0x10000 / SCROLL_INTERVALS)
void joystickOptionsHandleSlider(unsigned short* settingValue, float* sliderValue) {
OSContPad* pad = controllersGetControllerData(0);
int newValue = (int)*settingValue + pad->stick_x * SCROLL_MULTIPLIER;
if (controllerGetButtonDown(0, A_BUTTON | R_JPAD)) {
if (newValue >= 0xFFFF && controllerGetButtonDown(0, A_BUTTON)) {
newValue = 0;
} else {
newValue = newValue + SCROLL_CHUNK_SIZE;
newValue = newValue - (newValue % SCROLL_CHUNK_SIZE);
}
}
if (controllerGetButtonDown(0, L_JPAD)) {
newValue = newValue - 1;
newValue = newValue - (newValue % SCROLL_CHUNK_SIZE);
}
if (newValue < 0) {
newValue = 0;
}
if (newValue > 0xFFFF) {
newValue = 0xFFFF;
}
*settingValue = newValue;
*sliderValue = (float)newValue / 0xFFFF;
}
enum MenuDirection joystickOptionsUpdate(struct JoystickOptions* joystickOptions) {
@ -25,6 +76,44 @@ enum MenuDirection joystickOptionsUpdate(struct JoystickOptions* joystickOptions
return MenuDirectionUp;
}
if (controllerDir & ControllerDirectionDown) {
++joystickOptions->selectedItem;
if (joystickOptions->selectedItem == JoystickOptionCount) {
joystickOptions->selectedItem = 0;
}
}
if (controllerDir & ControllerDirectionUp) {
if (joystickOptions->selectedItem == 0) {
joystickOptions->selectedItem = JoystickOptionCount - 1;
} else {
--joystickOptions->selectedItem;
}
}
switch (joystickOptions->selectedItem) {
case JoystickOptionInvert:
if (controllerGetButtonDown(0, A_BUTTON)) {
joystickOptions->invertControls.checked = !joystickOptions->invertControls.checked;
soundPlayerPlay(SOUNDS_BUTTONCLICKRELEASE, 1.0f, 0.5f, NULL, NULL);
if (joystickOptions->invertControls.checked) {
gSaveData.controls.flags |= ControlSaveFlagsInvert;
} else {
gSaveData.controls.flags &= ~ControlSaveFlagsInvert;
}
}
break;
case JoystickOptionSensitivity:
joystickOptionsHandleSlider(&gSaveData.controls.sensitivity, &joystickOptions->lookSensitivity.value);
return MenuDirectionStay;
case JoystickOptionAcceleration:
joystickOptionsHandleSlider(&gSaveData.controls.acceleration, &joystickOptions->lookAcceleration.value);
return MenuDirectionStay;
}
if (controllerDir & ControllerDirectionLeft) {
return MenuDirectionLeft;
}
@ -40,13 +129,28 @@ void joystickOptionsRender(struct JoystickOptions* joystickOptions, struct Rende
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_ENV_INDEX]);
gSPDisplayList(renderState->dl++, joystickOptions->invertControls.outline);
renderState->dl = menuCheckboxRender(&joystickOptions->invertControls, renderState->dl);
gSPDisplayList(renderState->dl++, joystickOptions->lookSensitivity.back);
renderState->dl = menuSliderRender(&joystickOptions->lookSensitivity, renderState->dl);
gSPDisplayList(renderState->dl++, joystickOptions->lookAcceleration.back);
renderState->dl = menuSliderRender(&joystickOptions->lookAcceleration, renderState->dl);
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_ENV_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[DEJAVU_SANS_INDEX]);
gDPPipeSync(renderState->dl++);
menuSetRenderColor(renderState, joystickOptions->selectedItem == JoystickOptionInvert, &gSelectionGray, &gColorWhite);
gSPDisplayList(renderState->dl++, joystickOptions->invertControls.text);
gDPPipeSync(renderState->dl++);
menuSetRenderColor(renderState, joystickOptions->selectedItem == JoystickOptionSensitivity, &gSelectionGray, &gColorWhite);
gSPDisplayList(renderState->dl++, joystickOptions->lookSensitivityText);
gDPPipeSync(renderState->dl++);
menuSetRenderColor(renderState, joystickOptions->selectedItem == JoystickOptionAcceleration, &gSelectionGray, &gColorWhite);
gSPDisplayList(renderState->dl++, joystickOptions->lookAccelerationText);
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_INDEX]);
}

View file

@ -4,9 +4,20 @@
#include "./menu.h"
#include "../graphics/graphics.h"
enum JoystickOption {
JoystickOptionInvert,
JoystickOptionSensitivity,
JoystickOptionAcceleration,
JoystickOptionCount,
};
struct JoystickOptions {
struct MenuCheckbox invertControls;
struct MenuSlider lookSensitivity;
struct MenuSlider lookAcceleration;
Gfx* lookSensitivityText;
Gfx* lookAccelerationText;
short selectedItem;
};

View file

@ -197,36 +197,90 @@ struct MenuCheckbox menuBuildCheckbox(struct Font* font, char* message, int x, i
return result;
}
#define SLIDER_CENTER_HEIGHT 4
Gfx* menuCheckboxRender(struct MenuCheckbox* checkbox, Gfx* dl) {
if (!checkbox->checked) {
return dl;
}
struct MenuSlider menuBuildSlider(int x, int y, int w, int h, int tickCount) {
gDPPipeSync(dl++);
gDPSetEnvColor(dl++, 255, 255, 255, 255);
gDPFillRectangle(
dl++,
checkbox->x + 3,
checkbox->y + 3,
checkbox->x + 8,
checkbox->y + 8
);
return dl;
}
#define SLIDER_TRACK_HEIGHT 4
#define SLIDER_HEIGHT 12
#define SLIDER_WIDTH 6
#define TICK_Y 11
#define TICK_HEIGHT 3
struct MenuSlider menuBuildSlider(int x, int y, int w, int tickCount) {
struct MenuSlider result;
result.x = x;
result.y = y;
result.w = w;
result.h = h;
result.back = malloc(sizeof(Gfx) * 12 + tickCount + 2);
result.back = malloc(sizeof(Gfx) * (12 + tickCount));
Gfx* dl = result.back;
int sliderX = x;
int sliderY = y + (h >> 1) - (SLIDER_CENTER_HEIGHT >> 1);
int sliderY = y + (SLIDER_HEIGHT / 2) - (SLIDER_TRACK_HEIGHT / 2);
gDPPipeSync(dl++);
gDPSetEnvColor(dl++, 93, 96, 97, 255);
gDPSetEnvColor(dl++, 25, 25, 25, 255);
gDPFillRectangle(
dl++,
sliderX,
sliderY,
sliderX + w,
sliderY + SLIDER_CENTER_HEIGHT
sliderY + SLIDER_TRACK_HEIGHT
);
dl = menuRenderOutline(sliderX, sliderY, w, SLIDER_CENTER_HEIGHT, 1, dl);
int tickMin = x + (SLIDER_WIDTH / 2);
int tickWidth = w - SLIDER_WIDTH;
for (int i = 0; i < tickCount; ++i) {
int tickX = (i * tickWidth) / (tickCount - 1) + tickMin;
gDPFillRectangle(
dl++,
tickX,
y + TICK_Y,
tickX + 1,
y + TICK_Y + TICK_HEIGHT
);
}
dl = menuRenderOutline(sliderX, sliderY, w, SLIDER_TRACK_HEIGHT, 1, dl);
gSPEndDisplayList(dl++);
result.value = 0;
return result;
}
Gfx* menuSliderRender(struct MenuSlider* slider, Gfx* dl) {
gDPPipeSync(dl++);
gDPSetEnvColor(dl++, 93, 96, 97, 255);
int sliderPos = (slider->w - SLIDER_WIDTH) * slider->value + slider->x + (SLIDER_WIDTH / 2);
gDPFillRectangle(
dl++,
sliderPos - (SLIDER_WIDTH / 2),
slider->y,
sliderPos + (SLIDER_WIDTH / 2),
slider->y + SLIDER_HEIGHT
);
dl = menuRenderOutline(sliderPos - (SLIDER_WIDTH / 2), slider->y, SLIDER_WIDTH, SLIDER_HEIGHT, 0, dl);
return dl;
}

View file

@ -25,7 +25,7 @@ struct MenuSlider {
Gfx* back;
float value;
short x, y;
short w, h;
short w;
};
enum MenuDirection {
@ -55,6 +55,9 @@ struct MenuButton menuBuildButton(struct Font* font, char* message, int x, int y
void menuSetRenderColor(struct RenderState* renderState, int isSelected, struct Coloru8* selected, struct Coloru8* defaultColor);
struct MenuCheckbox menuBuildCheckbox(struct Font* font, char* message, int x, int y);
struct MenuSlider menuBuildSlider(int x, int y, int w, int h, int tickCount);
Gfx* menuCheckboxRender(struct MenuCheckbox* checkbox, Gfx* dl);
struct MenuSlider menuBuildSlider(int x, int y, int w, int tickCount);
Gfx* menuSliderRender(struct MenuSlider* slider, Gfx* dl);
#endif

View file

@ -186,9 +186,11 @@ void playerInit(struct Player* player, struct Location* startLocation, struct Ve
#define PLAYER_STOP_ACCEL (5.875f)
#define PLAYER_SLIDE_ACCEL (40.0f)
#define ROTATE_RATE (M_PI * 2.0f)
#define ROTATE_RATE_DELTA (M_PI * 0.125f)
#define ROTATE_RATE_STOP_DELTA (M_PI * 0.25f)
#define MIN_ROTATE_RATE (M_PI * 0.5f)
#define MAX_ROTATE_RATE (M_PI * 3.5f)
#define MIN_ROTATE_RATE_DELTA (M_PI * 0.06125f)
#define MAX_ROTATE_RATE_DELTA MAX_ROTATE_RATE
#define JUMP_IMPULSE 2.7f
@ -718,18 +720,26 @@ void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
}
struct Vector2 lookInput = controllerDirectionGet(ControllerActionRotate);
float targetYaw = -lookInput.x * ROTATE_RATE;
float targetPitch = lookInput.y * ROTATE_RATE;
float rotateRate = mathfLerp(MIN_ROTATE_RATE, MAX_ROTATE_RATE, (float)gSaveData.controls.sensitivity / 0xFFFF);
float targetYaw = -lookInput.x * rotateRate;
float targetPitch = lookInput.y * rotateRate;
if (gSaveData.controls.flags & ControlSaveFlagsInvert) {
targetYaw = -targetYaw;
targetPitch = -targetPitch;
}
float rotateRateDelta = mathfLerp(MIN_ROTATE_RATE_DELTA, MAX_ROTATE_RATE_DELTA, (float)gSaveData.controls.acceleration / 0xFFFF);
player->yawVelocity = mathfMoveTowards(
player->yawVelocity,
targetYaw,
player->yawVelocity * targetYaw > 0.0f ? ROTATE_RATE_DELTA : ROTATE_RATE_STOP_DELTA
rotateRateDelta
);
player->pitchVelocity = mathfMoveTowards(
player->pitchVelocity,
targetPitch,
player->pitchVelocity * targetPitch > 0.0f ? ROTATE_RATE_DELTA : ROTATE_RATE_STOP_DELTA
rotateRateDelta
);
struct Vector3 lookingForward;

View file

@ -90,6 +90,9 @@ void savefileNew() {
}
controllerSetDefaultSource();
gSaveData.controls.flags = 0;
gSaveData.controls.sensitivity = 0x7FFF;
gSaveData.controls.acceleration = 0x7FFF;
gSaveData.audio.soundVolume = 0xFF;
gSaveData.audio.musicVolume = 0xFF;

View file

@ -20,7 +20,7 @@
#define SCREEN_SHOT_SRAM(slotIndex) (((slotIndex) + 1) * SAVE_SLOT_SIZE + MAX_CHECKPOINT_SIZE + SRAM_START_ADDR)
#define SAVEFILE_HEADER 0xDEAD
#define SAVEFILE_HEADER 0xDEA0
// first save slot is always reserved for auto save
#define MAX_SAVE_SLOTS ((int)(SRAM_SIZE / SAVE_SLOT_SIZE) - 1)
@ -33,8 +33,15 @@ struct SaveHeader {
unsigned char nextTestSubject;
};
enum ControlSaveFlags {
ControlSaveFlagsInvert,
};
struct ControlSaveState {
unsigned char controllerSettings[2][ControllerActionSourceCount];
unsigned short flags;
unsigned short sensitivity;
unsigned short acceleration;
};
struct AudioSettingsSaveState {