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

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


wiki:it:dream_of_enc:metaverse:ui

๋ชฉ์ฐจ

๐ŸŽจ UI/UX ๊ตฌํ˜„

Phaser Baduk Metaverse ํ”„๋กœ์ ํŠธ์˜ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค์™€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ๊ตฌํ˜„์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.


1. UI/UX๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?

UI(User Interface)๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํ”„๋กœ๊ทธ๋žจ๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ํ™”๋ฉด์„ ์˜๋ฏธํ•˜๊ณ , UX(User Experience)๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํ”„๋กœ๊ทธ๋žจ์„ ์‚ฌ์šฉํ•  ๋•Œ ๋А๋ผ๋Š” ์ „์ฒด์ ์ธ ๊ฒฝํ—˜์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

UI/UX์˜ ์ค‘์š”์„ฑ:

  • ์‚ฌ์šฉ์ž๊ฐ€ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค.
  • ์ง๊ด€์ ์ธ ์กฐ์ž‘ ๋ฐฉ๋ฒ•.
  • ์ผ๊ด€๋œ ๋””์ž์ธ ์–ธ์–ด.
  • ์ ‘๊ทผ์„ฑ๊ณผ ์‚ฌ์šฉ์„ฑ ๊ณ ๋ ค.

๋ฐ”๋‘‘ ๊ฒŒ์ž„์—์„œ์˜ UI/UX:

  • ๋ช…ํ™•ํ•œ ๋ฐ”๋‘‘ํŒ ํ‘œ์‹œ.
  • ๋Œ์„ ๋†“๋Š” ๋ฐฉ๋ฒ•์ด ์ง๊ด€์ .
  • ๊ฒŒ์ž„ ์ƒํƒœ ์ •๋ณด๊ฐ€ ๋ช…ํ™•.
  • ๋ชจ๋ฐ”์ผ๊ณผ ๋ฐ์Šคํฌํ†ฑ ๋ชจ๋‘ ์ง€์›.

2. ๋””์ž์ธ ์›์น™

1) ์ง๊ด€์„ฑ

  • ๋ฐ”๋‘‘ํŒ์˜ ์ „ํ†ต์ ์ธ 19×19 ๊ฒฉ์ž ๋ ˆ์ด์•„์›ƒ.
  • ๋ช…ํ™•ํ•œ ์ƒ‰์ƒ ๊ตฌ๋ถ„ (ํ‘๋ฐฑ ๋Œ).
  • ์ง๊ด€์ ์ธ ๋ฒ„ํŠผ ๋ฐฐ์น˜์™€ ์•„์ด์ฝ˜.
  • ์‚ฌ์šฉ์ž๊ฐ€ ํ•œ๋ˆˆ์— ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค.

2) ๋ฐ˜์‘ํ˜•

  • ๋‹ค์–‘ํ•œ ํ™”๋ฉด ํฌ๊ธฐ์— ๋Œ€์‘.
  • ํ„ฐ์น˜ ์ธํ„ฐํŽ˜์ด์Šค ์ตœ์ ํ™”.
  • ํ‚ค๋ณด๋“œ ๋‹จ์ถ•ํ‚ค ์ง€์›.
  • ๋ชจ๋ฐ”์ผ๊ณผ ๋ฐ์Šคํฌํ†ฑ ๋ชจ๋‘ ์ตœ์ ํ™”.

3) ์ ‘๊ทผ์„ฑ

  • ๊ณ ๋Œ€๋น„ ์ƒ‰์ƒ ๋ชจ๋“œ.
  • ํ‚ค๋ณด๋“œ ๋„ค๋น„๊ฒŒ์ด์…˜.
  • ์Šคํฌ๋ฆฐ ๋ฆฌ๋” ์ง€์›.
  • ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„.

3. UI ๊ตฌ์กฐ ์ดํ•ดํ•˜๊ธฐ

1) ๊ธฐ๋ณธ UI ํด๋ž˜์Šค ๊ตฌ์กฐ

class BadukUI {
    constructor(scene) {
        this.scene = scene;
        this.board = null;
        this.stoneLayer = null;
        this.uiLayer = null;
        this.infoPanel = null;
        this.controlPanel = null;
 
        this.initUI();
    }
 
    initUI() {
        // ๋ฐ”๋‘‘ํŒ ์ƒ์„ฑ
        this.createBoard();
 
        // UI ๋ ˆ์ด์–ด ์ƒ์„ฑ
        this.createUILayer();
 
        // ์ •๋ณด ํŒจ๋„ ์ƒ์„ฑ
        this.createInfoPanel();
 
        // ์ปจํŠธ๋กค ํŒจ๋„ ์ƒ์„ฑ
        this.createControlPanel();
    }
}

์„ค๋ช…:

  • scene - Phaser.js์˜ ๊ฒŒ์ž„ ์”ฌ ๊ฐ์ฒด
  • board - ๋ฐ”๋‘‘ํŒ ๊ฐ์ฒด
  • stoneLayer - ๋Œ๋“ค์„ ํ‘œ์‹œํ•˜๋Š” ๋ ˆ์ด์–ด
  • uiLayer - UI ์š”์†Œ๋“ค์„ ํ‘œ์‹œํ•˜๋Š” ๋ ˆ์ด์–ด
  • infoPanel - ๊ฒŒ์ž„ ์ •๋ณด๋ฅผ ํ‘œ์‹œํ•˜๋Š” ํŒจ๋„
  • controlPanel - ๋ฒ„ํŠผ๋“ค์„ ํ‘œ์‹œํ•˜๋Š” ํŒจ๋„

2) ๋ ˆ์ด์–ด ๊ตฌ์กฐ

Phaser.js์˜ ๋ ˆ์ด์–ด ์‹œ์Šคํ…œ:

  • ๋ฐฐ๊ฒฝ ๋ ˆ์ด์–ด - ๋ฐ”๋‘‘ํŒ ๊ฒฉ์ž
  • ๋Œ ๋ ˆ์ด์–ด - ๋ฐ”๋‘‘๋Œ๋“ค
  • UI ๋ ˆ์ด์–ด - ๋ฒ„ํŠผ, ํ…์ŠคํŠธ, ํŒจ๋„
  • ํšจ๊ณผ ๋ ˆ์ด์–ด - ์• ๋‹ˆ๋ฉ”์ด์…˜, ํšจ๊ณผ

4. ๋ฐ”๋‘‘ํŒ ๋ Œ๋”๋ง

1) ๊ธฐ๋ณธ ๊ฒฉ์ž ์ƒ์„ฑ

createBoard() {
    // 19x19 ๊ฒฉ์ž ์ƒ์„ฑ
    const boardSize = 18 * 40; // 40px ๊ฐ„๊ฒฉ
    const startX = (800 - boardSize) / 2;
    const startY = (600 - boardSize) / 2;
 
    // ๊ฒฉ์ž ๊ทธ๋ฆฌ๊ธฐ
    const graphics = this.scene.add.graphics();
    graphics.lineStyle(1, 0x8B4513, 1);
 
    for (let i = 0; i < 19; i++) {
        // ์„ธ๋กœ์„ 
        graphics.moveTo(startX + i * 40, startY);
        graphics.lineTo(startX + i * 40, startY + boardSize);
 
        // ๊ฐ€๋กœ์„ 
        graphics.moveTo(startX, startY + i * 40);
        graphics.lineTo(startX + boardSize, startY + i * 40);
    }
 
    graphics.strokePaths();
}

์„ค๋ช…:

  • boardSize - ๋ฐ”๋‘‘ํŒ์˜ ์ „์ฒด ํฌ๊ธฐ (18 * 40 = 720px)
  • startX, startY - ๋ฐ”๋‘‘ํŒ์˜ ์‹œ์ž‘ ์œ„์น˜ (ํ™”๋ฉด ์ค‘์•™)
  • graphics.lineStyle() - ์„ ์˜ ์Šคํƒ€์ผ ์„ค์ • (๋‘๊ป˜, ์ƒ‰์ƒ)
  • graphics.moveTo() - ์„ ์˜ ์‹œ์ž‘์ 
  • graphics.lineTo() - ์„ ์˜ ๋์ 
  • graphics.strokePaths() - ๊ทธ๋ฆฐ ์„ ๋“ค์„ ์‹ค์ œ๋กœ ํ‘œ์‹œ

2) ๋ณ„์  ์œ„์น˜ ํ‘œ์‹œ

drawStarPoints(graphics, startX, startY) {
    const starPoints = [
        [3, 3], [3, 9], [3, 15],
        [9, 3], [9, 9], [9, 15],
        [15, 3], [15, 9], [15, 15]
    ];
 
    graphics.fillStyle(0x8B4513, 1);
 
    starPoints.forEach(([x, y]) => {
        graphics.fillCircle(
            startX + x * 40,
            startY + y * 40,
            3
        );
    });
}

์„ค๋ช…:

  • starPoints - ๋ฐ”๋‘‘ํŒ์˜ ๋ณ„์  ์œ„์น˜๋“ค (3,3,9,9,15,15 ๋“ฑ)
  • graphics.fillStyle() - ์›์˜ ์ƒ‰์ƒ ์„ค์ •
  • graphics.fillCircle() - ์› ๊ทธ๋ฆฌ๊ธฐ (x, y, ๋ฐ˜์ง€๋ฆ„)

3) ๋ฐ”๋‘‘ํŒ ๋ฐฐ๊ฒฝ

createBoardBackground() {
    const boardSize = 18 * 40;
    const startX = (800 - boardSize) / 2;
    const startY = (600 - boardSize) / 2;
 
    // ๋ฐ”๋‘‘ํŒ ๋ฐฐ๊ฒฝ (๋‚˜๋ฌด ์ƒ‰์ƒ)
    const background = this.scene.add.rectangle(
        startX + boardSize / 2,
        startY + boardSize / 2,
        boardSize + 20,
        boardSize + 20,
        0xD2B48C
    );
 
    background.setDepth(0); // ๊ฐ€์žฅ ๋’ค์ชฝ์— ๋ฐฐ์น˜
}

์„ค๋ช…:

  • rectangle - ์‚ฌ๊ฐํ˜• ์ƒ์„ฑ (x, y, width, height, color)
  • setDepth(0) - ๋ ˆ์ด์–ด ์ˆœ์„œ ์„ค์ • (์ˆซ์ž๊ฐ€ ์ž‘์„์ˆ˜๋ก ๋’ค์ชฝ)

5. ๋Œ ๋ Œ๋”๋ง

1) ๋Œ ์ƒ์„ฑ ํ•จ์ˆ˜

createStone(x, y, color) {
    const stoneSize = 18;
    const startX = (800 - 18 * 40) / 2;
    const startY = (600 - 18 * 40) / 2;
 
    const stone = this.scene.add.circle(
        startX + x * 40,
        startY + y * 40,
        stoneSize,
        color === 'black' ? 0x000000 : 0xFFFFFF
    );
 
    // ํฐ ๋Œ์— ํ…Œ๋‘๋ฆฌ ์ถ”๊ฐ€
    if (color === 'white') {
        stone.setStrokeStyle(1, 0x000000);
    }
 
    stone.setDepth(1); // ๊ฒฉ์ž๋ณด๋‹ค ์•ž์ชฝ์— ๋ฐฐ์น˜
    return stone;
}

์„ค๋ช…:

  • circle - ์› ์ƒ์„ฑ (x, y, ๋ฐ˜์ง€๋ฆ„, ์ƒ‰์ƒ)
  • setStrokeStyle() - ํ…Œ๋‘๋ฆฌ ์Šคํƒ€์ผ ์„ค์ •
  • setDepth(1) - ๊ฒฉ์ž๋ณด๋‹ค ์•ž์ชฝ์— ๋ฐฐ์น˜

2) ๋Œ ํด๋ฆญ ์ด๋ฒคํŠธ

addStoneClickHandler(stone, x, y) {
    stone.setInteractive();
 
    stone.on('pointerdown', () => {
        // ๋Œ ํด๋ฆญ ์‹œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
        this.onStoneClick(x, y);
    });
 
    // ํ˜ธ๋ฒ„ ํšจ๊ณผ
    stone.on('pointerover', () => {
        stone.setScale(1.1);
    });
 
    stone.on('pointerout', () => {
        stone.setScale(1.0);
    });
}

์„ค๋ช…:

  • setInteractive() - ํด๋ฆญ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์„ค์ •
  • on('pointerdown') - ๋งˆ์šฐ์Šค ํด๋ฆญ ์ด๋ฒคํŠธ
  • on('pointerover') - ๋งˆ์šฐ์Šค ํ˜ธ๋ฒ„ ์ด๋ฒคํŠธ
  • setScale() - ํฌ๊ธฐ ์กฐ์ • (1.1 = 10% ํ™•๋Œ€)

6. UI ํŒจ๋„ ์ƒ์„ฑ

1) ์ •๋ณด ํŒจ๋„

createInfoPanel() {
    const panel = this.scene.add.rectangle(
        650, 100, 120, 200, 0xF5F5F5
    );
    panel.setStrokeStyle(2, 0xCCCCCC);
 
    // ๊ฒŒ์ž„ ์ •๋ณด ํ…์ŠคํŠธ
    this.gameInfoText = this.scene.add.text(
        590, 20, '๊ฒŒ์ž„ ์ •๋ณด', 
        { fontSize: '16px', fill: '#333' }
    );
 
    // ํ˜„์žฌ ํ”Œ๋ ˆ์ด์–ด ํ‘œ์‹œ
    this.currentPlayerText = this.scene.add.text(
        590, 50, 'ํ˜„์žฌ: ํ‘', 
        { fontSize: '14px', fill: '#000' }
    );
 
    // ์บก์ฒ˜๋œ ๋Œ ์ˆ˜ ํ‘œ์‹œ
    this.capturedText = this.scene.add.text(
        590, 80, 'ํ‘: 0๊ฐœ, ๋ฐฑ: 0๊ฐœ', 
        { fontSize: '12px', fill: '#666' }
    );
}

์„ค๋ช…:

  • rectangle - ํŒจ๋„ ๋ฐฐ๊ฒฝ ์ƒ์„ฑ
  • setStrokeStyle() - ํ…Œ๋‘๋ฆฌ ์„ค์ •
  • add.text() - ํ…์ŠคํŠธ ์ถ”๊ฐ€ (x, y, ๋‚ด์šฉ, ์Šคํƒ€์ผ)

2) ์ปจํŠธ๋กค ํŒจ๋„

createControlPanel() {
    // ํŒจ์Šค ๋ฒ„ํŠผ
    this.passButton = this.scene.add.text(
        590, 250, 'ํŒจ์Šค', 
        { fontSize: '16px', fill: '#333', backgroundColor: '#DDD' }
    );
    this.passButton.setPadding(10, 5);
    this.passButton.setInteractive();
 
    this.passButton.on('pointerdown', () => {
        this.onPass();
    });
 
    // ํ•ญ๋ณต ๋ฒ„ํŠผ
    this.surrenderButton = this.scene.add.text(
        590, 300, 'ํ•ญ๋ณต', 
        { fontSize: '16px', fill: '#FFF', backgroundColor: '#D32F2F' }
    );
    this.surrenderButton.setPadding(10, 5);
    this.surrenderButton.setInteractive();
 
    this.surrenderButton.on('pointerdown', () => {
        this.onSurrender();
    });
}

์„ค๋ช…:

  • setPadding() - ํ…์ŠคํŠธ ์ฃผ๋ณ€ ์—ฌ๋ฐฑ ์„ค์ •
  • setInteractive() - ํด๋ฆญ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์„ค์ •
  • on('pointerdown') - ํด๋ฆญ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ

7. ๋ฐ˜์‘ํ˜• ๋””์ž์ธ

1) ํ™”๋ฉด ํฌ๊ธฐ ๊ฐ์ง€

handleResize() {
    const width = this.scene.game.config.width;
    const height = this.scene.game.config.height;
 
    // ํ™”๋ฉด ํฌ๊ธฐ์— ๋”ฐ๋ผ UI ์กฐ์ •
    if (width < 768) {
        // ๋ชจ๋ฐ”์ผ ๋ ˆ์ด์•„์›ƒ
        this.adjustForMobile();
    } else {
        // ๋ฐ์Šคํฌํ†ฑ ๋ ˆ์ด์•„์›ƒ
        this.adjustForDesktop();
    }
}
 
adjustForMobile() {
    // ๋ฐ”๋‘‘ํŒ ํฌ๊ธฐ ์ถ•์†Œ
    this.board.setScale(0.8);
 
    // UI ํŒจ๋„ ์œ„์น˜ ์กฐ์ •
    this.infoPanel.setPosition(300, 50);
    this.controlPanel.setPosition(300, 200);
}

์„ค๋ช…:

  • game.config.width/height - ๊ฒŒ์ž„ ํ™”๋ฉด ํฌ๊ธฐ
  • setScale() - ํฌ๊ธฐ ์กฐ์ • (0.8 = 80% ํฌ๊ธฐ)
  • setPosition() - ์œ„์น˜ ๋ณ€๊ฒฝ

2) ํ„ฐ์น˜ ์ธํ„ฐํŽ˜์ด์Šค

setupTouchInterface() {
    // ํ„ฐ์น˜ ์ด๋ฒคํŠธ ์„ค์ •
    this.scene.input.on('pointerdown', (pointer) => {
        const x = Math.floor((pointer.x - this.boardStartX) / 40);
        const y = Math.floor((pointer.y - this.boardStartY) / 40);
 
        if (x >= 0 && x < 19 && y >= 0 && y < 19) {
            this.onBoardClick(x, y);
        }
    });
}

์„ค๋ช…:

  • input.on('pointerdown') - ํ„ฐ์น˜/ํด๋ฆญ ์ด๋ฒคํŠธ
  • pointer.x/y - ํ„ฐ์น˜ํ•œ ์œ„์น˜
  • ์ขŒํ‘œ ๊ณ„์‚ฐ์œผ๋กœ ๋ฐ”๋‘‘ํŒ ์œ„์น˜ ํ™•์ธ

8. ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ

1) ๋Œ ๋†“๊ธฐ ์• ๋‹ˆ๋ฉ”์ด์…˜

animateStonePlacement(x, y, color) {
    const stone = this.createStone(x, y, color);
 
    // ์ฒ˜์Œ์—๋Š” ์ž‘๊ฒŒ ์‹œ์ž‘
    stone.setScale(0.1);
 
    // ์• ๋‹ˆ๋ฉ”์ด์…˜์œผ๋กœ ํฌ๊ธฐ ์กฐ์ •
    this.scene.tweens.add({
        targets: stone,
        scaleX: 1,
        scaleY: 1,
        duration: 300,
        ease: 'Back.easeOut'
    });
}

์„ค๋ช…:

  • setScale(0.1) - ์ฒ˜์Œ์—๋Š” 10% ํฌ๊ธฐ
  • tweens.add() - ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ถ”๊ฐ€
  • duration: 300 - 300ms ๋™์•ˆ ์• ๋‹ˆ๋ฉ”์ด์…˜
  • ease: 'Back.easeOut' - ํƒ„์„ฑ ํšจ๊ณผ

2) ๋Œ ์ œ๊ฑฐ ์• ๋‹ˆ๋ฉ”์ด์…˜

animateStoneRemoval(stone) {
    this.scene.tweens.add({
        targets: stone,
        scaleX: 0,
        scaleY: 0,
        alpha: 0,
        duration: 200,
        onComplete: () => {
            stone.destroy();
        }
    });
}

์„ค๋ช…:

  • alpha: 0 - ํˆฌ๋ช…๋„ 0์œผ๋กœ ์„ค์ •
  • onComplete - ์• ๋‹ˆ๋ฉ”์ด์…˜ ์™„๋ฃŒ ํ›„ ์‹คํ–‰
  • stone.destroy() - ๋Œ ๊ฐ์ฒด ์ œ๊ฑฐ

9. ์ ‘๊ทผ์„ฑ ๊ธฐ๋Šฅ

1) ๊ณ ๋Œ€๋น„ ๋ชจ๋“œ

enableHighContrast() {
    // ๊ณ ๋Œ€๋น„ ์ƒ‰์ƒ ์„ค์ •
    this.boardBackground.setFillStyle(0x000000);
    this.gridLines.setStrokeStyle(1, 0xFFFFFF);
 
    // ํ…์ŠคํŠธ ์ƒ‰์ƒ ์กฐ์ •
    this.gameInfoText.setColor('#FFFFFF');
    this.currentPlayerText.setColor('#FFFFFF');
}

์„ค๋ช…:

  • setFillStyle() - ๋ฐฐ๊ฒฝ์ƒ‰ ์„ค์ •
  • setStrokeStyle() - ์„  ์ƒ‰์ƒ ์„ค์ •
  • setColor() - ํ…์ŠคํŠธ ์ƒ‰์ƒ ์„ค์ •

2) ํ‚ค๋ณด๋“œ ๋„ค๋น„๊ฒŒ์ด์…˜

setupKeyboardNavigation() {
    this.scene.input.keyboard.on('keydown', (event) => {
        switch(event.key) {
            case 'ArrowUp':
                this.moveSelection(0, -1);
                break;
            case 'ArrowDown':
                this.moveSelection(0, 1);
                break;
            case 'ArrowLeft':
                this.moveSelection(-1, 0);
                break;
            case 'ArrowRight':
                this.moveSelection(1, 0);
                break;
            case 'Enter':
                this.placeStone();
                break;
        }
    });
}

