Files
naddie-jump/src/entities/Player.js
AnRil de1a3fcf56 Boost effects rewrite — flame, wind, speed lines, burst, puff
- EffectsManager handles all powerup visual feedback in one place
- Replace circle trail with proper effects per type:
  * Rocket: yellow->red flame particles from feet + occasional bright spark
  * Propeller: white/blue wind streaks around player
  * Spring: gold/green spark trail while ascending fast
- Boost start burst: two expanding rings + radial sparks + camera shake
  (orange/gold for rocket, cyan for propeller, green/gold for spring)
- Boost end puff: gray smoke cloud spreading from player
- Screen edge speed lines during boost (alternate left/right edges)
- Player no longer tilts with horizontal input during boost; rocket
  stays rigid upright with tiny lean, propeller has gentle sinusoidal wobble
2026-05-23 18:43:53 +07:00

132 lines
3.8 KiB
JavaScript

import { Physics } from 'phaser';
import {
GAME_WIDTH,
JUMP_VELOCITY,
ROCKET_VELOCITY,
PROPELLER_VELOCITY,
PLAYER_SPEED,
POWERUP_DURATION,
} from '../config/game.config.js';
export class Player extends Physics.Arcade.Sprite {
constructor(scene, x, y) {
super(scene, x, y, 'player_idle');
scene.add.existing(this);
scene.physics.add.existing(this);
this.setCollideWorldBounds(false);
this.setScale(0.45);
this.body.setSize(70, 90);
this.state = 'normal';
this.propellerTimer = 0;
this.rocketTimer = 0;
}
update(cursors, wasd, touchLeft, touchRight, time, delta) {
if (this.state === 'dead') return;
let velocityX = 0;
if (cursors.left.isDown || wasd.left.isDown || touchLeft) velocityX = -PLAYER_SPEED;
if (cursors.right.isDown || wasd.right.isDown || touchRight) velocityX = PLAYER_SPEED;
this.setVelocityX(velocityX);
if (this.x < -this.width / 2) this.x = GAME_WIDTH + this.width / 2;
if (this.x > GAME_WIDTH + this.width / 2) this.x = -this.width / 2;
if (this.state === 'rocket') {
this.rocketTimer -= delta;
this.setVelocityY(ROCKET_VELOCITY);
if (velocityX < 0) this.setFlipX(true);
else if (velocityX > 0) this.setFlipX(false);
// Rocket: rigid upright with tiny lean toward movement
this.setAngle(velocityX === 0 ? 0 : (velocityX < 0 ? -3 : 3));
if (this.rocketTimer <= 0) this.endPowerUp();
} else if (this.state === 'propeller') {
this.propellerTimer -= delta;
this.setVelocityY(PROPELLER_VELOCITY);
if (velocityX < 0) this.setFlipX(true);
else if (velocityX > 0) this.setFlipX(false);
// Propeller: gentle sinusoidal wobble
const wobble = Math.sin(time / 80) * 4;
this.setAngle(wobble + (velocityX < 0 ? -2 : velocityX > 0 ? 2 : 0));
if (this.propellerTimer <= 0) this.endPowerUp();
} else {
if (velocityX < 0) {
this.setFlipX(true);
this.setAngle(-5);
} else if (velocityX > 0) {
this.setFlipX(false);
this.setAngle(5);
} else {
this.setAngle(0);
}
}
}
jump(force = JUMP_VELOCITY) {
if (this.state === 'dead' || this.state === 'rocket' || this.state === 'propeller') return false;
this.setVelocityY(force);
this.scene.tweens.add({
targets: this,
scaleX: 0.55,
scaleY: 0.4,
duration: 80,
yoyo: true,
ease: 'Quad.easeOut',
});
return true;
}
cutJump(factor) {
if (this.state !== 'normal') return;
if (this.body.velocity.y < 0) {
this.setVelocityY(this.body.velocity.y * factor);
}
}
startPropeller() {
if (this.state === 'dead') return;
this.state = 'propeller';
this.propellerTimer = POWERUP_DURATION.propeller;
const oldHeight = this.displayHeight;
this.setTexture('player_propeller');
this.setScale(0.45);
this.body.setSize(70, 105);
this.y -= (this.displayHeight - oldHeight) / 2;
}
startRocket() {
if (this.state === 'dead') return;
this.state = 'rocket';
this.rocketTimer = POWERUP_DURATION.rocket;
const oldHeight = this.displayHeight;
this.setTexture('player_rocket');
this.setScale(0.52);
this.body.setSize(55, 180);
this.y -= (this.displayHeight - oldHeight) / 2;
}
endPowerUp() {
const oldHeight = this.displayHeight;
this.state = 'normal';
this.setTexture('player_idle');
this.setScale(0.45);
this.body.setSize(70, 90);
this.setAngle(0);
this.y -= (this.displayHeight - oldHeight) / 2;
}
die() {
if (this.state === 'dead') return;
this.state = 'dead';
this.setTexture('player_dead');
this.setScale(0.4);
this.setAngle(0);
this.body.setSize(70, 90);
this.body.checkCollision.none = true;
this.setVelocity(0, -250);
this.body.allowGravity = true;
}
}