====== ๐ŸŽฎ Phaser.js ๊ฒŒ์ž„ ์—”์ง„ ====== Phaser Baduk Metaverse ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉ๋˜๋Š” Phaser.js ๊ฒŒ์ž„ ์—”์ง„์˜ ๊ตฌํ˜„ ๋‚ด์šฉ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ---- ===== ๐Ÿ“‹ ๊ฐœ์š” ===== Phaser.js๋Š” HTML5 ๊ฒŒ์ž„ ๊ฐœ๋ฐœ์— ํŠนํ™”๋œ ๊ฐ•๋ ฅํ•œ JavaScript ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ์ด ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ๋ฐ”๋‘‘ ๊ฒŒ์ž„์˜ ์‹œ๊ฐ์  ์š”์†Œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , ์‚ฌ์šฉ์ž ์ธํ„ฐ๋ž™์…˜ ๋ฐ ์‹ค์‹œ๊ฐ„ ํ†ต์‹  ๊ธฐ๋Šฅ์„ ํ†ตํ•ฉํ•˜์—ฌ ๋ชฐ์ž…๊ฐ ์žˆ๋Š” ๊ฒŒ์ž„ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๋Š” ๋ฐ ํ•ต์‹ฌ์ ์ธ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. * ''HTML5 ๊ธฐ๋ฐ˜'': ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ง์ ‘ ์‹คํ–‰๋˜์–ด ๋ณ„๋„์˜ ์„ค์น˜ ์—†์ด ์ ‘๊ทผ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. * ''๊ฒŒ์ž„ ๊ฐœ๋ฐœ ํŠนํ™”'': ์Šคํ”„๋ผ์ดํŠธ, ์• ๋‹ˆ๋ฉ”์ด์…˜, ๋ฌผ๋ฆฌ ์—”์ง„ ๋“ฑ ๊ฒŒ์ž„ ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๋‚ด์žฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. * ''์œ ์—ฐํ•œ ๊ตฌ์กฐ'': ์”ฌ(Scene) ๊ธฐ๋ฐ˜์˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ํ†ตํ•ด ๊ฒŒ์ž„์˜ ๊ฐ ๋ถ€๋ถ„์„ ๋ชจ๋“ˆํ™”ํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ---- ==== 1. ๊ฒŒ์ž„ ์—”์ง„ ๊ธฐ๋ณธ ๊ตฌ์กฐ ๋ฐ ์„ค์ • ==== Phaser.js ๊ฒŒ์ž„ ์—”์ง„์˜ ํ•ต์‹ฌ ์ง„์ž…์ ์ธ ''game.js'' ํŒŒ์ผ์€ ๊ฒŒ์ž„์˜ ์ „๋ฐ˜์ ์ธ ์„ค์ •๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ์€ ๊ฒŒ์ž„์˜ ์บ”๋ฒ„์Šค ํฌ๊ธฐ, ๋ฐฐ๊ฒฝ์ƒ‰, ์‚ฌ์šฉํ•  ์”ฌ ๋ชฉ๋ก ๋“ฑ ํ•„์ˆ˜์ ์ธ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. === 1) ๋ฉ”์ธ ๊ฒŒ์ž„ ํŒŒ์ผ (game.js) === ''game.js''๋Š” Phaser ๊ฒŒ์ž„ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๊ฒŒ์ž„์˜ ์ „์—ญ ์„ค์ •์„ ์ •์˜ํ•˜๋Š” ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ์ด๊ณณ์—์„œ ๊ฒŒ์ž„์˜ ํ•ด์ƒ๋„, ๋ Œ๋”๋ง ๋ฐฉ์‹, ํฌํ•จ๋  ์”ฌ ๋ชฉ๋ก ๋“ฑ์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. import Phaser from 'phaser'; import BadukScene from './scenes/BadukScene'; import MenuScene from './scenes/MenuScene'; // 1. ๊ฒŒ์ž„ ์„ค์ • ๊ฐ์ฒด ์ •์˜ const config = { type: Phaser.AUTO, // ๋ Œ๋”๋ง ๋ฐฉ์‹ (WebGL ๋˜๋Š” Canvas ์ž๋™ ์„ ํƒ) width: 1200, // ๊ฒŒ์ž„ ํ™”๋ฉด ๋„ˆ๋น„ (ํ”ฝ์…€) height: 800, // ๊ฒŒ์ž„ ํ™”๋ฉด ๋†’์ด (ํ”ฝ์…€) parent: 'game-container', // ๊ฒŒ์ž„ ์บ”๋ฒ„์Šค๊ฐ€ ์‚ฝ์ž…๋  HTML ์š”์†Œ์˜ ID backgroundColor: '#2c3e50', // ๊ฒŒ์ž„ ๋ฐฐ๊ฒฝ์ƒ‰ scene: [MenuScene, BadukScene], // ๊ฒŒ์ž„์— ํฌํ•จ๋  ์”ฌ ๋ชฉ๋ก (์ˆœ์„œ ์ค‘์š”) physics: { // ๋ฌผ๋ฆฌ ์—”์ง„ ์„ค์ • default: 'arcade', // ๊ธฐ๋ณธ ๋ฌผ๋ฆฌ ์—”์ง„์œผ๋กœ Arcade ๋ฌผ๋ฆฌ ์—”์ง„ ์‚ฌ์šฉ arcade: { gravity: { y: 0 }, // y์ถ• ์ค‘๋ ฅ ์—†์Œ debug: false // ๋ฌผ๋ฆฌ ๊ฐ์ฒด ๋””๋ฒ„๊ทธ ์ •๋ณด ๋น„ํ™œ์„ฑํ™” } }, scale: { // ์Šค์ผ€์ผ๋ง ์„ค์ • mode: Phaser.Scale.FIT, // ํ™”๋ฉด์— ๋งž๊ฒŒ ๊ฒŒ์ž„ ํฌ๊ธฐ ์กฐ์ ˆ autoCenter: Phaser.Scale.CENTER_BOTH // ๊ฐ€๋กœ/์„ธ๋กœ ์ค‘์•™ ์ •๋ ฌ } }; // 2. Phaser ๊ฒŒ์ž„ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ const game = new Phaser.Game(config); // 3. ๊ฒŒ์ž„ ์ธ์Šคํ„ด์Šค ๋‚ด๋ณด๋‚ด๊ธฐ (๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก) export default game; ''์ฝ”๋“œ ์„ค๋ช…'': * ''์ž„ํฌํŠธ (Import)'': Phaser ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๊ฒŒ์ž„์—์„œ ์‚ฌ์šฉํ•  ''MenuScene'', ''BadukScene'' ์”ฌ๋“ค์„ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. * ''config ๊ฐ์ฒด'': ๊ฒŒ์ž„์˜ ์ „๋ฐ˜์ ์ธ ์„ค์ •์„ ๋‹ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์š” ์†์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. * ''type'': ๊ฒŒ์ž„ ๋ Œ๋”๋ง ๋ฐฉ์‹์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ''Phaser.AUTO''๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ง€์›ํ•˜๋Š” ์ตœ์ ์˜ ๋ Œ๋”๋ง ๋ฐฉ์‹(WebGL ๋˜๋Š” Canvas)์„ ์ž๋™์œผ๋กœ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. * ''width'', ''height'': ๊ฒŒ์ž„ ํ™”๋ฉด์˜ ํ•ด์ƒ๋„๋ฅผ ํ”ฝ์…€ ๋‹จ์œ„๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. * ''parent'': ๊ฒŒ์ž„ ์บ”๋ฒ„์Šค๊ฐ€ ์‚ฝ์ž…๋  HTML ๋ฌธ์„œ ๋‚ด์˜ ํŠน์ • DOM ์š”์†Œ ID๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ, ''id="game-container"''๋ฅผ ๊ฐ€์ง„ ์š”์†Œ์— ๊ฒŒ์ž„์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. * ''backgroundColor'': ๊ฒŒ์ž„์˜ ๊ธฐ๋ณธ ๋ฐฐ๊ฒฝ์ƒ‰์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. * ''scene'': ๊ฒŒ์ž„์—์„œ ์‚ฌ์šฉํ•  ๋ชจ๋“  ์”ฌ(Scene)๋“ค์˜ ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค. ๋ฐฐ์—ด์˜ ์ˆœ์„œ์— ๋”ฐ๋ผ ์”ฌ๋“ค์ด ๋กœ๋“œ๋˜์ง€๋งŒ, ๊ฒŒ์ž„ ์‹œ์ž‘ ์‹œ์—๋Š” ์ฒซ ๋ฒˆ์งธ ์”ฌ์ด ๊ธฐ๋ณธ์œผ๋กœ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค. * ''physics'': ๋ฌผ๋ฆฌ ์—”์ง„ ์„ค์ •์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๋ฐ”๋‘‘ ๊ฒŒ์ž„์— ํ•„์š”ํ•˜์ง€ ์•Š์€ ์ค‘๋ ฅ์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๊ณ  ๋””๋ฒ„๊ทธ ๋ชจ๋“œ๋ฅผ ๊บผ๋‘์—ˆ์Šต๋‹ˆ๋‹ค. * ''scale'': ๊ฒŒ์ž„์ด ๋‹ค์–‘ํ•œ ํ™”๋ฉด ํฌ๊ธฐ์— ๋งž์ถฐ ์–ด๋–ป๊ฒŒ ์กฐ์ ˆ๋ ์ง€ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ''FIT'' ๋ชจ๋“œ๋Š” ํ™”๋ฉด ๋น„์œจ์„ ์œ ์ง€ํ•˜๋ฉฐ ๊ฐ€๋Šฅํ•œ ํ•œ ํฌ๊ฒŒ ํ‘œ์‹œํ•˜๊ณ , ''CENTER_BOTH''๋Š” ๊ฒŒ์ž„์„ ํ™”๋ฉด ์ค‘์•™์— ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค. * ''Phaser.Game ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ'': ์œ„์—์„œ ์ •์˜ํ•œ ''config'' ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ๋กœ์šด Phaser ๊ฒŒ์ž„ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ์ธ์Šคํ„ด์Šค๊ฐ€ ์‹ค์ œ ๊ฒŒ์ž„์„ ์‹คํ–‰ํ•˜๋Š” ์ฃผ์ฒด์ž…๋‹ˆ๋‹ค. * ''export default game'': ์ด ๊ฒŒ์ž„ ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ค๋ฅธ JavaScript ํŒŒ์ผ์—์„œ ๋ถˆ๋Ÿฌ์™€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค. ---- ==== 2. ์”ฌ(Scene) ๊ด€๋ฆฌ ๋ฐ ์ „ํ™˜ ==== Phaser.js์—์„œ ''์”ฌ(Scene)''์€ ๊ฒŒ์ž„์˜ ํŠน์ • ์ƒํƒœ๋‚˜ ํ™”๋ฉด์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋…๋ฆฝ์ ์ธ ๋‹จ์œ„์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฒŒ์ž„์˜ ๋ฉ”๋‰ด ํ™”๋ฉด, ์‹ค์ œ ๊ฒŒ์ž„ ํ”Œ๋ ˆ์ด ํ™”๋ฉด, ๊ฒŒ์ž„ ์˜ค๋ฒ„ ํ™”๋ฉด ๋“ฑ์ด ๊ฐ๊ฐ์˜ ์”ฌ์œผ๋กœ ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์”ฌ์€ ๊ฒŒ์ž„์˜ ๋กœ๋“œ, ์ƒ์„ฑ, ์—…๋ฐ์ดํŠธ, ์ข…๋ฃŒ ๋“ฑ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. === 2) ๋ฉ”๋‰ด ์”ฌ (MenuScene.js) === ''MenuScene.js''๋Š” ๊ฒŒ์ž„์ด ์‹œ์ž‘๋  ๋•Œ ๊ฐ€์žฅ ๋จผ์ € ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ง€๋Š” ๋ฉ”๋‰ด ํ™”๋ฉด์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๊ฒŒ์ž„ ์‹œ์ž‘ ๋ฒ„ํŠผ, ์„ค์ • ๋ฒ„ํŠผ ๋“ฑ์„ ๋ฐฐ์น˜ํ•˜๊ณ , ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์”ฌ์œผ๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. import Phaser from 'phaser'; export default class MenuScene extends Phaser.Scene { constructor() { super({ key: 'MenuScene' }); // ์”ฌ์˜ ๊ณ ์œ  ํ‚ค ์ •์˜ } preload() { // 1. ํ•„์š”ํ•œ ์ด๋ฏธ์ง€ ์—์…‹ ๋กœ๋“œ this.load.image('menu-bg', 'assets/menu-background.png'); this.load.image('play-button', 'assets/play-button.png'); this.load.image('settings-button', 'assets/settings-button.png'); } create() { // 2. ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€ (ํ™”๋ฉด ์ค‘์•™์— ๋ฐฐ์น˜) this.add.image(600, 400, 'menu-bg'); // 3. ๊ฒŒ์ž„ ์ œ๋ชฉ ํ…์ŠคํŠธ ์ถ”๊ฐ€ this.add.text(600, 200, '๋ฐ”๋‘‘ ๋ฉ”ํƒ€๋ฒ„์Šค', { // x, y, ํ…์ŠคํŠธ, ์Šคํƒ€์ผ fontSize: '48px', fill: '#ffffff', // ํฐ์ƒ‰ ๊ธ€์ž fontFamily: 'Arial' }).setOrigin(0.5); // ํ…์ŠคํŠธ์˜ ๊ธฐ์ค€์ ์„ ์ค‘์•™์œผ๋กœ ์„ค์ • // 4. ํ”Œ๋ ˆ์ด ๋ฒ„ํŠผ ์ƒ์„ฑ ๋ฐ ์ƒํ˜ธ์ž‘์šฉ ์„ค์ • const playButton = this.add.image(600, 350, 'play-button') .setInteractive(); // ํด๋ฆญ ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ • playButton.on('pointerdown', () => { // ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์ด๋ฒคํŠธ this.scene.start('BadukScene'); // 'BadukScene'์œผ๋กœ ์ „ํ™˜ }); // 5. ์„ค์ • ๋ฒ„ํŠผ ์ƒ์„ฑ ๋ฐ ์ƒํ˜ธ์ž‘์šฉ ์„ค์ • const settingsButton = this.add.image(600, 450, 'settings-button') .setInteractive(); settingsButton.on('pointerdown', () => { console.log('์„ค์ • ๋ฉ”๋‰ด ์—ด๊ธฐ'); // ์„ค์ • ๊ธฐ๋Šฅ์€ ์ฝ˜์†” ๋กœ๊ทธ๋กœ ๋Œ€์ฒด }); } } ''์ฝ”๋“œ ์„ค๋ช…'': * ''constructor'': ์”ฌ์˜ ๊ณ ์œ ํ•œ ํ‚ค(์—ฌ๊ธฐ์„œ๋Š” 'MenuScene')๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค๋ฅธ ์”ฌ์—์„œ ์ด ์”ฌ์„ ์ฐธ์กฐํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. * ''preload()'': ์ด ์”ฌ์ด ์‹œ์ž‘๋˜๊ธฐ ์ „์— ํ•„์š”ํ•œ ๋ชจ๋“  ์ด๋ฏธ์ง€, ์˜ค๋””์˜ค ๋“ฑ์˜ ์—์…‹์„ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ฒŒ์ž„ ๋กœ๋”ฉ ์‹œ๊ฐ„์„ ๋‹จ์ถ•ํ•˜๊ณ , ์”ฌ์ด ์ค€๋น„๋˜์—ˆ์„ ๋•Œ ์ฆ‰์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. * ''create()'': ์”ฌ์˜ ์—์…‹ ๋กœ๋”ฉ์ด ์™„๋ฃŒ๋œ ํ›„, ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ(๋ฐฐ๊ฒฝ, ๋ฒ„ํŠผ, ํ…์ŠคํŠธ ๋“ฑ)๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐฐ์น˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. * ''this.add.image()'': ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€์™€ ๋ฒ„ํŠผ ์ด๋ฏธ์ง€๋ฅผ ํ™”๋ฉด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. * ''this.add.text()'': ๊ฒŒ์ž„ ์ œ๋ชฉ ํ…์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์Šคํƒ€์ผ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ''setOrigin(0.5)''๋Š” ํ…์ŠคํŠธ์˜ ์ค‘์•™์„ ๊ธฐ์ค€์œผ๋กœ ์œ„์น˜๋ฅผ ์žก๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. * ''setInteractive()'': ๋ฒ„ํŠผ ์ด๋ฏธ์ง€๋ฅผ ํด๋ฆญ ๊ฐ€๋Šฅํ•œ ์ƒํ˜ธ์ž‘์šฉ ๊ฐ์ฒด๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค. * ''on('pointerdown', ...)'': ๋ฒ„ํŠผ์ด ํด๋ฆญ(๋˜๋Š” ํ„ฐ์น˜)๋˜์—ˆ์„ ๋•Œ ์‹คํ–‰๋  ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ''this.scene.start('BadukScene')''์„ ํ†ตํ•ด ์‹ค์ œ ๋ฐ”๋‘‘ ๊ฒŒ์ž„ ์”ฌ์œผ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ---- === 2) ๋ฐ”๋‘‘ ๊ฒŒ์ž„ ์”ฌ (BadukScene.js) === ''BadukScene.js''๋Š” ๋ฐ”๋‘‘ ๊ฒŒ์ž„์˜ ํ•ต์‹ฌ ๋กœ์ง๊ณผ ์‚ฌ์šฉ์ž ์ธํ„ฐ๋ž™์…˜์ด ๊ตฌํ˜„๋˜๋Š” ์”ฌ์ž…๋‹ˆ๋‹ค. ๋ฐ”๋‘‘ํŒ, ๋ฐ”๋‘‘๋Œ์˜ ๋ฐฐ์น˜, ํด๋ฆญ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ, ํ„ด ๊ด€๋ฆฌ, ๊ทธ๋ฆฌ๊ณ  ์„œ๋ฒ„์™€์˜ ํ†ต์‹  ๋“ฑ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. import Phaser from 'phaser'; import BadukBoard from '../sprites/BadukBoard'; // ๋ฐ”๋‘‘ํŒ ์Šคํ”„๋ผ์ดํŠธ ์ž„ํฌํŠธ import BadukStone from '../sprites/BadukStone'; // ๋ฐ”๋‘‘๋Œ ์Šคํ”„๋ผ์ดํŠธ ์ž„ํฌํŠธ export default class BadukScene extends Phaser.Scene { constructor() { super({ key: 'BadukScene' }); this.board = null; // ๋ฐ”๋‘‘ํŒ ๊ฐ์ฒด this.stones = []; // ๋†“์—ฌ์ง„ ๋ฐ”๋‘‘๋Œ ๋ฐฐ์—ด this.currentPlayer = 'black'; // ํ˜„์žฌ ํ„ด ํ”Œ๋ ˆ์ด์–ด ('black' ๋˜๋Š” 'white') this.gameId = null; // ํ˜„์žฌ ๊ฒŒ์ž„ ID } preload() { // 1. ๋ฐ”๋‘‘ํŒ ๋ฐ ๋Œ ์ด๋ฏธ์ง€ ๋กœ๋“œ this.load.image('board', 'assets/baduk-board.png'); this.load.image('black-stone', 'assets/black-stone.png'); this.load.image('white-stone', 'assets/white-stone.png'); this.load.image('grid', 'assets/grid-lines.png'); // ๋ฐ”๋‘‘ํŒ ๊ทธ๋ฆฌ๋“œ ์ด๋ฏธ์ง€ } create() { // 2. ๋ฐ”๋‘‘ํŒ ์ƒ์„ฑ ๋ฐ ๊ทธ๋ฆฌ๋“œ ๋ผ์ธ ์ถ”๊ฐ€ this.board = new BadukBoard(this, 600, 400); // BadukBoard ์Šคํ”„๋ผ์ดํŠธ ์ƒ์„ฑ this.add.existing(this.board); // ์”ฌ์— ๋ฐ”๋‘‘ํŒ ์ถ”๊ฐ€ this.add.image(600, 400, 'grid'); // ๊ทธ๋ฆฌ๋“œ ๋ผ์ธ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€ // 3. ํด๋ฆญ ์ด๋ฒคํŠธ ์„ค์ •: ๋ฐ”๋‘‘ํŒ ํด๋ฆญ ์‹œ ์ฐฉ์ˆ˜ ์ฒ˜๋ฆฌ this.input.on('pointerdown', (pointer) => { this.handleBoardClick(pointer); }); // 4. ํ˜„์žฌ ํ”Œ๋ ˆ์ด์–ด ํ‘œ์‹œ UI ์ƒ์„ฑ this.createPlayerIndicator(); // 5. (์˜ต์…˜) ๊ฒŒ์ž„ ์‹œ์ž‘ ์‹œ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๊ฒŒ์ž„ ID ์ˆ˜์‹  if (window.socket) { window.socket.on('game-start', (data) => { console.log('๊ฒŒ์ž„์ด ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฒŒ์ž„ ID:', data.gameId); this.gameId = data.gameId; // ๊ฒŒ์ž„ ์ƒํƒœ ๋™๊ธฐํ™” ๋ฐ ์‹œ์ž‘ ๋กœ์ง ์ถ”๊ฐ€ ๊ฐ€๋Šฅ }); window.socket.on('game-update', (data) => { // ๋‹ค๋ฅธ ํ”Œ๋ ˆ์ด์–ด์˜ ์ฐฉ์ˆ˜ ์ •๋ณด ์ˆ˜์‹  ๋ฐ ์ฒ˜๋ฆฌ if (data.player !== this.currentPlayer) { // ์ž์‹ ์˜ ํ„ด์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ ์ฒ˜๋ฆฌ this.placeStone(data.x, data.y, data.player); } }); } } // 6. ๋ฐ”๋‘‘ํŒ ํด๋ฆญ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ handleBoardClick(pointer) { // ํด๋ฆญ๋œ ํ”ฝ์…€ ์ขŒํ‘œ๋ฅผ ๋ฐ”๋‘‘ํŒ์˜ ์ƒ๋Œ€ ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ const boardX = pointer.x - this.board.x; const boardY = pointer.y - this.board.y; // ์ƒ๋Œ€ ์ขŒํ‘œ๋ฅผ ๊ทธ๋ฆฌ๋“œ(๋ฐ”๋‘‘ํŒ ์นธ) ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ const gridX = Math.round(boardX / this.board.gridSize) + 9; // 0~18 ๋ฒ”์œ„๋กœ ์กฐ์ • const gridY = Math.round(boardY / this.board.gridSize) + 9; // ์œ ํšจํ•œ ์ฐฉ์ˆ˜ ์œ„์น˜์ธ์ง€ ํ™•์ธ ํ›„ ๋Œ ๋†“๊ธฐ if (this.isValidMove(gridX, gridY)) { this.placeStone(gridX, gridY, this.currentPlayer); } } // 7. ์ฐฉ์ˆ˜ ์œ„์น˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ isValidMove(x, y) { // ๋ฐ”๋‘‘ํŒ ๋ฒ”์œ„ (0~18) ๋‚ด์ธ์ง€ ํ™•์ธ if (x < 0 || x > 18 || y < 0 || y > 18) { return false; } // ์ด๋ฏธ ๋Œ์ด ๋†“์ธ ์œ„์น˜์ธ์ง€ ํ™•์ธ return !this.stones.some(stone => stone.gridX === x && stone.gridY === y ); // TODO: ์ž์ถฉ, ์ฝ” ๊ทœ์น™ ๋“ฑ ์ถ”๊ฐ€์ ์ธ ๋ฐ”๋‘‘ ๊ทœ์น™ ๊ฒ€์‚ฌ ํ•„์š” } // 8. ๋ฐ”๋‘‘๋Œ ๋†“๊ธฐ (์‹œ๊ฐ์  ์ฒ˜๋ฆฌ ๋ฐ ์ƒํƒœ ์—…๋ฐ์ดํŠธ) placeStone(x, y, playerColor) { // ํ˜„์žฌ ํ„ด ํ”Œ๋ ˆ์ด์–ด์˜ ๋Œ ์ด๋ฏธ์ง€ ์„ ํƒ const stoneImage = playerColor === 'black' ? 'black-stone' : 'white-stone'; // BadukStone ์Šคํ”„๋ผ์ดํŠธ ์ƒ์„ฑ (์• ๋‹ˆ๋ฉ”์ด์…˜ ํฌํ•จ) const stone = new BadukStone(this, x, y, playerColor); this.stones.push(stone); // ๋†“์—ฌ์ง„ ๋Œ ๋ชฉ๋ก์— ์ถ”๊ฐ€ // ํ”Œ๋ ˆ์ด์–ด ํ„ด ๋ณ€๊ฒฝ (๋‹ค์Œ ํ„ด) this.currentPlayer = this.currentPlayer === 'black' ? 'white' : 'black'; // UI ์—…๋ฐ์ดํŠธ (ํ˜„์žฌ ํ”Œ๋ ˆ์ด์–ด ํ‘œ์‹œ) this.updatePlayerIndicator(); // ์„œ๋ฒ„์— ์ฐฉ์ˆ˜ ์ •๋ณด ์ „์†ก this.sendMoveToServer(x, y, playerColor); } // 9. ํ˜„์žฌ ํ”Œ๋ ˆ์ด์–ด ํ‘œ์‹œ UI ์ƒ์„ฑ createPlayerIndicator() { this.playerText = this.add.text(50, 50, 'ํ˜„์žฌ ํ”Œ๋ ˆ์ด์–ด: ํ‘๋Œ', { fontSize: '24px', fill: '#ffffff' }); } // 10. ํ˜„์žฌ ํ”Œ๋ ˆ์ด์–ด ํ‘œ์‹œ UI ์—…๋ฐ์ดํŠธ updatePlayerIndicator() { const playerName = this.currentPlayer === 'black' ? 'ํ‘๋Œ' : '๋ฐฑ๋Œ'; this.playerText.setText(`ํ˜„์žฌ ํ”Œ๋ ˆ์ด์–ด: ${playerName}`); } // 11. ์„œ๋ฒ„์— ์ฐฉ์ˆ˜ ์ •๋ณด ์ „์†ก sendMoveToServer(x, y, player) { if (window.socket && this.gameId) { window.socket.emit('move', { // 'move' ์ด๋ฒคํŠธ๋กœ ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ ์ „์†ก x: x, y: y, player: player, gameId: this.gameId // ํ˜„์žฌ ๊ฒŒ์ž„ ID ํฌํ•จ }); } } } ''์ฝ”๋“œ ์„ค๋ช…'': * ''constructor'': ์”ฌ์˜ ๊ณ ์œ  ํ‚ค๋ฅผ ์ •์˜ํ•˜๊ณ , ๋ฐ”๋‘‘ํŒ ๊ฐ์ฒด, ๋†“์ธ ๋Œ๋“ค์„ ์ €์žฅํ•  ๋ฐฐ์—ด, ํ˜„์žฌ ํ„ด ํ”Œ๋ ˆ์ด์–ด, ๊ฒŒ์ž„ ID์™€ ๊ฐ™์€ ๊ฒŒ์ž„ ์ƒํƒœ ๋ณ€์ˆ˜๋“ค์„ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. * ''preload()'': ๋ฐ”๋‘‘ํŒ, ํ‘๋Œ, ๋ฐฑ๋Œ ์ด๋ฏธ์ง€ ๋“ฑ ๊ฒŒ์ž„ ํ”Œ๋ ˆ์ด์— ํ•„์š”ํ•œ ๋ชจ๋“  ์—์…‹์„ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. * ''create()'': * ''this.board = new BadukBoard(...)'': ์ปค์Šคํ…€ ''BadukBoard'' ์Šคํ”„๋ผ์ดํŠธ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์‹œ๊ฐ์ ์ธ ๋ฐ”๋‘‘ํŒ์„ ํ™”๋ฉด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. * ''this.input.on('pointerdown', ...)'': ๋งˆ์šฐ์Šค ํด๋ฆญ(๋˜๋Š” ํ„ฐ์น˜) ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ''handleBoardClick'' ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. * ''createPlayerIndicator()'': ํ˜„์žฌ ํ„ด์„ ํ‘œ์‹œํ•˜๋Š” UI ํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. * ''window.socket.on(...)'': Socket.IO๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๊ฒŒ์ž„ ์‹œ์ž‘ ๋ฐ ๋‹ค๋ฅธ ํ”Œ๋ ˆ์ด์–ด์˜ ์ฐฉ์ˆ˜ ์ •๋ณด๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ˆ˜์‹ ํ•˜์—ฌ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. * ''handleBoardClick(pointer)'': ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐ”๋‘‘ํŒ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ํด๋ฆญ๋œ ํ™”๋ฉด ํ”ฝ์…€ ์ขŒํ‘œ๋ฅผ ๋ฐ”๋‘‘ํŒ์˜ ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ(์˜ˆ: (0,0)์—์„œ (18,18)๊นŒ์ง€)๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , ''isValidMove''๋ฅผ ํ†ตํ•ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ›„ ''placeStone''์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. * ''isValidMove(x, y)'': ์ฃผ์–ด์ง„ ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ๊ฐ€ ๋ฐ”๋‘‘ํŒ ๋ฒ”์œ„ ๋‚ด์— ์žˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ์œ„์น˜์— ์ด๋ฏธ ๋Œ์ด ๋†“์—ฌ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ์ฐฉ์ˆ˜ ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. (''TODO''์— ์–ธ๊ธ‰๋œ ๊ฒƒ์ฒ˜๋Ÿผ ์‹ค์ œ ๋ฐ”๋‘‘ ๊ทœ์น™์€ ๋” ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค.) * ''placeStone(x, y, playerColor)'': * ''new BadukStone(...)'': ''BadukStone'' ์Šคํ”„๋ผ์ดํŠธ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํ•ด๋‹น ์œ„์น˜์— ์‹œ๊ฐ์ ์œผ๋กœ ๋Œ์„ ๋†“์Šต๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ๋Œ์ด ๋‚˜ํƒ€๋‚˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. * ''this.stones.push(stone)'': ๋†“์—ฌ์ง„ ๋Œ์„ ''stones'' ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฒŒ์ž„ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. * ''this.currentPlayer = ...'': ํ˜„์žฌ ํ”Œ๋ ˆ์ด์–ด์˜ ํ„ด์„ ํ‘๋Œ์—์„œ ๋ฐฑ๋Œ๋กœ, ๋˜๋Š” ๋ฐฑ๋Œ์—์„œ ํ‘๋Œ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค. * ''updatePlayerIndicator()'': UI๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ํ˜„์žฌ ํ„ด ํ”Œ๋ ˆ์ด์–ด๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. * ''sendMoveToServer()'': ๋†“์ธ ๋Œ์˜ ์ •๋ณด๋ฅผ ์„œ๋ฒ„๋กœ ์ „์†กํ•˜์—ฌ ๋‹ค๋ฅธ ํ”Œ๋ ˆ์ด์–ด์™€ ๊ฒŒ์ž„ ์ƒํƒœ๋ฅผ ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. * ''createPlayerIndicator()'', ''updatePlayerIndicator()'': ํ˜„์žฌ ํ„ด ํ”Œ๋ ˆ์ด์–ด๋ฅผ ํ™”๋ฉด์— ํ…์ŠคํŠธ๋กœ ํ‘œ์‹œํ•˜๊ณ  ์—…๋ฐ์ดํŠธํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. * ''sendMoveToServer(x, y, player)'': Socket.IO๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฐฉ์ˆ˜ ์ •๋ณด๋ฅผ ์„œ๋ฒ„์˜ 'move' ์ด๋ฒคํŠธ๋กœ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ๊ฒŒ์ž„ ID๋ฅผ ํ•จ๊ป˜ ๋ณด๋‚ด ํŠน์ • ๊ฒŒ์ž„ ์„ธ์…˜์— ๋Œ€ํ•œ ์ด๋™์ž„์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค. ---- ==== 3. ํ•ต์‹ฌ ์Šคํ”„๋ผ์ดํŠธ(Sprite) ๊ตฌํ˜„ ==== Phaser.js์—์„œ ''์Šคํ”„๋ผ์ดํŠธ(Sprite)''๋Š” ๊ฒŒ์ž„ ๋‚ด์—์„œ ์›€์ง์ด๊ฑฐ๋‚˜ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ๊ฐ์ ์ธ ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋ฐ”๋‘‘ ๊ฒŒ์ž„์—์„œ๋Š” ๋ฐ”๋‘‘ํŒ๊ณผ ๋ฐ”๋‘‘๋Œ์ด ๊ฐ๊ฐ์˜ ์Šคํ”„๋ผ์ดํŠธ๋กœ ๊ตฌํ˜„๋˜์–ด ๊ฒŒ์ž„ ์„ธ๊ณ„ ๋‚ด์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ ์กด์žฌํ•˜๋ฉฐ ํŠน์ • ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. === 3) ๋ฐ”๋‘‘ํŒ ์Šคํ”„๋ผ์ดํŠธ (BadukBoard.js) === ''BadukBoard.js''๋Š” ๋ฐ”๋‘‘ํŒ ์ด๋ฏธ์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์Šคํ”„๋ผ์ดํŠธ์ž…๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์„ ๋„˜์–ด, ๋ฐ”๋‘‘ํŒ์˜ ๊ทธ๋ฆฌ๋“œ ์‹œ์Šคํ…œ์„ ๊ด€๋ฆฌํ•˜๊ณ  ํ”ฝ์…€ ์ขŒํ‘œ์™€ ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ ๊ฐ„์˜ ๋ณ€ํ™˜์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. import Phaser from 'phaser'; export default class BadukBoard extends Phaser.GameObjects.Sprite { constructor(scene, x, y) { super(scene, x, y, 'board'); // Phaser.GameObjects.Sprite ์ƒ์„ฑ์ž ํ˜ธ์ถœ this.setOrigin(0.5); // ์Šคํ”„๋ผ์ดํŠธ์˜ ๊ธฐ์ค€์ ์„ ์ค‘์•™์œผ๋กœ ์„ค์ • this.setInteractive(); // ์ƒํ˜ธ์ž‘์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ • (ํด๋ฆญ ๋“ฑ) this.setScale(1.0); // ๋ฐ”๋‘‘ํŒ ํฌ๊ธฐ (์Šค์ผ€์ผ) ์„ค์ • // ๋ฐ”๋‘‘ํŒ ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ ์‹œ์Šคํ…œ ์„ค์ • this.gridSize = 40; // ํ•œ ์นธ์˜ ํ”ฝ์…€ ํฌ๊ธฐ this.boardSize = 19; // 19x19 ๋ฐ”๋‘‘ํŒ } // 1. ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ(0~18)๋ฅผ ๊ฒŒ์ž„ ํ™”๋ฉด์˜ ํ”ฝ์…€ ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ gridToPixel(gridX, gridY) { // ๋ฐ”๋‘‘ํŒ์˜ ์ค‘์•™์ด (0,0)์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ณ , ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ๋ฅผ ํ”ฝ์…€๋กœ ๋ณ€ํ™˜ // ์˜ˆ: gridX 9๋Š” ๋ฐ”๋‘‘ํŒ์˜ ์ค‘์•™ x์ถ•์— ํ•ด๋‹น const pixelX = this.x + (gridX - (this.boardSize - 1) / 2) * this.gridSize; const pixelY = this.y + (gridY - (this.boardSize - 1) / 2) * this.gridSize; return { x: pixelX, y: pixelY }; } // 2. ๊ฒŒ์ž„ ํ™”๋ฉด์˜ ํ”ฝ์…€ ์ขŒํ‘œ๋ฅผ ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ(0~18)๋กœ ๋ณ€ํ™˜ pixelToGrid(pixelX, pixelY) { // ํ”ฝ์…€ ์ขŒํ‘œ๋ฅผ ๋ฐ”๋‘‘ํŒ ์ค‘์•™์„ ๊ธฐ์ค€์œผ๋กœ ํ•œ ์ƒ๋Œ€ ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ ํ›„ ๊ทธ๋ฆฌ๋“œ ํฌ๊ธฐ๋กœ ๋‚˜๋ˆ„์–ด ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ ์–ป๊ธฐ const gridX = Math.round((pixelX - this.x) / this.gridSize) + (this.boardSize - 1) / 2; const gridY = Math.round((pixelY - this.y) / this.gridSize) + (this.boardSize - 1) / 2; return { x: gridX, y: gridY }; } } ''์ฝ”๋“œ ์„ค๋ช…'': * ''constructor(scene, x, y)'': * ''super(scene, x, y, 'board')'': ๋ถ€๋ชจ ํด๋ž˜์Šค์ธ ''Phaser.GameObjects.Sprite''์˜ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ, ์ด ๊ฐ์ฒด๊ฐ€ 'board'๋ผ๋Š” ํ‚ค๋กœ ๋กœ๋“œ๋œ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ''x''์™€ ''y''๋Š” ๋ฐ”๋‘‘ํŒ ์Šคํ”„๋ผ์ดํŠธ์˜ ํ™”๋ฉด์ƒ ์œ„์น˜์ž…๋‹ˆ๋‹ค. * ''this.setOrigin(0.5)'': ์Šคํ”„๋ผ์ดํŠธ์˜ ์›์ (๊ธฐ์ค€์ )์„ ์ค‘์•™์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ''x'', ''y'' ์ขŒํ‘œ๊ฐ€ ์Šคํ”„๋ผ์ดํŠธ์˜ ์ค‘์•™์„ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋˜์–ด ์œ„์น˜ ๊ณ„์‚ฐ์ด ํŽธ๋ฆฌํ•ด์ง‘๋‹ˆ๋‹ค. * ''this.setInteractive()'': ์ด ์Šคํ”„๋ผ์ดํŠธ๊ฐ€ ๋งˆ์šฐ์Šค ํด๋ฆญ ๊ฐ™์€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. * ''this.gridSize'', ''this.boardSize'': ๋ฐ”๋‘‘ํŒ์˜ ํ•œ ์นธ(์ ๊ณผ ์  ์‚ฌ์ด)์˜ ํ”ฝ์…€ ํฌ๊ธฐ์™€ ๋ฐ”๋‘‘ํŒ์˜ ๊ฐ€๋กœ/์„ธ๋กœ ์นธ ์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ”ฝ์…€ ์ขŒํ‘œ์™€ ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ ๊ฐ„ ๋ณ€ํ™˜์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. * ''gridToPixel(gridX, gridY)'': ๋ฐ”๋‘‘ํŒ์˜ ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ(์˜ˆ: (0,0)๋ถ€ํ„ฐ (18,18)๊นŒ์ง€)๋ฅผ ๊ฒŒ์ž„ ํ™”๋ฉด ์ƒ์˜ ์‹ค์ œ ํ”ฝ์…€ ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐ”๋‘‘๋Œ์„ ์ •ํ™•ํ•œ ์œ„์น˜์— ๋†“์„ ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. * ''pixelToGrid(pixelX, pixelY)'': ๊ฒŒ์ž„ ํ™”๋ฉด ์ƒ์˜ ํ”ฝ์…€ ์ขŒํ‘œ๋ฅผ ๋ฐ”๋‘‘ํŒ์˜ ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋งˆ์šฐ์Šค๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ ์–ด๋А ์นธ์„ ํด๋ฆญํ–ˆ๋Š”์ง€ ์•Œ์•„๋‚ผ ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ---- === 3) ๋ฐ”๋‘‘๋Œ ์Šคํ”„๋ผ์ดํŠธ (BadukStone.js) === ''BadukStone.js''๋Š” ๊ฒŒ์ž„ ๋‚ด์—์„œ ํ‘๋Œ๊ณผ ๋ฐฑ๋Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์Šคํ”„๋ผ์ดํŠธ์ž…๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ๋Œ์˜ ์‹œ๊ฐ์ ์ธ ํ‘œํ˜„๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์ฐฉ์ˆ˜ ์‹œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. import Phaser from 'phaser'; export default class BadukStone extends Phaser.GameObjects.Sprite { constructor(scene, gridX, gridY, color) { // ๋Œ ์ด๋ฏธ์ง€ ํ‚ค ์„ ํƒ ('black-stone' ๋˜๋Š” 'white-stone') const imageKey = color === 'black' ? 'black-stone' : 'white-stone'; // ๋ฐ”๋‘‘ํŒ ๊ฐ์ฒด์˜ gridToPixel ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ทธ๋ฆฌ๋“œ ์ขŒํ‘œ๋ฅผ ํ”ฝ์…€ ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ const { x, y } = scene.board.gridToPixel(gridX, gridY); super(scene, x, y, imageKey); // Phaser.GameObjects.Sprite ์ƒ์„ฑ์ž ํ˜ธ์ถœ this.gridX = gridX; // ๋Œ์˜ ๊ทธ๋ฆฌ๋“œ X ์ขŒํ‘œ ์ €์žฅ this.gridY = gridY; // ๋Œ์˜ ๊ทธ๋ฆฌ๋“œ Y ์ขŒํ‘œ ์ €์žฅ this.color = color; // ๋Œ์˜ ์ƒ‰์ƒ ์ €์žฅ this.setOrigin(0.5); // ๋Œ์˜ ๊ธฐ์ค€์ ์„ ์ค‘์•™์œผ๋กœ ์„ค์ • this.setScale(0.8); // ๋Œ์˜ ํฌ๊ธฐ(์Šค์ผ€์ผ) ์„ค์ • // 1. ์ฐฉ์ˆ˜ ์‹œ ๋Œ์ด ์ปค์ง€๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ (์Šค์ผ€์ผ 0 -> 0.8) this.setScale(0); // ์ฒ˜์Œ์—๋Š” ํฌ๊ธฐ๋ฅผ 0์œผ๋กœ ์„ค์ • scene.tweens.add({ // ํŠธ์œˆ(์• ๋‹ˆ๋ฉ”์ด์…˜) ์ถ”๊ฐ€ targets: this, // ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ ๋Œ€์ƒ scaleX: 0.8, // X์ถ• ์Šค์ผ€์ผ์„ 0.8๋กœ scaleY: 0.8, // Y์ถ• ์Šค์ผ€์ผ์„ 0.8