์„ค๋ช…:

  • input.keyboard.on('keydown') - ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ
  • ๋ฐฉํ–ฅํ‚ค๋กœ ์„ ํƒ ์œ„์น˜ ์ด๋™
  • Enter ํ‚ค๋กœ ๋Œ ๋†“๊ธฐ

10. ์‹ค์Šต ์˜ˆ์ œ

1) ๊ฐ„๋‹จํ•œ ๋ฐ”๋‘‘ํŒ UI

HTML ํŒŒ์ผ:

<!DOCTYPE html>
<html>
<head>
    <title>๋ฐ”๋‘‘ ๊ฒŒ์ž„</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.min.js"></script>
</head>
<body>
    <div id="game"></div>
    <script src="game.js"></script>
</body>
</html>

JavaScript ํŒŒ์ผ (game.js):

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'game',
    scene: {
        create: create
    }
};
 
const game = new Phaser.Game(config);
 
function create() {
    // ๋ฐ”๋‘‘ํŒ ๋ฐฐ๊ฒฝ
    const background = this.add.rectangle(400, 300, 720, 720, 0xD2B48C);
 
    // ๊ฒฉ์ž ๊ทธ๋ฆฌ๊ธฐ
    const graphics = this.add.graphics();
    graphics.lineStyle(1, 0x8B4513, 1);
 
    for (let i = 0; i < 19; i++) {
        const x = 40 + i * 40;
        const y = 40 + i * 40;
 
        // ์„ธ๋กœ์„ 
        graphics.moveTo(x, 40);
        graphics.lineTo(x, 760);
 
        // ๊ฐ€๋กœ์„ 
        graphics.moveTo(40, y);
        graphics.lineTo(760, y);
    }
 
    graphics.strokePaths();
 
    // ๋ณ„์  ๊ทธ๋ฆฌ๊ธฐ
    const starPoints = [[3,3], [3,9], [3,15], [9,3], [9,9], [9,15], [15,3], [15,9], [15,15]];
    graphics.fillStyle(0x8B4513, 1);
 
    starPoints.forEach(([x, y]) => {
        graphics.fillCircle(40 + x * 40, 40 + y * 40, 3);
    });
}

2) ์‹คํ–‰ ๋ฐฉ๋ฒ•

# ๋กœ์ปฌ ์„œ๋ฒ„ ์‹คํ–‰
python -m http.server 8000
# ๋˜๋Š”
npx http-server

ํ…Œ์ŠคํŠธ:

  • ๋ธŒ๋ผ์šฐ์ €์—์„œ http://localhost:8000 ์ ‘์†
  • ๋ฐ”๋‘‘ํŒ์ด ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธ

11. ๋‹ค์Œ ๋‹จ๊ณ„

UI/UX ๊ธฐ๋ณธ์„ ๋ฐฐ์› ๋‹ค๋ฉด ๋‹ค์Œ์„ ํ•™์Šตํ•ด๋ณด์„ธ์š”:

  • ๊ณ ๊ธ‰ ์• ๋‹ˆ๋ฉ”์ด์…˜ - ๋ณต์žกํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ
  • ์‚ฌ์šด๋“œ ๋””์ž์ธ - ํšจ๊ณผ์Œ๊ณผ ๋ฐฐ๊ฒฝ์Œ์•…
  • ๊ฒŒ์ž„ ์ƒํƒœ ๊ด€๋ฆฌ - UI ์ƒํƒœ ๊ด€๋ฆฌ
  • ์‚ฌ์šฉ์ž ํ…Œ์ŠคํŠธ - ์‹ค์ œ ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ
  • ์„ฑ๋Šฅ ์ตœ์ ํ™” - UI ๋ Œ๋”๋ง ์ตœ์ ํ™”

์ถ”์ฒœ ํ•™์Šต ์ˆœ์„œ:

โ€”

์นดํ…Œ๊ณ ๋ฆฌ: ๋ฉ”ํƒ€๋ฒ„์Šค | ๊ด€๋ จ ๊ธฐ์ˆ : Phaser.js, UI/UX, ๋ฐ˜์‘ํ˜• ๋””์ž์ธ

wiki/it/dream_of_enc/metaverse/ui.txt ยท ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋จ: ์ €์ž 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki