|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Raccoon Rumble</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.min.js"></script> |
|
<style> |
|
@font-face { |
|
font-family: 'PressStart2P'; |
|
src: url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); |
|
} |
|
|
|
body { |
|
margin: 0; |
|
padding: 0; |
|
overflow: hidden; |
|
background-color: #111; |
|
font-family: 'PressStart2P', cursive; |
|
} |
|
|
|
#game-container { |
|
position: relative; |
|
width: 100vw; |
|
height: 100vh; |
|
display: flex; |
|
justify-content: center; |
|
align-items: center; |
|
} |
|
|
|
#game-canvas { |
|
display: block; |
|
margin: 0 auto; |
|
background-color: #000; |
|
} |
|
|
|
.health-bar { |
|
height: 30px; |
|
transition: width 0.3s ease; |
|
} |
|
|
|
.combo-text { |
|
position: absolute; |
|
color: #ff0; |
|
font-size: 24px; |
|
text-shadow: 0 0 10px #f80; |
|
animation: pop 0.5s ease-out; |
|
} |
|
|
|
@keyframes pop { |
|
0% { transform: scale(0.5); opacity: 0; } |
|
80% { transform: scale(1.2); opacity: 1; } |
|
100% { transform: scale(1); opacity: 1; } |
|
} |
|
|
|
.menu-screen { |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
background-color: rgba(0, 0, 0, 0.8); |
|
display: flex; |
|
flex-direction: column; |
|
justify-content: center; |
|
align-items: center; |
|
z-index: 100; |
|
color: white; |
|
} |
|
|
|
.menu-title { |
|
font-size: 48px; |
|
color: #ff9500; |
|
margin-bottom: 40px; |
|
text-shadow: 0 0 10px #ff0; |
|
} |
|
|
|
.menu-button { |
|
background-color: #ff9500; |
|
color: #000; |
|
border: none; |
|
padding: 15px 30px; |
|
margin: 10px; |
|
font-size: 20px; |
|
cursor: pointer; |
|
border-radius: 5px; |
|
transition: all 0.3s; |
|
font-family: 'PressStart2P', cursive; |
|
} |
|
|
|
.menu-button:hover { |
|
background-color: #ff0; |
|
transform: scale(1.05); |
|
} |
|
|
|
.controls-display { |
|
background-color: rgba(0, 0, 0, 0.7); |
|
padding: 20px; |
|
border-radius: 10px; |
|
margin-top: 30px; |
|
max-width: 600px; |
|
} |
|
|
|
.control-item { |
|
display: flex; |
|
align-items: center; |
|
margin: 10px 0; |
|
} |
|
|
|
.key { |
|
background-color: #333; |
|
color: white; |
|
padding: 5px 10px; |
|
margin-right: 15px; |
|
border-radius: 5px; |
|
min-width: 40px; |
|
text-align: center; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div id="game-container"> |
|
<div id="game-canvas"></div> |
|
|
|
|
|
<div id="main-menu" class="menu-screen"> |
|
<h1 class="menu-title">RACCOON RUMBLE</h1> |
|
<button id="start-button" class="menu-button">START GAME</button> |
|
<button id="controls-button" class="menu-button">CONTROLS</button> |
|
|
|
<div class="mt-8 text-center"> |
|
<p>Player 1: WASD + JKL</p> |
|
<p>Player 2: Arrow Keys + Numpad 1-3</p> |
|
<p>Or connect a gamepad!</p> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="controls-screen" class="menu-screen" style="display: none;"> |
|
<h1 class="menu-title">CONTROLS</h1> |
|
|
|
<div class="controls-display"> |
|
<h2 class="text-xl mb-4 text-center">Player 1 (Keyboard)</h2> |
|
<div class="control-item"> |
|
<div class="key">W</div> |
|
<span>Jump</span> |
|
</div> |
|
<div class="control-item"> |
|
<div class="key">A</div> |
|
<span>Move Left</span> |
|
</div> |
|
<div class="control-item"> |
|
<div class="key">D</div> |
|
<span>Move Right</span> |
|
</div> |
|
<div class="control-item"> |
|
<div class="key">J</div> |
|
<span>Light Attack</span> |
|
</div> |
|
<div class="control-item"> |
|
<div class="key">K</div> |
|
<span>Heavy Attack</span> |
|
</div> |
|
<div class="control-item"> |
|
<div class="key">L</div> |
|
<span>Special Attack</span> |
|
</div> |
|
|
|
<h2 class="text-xl mt-8 mb-4 text-center">Player 2 (Keyboard)</h2> |
|
<div class="control-item"> |
|
<div class="key">↑</div> |
|
<span>Jump</span> |
|
</div> |
|
<div class="control-item"> |
|
<div class="key">←</div> |
|
<span>Move Left</span> |
|
</div> |
|
<div class="control-item"> |
|
<div class="key">→</div> |
|
<span>Move Right</span> |
|
</div> |
|
<div class="control-item"> |
|
<div class="key">Num 1</div> |
|
<span>Light Attack</span> |
|
</div> |
|
<div class="control-item"> |
|
<div class="key">Num 2</div> |
|
<span>Heavy Attack</span> |
|
</div> |
|
<div class="control-item"> |
|
<div class="key">Num 3</div> |
|
<span>Special Attack</span> |
|
</div> |
|
|
|
<p class="mt-8 text-center">Gamepads: Use left stick/d-pad to move and face buttons for attacks</p> |
|
</div> |
|
|
|
<button id="back-button" class="menu-button mt-8">BACK TO MENU</button> |
|
</div> |
|
|
|
|
|
<div id="game-over-screen" class="menu-screen" style="display: none;"> |
|
<h1 id="winner-text" class="menu-title">PLAYER 1 WINS!</h1> |
|
<button id="rematch-button" class="menu-button">REMATCH</button> |
|
<button id="menu-button" class="menu-button">MAIN MENU</button> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
|
|
const config = { |
|
type: Phaser.AUTO, |
|
width: 1024, |
|
height: 576, |
|
physics: { |
|
default: 'arcade', |
|
arcade: { |
|
gravity: { y: 800 }, |
|
debug: false |
|
} |
|
}, |
|
scene: { |
|
preload: preload, |
|
create: create, |
|
update: update |
|
}, |
|
parent: 'game-container', |
|
canvas: document.getElementById('game-canvas') |
|
}; |
|
|
|
|
|
let game = new Phaser.Game(config); |
|
let player1, player2; |
|
let platforms; |
|
let cursors, p2Cursors; |
|
let gamepads = []; |
|
let comboCount = 0; |
|
let lastHitTime = 0; |
|
let comboTexts = []; |
|
let background; |
|
let hitSound, jumpSound, specialSound, backgroundMusic; |
|
let gameState = 'menu'; |
|
|
|
|
|
class Raccoon extends Phaser.Physics.Arcade.Sprite { |
|
constructor(scene, x, y, isPlayer1) { |
|
super(scene, x, y, 'raccoon'); |
|
this.isPlayer1 = isPlayer1; |
|
this.health = 100; |
|
this.maxHealth = 100; |
|
this.isAttacking = false; |
|
this.isBlocking = false; |
|
this.isJumping = false; |
|
this.isSpecial = false; |
|
this.comboCount = 0; |
|
this.lastHitTime = 0; |
|
this.facingRight = isPlayer1; |
|
this.specialMeter = 0; |
|
this.maxSpecialMeter = 100; |
|
this.invulnerable = false; |
|
|
|
scene.add.existing(this); |
|
scene.physics.add.existing(this); |
|
|
|
this.setCollideWorldBounds(true); |
|
this.setBounce(0.2); |
|
this.setDragX(400); |
|
this.setSize(60, 90); |
|
this.setOffset(35, 30); |
|
|
|
|
|
this.createAnimations(); |
|
|
|
|
|
this.attackHitbox = scene.add.zone(0, 0, 80, 80); |
|
scene.physics.add.existing(this.attackHitbox); |
|
this.attackHitbox.body.enable = false; |
|
|
|
|
|
this.healthBar = scene.add.rectangle( |
|
isPlayer1 ? 100 : config.width - 100, |
|
50, |
|
this.health * 2, |
|
20, |
|
isPlayer1 ? 0x00ff00 : 0xff0000 |
|
); |
|
this.healthBar.setOrigin(isPlayer1 ? 0 : 1, 0.5); |
|
|
|
|
|
this.specialMeterBar = scene.add.rectangle( |
|
isPlayer1 ? 100 : config.width - 100, |
|
80, |
|
0, |
|
10, |
|
0x00aaff |
|
); |
|
this.specialMeterBar.setOrigin(isPlayer1 ? 0 : 1, 0.5); |
|
|
|
|
|
this.playerIndicator = scene.add.text( |
|
isPlayer1 ? 20 : config.width - 20, |
|
50, |
|
isPlayer1 ? 'P1' : 'P2', |
|
{ |
|
fontSize: '24px', |
|
fill: isPlayer1 ? '#00ff00' : '#ff0000', |
|
fontFamily: 'PressStart2P' |
|
} |
|
); |
|
this.playerIndicator.setOrigin(isPlayer1 ? 0 : 1, 0.5); |
|
} |
|
|
|
createAnimations() { |
|
const anims = this.scene.anims; |
|
|
|
|
|
anims.create({ |
|
key: `idle-${this.isPlayer1 ? 'p1' : 'p2'}`, |
|
frames: anims.generateFrameNumbers('raccoon', { start: 0, end: 3 }), |
|
frameRate: 8, |
|
repeat: -1 |
|
}); |
|
|
|
|
|
anims.create({ |
|
key: `walk-${this.isPlayer1 ? 'p1' : 'p2'}`, |
|
frames: anims.generateFrameNumbers('raccoon', { start: 4, end: 7 }), |
|
frameRate: 12, |
|
repeat: -1 |
|
}); |
|
|
|
|
|
anims.create({ |
|
key: `jump-${this.isPlayer1 ? 'p1' : 'p2'}`, |
|
frames: anims.generateFrameNumbers('raccoon', { start: 8, end: 11 }), |
|
frameRate: 8, |
|
repeat: 0 |
|
}); |
|
|
|
|
|
anims.create({ |
|
key: `light-attack-${this.isPlayer1 ? 'p1' : 'p2'}`, |
|
frames: anims.generateFrameNumbers('raccoon', { start: 12, end: 15 }), |
|
frameRate: 12, |
|
repeat: 0 |
|
}); |
|
|
|
|
|
anims.create({ |
|
key: `heavy-attack-${this.isPlayer1 ? 'p1' : 'p2'}`, |
|
frames: anims.generateFrameNumbers('raccoon', { start: 16, end: 19 }), |
|
frameRate: 10, |
|
repeat: 0 |
|
}); |
|
|
|
|
|
anims.create({ |
|
key: `special-attack-${this.isPlayer1 ? 'p1' : 'p2'}`, |
|
frames: anims.generateFrameNumbers('raccoon', { start: 20, end: 23 }), |
|
frameRate: 8, |
|
repeat: 0 |
|
}); |
|
|
|
|
|
anims.create({ |
|
key: `hit-${this.isPlayer1 ? 'p1' : 'p2'}`, |
|
frames: anims.generateFrameNumbers('raccoon', { start: 24, end: 27 }), |
|
frameRate: 10, |
|
repeat: 0 |
|
}); |
|
|
|
|
|
anims.create({ |
|
key: `block-${this.isPlayer1 ? 'p1' : 'p2'}`, |
|
frames: anims.generateFrameNumbers('raccoon', { start: 28, end: 31 }), |
|
frameRate: 8, |
|
repeat: 0 |
|
}); |
|
} |
|
|
|
update(cursors, gamepad) { |
|
if (this.health <= 0) return; |
|
|
|
|
|
this.healthBar.width = (this.health / this.maxHealth) * 200; |
|
|
|
|
|
this.specialMeterBar.width = (this.specialMeter / this.maxSpecialMeter) * 200; |
|
|
|
|
|
if (!this.isAttacking && !this.isBlocking) { |
|
let moveX = 0; |
|
|
|
|
|
if (cursors) { |
|
if (cursors.left.isDown) { |
|
moveX = -1; |
|
this.facingRight = false; |
|
} else if (cursors.right.isDown) { |
|
moveX = 1; |
|
this.facingRight = true; |
|
} |
|
|
|
if (cursors.up.isDown && this.body.onFloor()) { |
|
this.jump(); |
|
} |
|
} |
|
|
|
|
|
if (gamepad) { |
|
if (gamepad.axes[0] < -0.5 || gamepad.buttons[14].pressed) { |
|
moveX = -1; |
|
this.facingRight = false; |
|
} else if (gamepad.axes[0] > 0.5 || gamepad.buttons[15].pressed) { |
|
moveX = 1; |
|
this.facingRight = true; |
|
} |
|
|
|
if ((gamepad.buttons[0].pressed || gamepad.buttons[12].pressed) && this.body.onFloor()) { |
|
this.jump(); |
|
} |
|
} |
|
|
|
this.setVelocityX(moveX * 200); |
|
|
|
|
|
if (this.body.onFloor()) { |
|
if (moveX !== 0) { |
|
this.play(`walk-${this.isPlayer1 ? 'p1' : 'p2'}`, true); |
|
} else { |
|
this.play(`idle-${this.isPlayer1 ? 'p1' : 'p2'}`, true); |
|
} |
|
} |
|
} |
|
|
|
|
|
this.flipX = !this.facingRight; |
|
|
|
|
|
this.positionAttackHitbox(); |
|
|
|
|
|
if (!this.isAttacking && !this.isBlocking) { |
|
|
|
if (cursors) { |
|
if (cursors.lightAttack.isDown) { |
|
this.lightAttack(); |
|
} else if (cursors.heavyAttack.isDown) { |
|
this.heavyAttack(); |
|
} else if (cursors.specialAttack.isDown && this.specialMeter >= this.maxSpecialMeter) { |
|
this.specialAttack(); |
|
} |
|
} |
|
|
|
|
|
if (gamepad) { |
|
if (gamepad.buttons[2].pressed) { |
|
this.lightAttack(); |
|
} else if (gamepad.buttons[1].pressed) { |
|
this.heavyAttack(); |
|
} else if (gamepad.buttons[3].pressed && this.specialMeter >= this.maxSpecialMeter) { |
|
this.specialAttack(); |
|
} |
|
} |
|
} |
|
|
|
|
|
if (!this.isAttacking) { |
|
let isBlocking = false; |
|
|
|
|
|
if (cursors && cursors.down.isDown && !this.body.onFloor()) { |
|
isBlocking = true; |
|
} |
|
|
|
|
|
if (gamepad && (gamepad.buttons[8].pressed || gamepad.buttons[9].pressed)) { |
|
isBlocking = true; |
|
} |
|
|
|
if (isBlocking && !this.isBlocking) { |
|
this.block(); |
|
} else if (!isBlocking && this.isBlocking) { |
|
this.releaseBlock(); |
|
} |
|
} |
|
|
|
|
|
if (this.specialMeter < this.maxSpecialMeter) { |
|
this.specialMeter += 0.1; |
|
if (this.specialMeter > this.maxSpecialMeter) { |
|
this.specialMeter = this.maxSpecialMeter; |
|
} |
|
} |
|
} |
|
|
|
positionAttackHitbox() { |
|
if (!this.attackHitbox) return; |
|
|
|
const offsetX = this.facingRight ? 50 : -50; |
|
this.attackHitbox.x = this.x + offsetX; |
|
this.attackHitbox.y = this.y - 20; |
|
} |
|
|
|
jump() { |
|
if (this.body.onFloor()) { |
|
this.setVelocityY(-500); |
|
this.play(`jump-${this.isPlayer1 ? 'p1' : 'p2'}`, true); |
|
this.isJumping = true; |
|
jumpSound.play(); |
|
|
|
this.scene.time.delayedCall(1000, () => { |
|
this.isJumping = false; |
|
}); |
|
} |
|
} |
|
|
|
lightAttack() { |
|
this.isAttacking = true; |
|
this.play(`light-attack-${this.isPlayer1 ? 'p1' : 'p2'}`, true); |
|
hitSound.play(); |
|
|
|
|
|
this.attackHitbox.body.enable = true; |
|
this.attackHitbox.body.setSize(80, 80); |
|
|
|
|
|
this.scene.physics.overlap(this.attackHitbox, this.isPlayer1 ? player2 : player1, this.handleHit.bind(this, 10, 'light')); |
|
|
|
|
|
this.scene.time.delayedCall(300, () => { |
|
this.attackHitbox.body.enable = false; |
|
this.isAttacking = false; |
|
}); |
|
} |
|
|
|
heavyAttack() { |
|
this.isAttacking = true; |
|
this.play(`heavy-attack-${this.isPlayer1 ? 'p1' : 'p2'}`, true); |
|
hitSound.play({ volume: 0.8 }); |
|
|
|
|
|
this.attackHitbox.body.enable = true; |
|
this.attackHitbox.body.setSize(100, 100); |
|
|
|
|
|
this.scene.physics.overlap(this.attackHitbox, this.isPlayer1 ? player2 : player1, this.handleHit.bind(this, 20, 'heavy')); |
|
|
|
|
|
this.scene.time.delayedCall(400, () => { |
|
this.attackHitbox.body.enable = false; |
|
this.isAttacking = false; |
|
}); |
|
} |
|
|
|
specialAttack() { |
|
this.isAttacking = true; |
|
this.isSpecial = true; |
|
this.play(`special-attack-${this.isPlayer1 ? 'p1' : 'p2'}`, true); |
|
specialSound.play(); |
|
|
|
|
|
this.specialMeter = 0; |
|
|
|
|
|
this.attackHitbox.body.enable = true; |
|
this.attackHitbox.body.setSize(120, 120); |
|
|
|
|
|
this.scene.physics.overlap(this.attackHitbox, this.isPlayer1 ? player2 : player1, this.handleHit.bind(this, 30, 'special')); |
|
|
|
|
|
this.scene.time.delayedCall(600, () => { |
|
this.attackHitbox.body.enable = false; |
|
this.isAttacking = false; |
|
this.isSpecial = false; |
|
}); |
|
} |
|
|
|
block() { |
|
this.isBlocking = true; |
|
this.setVelocityX(0); |
|
this.play(`block-${this.isPlayer1 ? 'p1' : 'p2'}`, true); |
|
} |
|
|
|
releaseBlock() { |
|
this.isBlocking = false; |
|
} |
|
|
|
handleHit(damage, attackType, attacker, defender) { |
|
if (defender.invulnerable) return; |
|
|
|
|
|
if (defender.isBlocking) { |
|
|
|
damage *= 0.3; |
|
|
|
|
|
defender.play(`block-${defender.isPlayer1 ? 'p1' : 'p2'}`, true); |
|
|
|
|
|
const knockback = this.facingRight ? -100 : 100; |
|
defender.setVelocityX(knockback); |
|
|
|
|
|
defender.invulnerable = true; |
|
this.scene.time.delayedCall(500, () => { |
|
defender.invulnerable = false; |
|
}); |
|
} else { |
|
|
|
defender.play(`hit-${defender.isPlayer1 ? 'p1' : 'p2'}`, true); |
|
|
|
|
|
let knockback = 0; |
|
if (attackType === 'light') knockback = this.facingRight ? 150 : -150; |
|
else if (attackType === 'heavy') knockback = this.facingRight ? 250 : -250; |
|
else if (attackType === 'special') knockback = this.facingRight ? 400 : -400; |
|
|
|
defender.setVelocityX(knockback); |
|
defender.setVelocityY(-100); |
|
|
|
|
|
defender.invulnerable = true; |
|
this.scene.time.delayedCall(800, () => { |
|
defender.invulnerable = false; |
|
}); |
|
} |
|
|
|
|
|
defender.health -= damage; |
|
if (defender.health < 0) defender.health = 0; |
|
|
|
|
|
this.specialMeter += damage; |
|
if (this.specialMeter > this.maxSpecialMeter) { |
|
this.specialMeter = this.maxSpecialMeter; |
|
} |
|
|
|
|
|
const now = this.scene.time.now; |
|
if (now - this.lastHitTime < 1000) { |
|
this.comboCount++; |
|
|
|
|
|
const comboText = this.scene.add.text( |
|
defender.x, |
|
defender.y - 100, |
|
`COMBO x${this.comboCount + 1}!`, |
|
{ |
|
fontSize: '32px', |
|
fill: '#ff0', |
|
fontFamily: 'PressStart2P', |
|
stroke: '#000', |
|
strokeThickness: 4 |
|
} |
|
); |
|
comboText.setOrigin(0.5); |
|
|
|
|
|
comboTexts.push(comboText); |
|
|
|
|
|
this.scene.tweens.add({ |
|
targets: comboText, |
|
y: comboText.y - 50, |
|
alpha: 0, |
|
duration: 1000, |
|
onComplete: () => { |
|
comboText.destroy(); |
|
comboTexts = comboTexts.filter(t => t !== comboText); |
|
} |
|
}); |
|
} else { |
|
this.comboCount = 0; |
|
} |
|
|
|
this.lastHitTime = now; |
|
|
|
|
|
if (defender.health <= 0) { |
|
this.scene.gameOver(this.isPlayer1 ? 'Player 1' : 'Player 2'); |
|
} |
|
} |
|
} |
|
|
|
|
|
function preload() { |
|
|
|
this.load.spritesheet('raccoon', 'https://i.imgur.com/JQlY5zX.png', { |
|
frameWidth: 128, |
|
frameHeight: 128 |
|
}); |
|
|
|
|
|
this.load.image('background1', 'https://i.imgur.com/XH7QZ0a.png'); |
|
this.load.image('background2', 'https://i.imgur.com/Y9vBQ3c.png'); |
|
|
|
|
|
this.load.image('platform', 'https://i.imgur.com/8Z7WQkK.png'); |
|
|
|
|
|
this.load.audio('hit', 'https://assets.codepen.io/21542/hit.mp3'); |
|
this.load.audio('jump', 'https://assets.codepen.io/21542/jump.mp3'); |
|
this.load.audio('special', 'https://assets.codepen.io/21542/special.mp3'); |
|
this.load.audio('backgroundMusic', 'https://assets.codepen.io/21542/fight-music.mp3'); |
|
} |
|
|
|
|
|
function create() { |
|
|
|
const bgKey = Phaser.Math.Between(0, 1) === 0 ? 'background1' : 'background2'; |
|
background = this.add.image(config.width / 2, config.height / 2, bgKey); |
|
background.setDisplaySize(config.width, config.height); |
|
|
|
|
|
platforms = this.physics.add.staticGroup(); |
|
|
|
|
|
platforms.create(config.width / 2, config.height - 50, 'platform') |
|
.setScale(10, 1) |
|
.refreshBody(); |
|
|
|
|
|
platforms.create(200, 400, 'platform').setScale(3, 1).refreshBody(); |
|
platforms.create(config.width - 200, 400, 'platform').setScale(3, 1).refreshBody(); |
|
|
|
|
|
player1 = new Raccoon(this, 300, 300, true); |
|
player2 = new Raccoon(this, config.width - 300, 300, false); |
|
|
|
|
|
this.physics.add.collider(player1, platforms); |
|
this.physics.add.collider(player2, platforms); |
|
|
|
|
|
cursors = this.input.keyboard.addKeys({ |
|
up: Phaser.Input.Keyboard.KeyCodes.W, |
|
left: Phaser.Input.Keyboard.KeyCodes.A, |
|
right: Phaser.Input.Keyboard.KeyCodes.D, |
|
down: Phaser.Input.Keyboard.KeyCodes.S, |
|
lightAttack: Phaser.Input.Keyboard.KeyCodes.J, |
|
heavyAttack: Phaser.Input.Keyboard.KeyCodes.K, |
|
specialAttack: Phaser.Input.Keyboard.KeyCodes.L |
|
}); |
|
|
|
p2Cursors = this.input.keyboard.addKeys({ |
|
up: Phaser.Input.Keyboard.KeyCodes.UP, |
|
left: Phaser.Input.Keyboard.KeyCodes.LEFT, |
|
right: Phaser.Input.Keyboard.KeyCodes.RIGHT, |
|
down: Phaser.Input.Keyboard.KeyCodes.DOWN, |
|
lightAttack: Phaser.Input.Keyboard.KeyCodes.NUMPAD_ONE, |
|
heavyAttack: Phaser.Input.Keyboard.KeyCodes.NUMPAD_TWO, |
|
specialAttack: Phaser.Input.Keyboard.KeyCodes.NUMPAD_THREE |
|
}); |
|
|
|
|
|
this.input.gamepad.on('connected', (pad) => { |
|
console.log('Gamepad connected'); |
|
gamepads[pad.index] = pad; |
|
}); |
|
|
|
|
|
hitSound = this.sound.add('hit'); |
|
jumpSound = this.sound.add('jump'); |
|
specialSound = this.sound.add('special'); |
|
backgroundMusic = this.sound.add('backgroundMusic'); |
|
|
|
|
|
document.getElementById('start-button').addEventListener('click', () => { |
|
this.startGame(); |
|
}); |
|
|
|
document.getElementById('controls-button').addEventListener('click', () => { |
|
document.getElementById('main-menu').style.display = 'none'; |
|
document.getElementById('controls-screen').style.display = 'flex'; |
|
}); |
|
|
|
document.getElementById('back-button').addEventListener('click', () => { |
|
document.getElementById('controls-screen').style.display = 'none'; |
|
document.getElementById('main-menu').style.display = 'flex'; |
|
}); |
|
|
|
document.getElementById('rematch-button').addEventListener('click', () => { |
|
this.startGame(); |
|
}); |
|
|
|
document.getElementById('menu-button').addEventListener('click', () => { |
|
this.showMainMenu(); |
|
}); |
|
|
|
|
|
this.showMainMenu(); |
|
} |
|
|
|
|
|
function update() { |
|
if (gameState !== 'playing') return; |
|
|
|
|
|
const gamepads = navigator.getGamepads(); |
|
|
|
|
|
player1.update(cursors, gamepads[0]); |
|
player2.update(p2Cursors, gamepads[1]); |
|
|
|
|
|
comboTexts.forEach(text => { |
|
if (text.active) { |
|
text.y -= 1; |
|
} |
|
}); |
|
} |
|
|
|
|
|
function startGame() { |
|
|
|
gameState = 'playing'; |
|
|
|
|
|
document.getElementById('main-menu').style.display = 'none'; |
|
document.getElementById('controls-screen').style.display = 'none'; |
|
document.getElementById('game-over-screen').style.display = 'none'; |
|
|
|
|
|
player1.health = player1.maxHealth; |
|
player2.health = player2.maxHealth; |
|
player1.specialMeter = 0; |
|
player2.specialMeter = 0; |
|
player1.setPosition(300, 300); |
|
player2.setPosition(config.width - 300, 300); |
|
player1.setVelocity(0, 0); |
|
player2.setVelocity(0, 0); |
|
player1.isAttacking = false; |
|
player2.isAttacking = false; |
|
player1.isBlocking = false; |
|
player2.isBlocking = false; |
|
|
|
|
|
backgroundMusic.play({ |
|
loop: true, |
|
volume: 0.5 |
|
}); |
|
} |
|
|
|
function gameOver(winner) { |
|
gameState = 'gameover'; |
|
|
|
|
|
backgroundMusic.stop(); |
|
|
|
|
|
document.getElementById('game-over-screen').style.display = 'flex'; |
|
document.getElementById('winner-text').textContent = `${winner} WINS!`; |
|
} |
|
|
|
function showMainMenu() { |
|
gameState = 'menu'; |
|
|
|
|
|
backgroundMusic.stop(); |
|
|
|
|
|
document.getElementById('main-menu').style.display = 'flex'; |
|
document.getElementById('controls-screen').style.display = 'none'; |
|
document.getElementById('game-over-screen').style.display = 'none'; |
|
} |
|
</script> |
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=pijou/newlll" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
</html> |