์‚ฌ์šฉ์ž ๋„๊ตฌ

์‚ฌ์ดํŠธ ๋„๊ตฌ


wiki:it:dream_of_enc:metaverse:phaser

๐ŸŽฎ 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๋Š” ๊ฒŒ์ž„ ๋‚ด์—์„œ ํ‘๋Œ๊ณผ ๋ฐฑ๋Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์Šคํ”„๋ผ์ดํŠธ์ž…๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ๋Œ์˜ ์‹œ๊ฐ์ ์ธ ํ‘œํ˜„๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์ฐฉ์ˆ˜ ์‹œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

<file javascript> 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
wiki/it/dream_of_enc/metaverse/phaser.txt ยท ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋จ: ์ €์ž 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki