From bad9ab30daaeb958a13a66a86ea70c8302de6b0d Mon Sep 17 00:00:00 2001 From: nijuy Date: Sun, 21 Dec 2025 22:15:07 +0900 Subject: [PATCH 1/2] =?UTF-8?q?refactor:=20=EC=8A=A4=EB=82=B5=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=EC=9D=84=20=EC=83=81=EC=88=98=EB=A1=9C=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SnackGame/game/screen/BizGameScreen.ts | 3 ++- .../games/SnackGame/game/screen/GameScreen.ts | 5 +++-- .../games/SnackGame/game/snackGame/Snack.ts | 6 +++--- .../SnackGame/game/snackGame/SnackGameAction.ts | 8 +++++--- .../SnackGame/game/snackGame/SnackGameBoard.ts | 7 ++++--- .../SnackGame/game/snackGame/SnackGameUtil.ts | 17 ++++++++++++----- 6 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/pages/games/SnackGame/game/screen/BizGameScreen.ts b/src/pages/games/SnackGame/game/screen/BizGameScreen.ts index 4e1d2af8..09e61c50 100644 --- a/src/pages/games/SnackGame/game/screen/BizGameScreen.ts +++ b/src/pages/games/SnackGame/game/screen/BizGameScreen.ts @@ -14,6 +14,7 @@ import { SettingsPopup } from '../popup/SettingPopup'; import { Snack } from '../snackGame/Snack'; import { SnackGame, SnackGameOnPopData } from '../snackGame/SnackGame'; import { + SNACK_TYPE, SnackGameMode, Streak, snackGameGetConfig, @@ -95,7 +96,7 @@ export class BizGameScreen extends Container implements AppScreen { let isGolden = false; const streak = data.reduce((acc: Streak, snack) => { - if (snack.type === 2) isGolden = true; + if (snack.type === SNACK_TYPE.GOLDEN) isGolden = true; const { row: y, column: x } = snack.getGridPosition(); acc.push({ x, y }); diff --git a/src/pages/games/SnackGame/game/screen/GameScreen.ts b/src/pages/games/SnackGame/game/screen/GameScreen.ts index 90c0f242..60816d3c 100644 --- a/src/pages/games/SnackGame/game/screen/GameScreen.ts +++ b/src/pages/games/SnackGame/game/screen/GameScreen.ts @@ -12,6 +12,7 @@ import { SettingsPopup } from '../popup/SettingPopup'; import { Snack } from '../snackGame/Snack'; import { SnackGame, SnackGameOnPopData } from '../snackGame/SnackGame'; import { + SNACK_TYPE, SnackGameMode, SnackGamePosition, Streak, @@ -100,7 +101,7 @@ export class GameScreen extends Container implements AppScreen { const occurredAt = new Date().toISOString(); const streak = data.reduce((acc: Streak, snack) => { - if (snack.type === 2) isGolden = true; + if (snack.type === SNACK_TYPE.GOLDEN) isGolden = true; const { row: y, column: x } = snack.getGridPosition(); acc.push({ x, y }); @@ -118,7 +119,7 @@ export class GameScreen extends Container implements AppScreen { let isGolden = false; data.forEach((snack) => { - if (snack.type === 2) isGolden = true; + if (snack.type === SNACK_TYPE.GOLDEN) isGolden = true; }); return this.itemHandlers.bomb(position, isGolden); diff --git a/src/pages/games/SnackGame/game/snackGame/Snack.ts b/src/pages/games/SnackGame/game/snackGame/Snack.ts index 7e98ae64..1ed5575f 100644 --- a/src/pages/games/SnackGame/game/snackGame/Snack.ts +++ b/src/pages/games/SnackGame/game/snackGame/Snack.ts @@ -1,7 +1,7 @@ import gsap from 'gsap'; import { Container, Sprite, Texture } from 'pixi.js'; -import { SnackGamePosition } from './SnackGameUtil'; +import { SNACK_TYPE, SnackGamePosition, SnackType } from './SnackGameUtil'; import { Label } from '../ui/Label'; import { resolveAndKillTweens, @@ -14,7 +14,7 @@ const defaultSnackOptions = { /** 텍스처 선택을 위한 스낵 이름 */ name: '', /** 그리드 내부의 스낵 타입 */ - type: 0, + type: SNACK_TYPE.EMPTY as SnackType, /** 넓이와 높이 사이즈 */ size: 50, /** 스낵 숫자 */ @@ -42,7 +42,7 @@ export class Snack extends Container { /** 스낵의 열 인덱스 */ public column = 0; /** 그리드 내부의 스낵 타입 */ - public type = 0; + public type: SnackType = SNACK_TYPE.EMPTY; /** 텍스처 선택을 위한 스낵 이름 */ public name = ''; /** 스낵이 가진 숫자 */ diff --git a/src/pages/games/SnackGame/game/snackGame/SnackGameAction.ts b/src/pages/games/SnackGame/game/snackGame/SnackGameAction.ts index 060c353c..8e42dedb 100644 --- a/src/pages/games/SnackGame/game/snackGame/SnackGameAction.ts +++ b/src/pages/games/SnackGame/game/snackGame/SnackGameAction.ts @@ -1,7 +1,7 @@ import { ItemType } from '@utils/types/item.type'; import { SnackGame } from './SnackGame'; -import { SnackGamePosition } from './SnackGameUtil'; +import { SNACK_TYPE, SnackGamePosition } from './SnackGameUtil'; import { sfx } from '../util/audio'; import { HapticFeedback } from '../util/hapticFeedback'; @@ -46,7 +46,7 @@ export class SnackGameActions { if ( this.snackGame.board .getSelectedSnacks() - .some((snack) => snack.type === 2) + .some((snack) => snack.type === SNACK_TYPE.GOLDEN) ) { this.snackGame.board.reset(); this.snackGame.board.setup(this.snackGame.config, session!.board); @@ -77,7 +77,9 @@ export class SnackGameActions { const session = await this.snackGame.board.popAllSelectedSnacks(position); if ( - this.snackGame.board.getSelectedSnacks().some((snack) => snack.type === 2) + this.snackGame.board + .getSelectedSnacks() + .some((snack) => snack.type === SNACK_TYPE.GOLDEN) ) { this.snackGame.board.reset(); this.snackGame.board.setup(this.snackGame.config, session!.board); diff --git a/src/pages/games/SnackGame/game/snackGame/SnackGameBoard.ts b/src/pages/games/SnackGame/game/snackGame/SnackGameBoard.ts index 1638714b..f523a9bd 100644 --- a/src/pages/games/SnackGame/game/snackGame/SnackGameBoard.ts +++ b/src/pages/games/SnackGame/game/snackGame/SnackGameBoard.ts @@ -11,6 +11,7 @@ import { snackGameGetSnack, SnackGameGrid, SnackType, + SNACK_TYPE, snackGameGetSnackType, snackGameSetPieceType, snackGameCreateGrid, @@ -79,7 +80,7 @@ export class SnackGameBoard { for (let i = 0; i < snacks.length; i++) { const name = snacks[i]; - const type = i + 1; + const type = (i + 1) as SnackType; // TODO: SnackType <-> 에셋명 매핑을 다른 식으로 할 수 없을지? this.commonTypes.push(type); this.typesMap[type] = name; @@ -115,7 +116,7 @@ export class SnackGameBoard { * @param snackType 새 스낵의 유형 */ public createSnack(position: SnackGamePosition, snackInfo: SnackResponse) { - const type = snackInfo.golden ? 2 : 1; + const type = snackInfo.golden ? SNACK_TYPE.GOLDEN : SNACK_TYPE.NORMAL; const name = this.typesMap[type]; const snack = pool.get(Snack); const viewPosition = this.getViewPositionByGridPosition(position); @@ -162,7 +163,7 @@ export class SnackGameBoard { // const combo = this.snackGame.process.getProcessRound(); // 그리드의 해당 위치에 있는 스낵을 0으로 설정하고 보드에서 팝 - snackGameSetPieceType(this.grid, position, 0); + snackGameSetPieceType(this.grid, position, SNACK_TYPE.EMPTY); const popData = { snack, type }; this.snackGame.stats.registerPop(popData); this.snackGame.onPop?.(popData); diff --git a/src/pages/games/SnackGame/game/snackGame/SnackGameUtil.ts b/src/pages/games/SnackGame/game/snackGame/SnackGameUtil.ts index 0ee464d8..4e671245 100644 --- a/src/pages/games/SnackGame/game/snackGame/SnackGameUtil.ts +++ b/src/pages/games/SnackGame/game/snackGame/SnackGameUtil.ts @@ -1,7 +1,12 @@ import { SnackResponse } from '../game.type'; -/** 각 그리드 내부 스낵 타입 */ -export type SnackType = number; // TODO: 타입 안정성과 가독성을 위해 새로운 타입으로 정의 +/** 각 그리드 내부 스낵 타입 상수 */ +export const SNACK_TYPE = { + EMPTY: 0, + NORMAL: 1, + GOLDEN: 2, +} as const; +export type SnackType = (typeof SNACK_TYPE)[keyof typeof SNACK_TYPE]; /** 스낵게임 board를 표현하는 2차원 배열 타입 */ export type SnackGameGrid = SnackType[][]; @@ -76,10 +81,12 @@ export function snackGameCreateGrid( const grid: SnackGameGrid = []; for (let r = 0; r < rows; r++) { - const types = []; + const types: SnackType[] = []; for (let c = 0; c < columns; c++) { - const currentType = board[r][c].golden ? 2 : 1; + const currentType = board[r][c].golden + ? SNACK_TYPE.GOLDEN + : SNACK_TYPE.NORMAL; types.push(currentType); } @@ -127,7 +134,7 @@ export function snackGameGetSnackType( export function snackGameSetPieceType( grid: SnackGameGrid, position: SnackGamePosition, - type: number, + type: SnackType, ) { grid[position.row][position.column] = type; } From 50cf0cdeb09f32ac4dbc208aac9303689f068848 Mon Sep 17 00:00:00 2001 From: nijuy Date: Sun, 21 Dec 2025 22:35:30 +0900 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20=EC=8A=A4=EB=82=B5=20=ED=83=80?= =?UTF-8?q?=EC=9E=85-=EC=97=90=EC=85=8B=20=EB=A7=A4=ED=95=91=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../game/snackGame/SnackGameBoard.ts | 25 +++++-------------- .../SnackGame/game/snackGame/SnackGameUtil.ts | 25 +++++++++++-------- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/pages/games/SnackGame/game/snackGame/SnackGameBoard.ts b/src/pages/games/SnackGame/game/snackGame/SnackGameBoard.ts index f523a9bd..945fd9d3 100644 --- a/src/pages/games/SnackGame/game/snackGame/SnackGameBoard.ts +++ b/src/pages/games/SnackGame/game/snackGame/SnackGameBoard.ts @@ -8,10 +8,9 @@ import { SnackGame } from './SnackGame'; import { SnackGamePosition, SnackGameConfig, - snackGameGetSnack, SnackGameGrid, - SnackType, SNACK_TYPE, + getSnackAssets, snackGameGetSnackType, snackGameSetPieceType, snackGameCreateGrid, @@ -37,10 +36,8 @@ export class SnackGameBoard { public columns = 0; /** 각 보드 슬롯의 크기 (너비 및 높이) */ public tileSize = 0; - /** 게임에 사용 가능한 일반 유형 목록 */ - public commonTypes: SnackType[] = []; /** 스낵 유형을 스낵 이름에 매핑 */ - public typesMap!: Record; + public typesMap: Record | null = null; /** 선택된 Snack 스택 */ public selectedSnacks: Snack[] = []; @@ -72,19 +69,9 @@ export class SnackGameBoard { this.snacksMask.height = this.getHeight(); this.snacksContainer.visible = true; - // 게임에서 사용될 스낵 타입 배열 - const snacks = snackGameGetSnack(config.mode); - - if (!this.commonTypes.length) { - this.typesMap = {}; - - for (let i = 0; i < snacks.length; i++) { - const name = snacks[i]; - const type = (i + 1) as SnackType; // TODO: SnackType <-> 에셋명 매핑을 다른 식으로 할 수 없을지? - - this.commonTypes.push(type); - this.typesMap[type] = name; - } + // 게임 모드에 맞는 스낵 타입-에셋 매핑 설정 + if (!this.typesMap) { + this.typesMap = getSnackAssets(config.mode); } // 초기 격자 상태 생성 @@ -117,7 +104,7 @@ export class SnackGameBoard { */ public createSnack(position: SnackGamePosition, snackInfo: SnackResponse) { const type = snackInfo.golden ? SNACK_TYPE.GOLDEN : SNACK_TYPE.NORMAL; - const name = this.typesMap[type]; + const name = this.typesMap![type]; const snack = pool.get(Snack); const viewPosition = this.getViewPositionByGridPosition(position); snack.onTap = (position) => this.snackGame.actions.actionTap(position); diff --git a/src/pages/games/SnackGame/game/snackGame/SnackGameUtil.ts b/src/pages/games/SnackGame/game/snackGame/SnackGameUtil.ts index 4e671245..b9112eda 100644 --- a/src/pages/games/SnackGame/game/snackGame/SnackGameUtil.ts +++ b/src/pages/games/SnackGame/game/snackGame/SnackGameUtil.ts @@ -28,14 +28,22 @@ export const snackGameModes = ['default', 'inf'] as const; /** 게임 모드 타입 */ export type SnackGameMode = (typeof snackGameModes)[number]; -/** 각 게임 모드에 사용되는 snack 타입 배열 */ -const snacks: Record = { - /** 기본 모드 */ - default: ['snack', 'golden_snack'], - /** 무한 모드 */ - inf: ['snack'], +/** 각 게임 모드에 사용되는 스낵 타입-에셋 매핑 */ +const snackAssetsByMode: Record>> = { + default: { + [SNACK_TYPE.NORMAL]: 'snack', + [SNACK_TYPE.GOLDEN]: 'golden_snack', + }, + inf: { + [SNACK_TYPE.NORMAL]: 'snack', + }, }; +/** 게임 모드별 스낵 타입-에셋 매핑을 반환 */ +export function getSnackAssets(mode: SnackGameMode): Record { + return snackAssetsByMode[mode] as Record; +} + /** 스낵게임 기본 설정 */ export const defaultConfig = { /** 게임의 row 개수 */ @@ -60,11 +68,6 @@ export function snackGameGetConfig( return { ...defaultConfig, ...customConfig }; } -/** 스낵게임에 필요한 스낵들을 모드 기준으로 구별해 반환합니다. */ -export function snackGameGetSnack(mode: SnackGameMode): string[] { - return [...snacks[mode]]; -} - /** * 주어진 스낵 타입을 바탕으로 2차원 배열 그리드를 생성합니다. * 기믹을 가진 요소는 초기 실행 시 생성될 랜덤한 index를 초기화 합니다.