```git commit message
Add vertical movement controls (W/S keys), thruster effects with particle trails, dynamic background scrolling speed based on player position, and improved wave system with configurable waves This commit introduces several key gameplay enhancements: - Implemented W/S keyboard controls for vertical movement with boundary limits - Added thruster visual effects with flickering animation and sound when moving upward - Created particle trail effects that follow the player during thrust - Implemented dynamic background scrolling speed that increases as player moves upward - Enhanced wave system with configurable wave settings for easier management and extension - Updated menu controls display to reflect new W/A/S/D movement scheme The changes improve player mobility, visual feedback, and game progression system while maintaining existing functionality. ```
This commit is contained in:
parent
7b56d5b46a
commit
eb01c3d89c
Binary file not shown.
147
src/Player.js
147
src/Player.js
|
|
@ -3,6 +3,9 @@ export class Player {
|
|||
this.scene = scene;
|
||||
this.sprite = null;
|
||||
this.cursors = null;
|
||||
this.thruster = null;
|
||||
this.trailParticles = [];
|
||||
this.trailCounter = 0;
|
||||
}
|
||||
|
||||
create() {
|
||||
|
|
@ -13,15 +16,53 @@ export class Player {
|
|||
// Setup controls
|
||||
this.cursors = this.scene.input.keyboard.createCursorKeys();
|
||||
|
||||
// Replace cursor keys with A/D keys for movement
|
||||
// Replace cursor keys with A/D/W/S keys for movement
|
||||
const aKey = this.scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
|
||||
const dKey = this.scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
|
||||
const wKey = this.scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
|
||||
const sKey = this.scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
|
||||
|
||||
return { aKey, dKey };
|
||||
// Create thruster effect
|
||||
this.createThruster();
|
||||
|
||||
return { aKey, dKey, wKey, sKey };
|
||||
}
|
||||
|
||||
update(aKey, dKey) {
|
||||
// Player movement with A/D keys
|
||||
createThruster() {
|
||||
// Create a simple thruster graphic using canvas
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 32;
|
||||
canvas.height = 32;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// Draw thruster flame effect (yellow/orange gradient)
|
||||
const gradient = ctx.createRadialGradient(16, 16, 0, 16, 16, 16);
|
||||
gradient.addColorStop(0, '#ffff00');
|
||||
gradient.addColorStop(0.5, '#ff9900');
|
||||
gradient.addColorStop(1, '#ff3300');
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(16, 16, 12, 0, Math.PI * 2);
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fill();
|
||||
|
||||
// Add some flickering effect with a second inner circle
|
||||
ctx.beginPath();
|
||||
ctx.arc(16, 16, 8, 0, Math.PI * 2);
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.fill();
|
||||
|
||||
this.scene.textures.addCanvas('thruster', canvas);
|
||||
|
||||
// Create thruster sprite (initially hidden)
|
||||
this.thruster = this.scene.add.sprite(0, 0, 'thruster');
|
||||
this.thruster.setOrigin(0.5);
|
||||
this.thruster.setVisible(false);
|
||||
}
|
||||
|
||||
update(aKey, dKey, wKey, sKey) {
|
||||
// Player movement with A/D keys for horizontal
|
||||
if (aKey.isDown) {
|
||||
this.sprite.setVelocityX(-200);
|
||||
this.sprite.setFrame(1);
|
||||
|
|
@ -32,6 +73,104 @@ export class Player {
|
|||
this.sprite.setVelocityX(0);
|
||||
this.sprite.setFrame(0);
|
||||
}
|
||||
|
||||
// Player movement with W/S keys for vertical
|
||||
if (wKey.isDown) {
|
||||
// Limit upward movement to 200px from bottom of screen (500px y position)
|
||||
if (this.sprite.y > 500) {
|
||||
this.sprite.setVelocityY(-200);
|
||||
} else {
|
||||
this.sprite.setVelocityY(0);
|
||||
}
|
||||
} else if (sKey.isDown) {
|
||||
// Limit downward movement to 700px from top of screen
|
||||
if (this.sprite.y < 700) {
|
||||
this.sprite.setVelocityY(200);
|
||||
} else {
|
||||
this.sprite.setVelocityY(0);
|
||||
}
|
||||
} else {
|
||||
this.sprite.setVelocityY(0);
|
||||
}
|
||||
|
||||
// Handle thruster effect when player is accelerating upward
|
||||
if (wKey.isDown) {
|
||||
// Show and position the thruster
|
||||
if (!this.thruster.visible) {
|
||||
this.thruster.setVisible(true);
|
||||
// Play sound and store the instance
|
||||
this.thrusterSoundInstance = this.scene.sound.add('thruster');
|
||||
this.thrusterSoundInstance.play();
|
||||
}
|
||||
|
||||
// Position the thruster behind the player (below the ship)
|
||||
this.thruster.x = this.sprite.x;
|
||||
this.thruster.y = this.sprite.y + 25; // Position below player
|
||||
|
||||
// Add some flickering animation effect
|
||||
const scale = 0.8 + Math.sin(this.scene.time.now * 0.01) * 0.2;
|
||||
this.thruster.setScale(scale);
|
||||
|
||||
// Create trail particles when moving upward
|
||||
if (this.sprite.y > 500) {
|
||||
this.createTrail();
|
||||
}
|
||||
} else {
|
||||
// Hide the thruster when W key is not pressed
|
||||
if (this.thruster.visible) {
|
||||
this.thruster.setVisible(false);
|
||||
// Stop the thruster sound when thrusting stops
|
||||
if (this.thrusterSoundInstance) {
|
||||
this.thrusterSoundInstance.stop();
|
||||
this.thrusterSoundInstance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update trail particles
|
||||
this.updateTrails();
|
||||
}
|
||||
|
||||
createTrail() {
|
||||
// Only create a new trail particle every few frames to avoid too many particles
|
||||
this.trailCounter++;
|
||||
if (this.trailCounter < 3) return;
|
||||
|
||||
this.trailCounter = 0;
|
||||
|
||||
// Create a trail particle at player position
|
||||
const trailParticle = this.scene.add.sprite(this.sprite.x, this.sprite.y + 30, 'thruster');
|
||||
trailParticle.setOrigin(0.5);
|
||||
|
||||
// Make it smaller and more transparent for the trail effect
|
||||
trailParticle.setScale(0.4);
|
||||
trailParticle.setAlpha(0.7);
|
||||
|
||||
// Store particle with its fade speed
|
||||
this.trailParticles.push({
|
||||
sprite: trailParticle,
|
||||
alphaSpeed: 0.01,
|
||||
scaleSpeed: -0.005
|
||||
});
|
||||
}
|
||||
|
||||
updateTrails() {
|
||||
// Update and remove old trail particles
|
||||
for (let i = this.trailParticles.length - 1; i >= 0; i--) {
|
||||
const particle = this.trailParticles[i];
|
||||
|
||||
// Gradually fade out the particle
|
||||
particle.sprite.setAlpha(particle.sprite.alpha - particle.alphaSpeed);
|
||||
|
||||
// Gradually shrink the particle
|
||||
particle.sprite.setScale(particle.sprite.scale + particle.scaleSpeed);
|
||||
|
||||
// Remove particles that are fully faded or too small
|
||||
if (particle.sprite.alpha <= 0 || particle.sprite.scale <= 0) {
|
||||
particle.sprite.destroy();
|
||||
this.trailParticles.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shoot() {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,25 @@ export class GameScene extends Phaser.Scene {
|
|||
// Wave system
|
||||
this.waveTimer = 0;
|
||||
this.currentWave = 0;
|
||||
|
||||
// Wave configuration - easier to manage and extend
|
||||
this.waveConfig = [
|
||||
{
|
||||
waveNumber: 0,
|
||||
time: 0,
|
||||
enemyTypes: [0] // Only basic enemies in wave 1
|
||||
},
|
||||
{
|
||||
waveNumber: 1,
|
||||
time: 20000,
|
||||
enemyTypes: [1] // Enemies that can shoot in wave 2
|
||||
},
|
||||
{
|
||||
waveNumber: 2,
|
||||
time: 40000,
|
||||
enemyTypes: [2] // Special enemies in wave 3
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
preload() {
|
||||
|
|
@ -55,6 +74,7 @@ export class GameScene extends Phaser.Scene {
|
|||
this.load.audio('player-death', 'assets/sounds/player-death.mp3');
|
||||
this.load.audio('enemy-shoot', 'assets/sounds/enemy-shoot.mp3');
|
||||
this.load.audio('next-wave', 'assets/sounds/next-wave.mp3');
|
||||
this.load.audio('thruster', 'assets/sounds/thruster.mp3');
|
||||
|
||||
// Load Fonts
|
||||
this.load.font('Space', 'assets/space-age.otf');
|
||||
|
|
@ -124,29 +144,47 @@ export class GameScene extends Phaser.Scene {
|
|||
// Update wave timer
|
||||
this.waveTimer += delta;
|
||||
|
||||
// Check for wave changes every 30 seconds (30,000 milliseconds)
|
||||
if (this.waveTimer >= 30000 && this.currentWave === 0) {
|
||||
this.startWave(1);
|
||||
} else if (this.waveTimer >= 60000 && this.currentWave === 1) {
|
||||
this.startWave(2);
|
||||
}
|
||||
// Check for wave changes using the configuration array
|
||||
this.checkWaveChanges();
|
||||
|
||||
// Get A/D keys for player movement
|
||||
// Get keyboard keys for player movement
|
||||
const aKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
|
||||
const dKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
|
||||
const wKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
|
||||
const sKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
|
||||
|
||||
// Update player with A/D controls
|
||||
this.player.update(aKey, dKey);
|
||||
// Update player with movement controls
|
||||
this.player.update(aKey, dKey, wKey, sKey);
|
||||
|
||||
// Check if enemies are off-screen and destroy them
|
||||
this.checkEnemiesOffScreen();
|
||||
}
|
||||
|
||||
updateBackgrounds() {
|
||||
// Move background layers at different speeds
|
||||
this.bgLayer1.y += this.bgSpeed1;
|
||||
this.bgLayer2.y += this.bgSpeed2;
|
||||
this.bgLayer3.y += this.bgSpeed3;
|
||||
// Calculate speed multiplier based on player position
|
||||
// When player is at 700px (bottom), use normal speed
|
||||
// When player is at 500px (top), move faster (2x)
|
||||
const maxSpeed = 5.0; // Maximum speed multiplier
|
||||
const minSpeed = 1.0; // Minimum speed multiplier
|
||||
|
||||
let speedMultiplier = minSpeed;
|
||||
|
||||
if (this.player && this.player.sprite) {
|
||||
const playerY = this.player.sprite.y;
|
||||
|
||||
// Map Y position to speed multiplier (700px = normal, 500px = max)
|
||||
if (playerY < 700) {
|
||||
speedMultiplier = minSpeed + ((700 - playerY) / (700 - 500)) * (maxSpeed - minSpeed);
|
||||
}
|
||||
|
||||
// Ensure we don't go below minimum
|
||||
speedMultiplier = Math.max(minSpeed, speedMultiplier);
|
||||
}
|
||||
|
||||
// Move background layers at different speeds with the calculated multiplier
|
||||
this.bgLayer1.y += this.bgSpeed1 * speedMultiplier;
|
||||
this.bgLayer2.y += this.bgSpeed2 * speedMultiplier;
|
||||
this.bgLayer3.y += this.bgSpeed3 * speedMultiplier;
|
||||
|
||||
// Reset positions to create continuous scrolling effect
|
||||
if (this.bgLayer1.y > 736) {
|
||||
|
|
@ -160,6 +198,19 @@ export class GameScene extends Phaser.Scene {
|
|||
}
|
||||
}
|
||||
|
||||
checkWaveChanges() {
|
||||
// Iterate through wave configurations to find which wave should start
|
||||
for (let i = 0; i < this.waveConfig.length; i++) {
|
||||
const wave = this.waveConfig[i];
|
||||
|
||||
// If we haven't started this wave yet and the timer has passed
|
||||
if (this.waveTimer >= wave.time && this.currentWave === wave.waveNumber - 1) {
|
||||
this.startWave(wave.waveNumber);
|
||||
break; // Only start one wave per update cycle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setupMouseInput() {
|
||||
// Create mouse reticle as sprite (replacing the circle)
|
||||
this.reticle = this.add.sprite(0, 0, 'reticle');
|
||||
|
|
@ -244,7 +295,7 @@ export class GameScene extends Phaser.Scene {
|
|||
// align: 'center'
|
||||
// });
|
||||
// this.titleText.setOrigin(0.5);
|
||||
this.titleText = this.add.image(300, 50, 'logo').setScale(.1).setOrigin(0.5);
|
||||
this.titleText = this.add.image(500, 50, 'logo').setScale(.3).setOrigin(0.5).postFX.addGlow();
|
||||
}
|
||||
|
||||
shoot(pointer) {
|
||||
|
|
@ -374,6 +425,12 @@ export class GameScene extends Phaser.Scene {
|
|||
});
|
||||
gameOverText.setOrigin(0.5);
|
||||
|
||||
this.tweens.add({
|
||||
targets: this.bgMusic,
|
||||
volume: 0,
|
||||
duration: 5000,
|
||||
});
|
||||
|
||||
// Return to menu after delay
|
||||
this.time.delayedCall(5000, () => {
|
||||
// Fade camera out before returning to menu
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export class MenuScene extends Phaser.Scene {
|
|||
})
|
||||
|
||||
// Controls display with typing animation
|
||||
const controlsText = 'Controls: A and D to go Left and Right. Mouse to Aim and Fire';
|
||||
const controlsText = 'Controls: W,A,S,D to Move. Mouse to Aim and Fire';
|
||||
this.controlsText = this.add.text(300, 500, '', {
|
||||
fontFamily: 'Coder, Arial',
|
||||
fontSize: '16px',
|
||||
|
|
|
|||
Loading…
Reference in New Issue