[ui] make egg list scrollable

This commit is contained in:
MokaStitcher 2024-09-22 13:29:34 +02:00
parent 342bd5c726
commit 33a2a2b423
2 changed files with 114 additions and 26 deletions

View File

@ -3,14 +3,18 @@ import { Mode } from "./ui";
import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler";
import { TextStyle, addTextObject } from "./text"; import { TextStyle, addTextObject } from "./text";
import MessageUiHandler from "./message-ui-handler"; import MessageUiHandler from "./message-ui-handler";
import { Egg } from "../data/egg";
import { addWindow } from "./ui-theme"; import { addWindow } from "./ui-theme";
import {Button} from "#enums/buttons"; import {Button} from "#enums/buttons";
import i18next from "i18next"; import i18next from "i18next";
import { ScrollBar } from "./scroll-bar";
export default class EggListUiHandler extends MessageUiHandler { export default class EggListUiHandler extends MessageUiHandler {
private readonly ROWS = 9;
private readonly COLUMNS = 11;
private eggListContainer: Phaser.GameObjects.Container; private eggListContainer: Phaser.GameObjects.Container;
private eggListIconContainer: Phaser.GameObjects.Container; private eggListIconContainer: Phaser.GameObjects.Container;
private eggIcons: Phaser.GameObjects.Sprite[];
private eggSprite: Phaser.GameObjects.Sprite; private eggSprite: Phaser.GameObjects.Sprite;
private eggNameText: Phaser.GameObjects.Text; private eggNameText: Phaser.GameObjects.Text;
private eggDateText: Phaser.GameObjects.Text; private eggDateText: Phaser.GameObjects.Text;
@ -19,6 +23,8 @@ export default class EggListUiHandler extends MessageUiHandler {
private eggListMessageBoxContainer: Phaser.GameObjects.Container; private eggListMessageBoxContainer: Phaser.GameObjects.Container;
private cursorObj: Phaser.GameObjects.Image; private cursorObj: Phaser.GameObjects.Image;
private scrollCursor: number;
private scrollBar: ScrollBar;
private iconAnimHandler: PokemonIconAnimHandler; private iconAnimHandler: PokemonIconAnimHandler;
@ -64,7 +70,7 @@ export default class EggListUiHandler extends MessageUiHandler {
this.eggGachaInfoText.setWordWrapWidth(540); this.eggGachaInfoText.setWordWrapWidth(540);
this.eggListContainer.add(this.eggGachaInfoText); this.eggListContainer.add(this.eggGachaInfoText);
this.eggListIconContainer = this.scene.add.container(115, 9); this.eggListIconContainer = this.scene.add.container(113, 5);
this.eggListContainer.add(this.eggListIconContainer); this.eggListContainer.add(this.eggListIconContainer);
this.cursorObj = this.scene.add.image(0, 0, "select_cursor"); this.cursorObj = this.scene.add.image(0, 0, "select_cursor");
@ -74,6 +80,9 @@ export default class EggListUiHandler extends MessageUiHandler {
this.eggSprite = this.scene.add.sprite(54, 37, "egg"); this.eggSprite = this.scene.add.sprite(54, 37, "egg");
this.eggListContainer.add(this.eggSprite); this.eggListContainer.add(this.eggSprite);
this.scrollBar = new ScrollBar(this.scene, 310, 5, 4, 170, this.ROWS);
this.eggListContainer.add(this.scrollBar);
this.eggListMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6); this.eggListMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6);
this.eggListMessageBoxContainer.setVisible(false); this.eggListMessageBoxContainer.setVisible(false);
this.eggListContainer.add(this.eggListMessageBoxContainer); this.eggListContainer.add(this.eggListMessageBoxContainer);
@ -87,32 +96,55 @@ export default class EggListUiHandler extends MessageUiHandler {
this.eggListMessageBoxContainer.add(this.message); this.eggListMessageBoxContainer.add(this.message);
this.cursor = -1; this.cursor = -1;
this.scrollCursor = 0;
} }
show(args: any[]): boolean { show(args: any[]): boolean {
super.show(args); super.show(args);
this.initEggIcons();
this.getUi().bringToTop(this.eggListContainer); this.getUi().bringToTop(this.eggListContainer);
this.eggListContainer.setVisible(true); this.eggListContainer.setVisible(true);
let e = 0; this.scrollBar.setTotalRows(Math.ceil(this.scene.gameData.eggs.length / this.COLUMNS));
for (const egg of this.scene.gameData.eggs) { this.updateEggIcons();
const x = (e % 11) * 18; this.setCursor(0);
const y = Math.floor(e / 11) * 18; this.setScrollCursor(0);
return true;
}
private initEggIcons() {
this.eggIcons = [];
for (let i = 0; i < Math.min(this.ROWS * this.COLUMNS, this.scene.gameData.eggs.length); i++) {
const x = (i % this.COLUMNS) * 18;
const y = Math.floor(i / this.COLUMNS) * 18;
const icon = this.scene.add.sprite(x - 2, y + 2, "egg_icons"); const icon = this.scene.add.sprite(x - 2, y + 2, "egg_icons");
icon.setScale(0.5); icon.setScale(0.5);
icon.setOrigin(0, 0); icon.setOrigin(0, 0);
icon.setFrame(egg.getKey());
this.eggListIconContainer.add(icon); this.eggListIconContainer.add(icon);
this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.NONE); this.eggIcons.push(icon);
e++;
} }
}
this.setCursor(0); private updateEggIcons() {
const indexOffset = this.scrollCursor * this.COLUMNS;
const eggsToShow = Math.min(this.eggIcons.length, this.scene.gameData.eggs.length - indexOffset);
this.eggIcons.forEach((icon, i) => {
this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.NONE);
if (i < eggsToShow) {
const egg = this.scene.gameData.eggs[i + indexOffset];
icon.setFrame(egg.getKey());
icon.setVisible(true);
} else {
icon.setVisible(false);
}
});
return true;
} }
processInput(button: Button): boolean { processInput(button: Button): boolean {
@ -125,27 +157,53 @@ export default class EggListUiHandler extends MessageUiHandler {
ui.revertMode(); ui.revertMode();
success = true; success = true;
} else { } else {
const eggCount = this.eggListIconContainer.getAll().length; const totalEggs = this.scene.gameData.eggs.length;
const rows = Math.ceil(eggCount / 11); const onScreenRows = Math.min(this.ROWS, Math.ceil(this.eggIcons.length / this.COLUMNS));
const row = Math.floor(this.cursor / 11); const maxScrollCursor = Math.max(0, Math.ceil(totalEggs / this.COLUMNS) - onScreenRows);
const currentRowIndex = Math.floor(this.cursor / this.COLUMNS);
const currentColumnIndex = this.cursor % this.COLUMNS;
const lastEggIndex = Math.min(this.eggIcons.length - 1, totalEggs - maxScrollCursor * this.COLUMNS - 1);
switch (button) { switch (button) {
case Button.UP: case Button.UP:
if (row) { if (currentRowIndex > 0) {
success = this.setCursor(this.cursor - 11); success = this.setCursor(this.cursor - this.COLUMNS);
} else if (this.scrollCursor > 0) {
success = this.setScrollCursor(this.scrollCursor - 1);
} else {
// wrap around to the last row
const newCursor = this.cursor + (onScreenRows - 1) * this.COLUMNS;
if (newCursor > lastEggIndex) {
success = this.setCursor(newCursor - this.COLUMNS);
} else {
success = this.setCursor(newCursor);
}
success = this.setScrollCursor(maxScrollCursor) || success;
} }
break; break;
case Button.DOWN: case Button.DOWN:
if (row < rows - 2 || (row < rows - 1 && this.cursor % 11 <= (eggCount - 1) % 11)) { if (currentRowIndex < onScreenRows - 1) {
success = this.setCursor(this.cursor + 11); // Go down one row
success = this.setCursor(Math.min(this.cursor + this.COLUMNS, totalEggs - this.scrollCursor * this.COLUMNS - 1));
} else if (this.scrollCursor < maxScrollCursor) {
// Scroll down one row
success = this.setScrollCursor(this.scrollCursor + 1);
} else {
// Wrap around to the top row
success = this.setCursor(this.cursor % this.COLUMNS);
success = this.setScrollCursor(0) || success;
} }
break; break;
case Button.LEFT: case Button.LEFT:
if (this.cursor % 11) { if (currentColumnIndex > 0) {
success = this.setCursor(this.cursor - 1); success = this.setCursor(this.cursor - 1);
} else {
success = this.setCursor(Math.min(this.cursor + this.COLUMNS - 1, lastEggIndex));
} }
break; break;
case Button.RIGHT: case Button.RIGHT:
if (this.cursor % 11 < (row < rows - 1 ? 10 : (eggCount - 1) % 11)) { if (currentColumnIndex === this.COLUMNS - 1 || this.cursor === lastEggIndex) {
success = this.setCursor(this.cursor - currentColumnIndex);
} else {
success = this.setCursor(this.cursor + 1); success = this.setCursor(this.cursor + 1);
} }
break; break;
@ -161,7 +219,8 @@ export default class EggListUiHandler extends MessageUiHandler {
return success || error; return success || error;
} }
setEggDetails(egg: Egg): void { setEggDetails(index: number): void {
const egg = this.scene.gameData.eggs[index];
this.eggSprite.setFrame(`egg_${egg.getKey()}`); this.eggSprite.setFrame(`egg_${egg.getKey()}`);
this.eggNameText.setText(`${i18next.t("egg:egg")} (${egg.getEggDescriptor()})`); this.eggNameText.setText(`${i18next.t("egg:egg")} (${egg.getEggDescriptor()})`);
this.eggDateText.setText( this.eggDateText.setText(
@ -176,7 +235,7 @@ export default class EggListUiHandler extends MessageUiHandler {
this.eggGachaInfoText.setText(egg.getEggTypeDescriptor(this.scene)); this.eggGachaInfoText.setText(egg.getEggTypeDescriptor(this.scene));
} }
setCursor(cursor: integer): boolean { setCursor(cursor: number): boolean {
let changed = false; let changed = false;
const lastCursor = this.cursor; const lastCursor = this.cursor;
@ -184,24 +243,46 @@ export default class EggListUiHandler extends MessageUiHandler {
changed = super.setCursor(cursor); changed = super.setCursor(cursor);
if (changed) { if (changed) {
this.cursorObj.setPosition(114 + 18 * (cursor % 11), 10 + 18 * Math.floor(cursor / 11)); const icon = this.eggIcons[cursor];
this.cursorObj.setPosition(icon.x + 114, icon.y + 5);
if (lastCursor > -1) { if (lastCursor > -1) {
this.iconAnimHandler.addOrUpdate(this.eggListIconContainer.getAt(lastCursor) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.NONE); this.iconAnimHandler.addOrUpdate(this.eggListIconContainer.getAt(lastCursor) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.NONE);
} }
this.iconAnimHandler.addOrUpdate(this.eggListIconContainer.getAt(cursor) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.ACTIVE); this.iconAnimHandler.addOrUpdate(this.eggListIconContainer.getAt(cursor) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.ACTIVE);
this.setEggDetails(this.scene.gameData.eggs[cursor]); this.setEggDetails(cursor + this.scrollCursor * this.COLUMNS);
} }
return changed; return changed;
} }
setScrollCursor(cursor: number): boolean {
if (cursor === this.scrollCursor) {
return false;
}
this.scrollCursor = cursor;
this.scrollBar.setScrollCursor(cursor);
const newEggIndex = this.cursor + this.scrollCursor * this.COLUMNS;
if (newEggIndex >= this.scene.gameData.eggs.length) {
this.setCursor(this.scene.gameData.eggs.length - this.scrollCursor * this.COLUMNS - 1);
} else {
this.setEggDetails(newEggIndex);
}
this.updateEggIcons();
return true;
}
clear(): void { clear(): void {
super.clear(); super.clear();
this.setScrollCursor(0);
this.cursor = -1; this.cursor = -1;
this.eggListContainer.setVisible(false); this.eggListContainer.setVisible(false);
this.iconAnimHandler.removeAll(); this.iconAnimHandler.removeAll();
this.eggListIconContainer.removeAll(true); this.eggListIconContainer.removeAll(true);
this.eggIcons = [];
} }
} }

View File

@ -22,6 +22,8 @@ export class ScrollBar extends Phaser.GameObjects.Container {
super(scene, x, y); super(scene, x, y);
this.maxRows = maxRows; this.maxRows = maxRows;
this.totalRows = maxRows;
this.currentRow = 0;
const borderSize = 2; const borderSize = 2;
width = Math.max(width, 4); width = Math.max(width, 4);
@ -46,8 +48,7 @@ export class ScrollBar extends Phaser.GameObjects.Container {
*/ */
setScrollCursor(scrollCursor: number): void { setScrollCursor(scrollCursor: number): void {
this.currentRow = scrollCursor; this.currentRow = scrollCursor;
this.handleBody.y = 1 + (this.bg.displayHeight - 1 - this.handleBottom.displayHeight) / this.totalRows * this.currentRow; this.updateHandlePosition();
this.handleBottom.y = this.handleBody.y + this.handleBody.displayHeight;
} }
/** /**
@ -59,7 +60,13 @@ export class ScrollBar extends Phaser.GameObjects.Container {
setTotalRows(rows: number): void { setTotalRows(rows: number): void {
this.totalRows = rows; this.totalRows = rows;
this.handleBody.height = (this.bg.displayHeight - 1 - this.handleBottom.displayHeight) * this.maxRows / this.totalRows; this.handleBody.height = (this.bg.displayHeight - 1 - this.handleBottom.displayHeight) * this.maxRows / this.totalRows;
this.updateHandlePosition();
this.setVisible(this.totalRows > this.maxRows); this.setVisible(this.totalRows > this.maxRows);
} }
private updateHandlePosition(): void {
this.handleBody.y = 1 + (this.bg.displayHeight - 1 - this.handleBottom.displayHeight) / this.totalRows * this.currentRow;
this.handleBottom.y = this.handleBody.y + this.handleBody.displayHeight;
}
} }