🎯 Exemplos recomendados
Balanced sample collections from various categories for you to explore
Exemplos Phaser.js
Exemplos do motor de jogo Phaser.js incluindo jogos 2D, animações, física, sprites e mecânicas de jogo interativas
💻 Phaser.js Hello World javascript
🟢 simple
⭐
Configuração básica do Phaser.js e exemplos Hello World com sprites, texto e interações 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
};
💻 Animação de Sprites e Tweening javascript
🟡 intermediate
⭐⭐⭐
Animações avançadas de sprites, sprite sheets, tweening e movimento de personagens no 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
};
💻 Mecânicas de Jogo e Física javascript
🔴 complex
⭐⭐⭐⭐
Mecânicas completas de jogo incluindo física, detecção de colisão, estados de jogo e controles do jogador
⏱️ 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
};