목차

🎨 UI/UX 구현

Phaser Baduk Metaverse 프로젝트의 사용자 인터페이스와 사용자 경험 구현에 대해 설명합니다.


1. UI/UX란 무엇인가요?

UI(User Interface)는 사용자가 프로그램과 상호작용하는 화면을 의미하고, UX(User Experience)는 사용자가 프로그램을 사용할 때 느끼는 전체적인 경험을 의미합니다.

UI/UX의 중요성:

바둑 게임에서의 UI/UX:


2. 디자인 원칙

1) 직관성

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();
    }
}

설명:

2) 레이어 구조

Phaser.js의 레이어 시스템:


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();
}

설명:

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
        );
    });
}

설명:

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); // 가장 뒤쪽에 배치
}

설명:


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;
}

설명:

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);
    });
}

설명:


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' }
    );
}

설명:

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();
    });
}

설명:


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);
}

설명:

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);
        }
    });
}

설명:


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'
    });
}

설명:

2) 돌 제거 애니메이션

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

설명:


9. 접근성 기능

1) 고대비 모드

enableHighContrast() {
    // 고대비 색상 설정
    this.boardBackground.setFillStyle(0x000000);
    this.gridLines.setStrokeStyle(1, 0xFFFFFF);
 
    // 텍스트 색상 조정
    this.gameInfoText.setColor('#FFFFFF');
    this.currentPlayerText.setColor('#FFFFFF');
}

설명:

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;
        }
    });
}

설명:


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

테스트:


11. 다음 단계

UI/UX 기본을 배웠다면 다음을 학습해보세요:

추천 학습 순서:

카테고리: 메타버스 | 관련 기술: Phaser.js, UI/UX, 반응형 디자인