🎯 Exemples recommandés
Balanced sample collections from various categories for you to explore
Exemples Phaser.js
Exemples du moteur de jeu Phaser.js incluant jeux 2D, animations, physique, sprites et mécaniques de jeu interactives
💻 Phaser.js Hello World javascript
🟢 simple
⭐
Configuration de base Phaser.js et exemples Hello World avec sprites, texte et interactions simples
⏱️ 20 min
🏷️ phaser, game, 2d, sprite, physics
Prerequisites:
JavaScript basics, HTML5 Canvas basics
// Phaser.js Hello World Examples
// 1. Basic Phaser Game Setup
import Phaser from 'phaser';
class HelloWorldScene extends Phaser.Scene {
constructor() {
super('HelloWorld');
}
preload() {
// Load assets
this.load.image('sky', 'assets/sky.png');
this.load.image('ground', 'assets/platform.png');
this.load.image('star', 'assets/star.png');
this.load.spritesheet('dude', 'assets/dude.png', {
frameWidth: 32,
frameHeight: 48
});
}
create() {
// Add background
this.add.image(400, 300, 'sky');
// Add platforms
const platforms = this.physics.add.staticGroup();
platforms.create(400, 568, 'ground').setScale(2).refreshBody();
platforms.create(600, 400, 'ground');
platforms.create(50, 250, 'ground');
platforms.create(750, 220, 'ground');
// Add player
const player = this.physics.add.sprite(100, 450, 'dude');
player.setBounce(0.2);
player.setCollideWorldBounds(true);
this.physics.add.collider(player, platforms);
// Add animations
this.anims.create({
key: 'left',
frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3 }),
frameRate: 10,
repeat: -1
});
this.anims.create({
key: 'turn',
frames: [{ key: 'dude', frame: 4 }],
frameRate: 20
});
this.anims.create({
key: 'right',
frames: this.anims.generateFrameNumbers('dude', { start: 5, end: 8 }),
frameRate: 10,
repeat: -1
});
// Add stars
const stars = this.physics.add.group({
key: 'star',
repeat: 11,
setXY: { x: 12, y: 0, stepX: 70 }
});
stars.children.entries.forEach(child => {
child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
});
this.physics.add.collider(stars, platforms);
this.physics.add.overlap(player, stars, this.collectStar, null, this);
// Score text
const scoreText = this.add.text(16, 16, 'Score: 0', {
fontSize: '32px',
color: '#000'
});
// Store references
this.player = player;
this.stars = stars;
this.scoreText = scoreText;
this.score = 0;
// Add Hello World text
this.add.text(400, 100, 'Hello Phaser World!', {
fontSize: '48px',
color: '#fff',
backgroundColor: '#000',
padding: { x: 20, y: 10 }
}).setOrigin(0.5);
// Controls
this.cursors = this.input.keyboard.createCursorKeys();
}
update() {
const { cursors, player } = this;
if (cursors.left.isDown) {
player.setVelocityX(-160);
player.anims.play('left', true);
} else if (cursors.right.isDown) {
player.setVelocityX(160);
player.anims.play('right', true);
} else {
player.setVelocityX(0);
player.anims.play('turn');
}
if (cursors.up.isDown && player.body.touching.down) {
player.setVelocityY(-330);
}
}
collectStar(player, star) {
star.disableBody(true, true);
this.score += 10;
this.scoreText.setText('Score: ' + this.score);
}
}
// 2. Game Configuration
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 300 },
debug: false
}
},
scene: HelloWorldScene
};
// 3. Initialize Game
const game = new Phaser.Game(config);
// 4. Simple Text Only Game
class TextGame extends Phaser.Scene {
constructor() {
super('TextGame');
}
create() {
// Add text elements
this.add.text(400, 200, 'Hello Phaser!', {
fontSize: '64px',
color: '#ff0000',
fontFamily: 'Arial'
}).setOrigin(0.5);
this.add.text(400, 300, 'Welcome to Game Development', {
fontSize: '32px',
color: '#00ff00',
fontFamily: 'Arial'
}).setOrigin(0.5);
// Interactive text
const clickText = this.add.text(400, 400, 'Click Me!', {
fontSize: '24px',
color: '#0000ff',
backgroundColor: '#ffff00',
padding: { x: 10, y: 5 }
}).setOrigin(0.5).setInteractive();
clickText.on('pointerdown', () => {
clickText.setColor('#ff00ff');
clickText.setText('Clicked!');
});
}
}
// 5. Simple Animation Example
class AnimationExample extends Phaser.Scene {
constructor() {
super('AnimationExample');
}
preload() {
// Create colored rectangles as placeholders for sprites
this.add.graphics()
.fillStyle(0xff0000)
.fillRect(0, 0, 64, 64)
.generateTexture('redBox', 64, 64);
this.add.graphics()
.fillStyle(0x00ff00)
.fillRect(0, 0, 64, 64)
.generateTexture('greenBox', 64, 64);
this.add.graphics()
.fillStyle(0x0000ff)
.fillRect(0, 0, 64, 64)
.generateTexture('blueBox', 64, 64);
}
create() {
// Create sprite with tweens
const sprite = this.add.sprite(400, 300, 'redBox');
// Scale animation
this.tweens.add({
targets: sprite,
scaleX: 2,
scaleY: 2,
duration: 2000,
ease: 'Power2',
yoyo: true,
repeat: -1
});
// Rotation animation
const rotatingSprite = this.add.sprite(200, 200, 'greenBox');
this.tweens.add({
targets: rotatingSprite,
angle: 360,
duration: 3000,
repeat: -1
});
// Position animation
const movingSprite = this.add.sprite(600, 200, 'blueBox');
this.tweens.add({
targets: movingSprite,
x: 200,
y: 400,
duration: 2500,
ease: 'Sine.inOut',
yoyo: true,
repeat: -1
});
this.add.text(400, 500, 'Animation Examples', {
fontSize: '24px',
color: '#ffffff'
}).setOrigin(0.5);
}
}
// 6. Mouse Interaction Example
class MouseInteraction extends Phaser.Scene {
constructor() {
super('MouseInteraction');
}
create() {
// Create interactive sprites
for (let i = 0; i < 5; i++) {
const x = Phaser.Math.Between(50, 750);
const y = Phaser.Math.Between(50, 550);
const color = Phaser.Math.Between(0, 0xffffff);
const sprite = this.add.circle(x, y, 30, color).setInteractive();
sprite.on('pointerover', () => {
sprite.setScale(1.5);
sprite.setTint(0xff0000);
});
sprite.on('pointerout', () => {
sprite.setScale(1);
sprite.clearTint();
});
sprite.on('pointerdown', () => {
sprite.setFillStyle(Phaser.Math.Between(0, 0xffffff));
});
}
this.add.text(400, 30, 'Hover and Click the Circles!', {
fontSize: '20px',
color: '#ffffff'
}).setOrigin(0.5);
}
}
// 7. Particle System Example
class ParticleExample extends Phaser.Scene {
constructor() {
super('ParticleExample');
}
create() {
// Create particle system
const particles = this.add.particles(0, 0, 'redBox', {
x: 400,
y: 300,
speed: { min: -100, max: 100 },
angle: { min: 0, max: 360 },
scale: { start: 1, end: 0 },
lifespan: 2000,
emitting: false
});
const text = this.add.text(400, 500, 'Click to Emit Particles', {
fontSize: '24px',
color: '#ffffff'
}).setOrigin(0.5).setInteractive();
text.on('pointerdown', () => {
particles.explode(50);
});
}
}
// 8. Game State Management Example
class GameStateExample extends Phaser.Scene {
constructor() {
super('GameStateExample');
this.gameState = {
score: 0,
lives: 3,
level: 1,
gameOver: false
};
}
create() {
// Create game state display
this.scoreText = this.add.text(16, 16, `Score: ${this.gameState.score}`, {
fontSize: '20px',
color: '#ffffff'
});
this.livesText = this.add.text(16, 50, `Lives: ${this.gameState.lives}`, {
fontSize: '20px',
color: '#ffffff'
});
this.levelText = this.add.text(16, 84, `Level: ${this.gameState.level}`, {
fontSize: '20px',
color: '#ffffff'
});
// Create buttons to modify game state
const scoreButton = this.add.text(400, 200, 'Add Score', {
fontSize: '24px',
backgroundColor: '#00ff00',
padding: { x: 20, y: 10 }
}).setOrigin(0.5).setInteractive();
scoreButton.on('pointerdown', () => {
this.gameState.score += 10;
this.updateDisplay();
});
const loseLifeButton = this.add.text(400, 300, 'Lose Life', {
fontSize: '24px',
backgroundColor: '#ff0000',
padding: { x: 20, y: 10 }
}).setOrigin(0.5).setInteractive();
loseLifeButton.on('pointerdown', () => {
this.gameState.lives--;
this.updateDisplay();
if (this.gameState.lives <= 0) {
this.gameOver();
}
});
const levelButton = this.add.text(400, 400, 'Next Level', {
fontSize: '24px',
backgroundColor: '#0000ff',
padding: { x: 20, y: 10 }
}).setOrigin(0.5).setInteractive();
levelButton.on('pointerdown', () => {
this.gameState.level++;
this.updateDisplay();
});
}
updateDisplay() {
this.scoreText.setText(`Score: ${this.gameState.score}`);
this.livesText.setText(`Lives: ${this.gameState.lives}`);
this.levelText.setText(`Level: ${this.gameState.level}`);
}
gameOver() {
this.gameState.gameOver = true;
this.add.text(400, 300, 'GAME OVER', {
fontSize: '64px',
color: '#ff0000',
backgroundColor: '#000000',
padding: { x: 20, y: 10 }
}).setOrigin(0.5);
}
}
export {
HelloWorldScene,
TextGame,
AnimationExample,
MouseInteraction,
ParticleExample,
GameStateExample
};
💻 Animation de Sprites et Tweening javascript
🟡 intermediate
⭐⭐⭐
Animations avancées de sprites, sprite sheets, tweening et mouvement de personnages dans Phaser.js
⏱️ 30 min
🏷️ phaser, animation, sprite, effects
Prerequisites:
Phaser.js basics, JavaScript ES6+, Animation concepts
// Phaser Sprite Animation and Tweening Examples
import Phaser from 'phaser';
// 1. Character Animation System
class CharacterAnimation extends Phaser.Scene {
constructor() {
super('CharacterAnimation');
this.character = null;
this.cursors = null;
this.wasMoving = false;
}
preload() {
// Create placeholder sprite sheet
this.createPlayerSpritesheet();
this.load.spritesheet('player', 'player_spritesheet', {
frameWidth: 32,
frameHeight: 48
});
}
createPlayerSpritesheet() {
// Create simple colored rectangles for each animation frame
const graphics = this.add.graphics();
// Idle frames (frames 0-1)
for (let i = 0; i < 2; i++) {
graphics.clear();
graphics.fillStyle(0x00ff00);
graphics.fillRect(i * 32, 0, 32, 48);
graphics.fillStyle(0x000000);
graphics.fillRect(i * 32 + 8, 8, 6, 6); // left eye
graphics.fillRect(i * 32 + 18, 8, 6, 6); // right eye
}
// Walk frames (frames 2-7)
for (let i = 2; i < 8; i++) {
graphics.clear();
graphics.fillStyle(0x0000ff);
graphics.fillRect(i * 32, 0, 32, 48);
// Animated legs
const legOffset = (i % 2) * 4;
graphics.fillRect(i * 32 + 10, 32 + legOffset, 4, 16);
graphics.fillRect(i * 32 + 18, 32 - legOffset, 4, 16);
}
// Jump frame (frame 8)
graphics.clear();
graphics.fillStyle(0xff0000);
graphics.fillRect(8 * 32, 0, 32, 48);
graphics.generateTexture('player_spritesheet', 9 * 32, 48);
graphics.destroy();
}
create() {
// Create character
this.character = this.physics.add.sprite(400, 300, 'player');
this.character.setCollideWorldBounds(true);
// Create animations
this.createAnimations();
// Setup controls
this.cursors = this.input.keyboard.createCursorKeys();
this.wasd = this.input.keyboard.addKeys('W,S,A,D');
// Display instructions
this.add.text(400, 50, 'Use Arrow Keys or WASD to Move', {
fontSize: '20px',
color: '#ffffff'
}).setOrigin(0.5);
// Character info display
this.stateText = this.add.text(16, 16, 'State: Idle', {
fontSize: '16px',
color: '#ffffff'
});
}
createAnimations() {
// Idle animation
this.anims.create({
key: 'idle',
frames: [{ key: 'player', frame: 0 }],
frameRate: 1,
repeat: -1
});
// Walk animation
this.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('player', { start: 2, end: 7 }),
frameRate: 10,
repeat: -1
});
// Jump animation
this.anims.create({
key: 'jump',
frames: [{ key: 'player', frame: 8 }],
frameRate: 1
});
}
update() {
const { cursors, wasd, character } = this;
const left = cursors.left.isDown || wasd.A.isDown;
const right = cursors.right.isDown || wasd.D.isDown;
const up = cursors.up.isDown || wasd.W.isDown;
let isMoving = false;
let currentState = 'Idle';
// Horizontal movement
if (left) {
character.setVelocityX(-200);
character.setFlipX(true);
isMoving = true;
currentState = 'Walking';
} else if (right) {
character.setVelocityX(200);
character.setFlipX(false);
isMoving = true;
currentState = 'Walking';
} else {
character.setVelocityX(0);
}
// Jump
if (up && character.body.touching.down) {
character.setVelocityY(-400);
character.anims.play('jump');
currentState = 'Jumping';
}
// Play appropriate animation
if (!character.body.touching.down) {
// Keep jump animation when in air
if (!character.anims.isPlaying || character.anims.currentAnim.key !== 'jump') {
character.anims.play('jump');
}
} else if (isMoving) {
character.anims.play('walk', true);
} else {
character.anims.play('idle');
}
// Update state display
this.stateText.setText(`State: ${currentState}`);
this.wasMoving = isMoving;
}
}
// 2. Advanced Tweening System
class TweeningSystem extends Phaser.Scene {
constructor() {
super('TweeningSystem');
this.sprites = [];
}
create() {
this.createTweeningExamples();
this.createUI();
}
createTweeningExamples() {
// Linear movement
const sprite1 = this.add.rectangle(100, 100, 50, 50, 0xff0000);
this.tweens.add({
targets: sprite1,
x: 700,
duration: 2000,
ease: 'Linear',
repeat: -1,
yoyo: true
});
// Easing examples
const easeTypes = ['Power0', 'Power1', 'Power2', 'Power3', 'Sine', 'Back', 'Elastic', 'Bounce'];
easeTypes.forEach((ease, index) => {
const x = 100 + (index % 4) * 180;
const y = 200 + Math.floor(index / 4) * 100;
const color = Phaser.Math.Between(0x100000, 0xffffff);
const sprite = this.add.circle(x, y, 20, color);
this.tweens.add({
targets: sprite,
x: x + 140,
duration: 2000,
ease: ease,
repeat: -1,
yoyo: true,
delay: index * 100
});
// Label
this.add.text(x + 70, y - 30, ease, {
fontSize: '12px',
color: '#ffffff'
}).setOrigin(0.5);
});
// Complex path animation
const pathSprite = this.add.rectangle(400, 400, 40, 40, 0x00ff00);
this.tweens.timeline({
targets: pathSprite,
loop: -1,
tweens: [
{
x: 200,
y: 300,
duration: 500,
ease: 'Power2'
},
{
x: 600,
y: 300,
duration: 1000,
ease: 'Sine.inOut'
},
{
x: 600,
y: 500,
duration: 500,
ease: 'Power2'
},
{
x: 200,
y: 500,
duration: 1000,
ease: 'Sine.inOut'
},
{
x: 200,
y: 300,
duration: 500,
ease: 'Power2'
},
{
x: 400,
y: 400,
duration: 500,
ease: 'Power2'
}
]
});
}
createUI() {
this.add.text(400, 30, 'Tweening Examples - Different Easing Functions', {
fontSize: '24px',
color: '#ffffff'
}).setOrigin(0.5);
}
}
// 3. Particle Effects System
class ParticleEffects extends Phaser.Scene {
constructor() {
super('ParticleEffects');
this.particleManager = null;
}
preload() {
// Create particle textures
this.createParticleTextures();
}
createParticleTextures() {
// Create star particle
const starGraphics = this.add.graphics();
starGraphics.fillStyle(0xffff00);
starGraphics.beginPath();
for (let i = 0; i < 5; i++) {
const angle = (i * 72 - 90) * Math.PI / 180;
const x = Math.cos(angle) * 15;
const y = Math.sin(angle) * 15;
if (i === 0) starGraphics.moveTo(x, y);
else starGraphics.lineTo(x, y);
const innerAngle = ((i * 72 + 36) - 90) * Math.PI / 180;
const innerX = Math.cos(innerAngle) * 7;
const innerY = Math.sin(innerAngle) * 7;
starGraphics.lineTo(innerX, innerY);
}
starGraphics.closePath();
starGraphics.fillPath();
starGraphics.generateTexture('star_particle', 30, 30);
starGraphics.destroy();
}
create() {
this.add.text(400, 30, 'Click to Create Different Particle Effects', {
fontSize: '20px',
color: '#ffffff'
}).setOrigin(0.5);
// Create different particle effects
this.createExplosionEffect();
this.createTrailEffect();
this.createFountainEffect();
this.createRainEffect();
}
createExplosionEffect() {
const explosionZone = this.add.zone(200, 200, 100, 100).setInteractive();
this.add.graphics().lineStyle(2, 0xff0000).strokeRect(150, 150, 100, 100);
this.add.text(200, 120, 'Explosion', { fontSize: '16px', color: '#ffffff' }).setOrigin(0.5);
explosionZone.on('pointerdown', (pointer) => {
const particles = this.add.particles(pointer.x, pointer.y, 'star_particle', {
speed: { min: -300, max: 300 },
angle: { min: 0, max: 360 },
scale: { start: 0.5, end: 0 },
lifespan: 1500,
quantity: 30,
blendMode: 'ADD'
});
particles.explode();
});
}
createTrailEffect() {
const trailSprite = this.add.circle(400, 300, 20, 0x00ff00);
const trailParticles = this.add.particles(trailSprite.x, trailSprite.y, 'star_particle', {
scale: { start: 0.3, end: 0 },
speed: 50,
lifespan: 500,
quantity: 2
});
this.tweens.add({
targets: trailSprite,
x: 600,
y: 300,
duration: 2000,
ease: 'Sine.inOut',
yoyo: true,
repeat: -1,
onUpdate: () => {
trailParticles.setPosition(trailSprite.x, trailSprite.y);
}
});
this.add.text(400, 250, 'Trail Effect', { fontSize: '16px', color: '#ffffff' }).setOrigin(0.5);
}
createFountainEffect() {
const fountainParticles = this.add.particles(600, 450, 'star_particle', {
x: 600,
y: 450,
speedY: { min: -400, max: -200 },
speedX: { min: -50, max: 50 },
scale: { start: 0.3, end: 0.1 },
lifespan: 3000,
gravityY: 300,
quantity: 3
});
this.add.text(600, 500, 'Fountain', { fontSize: '16px', color: '#ffffff' }).setOrigin(0.5);
}
createRainEffect() {
const rainParticles = this.add.particles(0, 0, 'star_particle', {
x: { min: 0, max: 800 },
y: -10,
speedY: 200,
scale: { start: 0.2, end: 0.2 },
lifespan: 4000,
quantity: 2,
frequency: 50
});
this.add.text(100, 500, 'Rain Effect', { fontSize: '16px', color: '#ffffff' }).setOrigin(0.5);
}
}
// 4. Sprite Manipulation and Effects
class SpriteEffects extends Phaser.Scene {
constructor() {
super('SpriteEffects');
this.sprites = [];
}
create() {
this.createInteractiveSprites();
this.addInstructions();
}
createInteractiveSprites() {
// Scale effect
const scaleSprite = this.add.circle(150, 200, 30, 0xff0000).setInteractive();
scaleSprite.on('pointerover', () => {
this.tweens.add({
targets: scaleSprite,
scaleX: 1.5,
scaleY: 1.5,
duration: 200,
ease: 'Back.out'
});
});
scaleSprite.on('pointerout', () => {
this.tweens.add({
targets: scaleSprite,
scaleX: 1,
scaleY: 1,
duration: 200,
ease: 'Back.out'
});
});
// Color effect
const colorSprite = this.add.circle(400, 200, 30, 0x00ff00).setInteractive();
colorSprite.on('pointerdown', () => {
const newColor = Phaser.Math.Between(0, 0xffffff);
this.tweens.add({
targets: colorSprite,
duration: 500,
props: {
red: { value: (newColor >> 16) & 255, ease: 'Power1' },
green: { value: (newColor >> 8) & 255, ease: 'Power1' },
blue: { value: newColor & 255, ease: 'Power1' }
}
});
});
// Rotation effect
const rotationSprite = this.add.rectangle(650, 200, 60, 30, 0x0000ff).setInteractive();
rotationSprite.on('pointerdown', () => {
this.tweens.add({
targets: rotationSprite,
angle: 360,
duration: 1000,
ease: 'Power2',
repeat: -1
});
});
// Fade effect
const fadeSprite = this.add.circle(150, 350, 30, 0xffff00).setInteractive();
fadeSprite.on('pointerdown', () => {
this.tweens.add({
targets: fadeSprite,
alpha: 0,
duration: 1000,
yoyo: true,
repeat: -1
});
});
// Shake effect
const shakeSprite = this.add.circle(400, 350, 30, 0xff00ff).setInteractive();
shakeSprite.on('pointerdown', () => {
this.cameras.main.shake(500, 0.01);
});
// Blink effect
const blinkSprite = this.add.circle(650, 350, 30, 0x00ffff).setInteractive();
blinkSprite.on('pointerdown', () => {
this.tweens.add({
targets: blinkSprite,
alpha: { from: 1, to: 0 },
duration: 200,
ease: 'Power2',
yoyo: true,
repeat: 5
});
});
}
addInstructions() {
this.add.text(400, 50, 'Interactive Sprite Effects', {
fontSize: '24px',
color: '#ffffff'
}).setOrigin(0.5);
const instructions = [
'Red: Hover to Scale',
'Green: Click to Change Color',
'Blue: Click to Rotate',
'Yellow: Click to Fade',
'Purple: Click to Shake Camera',
'Cyan: Click to Blink'
];
instructions.forEach((text, index) => {
const x = 150 + (index % 3) * 250;
const y = 450 + Math.floor(index / 3) * 30;
this.add.text(x, y, text, {
fontSize: '14px',
color: '#ffffff'
}).setOrigin(0.5);
});
}
}
// 5. Animation Blending and States
class AnimationBlending extends Phaser.Scene {
constructor() {
super('AnimationBlending');
this.character = null;
this.animationState = 'idle';
this.blendValue = 0;
}
preload() {
this.createAnimationSpritesheet();
}
createAnimationSpritesheet() {
const graphics = this.add.graphics();
// Create blend animation frames
for (let i = 0; i < 8; i++) {
graphics.clear();
// Blend between idle and run based on frame
const blend = i / 7;
const width = 32;
const height = 48;
// Body
graphics.fillStyle(
Phaser.Math.Interpolation.Colors.Interpolation([0x00ff00, 0xff0000], blend)
);
graphics.fillRect(i * width, height/2, width, height/2);
// Head
graphics.fillRect(i * width + 8, 4, 16, 16);
// Moving legs
if (blend > 0.3) {
const legMove = (i % 2) * 8 * blend;
graphics.fillRect(i * width + 8, height - 12 + legMove, 4, 12);
graphics.fillRect(i * width + 20, height - 12 - legMove, 4, 12);
}
}
graphics.generateTexture('character_anim', 256, 48);
graphics.destroy();
}
create() {
this.character = this.add.sprite(400, 300, 'character_anim');
// Create blend animation
this.anims.create({
key: 'blend',
frames: this.anims.generateFrameNumbers('character_anim', { start: 0, end: 7 }),
frameRate: 12,
repeat: -1
});
this.character.anims.play('blend');
// Create UI
this.createUI();
}
createUI() {
this.add.text(400, 50, 'Animation Blending Control', {
fontSize: '24px',
color: '#ffffff'
}).setOrigin(0.5);
this.blendText = this.add.text(400, 500, 'Blend: Idle', {
fontSize: '18px',
color: '#ffffff'
}).setOrigin(0.5);
// Create clickable zones for different blend states
const states = [
{ x: 200, y: 200, label: 'Idle', value: 0 },
{ x: 400, y: 200, label: 'Walk', value: 0.5 },
{ x: 600, y: 200, label: 'Run', value: 1 }
];
states.forEach(state => {
const zone = this.add.zone(state.x, state.y, 100, 60).setInteractive();
this.add.graphics()
.lineStyle(2, 0xffffff)
.strokeRect(state.x - 50, state.y - 30, 100, 60);
this.add.text(state.x, state.y, state.label, {
fontSize: '16px',
color: '#ffffff'
}).setOrigin(0.5);
zone.on('pointerdown', () => {
this.blendValue = state.value;
this.updateAnimation();
});
});
}
updateAnimation() {
let stateLabel = 'Idle';
if (this.blendValue === 0.5) stateLabel = 'Walk';
else if (this.blendValue === 1) stateLabel = 'Run';
this.blendText.setText(`Blend: ${stateLabel}`);
// Update animation speed based on blend
const frameRate = 12 + (this.blendValue * 8);
this.character.anims.currentAnim.msPerFrame = 1000 / frameRate;
}
}
export {
CharacterAnimation,
TweeningSystem,
ParticleEffects,
SpriteEffects,
AnimationBlending
};
💻 Mécaniques de Jeu et Physique javascript
🔴 complex
⭐⭐⭐⭐
Mécaniques complètes de jeu incluant physique, détection de collisions, états de jeu et contrôles joueur
⏱️ 45 min
🏷️ phaser, physics, collision, game mechanics
Prerequisites:
Phaser.js basics, Physics concepts, Game design fundamentals
// Phaser Game Mechanics and Physics Examples
import Phaser from 'phaser';
// 1. Platformer Physics System
class PlatformerGame extends Phaser.Scene {
constructor() {
super('PlatformerGame');
this.player = null;
this.platforms = null;
this.collectibles = null;
this.enemies = null;
this.gameState = {
score: 0,
lives: 3,
level: 1,
gameOver: false
};
}
preload() {
// Create game assets
this.createGameAssets();
}
createGameAssets() {
// Create tile graphics
const graphics = this.add.graphics();
// Ground tile
graphics.fillStyle(0x8B4513).fillRect(0, 0, 64, 64);
graphics.fillStyle(0x228B22).fillRect(0, 0, 64, 20);
graphics.generateTexture('ground', 64, 64);
// Platform tile
graphics.clear();
graphics.fillStyle(0x808080).fillRect(0, 0, 64, 16);
graphics.generateTexture('platform', 64, 16);
// Collectible (star)
graphics.clear();
graphics.fillStyle(0xFFD700);
graphics.beginPath();
for (let i = 0; i < 8; i++) {
const angle = (i * 45 - 90) * Math.PI / 180;
const x = Math.cos(angle) * 20;
const y = Math.sin(angle) * 20;
if (i === 0) graphics.moveTo(x + 25, y + 25);
else graphics.lineTo(x + 25, y + 25);
const innerAngle = ((i * 45 + 22.5) - 90) * Math.PI / 180;
const innerX = Math.cos(innerAngle) * 10;
const innerY = Math.sin(innerAngle) * 10;
graphics.lineTo(innerX + 25, innerY + 25);
}
graphics.closePath();
graphics.fillPath();
graphics.generateTexture('star', 50, 50);
// Enemy
graphics.clear();
graphics.fillStyle(0xFF0000).fillRect(0, 0, 40, 40);
graphics.fillStyle(0x000000).fillRect(8, 8, 6, 6);
graphics.fillStyle(0x000000).fillRect(26, 8, 6, 6);
graphics.generateTexture('enemy', 40, 40);
// Player
graphics.clear();
graphics.fillStyle(0x00FF00).fillRect(0, 0, 32, 48);
graphics.fillStyle(0x000000).fillRect(6, 8, 5, 5);
graphics.fillStyle(0x000000).fillRect(21, 8, 5, 5);
graphics.generateTexture('player', 32, 48);
graphics.destroy();
}
create() {
// Setup physics world
this.physics.world.setBounds(0, 0, 1600, 600);
this.cameras.main.setBounds(0, 0, 1600, 600);
// Create platforms
this.platforms = this.physics.add.staticGroup();
// Ground
for (let i = 0; i < 25; i++) {
this.platforms.create(i * 64, 600 - 32, 'ground').refreshBody();
}
// Floating platforms
this.platforms.create(300, 450, 'platform');
this.platforms.create(500, 350, 'platform');
this.platforms.create(800, 400, 'platform');
this.platforms.create(1100, 300, 'platform');
this.platforms.create(1300, 450, 'platform');
// Create player
this.player = this.physics.add.sprite(100, 400, 'player');
this.player.setBounce(0.2);
this.player.setCollideWorldBounds(true);
this.player.body.setGravityY(300);
this.physics.add.collider(this.player, this.platforms);
// Create collectibles
this.collectibles = this.physics.add.group({
key: 'star',
repeat: 15,
setXY: { x: 200, y: 100, stepX: 80 }
});
this.collectibles.children.entries.forEach(child => {
child.setBounce(Phaser.Math.FloatBetween(0.4, 0.8));
child.setGravityY(100);
});
this.physics.add.collider(this.collectibles, this.platforms);
this.physics.add.overlap(this.player, this.collectibles, this.collectStar, null, this);
// Create enemies
this.enemies = this.physics.add.group();
this.createEnemies();
this.physics.add.collider(this.enemies, this.platforms);
this.physics.add.collider(this.player, this.enemies, this.hitEnemy, null, this);
// Setup controls
this.cursors = this.input.keyboard.createCursorKeys();
this.wasd = this.input.keyboard.addKeys('W,S,A,D');
// Camera follow
this.cameras.main.startFollow(this.player, true, 0.05, 0.05);
// Create UI
this.createUI();
// Create player animations
this.createPlayerAnimations();
}
createPlayerAnimations() {
// Create simple animation
this.anims.create({
key: 'idle',
frames: [{ key: 'player', frame: 0 }],
frameRate: 1
});
}
createEnemies() {
const enemyPositions = [
{ x: 400, y: 400 },
{ x: 700, y: 250 },
{ x: 1000, y: 300 },
{ x: 1400, y: 400 }
];
enemyPositions.forEach(pos => {
const enemy = this.enemies.create(pos.x, pos.y, 'enemy');
enemy.setBounce(1);
enemy.setCollideWorldBounds(true);
enemy.setVelocity(Phaser.Math.Between(-50, 50), 0);
enemy.body.setGravityY(300);
});
}
createUI() {
this.scoreText = this.add.text(16, 16, `Score: ${this.gameState.score}`, {
fontSize: '20px',
color: '#ffffff',
backgroundColor: '#000000',
padding: { x: 10, y: 5 }
}).setScrollFactor(0);
this.livesText = this.add.text(16, 50, `Lives: ${this.gameState.lives}`, {
fontSize: '20px',
color: '#ffffff',
backgroundColor: '#000000',
padding: { x: 10, y: 5 }
}).setScrollFactor(0);
}
update() {
if (this.gameState.gameOver) return;
// Player movement
const { cursors, wasd, player } = this;
const left = cursors.left.isDown || wasd.A.isDown;
const right = cursors.right.isDown || wasd.D.isDown;
const up = cursors.up.isDown || wasd.W.isDown;
if (left) {
player.setVelocityX(-200);
player.setFlipX(true);
} else if (right) {
player.setVelocityX(200);
player.setFlipX(false);
} else {
player.setVelocityX(0);
}
if (up && player.body.touching.down) {
player.setVelocityY(-500);
}
// Check win condition
if (this.collectibles.countActive() === 0) {
this.levelComplete();
}
}
collectStar(player, star) {
star.disableBody(true, true);
this.gameState.score += 10;
this.scoreText.setText(`Score: ${this.gameState.score}`);
}
hitEnemy(player, enemy) {
if (player.body.touching.down && enemy.body.touching.up) {
// Player stomped enemy
enemy.disableBody(true, true);
this.gameState.score += 50;
this.scoreText.setText(`Score: ${this.gameState.score}`);
player.setVelocityY(-300);
} else {
// Player hit by enemy
this.playerHit();
}
}
playerHit() {
this.gameState.lives--;
this.livesText.setText(`Lives: ${this.gameState.lives}`);
if (this.gameState.lives <= 0) {
this.gameOver();
} else {
// Reset player position
this.player.setPosition(100, 400);
this.player.setVelocity(0, 0);
// Flash player
this.tweens.add({
targets: this.player,
alpha: 0.5,
duration: 100,
repeat: 5,
yoyo: true
});
}
}
levelComplete() {
this.gameState.level++;
this.gameState.score += 100;
this.add.text(this.cameras.main.midX, this.cameras.main.midY, 'Level Complete!', {
fontSize: '64px',
color: '#00ff00',
backgroundColor: '#000000',
padding: { x: 20, y: 10 }
}).setOrigin(0.5).setScrollFactor(0);
this.time.delayedCall(2000, () => {
this.nextLevel();
});
}
nextLevel() {
// Reset collectibles
this.collectibles.clear(true, true);
this.collectibles = this.physics.add.group({
key: 'star',
repeat: 20,
setXY: { x: 200, y: 100, stepX: 70 }
});
this.collectibles.children.entries.forEach(child => {
child.setBounce(Phaser.Math.FloatBetween(0.4, 0.8));
child.setGravityY(100);
});
this.physics.add.collider(this.collectibles, this.platforms);
this.physics.add.overlap(this.player, this.collectibles, this.collectStar, null, this);
}
gameOver() {
this.gameState.gameOver = true;
this.physics.pause();
this.add.text(this.cameras.main.midX, this.cameras.main.midY, 'GAME OVER', {
fontSize: '64px',
color: '#ff0000',
backgroundColor: '#000000',
padding: { x: 20, y: 10 }
}).setOrigin(0.5).setScrollFactor(0);
}
}
// 2. Top-Down Shooter Mechanics
class TopDownShooter extends Phaser.Scene {
constructor() {
super('TopDownShooter');
this.player = null;
this.bullets = null;
this.enemies = null;
this.walls = null;
this.gameState = {
score: 0,
wave: 1,
gameOver: false
};
}
preload() {
this.createShooterAssets();
}
createShooterAssets() {
const graphics = this.add.graphics();
// Player (triangle)
graphics.fillStyle(0x0000FF);
graphics.beginPath();
graphics.moveTo(15, 0);
graphics.lineTo(0, 25);
graphics.lineTo(30, 25);
graphics.closePath();
graphics.fillPath();
graphics.generateTexture('player', 30, 30);
// Bullet
graphics.clear();
graphics.fillStyle(0xFFFF00).fillCircle(5, 5, 4);
graphics.generateTexture('bullet', 10, 10);
// Enemy
graphics.clear();
graphics.fillStyle(0xFF0000).fillCircle(15, 15, 15);
graphics.generateTexture('enemy', 30, 30);
// Wall
graphics.clear();
graphics.fillStyle(0x808080).fillRect(0, 0, 50, 50);
graphics.generateTexture('wall', 50, 50);
graphics.destroy();
}
create() {
// Create world boundaries
this.physics.world.setBounds(0, 0, 800, 600);
// Create player
this.player = this.physics.add.sprite(400, 300, 'player');
this.player.setCollideWorldBounds(true);
// Create walls
this.walls = this.physics.add.staticGroup();
this.createWalls();
// Create bullets
this.bullets = this.physics.add.group({
defaultKey: 'bullet',
maxSize: 50
});
// Create enemies
this.enemies = this.physics.add.group();
this.spawnEnemyWave();
// Setup physics
this.physics.add.collider(this.player, this.walls);
this.physics.add.collider(this.enemies, this.walls);
this.physics.add.overlap(this.bullets, this.enemies, this.hitEnemy, null, this);
this.physics.add.overlap(this.bullets, this.walls, this.bulletHitWall, null, this);
this.physics.add.overlap(this.player, this.enemies, this.playerHitEnemy, null, this);
// Setup controls
this.cursors = this.input.keyboard.createCursorKeys();
this.wasd = this.input.keyboard.addKeys('W,S,A,D');
this.space = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
// Follow player with camera
this.cameras.main.startFollow(this.player);
// Create UI
this.createShooterUI();
// Setup continuous enemy spawning
this.enemySpawnTimer = this.time.addEvent({
delay: 2000,
callback: this.spawnEnemy,
callbackScope: this,
loop: true
});
}
createWalls() {
// Create maze-like walls
const wallPositions = [
{ x: 200, y: 150 },
{ x: 600, y: 150 },
{ x: 200, y: 450 },
{ x: 600, y: 450 },
{ x: 100, y: 300 },
{ x: 700, y: 300 },
{ x: 400, y: 100 },
{ x: 400, y: 500 }
];
wallPositions.forEach(pos => {
this.walls.create(pos.x, pos.y, 'wall');
});
}
createShooterUI() {
this.scoreText = this.add.text(16, 16, `Score: ${this.gameState.score}`, {
fontSize: '18px',
color: '#ffffff',
backgroundColor: '#000000',
padding: { x: 10, y: 5 }
}).setScrollFactor(0);
this.waveText = this.add.text(16, 45, `Wave: ${this.gameState.wave}`, {
fontSize: '18px',
color: '#ffffff',
backgroundColor: '#000000',
padding: { x: 10, y: 5 }
}).setScrollFactor(0);
this.healthText = this.add.text(16, 74, 'Health: 100', {
fontSize: '18px',
color: '#ffffff',
backgroundColor: '#000000',
padding: { x: 10, y: 5 }
}).setScrollFactor(0);
}
spawnEnemyWave() {
const enemyCount = 3 + this.gameState.wave;
for (let i = 0; i < enemyCount; i++) {
this.spawnEnemy();
}
}
spawnEnemy() {
const side = Math.floor(Math.random() * 4);
let x, y;
switch(side) {
case 0: // Top
x = Math.random() * 800;
y = 0;
break;
case 1: // Right
x = 800;
y = Math.random() * 600;
break;
case 2: // Bottom
x = Math.random() * 800;
y = 600;
break;
case 3: // Left
x = 0;
y = Math.random() * 600;
break;
}
const enemy = this.enemies.create(x, y, 'enemy');
enemy.health = 2;
}
update() {
if (this.gameState.gameOver) return;
// Player movement
const speed = 200;
let velocityX = 0;
let velocityY = 0;
if (this.cursors.left.isDown || this.wasd.A.isDown) velocityX = -speed;
if (this.cursors.right.isDown || this.wasd.D.isDown) velocityX = speed;
if (this.cursors.up.isDown || this.wasd.W.isDown) velocityY = -speed;
if (this.cursors.down.isDown || this.wasd.S.isDown) velocityY = speed;
this.player.setVelocity(velocityX, velocityY);
// Point player towards mouse
const pointer = this.input.activePointer;
const angle = Phaser.Math.Angle.BetweenPoints(this.player, pointer);
this.player.rotation = angle + Math.PI / 2;
// Shooting
if (this.space.isDown && !this.shootCooldown) {
this.shoot(angle);
this.shootCooldown = true;
this.time.delayedCall(200, () => {
this.shootCooldown = false;
});
}
// Move enemies towards player
this.enemies.children.entries.forEach(enemy => {
if (enemy.active) {
const enemyAngle = Phaser.Math.Angle.BetweenPoints(enemy, this.player);
const enemySpeed = 50 + (this.gameState.wave * 10);
enemy.setVelocity(
Math.cos(enemyAngle) * enemySpeed,
Math.sin(enemyAngle) * enemySpeed
);
enemy.rotation = enemyAngle + Math.PI / 2;
}
});
// Check wave completion
if (this.enemies.countActive() === 0) {
this.nextWave();
}
}
shoot(angle) {
const bullet = this.bullets.get(this.player.x, this.player.y);
if (bullet) {
bullet.setActive(true);
bullet.setVisible(true);
bullet.body.setVelocity(
Math.cos(angle) * 600,
Math.sin(angle) * 600
);
// Remove bullet after 1 second
this.time.delayedCall(1000, () => {
bullet.setActive(false);
bullet.setVisible(false);
});
}
}
hitEnemy(bullet, enemy) {
bullet.setActive(false);
bullet.setVisible(false);
enemy.health--;
if (enemy.health <= 0) {
enemy.setActive(false);
enemy.setVisible(false);
this.gameState.score += 10;
this.scoreText.setText(`Score: ${this.gameState.score}`);
} else {
// Flash enemy
this.tweens.add({
targets: enemy,
tint: 0xFFFFFF,
duration: 100,
yoyo: true
});
}
}
bulletHitWall(bullet, wall) {
bullet.setActive(false);
bullet.setVisible(false);
}
playerHitEnemy(player, enemy) {
this.gameState.health = (this.gameState.health || 100) - 10;
this.healthText.setText(`Health: ${this.gameState.health}`);
// Push enemy back
const pushAngle = Phaser.Math.Angle.BetweenPoints(enemy, player);
enemy.setVelocity(
Math.cos(pushAngle) * 200,
Math.sin(pushAngle) * 200
);
// Flash player
this.tweens.add({
targets: player,
tint: 0xFF0000,
duration: 100,
yoyo: true
});
if (this.gameState.health <= 0) {
this.gameOverShooter();
}
}
nextWave() {
this.gameState.wave++;
this.waveText.setText(`Wave: ${this.gameState.wave}`);
this.gameState.health = Math.min(100, (this.gameState.health || 50) + 20);
this.healthText.setText(`Health: ${this.gameState.health}`);
this.add.text(400, 300, `Wave ${this.gameState.wave}!`, {
fontSize: '48px',
color: '#00ff00',
backgroundColor: '#000000',
padding: { x: 20, y: 10 }
}).setOrigin(0.5).setScrollFactor(0);
this.time.delayedCall(2000, () => {
this.spawnEnemyWave();
});
}
gameOverShooter() {
this.gameState.gameOver = true;
this.physics.pause();
this.enemySpawnTimer.remove();
this.add.text(400, 300, 'GAME OVER', {
fontSize: '64px',
color: '#ff0000',
backgroundColor: '#000000',
padding: { x: 20, y: 10 }
}).setOrigin(0.5).setScrollFactor(0);
}
}
// 3. Pong Game Physics
class PongGame extends Phaser.Scene {
constructor() {
super('PongGame');
this.leftPaddle = null;
this.rightPaddle = null;
this.ball = null;
this.score = { left: 0, right: 0 };
this.paddleSpeed = 400;
}
preload() {
this.createPongAssets();
}
createPongAssets() {
const graphics = this.add.graphics();
// Paddle
graphics.fillStyle(0xFFFFFF).fillRect(0, 0, 15, 80);
graphics.generateTexture('paddle', 15, 80);
// Ball
graphics.clear();
graphics.fillStyle(0xFFFFFF).fillCircle(10, 10, 8);
graphics.generateTexture('ball', 20, 20);
graphics.destroy();
}
create() {
// Create paddles
this.leftPaddle = this.physics.add.sprite(50, 300, 'paddle')
.setImmovable(true)
.setCollideWorldBounds(true);
this.rightPaddle = this.physics.add.sprite(750, 300, 'paddle')
.setImmovable(true)
.setCollideWorldBounds(true);
// Create ball
this.ball = this.physics.add.sprite(400, 300, 'ball')
.setBounce(1)
.setCollideWorldBounds(true);
// Setup collisions
this.physics.add.collider(this.ball, this.leftPaddle, this.hitPaddle, null, this);
this.physics.add.collider(this.ball, this.rightPaddle, this.hitPaddle, null, this);
// Setup world bounds
this.physics.world.setBoundsCollision(true, true, false, false);
// Setup controls
this.cursors = this.input.keyboard.createCursorKeys();
this.wasd = this.input.keyboard.addKeys('W,S,A,D');
// Create UI
this.createPongUI();
// Start ball
this.resetBall();
}
createPongUI() {
this.scoreText = this.add.text(400, 50, `${this.score.left} - ${this.score.right}`, {
fontSize: '48px',
color: '#ffffff'
}).setOrigin(0.5);
this.add.text(400, 100, 'W/S: Left Paddle | Arrow Keys: Right Paddle', {
fontSize: '16px',
color: '#ffffff'
}).setOrigin(0.5);
}
update() {
// Left paddle controls (W/S)
if (this.wasd.W.isDown) {
this.leftPaddle.setVelocityY(-this.paddleSpeed);
} else if (this.wasd.S.isDown) {
this.leftPaddle.setVelocityY(this.paddleSpeed);
} else {
this.leftPaddle.setVelocityY(0);
}
// Right paddle controls (Arrow Keys)
if (this.cursors.up.isDown) {
this.rightPaddle.setVelocityY(-this.paddleSpeed);
} else if (this.cursors.down.isDown) {
this.rightPaddle.setVelocityY(this.paddleSpeed);
} else {
this.rightPaddle.setVelocityY(0);
}
// Keep paddles on screen
this.leftPaddle.y = Phaser.Math.Clamp(this.leftPaddle.y, 40, 560);
this.rightPaddle.y = Phaser.Math.Clamp(this.rightPaddle.y, 40, 560);
// Check scoring
if (this.ball.x < 0) {
this.score.right++;
this.scoreText.setText(`${this.score.left} - ${this.score.right}`);
this.resetBall();
} else if (this.ball.x > 800) {
this.score.left++;
this.scoreText.setText(`${this.score.left} - ${this.score.right}`);
this.resetBall();
}
}
hitPaddle(ball, paddle) {
// Increase ball speed slightly
ball.setVelocityX(ball.body.velocity.x * 1.05);
// Add some spin based on where the ball hits the paddle
const paddleCenter = paddle.y;
const ballCenter = ball.y;
const diff = ballCenter - paddleCenter;
ball.setVelocityY(diff * 4);
}
resetBall() {
this.ball.setPosition(400, 300);
this.ball.setVelocity(
Phaser.Math.Between(-200, 200),
Phaser.Math.Between(-200, 200)
);
}
}
export {
PlatformerGame,
TopDownShooter,
PongGame
};