🚀 Phaser.js Mänguraamistik
Professionaalne 2D mängumootor brauseris. Sprite'id, füüsika, animatsioonid, stseenid, tilemap'id — kõik mida vajad täisväärtusliku mängu loomiseks!
📋 Eeldused
Peaksid olema läbinud Moodul 03 ja mõistma mängutsüklit. Phaser teeb raskema töö sinu eest!
⚡ Samm 1 — Projekti Seadistamine
# Loo uus projekt
mkdir phaser-game && cd phaser-game
npm init -y
# Paigalda Phaser 3
npm install phaser
# Paigalda Vite arendusserveriks
npm install -D vite
# package.json skriptid:
# "scripts": {
# "dev": "vite",
# "build": "vite build",
# "preview": "vite preview"
# }
<!DOCTYPE html>
<html lang="et">
<head>
<meta charset="UTF-8">
<title>Minu Phaser Mäng</title>
<style>
body { margin: 0; background: #0a0a0a; display: flex; justify-content: center; align-items: center; height: 100vh; }
</style>
</head>
<body>
<script type="module" src="/src/main.js"></script>
</body>
</html>
🎮 Samm 2 — Phaser Konfiguratsioon ja Stseenid
Phaser mäng koosneb stseenidest (Scenes). Iga stseen on eraldi "ekraan" — menüü, mängu tase, game over jne.
import Phaser from 'phaser';
import { BootScene } from './scenes/BootScene.js';
import { MenuScene } from './scenes/MenuScene.js';
import { GameScene } from './scenes/GameScene.js';
import { GameOverScene } from './scenes/GameOverScene.js';
const config = {
type: Phaser.AUTO, // WebGL automaatselt, fallback Canvas
width: 800,
height: 600,
parent: 'game-container',
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0 },
debug: false // true = näita hitbox'e
}
},
scene: [BootScene, MenuScene, GameScene, GameOverScene]
};
const game = new Phaser.Game(config);
📦 Samm 3 — Boot ja Preload
export class BootScene extends Phaser.Scene {
constructor() {
super('BootScene');
}
preload() {
// Lae kõik varad (assets)
this.load.image('player', 'assets/player.png');
this.load.image('enemy', 'assets/enemy.png');
this.load.image('bullet', 'assets/bullet.png');
this.load.image('background', 'assets/bg.png');
// Spritesheet animatsioonideks
this.load.spritesheet('playerAnim', 'assets/player-sheet.png', {
frameWidth: 64,
frameHeight: 64
});
// Heli
this.load.audio('shoot', 'assets/audio/shoot.wav');
this.load.audio('explosion', 'assets/audio/explosion.wav');
this.load.audio('bgMusic', 'assets/audio/music.mp3');
// Laadimisriba
const bar = this.add.graphics();
this.load.on('progress', (value) => {
bar.clear();
bar.fillStyle(0x22c55e, 1);
bar.fillRect(200, 290, 400 * value, 20);
});
}
create() {
// Loo animatsioonid
this.anims.create({
key: 'playerIdle',
frames: this.anims.generateFrameNumbers('playerAnim', { start: 0, end: 3 }),
frameRate: 8,
repeat: -1 // -1 = lõpmatu kordus
});
this.anims.create({
key: 'playerRun',
frames: this.anims.generateFrameNumbers('playerAnim', { start: 4, end: 11 }),
frameRate: 12,
repeat: -1
});
this.scene.start('MenuScene');
}
}
🏃 Samm 4 — Mängustseen ja Mängija
export class GameScene extends Phaser.Scene {
constructor() {
super('GameScene');
this.score = 0;
}
create() {
// Taust
this.add.image(400, 300, 'background');
// Mängija füüsikakehaga
this.player = this.physics.add.sprite(400, 500, 'player');
this.player.setCollideWorldBounds(true);
// Vaenlaste grupp (object pool!)
this.enemies = this.physics.add.group({
maxSize: 30,
classType: Phaser.Physics.Arcade.Sprite
});
// Kuulide grupp
this.bullets = this.physics.add.group({
maxSize: 20,
classType: Phaser.Physics.Arcade.Sprite
});
// Sisend
this.cursors = this.input.keyboard.createCursorKeys();
this.fireKey = this.input.keyboard.addKey('SPACE');
// Vaenlaste spawn timer
this.spawnTimer = this.time.addEvent({
delay: 1500,
callback: this.spawnEnemy,
callbackScope: this,
loop: true
});
// Kokkupõrke kontroll
this.physics.add.overlap(
this.bullets, this.enemies, this.hitEnemy, null, this
);
this.physics.add.overlap(
this.player, this.enemies, this.gameOver, null, this
);
// Skoori tekst
this.scoreText = this.add.text(16, 16, 'Skoor: 0', {
fontSize: '24px',
fontFamily: 'Inter',
color: '#ffffff',
stroke: '#000000',
strokeThickness: 4
});
}
update(time, delta) {
// Mängija liikumine
const speed = 300;
if (this.cursors.left.isDown) {
this.player.setVelocityX(-speed);
this.player.anims.play('playerRun', true);
this.player.setFlipX(true);
} else if (this.cursors.right.isDown) {
this.player.setVelocityX(speed);
this.player.anims.play('playerRun', true);
this.player.setFlipX(false);
} else {
this.player.setVelocityX(0);
this.player.anims.play('playerIdle', true);
}
if (this.cursors.up.isDown) {
this.player.setVelocityY(-speed);
} else if (this.cursors.down.isDown) {
this.player.setVelocityY(speed);
} else {
this.player.setVelocityY(0);
}
// Tulistamine
if (Phaser.Input.Keyboard.JustDown(this.fireKey)) {
this.shoot();
}
}
shoot() {
const bullet = this.bullets.get(this.player.x, this.player.y - 20, 'bullet');
if (bullet) {
bullet.setActive(true).setVisible(true);
bullet.setVelocityY(-400);
this.sound.play('shoot', { volume: 0.3 });
// Hävita kuul kui läheb ekraanilt välja
this.time.delayedCall(2000, () => {
bullet.setActive(false).setVisible(false);
bullet.body.stop();
});
}
}
spawnEnemy() {
const x = Phaser.Math.Between(50, 750);
const enemy = this.enemies.get(x, -30, 'enemy');
if (enemy) {
enemy.setActive(true).setVisible(true);
enemy.setVelocityY(Phaser.Math.Between(100, 250));
}
}
hitEnemy(bullet, enemy) {
bullet.setActive(false).setVisible(false);
enemy.setActive(false).setVisible(false);
bullet.body.stop();
enemy.body.stop();
this.score += 10;
this.scoreText.setText('Skoor: ' + this.score);
this.sound.play('explosion', { volume: 0.5 });
// Partikliefekt (sisseehitatud!)
const particles = this.add.particles(enemy.x, enemy.y, 'bullet', {
speed: { min: 50, max: 200 },
scale: { start: 0.5, end: 0 },
lifespan: 500,
quantity: 15,
emitting: false
});
particles.explode();
}
gameOver() {
this.scene.start('GameOverScene', { score: this.score });
}
}
🗺️ Samm 5 — Tilemap'id (Tiled)
Tilemap võimaldab visuaalselt disainida mängu tasemeid Tiled editoriga. See on 2D mängude "level editor" standard.
Tiled töövoog: Laadi alla Tiled Map Editor (tasuta). Loo uus kaart → määra tile suurus (nt 32x32) → impordi tileset pilt → joonista kihid → ekspordi JSON.
# 1. Ava Tiled → File → New → New Map
# Orientation: Orthogonal
# Tile size: 32 x 32 px
# Map size: 40 x 30 tiles (1280 x 960 px)
# 2. Tileset: Map → New Tileset
# Name: "tileset"
# Source: tileset.png (nt kenney.nl tiles)
# Tile width/height: 32 x 32
# 3. Loo kihid (Layers panel):
# - "Ground" → muru, liiv, vesi (aluskiht)
# - "Walls" → seinad, kivid, platvormid
# - "Decor" → puud, lilled, lambid (ülekiht)
# - "Objects" → Object Layer (spawn points, kogutavad jne)
# 4. Walls kihi omadused:
# Vali tile → Properties → Lisa: collides = true (boolean)
# Nii saab Phaser teada millised tile'd blokeerivad liikumist
# 5. Object Layer:
# Insert Point → nimeta "PlayerSpawn" (x, y positsioon)
# Insert Point → nimeta "CoinSpawn" (mitu tükki)
# Insert Rectangle → nimeta "KillZone" (ohtlik ala)
# 6. Ekspordi: File → Export As → level1.json
# Kopeeri JSON + tileset.png → assets/maps/ kausta
// preload() meetodis:
// Tilemap JSON (Tiled eksport)
this.load.tilemapTiledJSON('level1', 'assets/maps/level1.json');
this.load.tilemapTiledJSON('level2', 'assets/maps/level2.json');
// Tileset pildid (peab kattuma Tiled tileset nimega!)
this.load.image('terrain-tiles', 'assets/maps/terrain.png');
this.load.image('decor-tiles', 'assets/maps/decorations.png');
create() {
// ---- TILEMAP ----
const map = this.make.tilemap({ key: 'level1' });
// Ühenda tileset pilt nimega Tiled-is
// addTilesetImage("nimi Tiled-is", "Phaser cache key")
const terrain = map.addTilesetImage('terrain', 'terrain-tiles');
const decor = map.addTilesetImage('decorations', 'decor-tiles');
// ---- KIHID (alumisest ülemiseni) ----
const groundLayer = map.createLayer('Ground', terrain, 0, 0);
const wallsLayer = map.createLayer('Walls', terrain, 0, 0);
const decorLayer = map.createLayer('Decor', decor, 0, 0);
// Dekoratsioonid mängija EES (sügavus)
decorLayer.setDepth(10);
// ---- KOKKUPÕRKED ----
// Variant A: Property järgi (Tiled-is märgitud collides=true)
wallsLayer.setCollisionByProperty({ collides: true });
// Variant B: Tile indeksite järgi
// wallsLayer.setCollision([1, 2, 5, 6, 12, 13]);
// Variant C: Kõik mitte-tühjad tile'd
// wallsLayer.setCollisionByExclusion([-1]);
// ---- MÄNGIJA SPAWN ----
// Loe spawn point Object Layer'ist
const spawnPoint = map.findObject('Objects', obj => obj.name === 'PlayerSpawn');
this.player = this.physics.add.sprite(spawnPoint.x, spawnPoint.y, 'player');
this.player.setCollideWorldBounds(true);
// Füüsika kokkupõrge tile kihtidega
this.physics.add.collider(this.player, wallsLayer);
// ---- KOGUTAVAD OBJEKTID (Object Layer'ist) ----
this.coins = this.physics.add.group({ allowGravity: false });
const coinObjects = map.filterObjects('Objects', obj => obj.name === 'CoinSpawn');
coinObjects.forEach(coinObj => {
const coin = this.coins.create(coinObj.x, coinObj.y, 'coin');
coin.setOrigin(0.5, 1); // Tiled kasutab bottom-left origin
});
this.physics.add.overlap(this.player, this.coins, this.collectCoin, null, this);
// ---- OHTLIKUD ALAD (Rectangles Object Layer'ist) ----
const killZones = map.filterObjects('Objects', obj => obj.name === 'KillZone');
killZones.forEach(zone => {
const zoneSprite = this.add.zone(zone.x + zone.width / 2, zone.y + zone.height / 2,
zone.width, zone.height);
this.physics.world.enable(zoneSprite);
zoneSprite.body.setAllowGravity(false);
this.physics.add.overlap(this.player, zoneSprite, this.playerDie, null, this);
});
// ---- KAAMERA ----
// Maailma piirid = kaardi suurus
this.physics.world.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
// Kaamera jälgib mängijat sujuvalt
this.cameras.main.startFollow(this.player, true, 0.08, 0.08);
this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
// Dead zone: kaamera ei liigu kui mängija on ekraani keskel
this.cameras.main.setDeadzone(200, 150);
}
collectCoin(player, coin) {
coin.disableBody(true, true); // Eemalda füüsika + peida
this.score += 10;
this.scoreText.setText('Mündid: ' + this.score);
this.sound.play('coinCollect');
}
create() {
// Parallax taustakihid (liiguvad aeglasemalt kui kaamera)
// scrollFactor < 1 = liigub aeglasemalt (kaugel)
// scrollFactor = 1 = liigub kaameraga kaasa (normaalne)
// Taevas (ei liigu üldse)
this.add.image(400, 200, 'sky').setScrollFactor(0);
// Kauged mäed (liiguvad väga aeglaselt)
this.add.tileSprite(400, 400, 800, 200, 'mountains')
.setScrollFactor(0.1);
// Lähemad puud
this.add.tileSprite(400, 450, 800, 200, 'trees')
.setScrollFactor(0.4);
// ... siis tilemap kihid (scrollFactor = 1, vaikimisi)
}
Tilemap'id toetavad ka animeeritud tile'e — Tiled-is: Tileset → Animation Editor. Sobib ideaalselt vee, laava ja tule tile'idele!
🎬 Samm 6 — Tweens ja Efektid
Tweens on Phaser'i animatsioonimootor mis interpoleerib väärtusi ajas. Ideaalne UI animatsioonide, mündi hõljumise, surmaefektide ja "juice" lisamise jaoks.
// ============================================
// 1. HÕLJUV MÜNT (üles-alla, lõpmatu)
// ============================================
this.tweens.add({
targets: coin,
y: coin.y - 10, // Liigu 10px üles
duration: 800, // 0.8 sekundit
ease: 'Sine.easeInOut', // Sujuv kiirendus/aeglustus
yoyo: true, // Tagasi algpositsioonile
repeat: -1 // Lõpmatu kordus
});
// ============================================
// 2. MÜNDI KOGUMINE (scale up + fade out)
// ============================================
collectCoin(player, coin) {
coin.disableBody(true, false); // Keela füüsika, ära peida veel
this.tweens.add({
targets: coin,
y: coin.y - 40, // Lenda üles
alpha: 0, // Fade out
scale: 1.5, // Suurenda
duration: 300,
ease: 'Power2',
onComplete: () => coin.destroy()
});
// "+10" tekst mis lendab üles
const scorePopup = this.add.text(coin.x, coin.y, '+10', {
fontSize: '20px', fontFamily: 'Inter', color: '#ffd700',
stroke: '#000', strokeThickness: 3
}).setOrigin(0.5);
this.tweens.add({
targets: scorePopup,
y: scorePopup.y - 50,
alpha: 0,
duration: 600,
ease: 'Power2',
onComplete: () => scorePopup.destroy()
});
}
// ============================================
// 3. VAENLASE SURM (keerlev + fade)
// ============================================
killEnemy(enemy) {
enemy.disableBody(true, false);
enemy.setTint(0xff0000); // Punane flash
this.tweens.add({
targets: enemy,
alpha: 0,
scale: 2,
angle: 360,
duration: 400,
ease: 'Power3',
onComplete: () => enemy.destroy()
});
}
// ============================================
// 4. KAAMERAEFEKTID
// ============================================
// Ekraani raputus (tabamus, plahvatus)
this.cameras.main.shake(200, 0.005);
// Punane flash (damage)
this.cameras.main.flash(100, 255, 0, 0, true);
// Fade out → fade in (stseeni vahetus)
this.cameras.main.fadeOut(500, 0, 0, 0);
this.cameras.main.once('camerafadeoutcomplete', () => {
this.scene.start('NextLevel');
});
// Aeglane zoom efekt (boss ilmumine)
this.tweens.add({
targets: this.cameras.main,
zoom: 1.3,
duration: 1000,
ease: 'Sine.easeInOut',
yoyo: true
});
// Slow motion efekt!
sloMo() {
this.time.timeScale = 0.3; // 30% kiirusega
this.tweens.add({
targets: this.time,
timeScale: 1, // Tagasi normaalkiirusele
duration: 1000,
ease: 'Power2'
});
}
// ============================================
// 5. PARTIKLIEFEKTID (Phaser 3.60+)
// ============================================
// Plahvatus (ühekordne)
createExplosion(x, y) {
const particles = this.add.particles(x, y, 'spark', {
speed: { min: 80, max: 300 },
angle: { min: 0, max: 360 },
scale: { start: 0.6, end: 0 },
alpha: { start: 1, end: 0 },
lifespan: 600,
quantity: 20,
tint: [0xff4444, 0xff8800, 0xffff00], // Punane→oranž→kollane
emitting: false
});
particles.explode();
// Hävita emitter mälu puhastamiseks
this.time.delayedCall(1000, () => particles.destroy());
}
// Jälg mängija taga (pidevalt emiteerib)
createPlayerTrail() {
this.playerTrail = this.add.particles(0, 0, 'dot', {
follow: this.player, // Jälgi mängijat
followOffset: { y: 16 }, // Jalgade juurest
scale: { start: 0.3, end: 0 },
alpha: { start: 0.5, end: 0 },
lifespan: 400,
frequency: 50, // Iga 50ms uus partikkel
tint: 0xaaaaff,
blendMode: 'ADD' // Helendav efekt
});
}
// Vihm
createRain() {
this.add.particles(400, -10, 'raindrop', {
x: { min: -400, max: 400 },
speedY: { min: 300, max: 500 },
speedX: { min: -20, max: -50 },
scale: { min: 0.1, max: 0.3 },
alpha: { min: 0.3, max: 0.6 },
lifespan: 2000,
frequency: 20,
quantity: 2
});
}
// ============================================
// 6. UI ANIMATSIOONID
// ============================================
// Menüü nupp ilmumine (alt üles + fade in)
showMenu(buttons) {
buttons.forEach((btn, i) => {
btn.setAlpha(0);
btn.y += 30;
this.tweens.add({
targets: btn,
alpha: 1,
y: btn.y - 30,
duration: 400,
delay: i * 100, // Staggered — iga nupp hilineb 100ms
ease: 'Back.easeOut' // Natuke üle vibutab
});
});
}
// "GAME OVER" tekst mis suureneb
showGameOver() {
const text = this.add.text(400, 300, 'GAME OVER', {
fontSize: '64px', fontFamily: 'Inter', color: '#ff4444',
stroke: '#000', strokeThickness: 6
}).setOrigin(0.5).setScale(0);
this.tweens.add({
targets: text,
scale: 1,
duration: 600,
ease: 'Elastic.easeOut' // Vedru-efekt!
});
}
// ============================================
// EASE FUNKTSIOONIDE SPIKKER:
// ============================================
// 'Linear' — ühtlane kiirus
// 'Power2' — kiirenemine (Quad)
// 'Power3' — veelgi kiirem kiirenemine (Cubic)
// 'Sine.easeInOut' — sujuv algus ja lõpp
// 'Back.easeOut' — läheb natuke üle ja tuleb tagasi
// 'Bounce.easeOut' — põrkav efekt
// 'Elastic.easeOut' — vedru efekt
// 'Expo.easeOut' — järsk algus, aeglane lõpp
//
// Proovi visuaalselt: https://easings.net/
- ✅ Ekraani shake tabamuse/plahvatuse korral
- ✅ Partiklid surma/kogumise juures
- ✅ Score popup mis lendab üles
- ✅ Tint flash (punane = damage, valge = kogutud)
- ✅ Slow-motion kriitilise tabamuse korral
- ✅ Hõljuvad/pulseerivad kogutavad esemed
- ✅ Sujuvad UI üleminekud (fade, slide, scale)
📝 Harjutused
-
Seadista Phaser + Vite projekt
Loo uus projekt
npm init+ Phaser 3 + Vite. Loo BootScene, MenuScene ja GameScene. Kontrolli et mäng käivitub brauseris. -
Sprite liikumine ja animatsioon
Lae spritesheet (nt kenney.nl), loo animatsioonid (idle, run, jump) ja juhi mängijat klaviatuuriga. Lisa
setCollideWorldBounds. -
Füüsikaobjektid ja kokkupõrked
Loo grupp kukkuvaid objekte, lisa gravitatsioon. Mängija peab neid vältima. Lisa skoor ja elude süsteem. Kasuta
physics.add.overlap(). -
Tulistamismäng (Shooter)
Loo top-down shooter: mängija tulistab kuule, vaenlased spawni'vad lainetes. Lisa object pooling (
group.maxSize), partikliefektid ja heliefektid. -
Platformer Tilemap'iga
Loo platformer: disaini tase Tiled editoris, ekspordi JSON. Lae Phaser'isse, lisa kokkupõrked seintega. Mängija saab joosta ja hüpata.
-
Stseenide haldus
Loo täielik mängutsükkel: Boot → Menu → Game → GameOver → Menu. Lisa andmete edastamine stseenide vahel (skoor). Lisa pause stseen.
-
Kaamera süsteem
Loo suur maailm ja kaamera mis jälgib mängijat. Lisa "dead zone", parallax tausta kihid ja zoom efektid.
-
Tweens ja visuaalsed efektid
Lisa mängule poleeritud efektid: mündi hõljumine tweeniga, surma animatsioon (fade + scale), ekraani shake tabamuse korral, flash efektid.