====== ๐ฎ Phaser.js ======
Phaser.js๋ HTML5 ๊ฒ์ ๊ฐ๋ฐ์ ์ํ JavaScript ํ๋ ์์ํฌ๋ก, ์น ๋ธ๋ผ์ฐ์ ์์ ๊ฒ์์ ๋ง๋ค ์ ์๊ฒ ํด์ค๋๋ค.
===== ๐ ์ ์ =====
**Phaser.js**๋ HTML5 Canvas์ WebGL์ ๊ธฐ๋ฐ์ผ๋ก ํ ์คํ์์ค ๊ฒ์ ํ๋ ์์ํฌ์
๋๋ค. ์คํ๋ผ์ดํธ, ์ ๋๋ฉ์ด์
, ์ฌ์ด๋, ๋ฌผ๋ฆฌ ์์ง ๋ฑ ๊ฒ์ ๊ฐ๋ฐ์ ํ์ํ ๋ชจ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
===== ๐ฏ ์ฃผ์ ํน์ง =====
**1. ํฌ๋ก์ค ํ๋ซํผ ์ง์**
- ์น ๋ธ๋ผ์ฐ์ ์์ ์คํ๋๋ HTML5 ๊ฒ์์ ๊ฐ๋ฐํ ์ ์์ต๋๋ค.
- ๋ชจ๋ฐ์ผ, ๋ฐ์คํฌํฑ, ํ๋ธ๋ฆฟ ๋ฑ ๋ค์ํ ๊ธฐ๊ธฐ์์ ๋์ํฉ๋๋ค.
**2. ํ๋ถํ ๊ฒ์ ๊ธฐ๋ฅ**
- ์คํ๋ผ์ดํธ ๊ด๋ฆฌ ๋ฐ ์ ๋๋ฉ์ด์
- ์ฌ์ด๋ ๋ฐ ์์
์ฌ์
- ๋ฌผ๋ฆฌ ์์ง (Arcade Physics, Matter.js)
- ์
๋ ฅ ์ฒ๋ฆฌ (ํค๋ณด๋, ๋ง์ฐ์ค, ํฐ์น)
- ์นด๋ฉ๋ผ ๋ฐ ์๊ฐ ํจ๊ณผ
**3. ์ง๊ด์ ์ธ API**
- ๊ฒ์ ๊ฐ๋ฐ์ ํนํ๋ API๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์ฌ(Scene) ๊ธฐ๋ฐ ๊ตฌ์กฐ๋ก ๊ฒ์ ์ํ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
===== ๐๏ธ ๊ธฐ๋ณธ ๊ตฌ์กฐ =====
**Phaser ๊ฒ์ ์ค์ :**
import Phaser from 'phaser';
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'game-container',
backgroundColor: '#2c3e50',
scene: {
preload: preload,
create: create,
update: update
},
physics: {
default: 'arcade',
arcade: {
gravity: { y: 300 },
debug: false
}
}
};
const game = new Phaser.Game(config);
**๊ธฐ๋ณธ ๊ฒ์ ์ฌ:**
function preload() {
// ์์
๋ก๋
this.load.image('player', 'assets/player.png');
this.load.image('background', 'assets/background.png');
this.load.audio('jump', 'assets/jump.wav');
}
function create() {
// ๊ฒ์ ๊ฐ์ฒด ์์ฑ
this.add.image(400, 300, 'background');
this.player = this.physics.add.sprite(100, 450, 'player');
// ์
๋ ฅ ์ค์
this.cursors = this.input.keyboard.createCursorKeys();
// ์ฌ์ด๋ ์ค์
this.jumpSound = this.sound.add('jump');
}
function update() {
// ๊ฒ์ ๋ก์ง ์
๋ฐ์ดํธ
if (this.cursors.left.isDown) {
this.player.setVelocityX(-160);
} else if (this.cursors.right.isDown) {
this.player.setVelocityX(160);
} else {
this.player.setVelocityX(0);
}
if (this.cursors.up.isDown && this.player.body.touching.down) {
this.player.setVelocityY(-330);
this.jumpSound.play();
}
}
===== ๐จ ์คํ๋ผ์ดํธ ๊ด๋ฆฌ =====
์คํ๋ผ์ดํธ๋ ๋น๋์ค ๊ฒ์์ด๋ ์ปดํจํฐ ๊ทธ๋ํฝ์์ ์ฌ์ฉ๋๋ 2D ๋นํธ๋งต ์ด๋ฏธ์ง ๋๋ ์ ๋๋ฉ์ด์
์ ๊ตฌ์ฑ ์์์
๋๋ค. ํ๋ฉด์ ํ์๋๋ ์บ๋ฆญํฐ, ์ค๋ธ์ ํธ ๋๋ ๋ฐฐ๊ฒฝ ์์๊ฐ ๋ ์ ์์ต๋๋ค.
**์คํ๋ผ์ดํธ ์์ฑ:**
// ์ด๋ฏธ์ง ์คํ๋ผ์ดํธ
const sprite = this.add.sprite(x, y, 'spriteKey');
// ๋ฌผ๋ฆฌ ๋ฐ๋ ์ถ๊ฐ
const physicsSprite = this.physics.add.sprite(x, y, 'spriteKey');
// ๊ทธ๋ฃน ์์ฑ
const group = this.add.group();
group.add(sprite1);
group.add(sprite2);
**์ ๋๋ฉ์ด์
์ค์ :**
// ์คํ๋ผ์ดํธ ์ํธ์์ ์ ๋๋ฉ์ด์
์์ฑ
this.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('player', { start: 0, end: 3 }),
frameRate: 10,
repeat: -1
});
// ์ ๋๋ฉ์ด์
์ฌ์
sprite.play('walk');
===== ๐ต ์ฌ์ด๋ ์์คํ
=====
**์ฌ์ด๋ ๊ด๋ฆฌ:**
// ์ฌ์ด๋ ๋ก๋
this.load.audio('bgMusic', 'assets/music.mp3');
this.load.audio('jumpSound', 'assets/jump.wav');
// ์ฌ์ด๋ ์ฌ์
const bgMusic = this.sound.add('bgMusic', { loop: true, volume: 0.5 });
bgMusic.play();
// ํจ๊ณผ์ ์ฌ์
this.sound.play('jumpSound');
===== ๐ฎ ์
๋ ฅ ์ฒ๋ฆฌ =====
**ํค๋ณด๋ ์
๋ ฅ:**
// ์ปค์ ํค ์ค์
this.cursors = this.input.keyboard.createCursorKeys();
// ํน์ ํค ์ค์
this.spaceKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
// ํค ์ด๋ฒคํธ
this.input.keyboard.on('keydown-A', function() {
console.log('A ํค๊ฐ ๋๋ ธ์ต๋๋ค!');
});
**๋ง์ฐ์ค/ํฐ์น ์
๋ ฅ:**
// ํด๋ฆญ ์ด๋ฒคํธ
this.input.on('pointerdown', function(pointer) {
console.log('ํด๋ฆญ ์์น:', pointer.x, pointer.y);
});
// ์คํ๋ผ์ดํธ ํด๋ฆญ ์ด๋ฒคํธ
sprite.setInteractive();
sprite.on('pointerdown', function() {
console.log('์คํ๋ผ์ดํธ๊ฐ ํด๋ฆญ๋์์ต๋๋ค!');
});
===== ๐ ๋ฌผ๋ฆฌ ์์ง =====
**Arcade Physics:**
// ๋ฌผ๋ฆฌ ๋ฐ๋ ์ถ๊ฐ
this.player = this.physics.add.sprite(100, 450, 'player');
// ์ค๋ ฅ ์ค์
this.player.body.setGravityY(300);
// ์ถฉ๋ ๊ฐ์ง
this.physics.add.collider(this.player, this.platforms);
// ์ค๋ฒ๋ฉ ๊ฐ์ง
this.physics.add.overlap(this.player, this.coins, this.collectCoin, null, this);
**์ถฉ๋ ์ฒ๋ฆฌ:**
function collectCoin(player, coin) {
coin.disableBody(true, true);
this.score += 10;
this.scoreText.setText('Score: ' + this.score);
}
===== ๐ฑ ๋ชจ๋ฐ์ผ ์ต์ ํ =====
**๋ฐ์ํ ๋์์ธ:**
const config = {
type: Phaser.AUTO,
width: window.innerWidth,
height: window.innerHeight,
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH
}
};
**ํฐ์น ์ปจํธ๋กค:**
// ๊ฐ์ ์กฐ์ด์คํฑ
this.joyStick = this.plugins.get('rexvirtualjoystickplugin').add(this, {
x: 100,
y: 500,
radius: 50,
base: this.add.circle(0, 0, 50, 0x888888),
thumb: this.add.circle(0, 0, 25, 0xcccccc),
// ... ๊ธฐํ ์ค์
});
===== ๐จ ์๊ฐ ํจ๊ณผ =====
**ํํฐํด ์์คํ
:**
// ํํฐํด ์์ฑ
const particles = this.add.particles('particle');
const emitter = particles.createEmitter({
speed: 100,
scale: { start: 1, end: 0 },
blendMode: 'ADD'
});
// ํํฐํด ๋ฐ์ฌ
emitter.setPosition(400, 300);
**์นด๋ฉ๋ผ ํจ๊ณผ:**
// ์นด๋ฉ๋ผ ํ๋ก์ฐ
this.cameras.main.startFollow(this.player);
// ์นด๋ฉ๋ผ ํ๋ค๊ธฐ
this.cameras.main.shake(500, 0.01);
// ํ์ด๋ ํจ๊ณผ
this.cameras.main.fade(1000, 0, 0, 0);
===== ๐ ์ฑ๋ฅ ์ต์ ํ =====
**๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ:**
// ์ฌ์ฉํ์ง ์๋ ํ
์ค์ฒ ์ ๊ฑฐ
this.textures.remove('unusedSprite');
// ์คํ๋ผ์ดํธ ํ๋ง
const spritePool = this.add.group();
for (let i = 0; i < 10; i++) {
const sprite = this.add.sprite(0, 0, 'bullet');
sprite.setActive(false);
sprite.setVisible(false);
spritePool.add(sprite);
}
**๋ ๋๋ง ์ต์ ํ:**
// ์ ์ ๊ฐ์ฒด๋ ํ ๋ฒ๋ง ๋ ๋๋ง
this.add.staticGroup();
// ๋ฐฐ์น ๋ ๋๋ง ์ฌ์ฉ
this.add.batch('sprites');
===== ๐ ๊ด๋ จ ์ฉ์ด =====
* [[wiki:glossary:web_technologies:javascript|JavaScript]] - ํ๋ก๊ทธ๋๋ฐ ์ธ์ด
* [[wiki:glossary:web_technologies:css|CSS]] - ์คํ์ผ๋ง
* [[wiki:glossary:development_tools:git:github|GitHub]] - ์ฝ๋ ์ ์ฅ์
===== ๐ ๊ด๋ จ ๋ฌธ์ =====
* [[wiki:it:dream_of_enc:metaverse:phaser|Phaser.js ๊ฒ์ ์์ง]]
* [[wiki:it:dream_of_enc:metaverse:game_logic|๋ฐ๋ ๊ฒ์ ๋ก์ง]]
* [[wiki:glossary:web_technologies:css|CSS]] - ์คํ์ผ๋ง
* [[wiki:glossary:development_tools:git:github|GitHub]] - ์ฝ๋ ์ ์ฅ์
---
//์ด ํ์ด์ง๋ ์๋์ผ๋ก ์์ฑ๋์์ต๋๋ค.//