[Bug,Enhancement] Fix and improve Starter selector UI (#3340)

* apply offset to all hybrid filter

* make dropDownType to public for offsetHybridFilter function

* refactoring defaultSettings to additional suport default cursor.

* fix to remember last cursor on hover mode

* remove unnecessary reset code

* fix sort reset function

* update resetFilter function

* update requested changes

* remove log msg

* fix checking default on sort

* refactoring hasDefaultValues function for readability

* fix lastdir bug
This commit is contained in:
Leo Kim 2024-08-06 00:42:15 +09:00 committed by GitHub
parent 97e362368c
commit 91b32132d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 68 additions and 68 deletions

View File

@ -27,10 +27,10 @@ export class DropDownLabel {
public text: string;
public sprite?: Phaser.GameObjects.Sprite;
constructor(label: string, sprite?: Phaser.GameObjects.Sprite, state: DropDownState = DropDownState.ON) {
constructor(label: string, sprite?: Phaser.GameObjects.Sprite, state: DropDownState = DropDownState.OFF) {
this.text = label || "";
this.sprite = sprite;
this.state = state || DropDownState.ON;
this.state = state;
}
}
@ -262,12 +262,13 @@ export class DropDown extends Phaser.GameObjects.Container {
public options: DropDownOption[];
private window: Phaser.GameObjects.NineSlice;
private cursorObj: Phaser.GameObjects.Image;
private dropDownType: DropDownType = DropDownType.MULTI;
public dropDownType: DropDownType = DropDownType.MULTI;
public cursor: number = 0;
private lastCursor: number = -1;
public defaultCursor: number = 0;
private onChange: () => void;
private lastDir: SortDirection = SortDirection.ASC;
private defaultValues: any[];
private defaultSettings: any[];
constructor(scene: BattleScene, x: number, y: number, options: DropDownOption[], onChange: () => void, type: DropDownType = DropDownType.MULTI, optionSpacing: number = 2) {
const windowPadding = 5;
@ -292,7 +293,7 @@ export class DropDown extends Phaser.GameObjects.Container {
this.options.unshift(new DropDownOption(scene, "ALL", new DropDownLabel(i18next.t("filterBar:all"), undefined, this.checkForAllOn() ? DropDownState.ON : DropDownState.OFF)));
}
this.defaultValues = this.getVals();
this.defaultSettings = this.getSettings();
// Place ui elements in the correct spot
options.forEach((option, index) => {
@ -339,8 +340,8 @@ export class DropDown extends Phaser.GameObjects.Container {
resetCursor(): boolean {
// If we are an hybrid dropdown in "hover" mode, don't move the cursor back to 0
if (this.dropDownType === DropDownType.HYBRID && this.checkForAllOff() && this.cursor > 0) {
return false;
if (this.dropDownType === DropDownType.HYBRID && this.checkForAllOff()) {
return this.setCursor(this.lastCursor);
}
return this.setCursor(this.defaultCursor);
}
@ -361,6 +362,7 @@ export class DropDown extends Phaser.GameObjects.Container {
this.cursorObj.setVisible(true);
// If hydrid type, we need to update the filters when going up/down in the list
if (this.dropDownType === DropDownType.HYBRID) {
this.lastCursor = cursor;
this.onChange();
}
}
@ -457,23 +459,43 @@ export class DropDown extends Phaser.GameObjects.Container {
}
}
/**
* Get the current selected settings dictionary for each option
* @returns an array of dictionaries with the current state of each option
* - the settings dictionary is like this { val: any, state: DropDownState, cursor: boolean, dir: SortDirection }
*/
private getSettings(): any[] {
const settings = [];
for (let i = 0; i < this.options.length; i++) {
settings.push({ val: this.options[i].val, state: this.options[i].state , cursor: (this.cursor === i), dir: this.options[i].dir });
}
return settings;
}
/**
* Check whether the values of all options are the same as the default ones
* @returns true if they are the same, false otherwise
*/
public hasDefaultValues(): boolean {
const currentValues = this.getVals();
const currentValues = this.getSettings();
const compareValues = (keys: string[]): boolean => {
return currentValues.length === this.defaultSettings.length &&
currentValues.every((value, index) =>
keys.every(key => value[key] === this.defaultSettings[index][key])
);
};
switch (this.dropDownType) {
case DropDownType.MULTI:
case DropDownType.HYBRID:
return currentValues.length === this.defaultValues.length && currentValues.every((value, index) => value === this.defaultValues[index]);
case DropDownType.RADIAL:
return currentValues.every((value, index) => value["val"] === this.defaultValues[index]["val"] && value["state"] === this.defaultValues[index]["state"]);
return compareValues(["val", "state"]);
case DropDownType.HYBRID:
return compareValues(["val", "state", "cursor"]);
case DropDownType.SINGLE:
return currentValues[0]["dir"] === this.defaultValues[0]["dir"] && currentValues[0]["val"] === this.defaultValues[0]["val"];
return compareValues(["val", "state", "dir"]);
default:
return false;
@ -484,46 +506,29 @@ export class DropDown extends Phaser.GameObjects.Container {
* Set all values to their default state
*/
public resetToDefault(): void {
this.setCursor(this.defaultCursor);
if (this.defaultSettings.length > 0) {
this.setCursor(this.defaultCursor);
this.lastDir = SortDirection.ASC;
for (let i = 0; i < this.options.length; i++) {
const option = this.options[i];
// reset values
switch (this.dropDownType) {
case DropDownType.HYBRID:
case DropDownType.MULTI:
if (this.defaultValues.includes(option.val)) {
option.setOptionState(DropDownState.ON);
for (let i = 0; i < this.options.length; i++) {
// reset values with the defaultValues
if (this.dropDownType === DropDownType.SINGLE) {
if (this.defaultSettings[i].state === DropDownState.OFF) {
this.options[i].setOptionState(DropDownState.OFF);
this.options[i].setDirection(SortDirection.ASC);
this.options[i].toggle.setVisible(false);
} else {
this.options[i].setOptionState(DropDownState.ON);
this.options[i].setDirection(SortDirection.ASC);
this.options[i].toggle.setVisible(true);
}
} else {
option.setOptionState(DropDownState.OFF);
}
break;
case DropDownType.RADIAL:
const targetValue = this.defaultValues.find(value => value.val === option.val);
option.setOptionState(targetValue.state);
break;
case DropDownType.SINGLE:
if (option.val === this.defaultValues[0].val) {
if (option.state !== DropDownState.ON) {
this.toggleOptionState(i);
}
if (option.dir !== this.defaultValues[0].dir) {
this.toggleOptionState(i);
if (this.defaultSettings[i]) {
this.options[i].setOptionState(this.defaultSettings[i]["state"]);
}
}
break;
}
}
// Select or unselect "ALL" button if applicable
if (this.dropDownType === DropDownType.MULTI || this.dropDownType === DropDownType.HYBRID) {
if (this.checkForAllOn()) {
this.options[0].setOptionState(DropDownState.ON);
} else {
this.options[0].setOptionState(DropDownState.OFF);
}
}
}
/**

View File

@ -1,5 +1,5 @@
import BattleScene from "#app/battle-scene.js";
import { DropDown } from "./dropdown";
import { DropDown, DropDownType } from "./dropdown";
import { StarterContainer } from "./starter-container";
import { addTextObject, getTextColor, TextStyle } from "./text";
import { UiTheme } from "#enums/ui-theme";
@ -120,11 +120,13 @@ export class FilterBar extends Phaser.GameObjects.Container {
/**
* Move the leftmost dropdown to the left of the FilterBar instead of below it
*/
offsetFirstFilter(): void {
if (this.dropDowns[0]) {
this.dropDowns[0].autoSize();
this.dropDowns[0].x -= this.dropDowns[0].getWidth();
this.dropDowns[0].y = 0;
offsetHybridFilters(): void {
for (let i=0; i<this.dropDowns.length; i++) {
if (this.dropDowns[i].dropDownType === DropDownType.HYBRID) {
this.dropDowns[i].autoSize();
this.dropDowns[i].x = - this.dropDowns[i].getWidth();
this.dropDowns[i].y = 0;
}
}
}

View File

@ -450,11 +450,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
// sort filter
const sortOptions = [
new DropDownOption(this.scene, 0, new DropDownLabel(i18next.t("filterBar:sortByNumber"))),
new DropDownOption(this.scene, 1, new DropDownLabel(i18next.t("filterBar:sortByCost"), undefined, DropDownState.OFF)),
new DropDownOption(this.scene, 2, new DropDownLabel(i18next.t("filterBar:sortByCandies"), undefined, DropDownState.OFF)),
new DropDownOption(this.scene, 3, new DropDownLabel(i18next.t("filterBar:sortByIVs"), undefined, DropDownState.OFF)),
new DropDownOption(this.scene, 4, new DropDownLabel(i18next.t("filterBar:sortByName"), undefined, DropDownState.OFF))
new DropDownOption(this.scene, 0, new DropDownLabel(i18next.t("filterBar:sortByNumber"), undefined, DropDownState.ON)),
new DropDownOption(this.scene, 1, new DropDownLabel(i18next.t("filterBar:sortByCost"))),
new DropDownOption(this.scene, 2, new DropDownLabel(i18next.t("filterBar:sortByCandies"))),
new DropDownOption(this.scene, 3, new DropDownLabel(i18next.t("filterBar:sortByIVs"))),
new DropDownOption(this.scene, 4, new DropDownLabel(i18next.t("filterBar:sortByName")))
];
this.filterBar.addFilter(DropDownColumn.SORT, i18next.t("filterBar:sortFilter"), new DropDown(this.scene, 0, 0, sortOptions, this.updateStarters, DropDownType.SINGLE));
this.filterBarContainer.add(this.filterBar);
@ -462,7 +462,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectContainer.add(this.filterBarContainer);
// Offset the generation filter dropdown to avoid covering the filtered pokemon
this.filterBar.offsetFirstFilter();
this.filterBar.offsetHybridFilters();
if (!this.scene.uiTheme) {
starterContainerWindow.setVisible(false);
@ -914,19 +914,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
*/
resetFilters() : void {
const genDropDown: DropDown = this.filterBar.getFilter(DropDownColumn.GEN);
if (this.scene.gameMode.isChallenge) {
// In challenge mode all gens are selected by default
genDropDown.defaultCursor = 0;
} else {
// in other modes, gen 1 is selected by default, and all options disabled
genDropDown.defaultCursor = 1;
}
this.filterBar.setValsToDefault();
// for all modes except challenge, disable all gen options to enable hovering behavior
if (!this.scene.gameMode.isChallenge) {
genDropDown.unselectAllOptions();
// if not in a challenge, in Gen hybrid filter hovering mode, set the cursor to the Gen1
genDropDown.setCursor(1);
}
}