first commit
This commit is contained in:
commit
425978dcb4
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
|
@ -0,0 +1,58 @@
|
||||||
|
{ "compressionlevel":-1,
|
||||||
|
"height":18,
|
||||||
|
"infinite":false,
|
||||||
|
"layers":[
|
||||||
|
{
|
||||||
|
"data":[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 3, 1, 2147483651, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1, 1, 2147483651, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1, 2147483651, 2, 2,
|
||||||
|
2, 3, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 2147483651, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2147483651, 2,
|
||||||
|
2, 1, 1, 1, 1, 2147483651, 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2147483651, 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1, 1, 2, 2, 2, 3, 1, 1, 1, 1, 4, 2, 2, 2147483652, 1, 1, 1, 1, 2147483651, 2, 2, 2, 1, 1, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1, 1, 2147483651, 3, 1, 1, 1, 1, 1, 4, 2, 2, 2, 2, 2147483652, 1, 1, 1, 1, 1, 2147483651, 3, 1, 1, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 2, 2, 2, 3, 2147483651, 2, 2, 2, 2147483652, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1, 1, 1, 1, 1, 4, 2, 2, 2, 3, 1, 1, 1, 1, 2147483651, 2, 2, 2, 2147483652, 1, 1, 1, 1, 1, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1, 1, 1, 1, 1, 2147483651, 2, 2, 2, 2147483652, 1073741825, 1073741825, 1073741825, 1073741825, 4, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1, 1, 1, 1, 1, 1073741825, 1073741825, 2147483651, 2, 2, 2, 2147483652, 4, 2, 2, 2, 3, 1073741825, 1073741825, 1, 1, 1, 1, 1, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1073741825, 1073741825, 4, 2147483652, 1073741825, 1073741825, 1073741825, 1073741825, 1073741825, 2147483651, 2, 2, 2, 2, 3, 1073741825, 1073741825, 1073741825, 1073741825, 1073741825, 4, 2147483652, 1073741825, 1073741825, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1073741825, 1073741825, 2, 2, 2, 2147483652, 1073741825, 1073741825, 1073741825, 1073741825, 2147483651, 2, 2, 3, 1073741825, 1073741825, 1073741825, 1073741825, 4, 2, 2, 2, 1073741825, 1073741825, 1, 1, 1, 2,
|
||||||
|
2, 1, 1, 1, 1073741825, 4, 2, 2, 2, 2, 2, 2147483652, 1073741825, 1073741825, 1073741825, 1073741825, 1073741825, 1073741825, 1073741825, 1073741825, 4, 2, 2, 2, 2, 2, 2147483652, 1073741825, 1, 1, 1, 2,
|
||||||
|
2, 2147483652, 1, 1, 1073741825, 2, 2, 2, 2, 2, 2, 2, 2, 2147483652, 1073741825, 1073741825, 1073741825, 1073741825, 4, 2, 2, 2, 2, 2, 2, 2, 2, 1073741825, 1, 1, 4, 2,
|
||||||
|
2, 2, 2147483652, 1, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2147483652, 1073741825, 1073741825, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2147483652, 1, 4, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
|
||||||
|
"height":18,
|
||||||
|
"id":1,
|
||||||
|
"name":"main",
|
||||||
|
"opacity":1,
|
||||||
|
"type":"tilelayer",
|
||||||
|
"visible":true,
|
||||||
|
"width":32,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
}],
|
||||||
|
"nextlayerid":2,
|
||||||
|
"nextobjectid":1,
|
||||||
|
"orientation":"orthogonal",
|
||||||
|
"renderorder":"right-down",
|
||||||
|
"tiledversion":"1.11.2",
|
||||||
|
"tileheight":64,
|
||||||
|
"tilesets":[
|
||||||
|
{
|
||||||
|
"columns":10,
|
||||||
|
"firstgid":1,
|
||||||
|
"image":"terrain.png",
|
||||||
|
"imageheight":640,
|
||||||
|
"imagewidth":640,
|
||||||
|
"margin":0,
|
||||||
|
"name":"terrain",
|
||||||
|
"spacing":0,
|
||||||
|
"tilecount":100,
|
||||||
|
"tileheight":64,
|
||||||
|
"tilewidth":64
|
||||||
|
}],
|
||||||
|
"tilewidth":64,
|
||||||
|
"type":"map",
|
||||||
|
"version":"1.10",
|
||||||
|
"width":32
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Battle Game</title>
|
||||||
|
<style>
|
||||||
|
body { margin: 0; background-color: black; }
|
||||||
|
canvas { display: block; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="game-container"></div>
|
||||||
|
<script src="./src/phaser.min.js"></script>
|
||||||
|
<script type="module" src="./src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<map version="1.10" tiledversion="1.11.2" orientation="orthogonal" renderorder="right-down" width="32" height="18" tilewidth="64" tileheight="64" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||||
|
<editorsettings>
|
||||||
|
<export target="../assets/night-woods.json" format="json"/>
|
||||||
|
</editorsettings>
|
||||||
|
<tileset firstgid="1" name="terrain" tilewidth="64" tileheight="64" tilecount="100" columns="10">
|
||||||
|
<image source="../assets/terrain.png" width="640" height="640"/>
|
||||||
|
</tileset>
|
||||||
|
<layer id="1" name="main" width="32" height="18">
|
||||||
|
<data encoding="csv">
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||||
|
2,2,3,1,2147483651,2,2,2,2,2,2,2,2,2,3,1,1,2147483651,2,2,2,2,2,2,2,2,2,3,1,2147483651,2,2,
|
||||||
|
2,3,1,1,1,2,2,2,2,2,2,2,2,3,1,1,1,1,2147483651,2,2,2,2,2,2,2,2,1,1,1,2147483651,2,
|
||||||
|
2,1,1,1,1,2147483651,2,2,2,2,2,3,1,1,1,1,1,1,1,1,2147483651,2,2,2,2,2,3,1,1,1,1,2,
|
||||||
|
2,1,1,1,1,1,2,2,2,3,1,1,1,1,4,2,2,2147483652,1,1,1,1,2147483651,2,2,2,1,1,1,1,1,2,
|
||||||
|
2,1,1,1,1,1,2147483651,3,1,1,1,1,1,4,2,2,2,2,2147483652,1,1,1,1,1,2147483651,3,1,1,1,1,1,2,
|
||||||
|
2,1,1,1,1,1,1,1,1,1,1,4,2,2,2,3,2147483651,2,2,2,2147483652,1,1,1,1,1,1,1,1,1,1,2,
|
||||||
|
2,1,1,1,1,1,1,1,1,4,2,2,2,3,1,1,1,1,2147483651,2,2,2,2147483652,1,1,1,1,1,1,1,1,2,
|
||||||
|
2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
|
||||||
|
2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
|
||||||
|
2,1,1,1,1,1,1,1,1,2147483651,2,2,2,2147483652,1073741825,1073741825,1073741825,1073741825,4,2,2,2,3,1,1,1,1,1,1,1,1,2,
|
||||||
|
2,1,1,1,1,1,1,1,1,1073741825,1073741825,2147483651,2,2,2,2147483652,4,2,2,2,3,1073741825,1073741825,1,1,1,1,1,1,1,1,2,
|
||||||
|
2,1,1,1,1073741825,1073741825,4,2147483652,1073741825,1073741825,1073741825,1073741825,1073741825,2147483651,2,2,2,2,3,1073741825,1073741825,1073741825,1073741825,1073741825,4,2147483652,1073741825,1073741825,1,1,1,2,
|
||||||
|
2,1,1,1,1073741825,1073741825,2,2,2,2147483652,1073741825,1073741825,1073741825,1073741825,2147483651,2,2,3,1073741825,1073741825,1073741825,1073741825,4,2,2,2,1073741825,1073741825,1,1,1,2,
|
||||||
|
2,1,1,1,1073741825,4,2,2,2,2,2,2147483652,1073741825,1073741825,1073741825,1073741825,1073741825,1073741825,1073741825,1073741825,4,2,2,2,2,2,2147483652,1073741825,1,1,1,2,
|
||||||
|
2,2147483652,1,1,1073741825,2,2,2,2,2,2,2,2,2147483652,1073741825,1073741825,1073741825,1073741825,4,2,2,2,2,2,2,2,2,1073741825,1,1,4,2,
|
||||||
|
2,2,2147483652,1,4,2,2,2,2,2,2,2,2,2,2147483652,1073741825,1073741825,4,2,2,2,2,2,2,2,2,2,2147483652,1,4,2,2,
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
|
||||||
|
</data>
|
||||||
|
</layer>
|
||||||
|
</map>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
export const FACTION_CONFIG = {
|
||||||
|
'dark-ages': {
|
||||||
|
0: {
|
||||||
|
name: 'Knight',
|
||||||
|
description: 'Ye Magesty\'s base unit',
|
||||||
|
stats: {
|
||||||
|
type: 'melee',
|
||||||
|
health: 5,
|
||||||
|
attackMin: 1,
|
||||||
|
attackMax: 4,
|
||||||
|
meleeDefense: 1,
|
||||||
|
rangeDefense: 2,
|
||||||
|
magicDefense: 1,
|
||||||
|
sight: 150,
|
||||||
|
range: 64
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
export const PATH_CONFIG = {
|
||||||
|
'left': {
|
||||||
|
1: {
|
||||||
|
0: {
|
||||||
|
'x': 4,
|
||||||
|
'y': 5,
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
'x': 6,
|
||||||
|
'y': 8,
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
'x': 11,
|
||||||
|
'y': 4,
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
'x': 15,
|
||||||
|
'y': 2,
|
||||||
|
},
|
||||||
|
4: {
|
||||||
|
'x': 19,
|
||||||
|
'y': 4,
|
||||||
|
},
|
||||||
|
5: {
|
||||||
|
'x': 27,
|
||||||
|
'y': 8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'right': {
|
||||||
|
1: {
|
||||||
|
0: {
|
||||||
|
'x': 27,
|
||||||
|
'y': 4,
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
'x': 25,
|
||||||
|
'y': 7,
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
'x': 20,
|
||||||
|
'y': 4,
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
'x': 16,
|
||||||
|
'y': 2,
|
||||||
|
},
|
||||||
|
4: {
|
||||||
|
'x': 11,
|
||||||
|
'y': 5,
|
||||||
|
},
|
||||||
|
5: {
|
||||||
|
'x': 5,
|
||||||
|
'y': 7,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
import { PATH_CONFIG } from "../config/night-woods-config.js";
|
||||||
|
import { FACTION_CONFIG } from "../config/faction.js";
|
||||||
|
|
||||||
|
export class Faction extends Phaser.GameObjects.Sprite {
|
||||||
|
constructor(scene, x, y, texture, frame, side, path, faction) {
|
||||||
|
super(scene, x, y, texture, frame);
|
||||||
|
this.scene = scene;
|
||||||
|
|
||||||
|
scene.add.existing(this);
|
||||||
|
scene.physics.world.enable(this);
|
||||||
|
this.body.setCollideWorldBounds(true);
|
||||||
|
if (side === 'left') {
|
||||||
|
scene.factionLeft.add(this);
|
||||||
|
}
|
||||||
|
if (side === 'right') {
|
||||||
|
scene.factionRight.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
this.stats = {};
|
||||||
|
Object.entries(FACTION_CONFIG[faction][frame].stats).forEach(([key, value]) => {
|
||||||
|
this.stats[key] = value;
|
||||||
|
});
|
||||||
|
console.log(this);
|
||||||
|
|
||||||
|
// Path following properties
|
||||||
|
this.path = path;
|
||||||
|
this.side = side;
|
||||||
|
this.currentWaypoint = 0;
|
||||||
|
this.speed = 50;
|
||||||
|
this.arrived = false;
|
||||||
|
this.isPathPaused = false;
|
||||||
|
|
||||||
|
this.animKey = `${texture}-${frame}`;
|
||||||
|
this.createAnim();
|
||||||
|
this.play(this.animKey);
|
||||||
|
|
||||||
|
// Initialize path following
|
||||||
|
this.initializePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
createAnim() {
|
||||||
|
if (!this.scene.anims.get(this.animKey)) {
|
||||||
|
this.scene.anims.create({
|
||||||
|
key: this.animKey,
|
||||||
|
frames: [
|
||||||
|
{ key: this.texture.key, frame: this.frame.name },
|
||||||
|
{ key: this.texture.key, frame: this.frame.name+1 }
|
||||||
|
],
|
||||||
|
frameRate: 2,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initializePath() {
|
||||||
|
// Get the path data from config
|
||||||
|
const pathData = PATH_CONFIG[this.side][this.path];
|
||||||
|
if (pathData) {
|
||||||
|
this.waypoints = [];
|
||||||
|
for (let i = 0; i < Object.keys(pathData).length; i++) {
|
||||||
|
this.waypoints.push({
|
||||||
|
x: pathData[i].x*64,
|
||||||
|
y: pathData[i].y*64
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start moving towards first waypoint
|
||||||
|
if (this.waypoints.length > 0) {
|
||||||
|
this.moveToWaypoint(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
moveToWaypoint(waypointIndex) {
|
||||||
|
if (this.isPathPaused) return;
|
||||||
|
|
||||||
|
if (waypointIndex >= this.waypoints.length) {
|
||||||
|
this.arrived = true;
|
||||||
|
this.body.setVelocity(0, 0);
|
||||||
|
this.stop(this.animKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = this.waypoints[waypointIndex];
|
||||||
|
const distance = Phaser.Math.Distance.Between(this.x, this.y, target.x, target.y);
|
||||||
|
|
||||||
|
if (distance < 5) { // Threshold for reaching waypoint
|
||||||
|
this.currentWaypoint = waypointIndex + 1;
|
||||||
|
this.moveToWaypoint(this.currentWaypoint);
|
||||||
|
} else {
|
||||||
|
// Calculate direction vector
|
||||||
|
const angle = Phaser.Math.Angle.Between(this.x, this.y, target.x, target.y);
|
||||||
|
|
||||||
|
// Set velocity based on angle and speed
|
||||||
|
this.body.setVelocity(
|
||||||
|
Math.cos(angle) * this.speed,
|
||||||
|
Math.sin(angle) * this.speed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pausePath() {
|
||||||
|
this.isPathPaused = true;
|
||||||
|
this.body.setVelocity(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
resumePath() {
|
||||||
|
this.isPathPaused = false;
|
||||||
|
// Resume from current waypoint
|
||||||
|
this.moveToWaypoint(this.currentWaypoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(time, delta) {
|
||||||
|
// Flip sprite based on movement direction
|
||||||
|
if (this.body && this.body.velocity) {
|
||||||
|
if (this.body.velocity.x > 0) {
|
||||||
|
this.setFlipX(true); // Moving right, normal orientation
|
||||||
|
} else if (this.body.velocity.x < 0) {
|
||||||
|
this.setFlipX(false); // Moving left, flipped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move towards next waypoint if not arrived and path is not paused
|
||||||
|
if (!this.arrived && !this.isPathPaused) {
|
||||||
|
this.moveToWaypoint(this.currentWaypoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Level } from './scenes/level.js'
|
||||||
|
|
||||||
|
const GAME_CONFIG = {
|
||||||
|
type: Phaser.AUTO,
|
||||||
|
scale: {
|
||||||
|
mode: Phaser.Scale.FIT,
|
||||||
|
autoCenter: Phaser.Scale.CENTER_BOTH,
|
||||||
|
width: 1600,
|
||||||
|
height: 900,
|
||||||
|
parent: 'game-container'
|
||||||
|
},
|
||||||
|
parent: 'game-container',
|
||||||
|
backgroundColor: '#bb7432ff',
|
||||||
|
scene: [
|
||||||
|
Level,
|
||||||
|
],
|
||||||
|
physics: {
|
||||||
|
default: 'arcade',
|
||||||
|
arcade: {
|
||||||
|
gravity: { y: 0 },
|
||||||
|
debug: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the game instance
|
||||||
|
const game = new Phaser.Game(GAME_CONFIG);
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,312 @@
|
||||||
|
export class AudioManager extends Phaser.Scene {
|
||||||
|
constructor() {
|
||||||
|
super({ key: 'AudioManager', active: true });
|
||||||
|
this.soundInstances = {};
|
||||||
|
this.currentTrackIndex = 0;
|
||||||
|
this.isShuffled = false;
|
||||||
|
this.trackQueue = [];
|
||||||
|
this.currentSoundtrack = null;
|
||||||
|
|
||||||
|
this.tracks = {
|
||||||
|
'levelMusic1': {
|
||||||
|
'title': 'Kevin be Wack',
|
||||||
|
'artist': 'The Scrum Masta',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusic2': {
|
||||||
|
'title': 'ClienTek is Coming!',
|
||||||
|
'artist': 'Tha Day-Lee St4nd',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusic3': {
|
||||||
|
'title': 'How Would Amazon Do it?',
|
||||||
|
'artist': 'Billy Gitpull Jr.',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusic4': {
|
||||||
|
'title': 'Commit to the Git',
|
||||||
|
'artist': 'Peer Review',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusic5': {
|
||||||
|
'title': 'ClienTek C4shin\' Checks',
|
||||||
|
'artist': 'MC Cr4iG V',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusic6': {
|
||||||
|
'title': 'Solutions of the Heart',
|
||||||
|
'artist': 'Kevin Smooth',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusic7': {
|
||||||
|
'title': 'Keepin\' Your Website Country',
|
||||||
|
'artist': 'Git-e-up Gang',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusic8': {
|
||||||
|
'title': 'Hello Humans',
|
||||||
|
'artist': 'Robotic Bryce',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusic9': {
|
||||||
|
'title': '2 o\'clock Zoo o\'clock',
|
||||||
|
'artist': 'The HR Brothers',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusicA': {
|
||||||
|
'title': 'Best Launch Ever',
|
||||||
|
'artist': 'Syntax',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusicB': {
|
||||||
|
'title': 'Town Hall',
|
||||||
|
'artist': 'The KEGR Krew',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusicC': {
|
||||||
|
'title': 'It\'s Stupid',
|
||||||
|
'artist': 'The Burlimonsters',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusicD': {
|
||||||
|
'title': 'Fat Hawk',
|
||||||
|
'artist': 'Oliver Quantum',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
'levelMusicE': {
|
||||||
|
'title': 'Kevin Ghould Dance',
|
||||||
|
'artist': 'Hema-to-logic',
|
||||||
|
'misc': '2025 - IT Records'
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
this.load.audio('pickup', 'assets/sounds/pickup.mp3');
|
||||||
|
this.load.audio('catFight1', 'assets/sounds/catFight1.mp3');
|
||||||
|
this.load.audio('catFight2', 'assets/sounds/catFight2.mp3');
|
||||||
|
this.load.audio('catFight3', 'assets/sounds/catFight3.mp3');
|
||||||
|
this.load.audio('chain', 'assets/sounds/chain.mp3');
|
||||||
|
this.load.audio('monster', 'assets/sounds/monster.mp3');
|
||||||
|
this.load.audio('hobbies', 'assets/sounds/hobbies.mp3');
|
||||||
|
this.load.audio('bread', 'assets/sounds/bread.mp3');
|
||||||
|
this.load.audio('freeze', 'assets/sounds/freeze.mp3');
|
||||||
|
this.load.audio('launch', 'assets/sounds/launch.mp3');
|
||||||
|
this.load.audio('banana', 'assets/sounds/banana.mp3');
|
||||||
|
this.load.audio('bonusDonut', 'assets/sounds/bonusDonut.mp3');
|
||||||
|
this.load.audio('bonusFreeze', 'assets/sounds/bonusFreeze.mp3');
|
||||||
|
this.load.audio('bonusKill', 'assets/sounds/bonusKill.mp3');
|
||||||
|
this.load.audio('explosion', 'assets/sounds/explosion.mp3');
|
||||||
|
|
||||||
|
this.load.audio('levelMusic1', 'assets/levelMusic1.mp3');
|
||||||
|
this.load.audio('levelMusic2', 'assets/menuMusic.mp3');
|
||||||
|
this.load.audio('levelMusic3', 'assets/levelMusic3.mp3');
|
||||||
|
this.load.audio('levelMusic4', 'assets/levelMusic4.mp3');
|
||||||
|
this.load.audio('levelMusic5', 'assets/levelMusic5.mp3');
|
||||||
|
this.load.audio('levelMusic6', 'assets/levelMusic6.mp3');
|
||||||
|
this.load.audio('levelMusic7', 'assets/levelMusic7.mp3');
|
||||||
|
this.load.audio('levelMusic8', 'assets/levelMusic8.mp3');
|
||||||
|
this.load.audio('levelMusic9', 'assets/levelMusic9.mp3');
|
||||||
|
this.load.audio('levelMusicA', 'assets/levelMusicA.mp3');
|
||||||
|
this.load.audio('levelMusicB', 'assets/levelMusicB.mp3');
|
||||||
|
this.load.audio('levelMusicC', 'assets/levelMusicC.mp3');
|
||||||
|
this.load.audio('levelMusicD', 'assets/levelMusicD.mp3');
|
||||||
|
this.load.audio('levelMusicE', 'assets/levelMusicE.mp3');
|
||||||
|
|
||||||
|
this.load.spritesheet('cassette', 'assets/cassette.png', {
|
||||||
|
frameWidth: 424,
|
||||||
|
frameHeight: 240
|
||||||
|
});
|
||||||
|
this.load.audio('playerHit', 'assets/sounds/playerHit.mp3');
|
||||||
|
this.load.audio('hit', 'assets/sounds/hit.mp3');
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
playManagedSound(key, maxInstances = 1, volume = 1) {
|
||||||
|
if (!this.soundInstances[key]) {
|
||||||
|
this.soundInstances[key] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up old sound instances that have finished playing
|
||||||
|
this.soundInstances[key] = this.soundInstances[key].filter(s => s.isPlaying);
|
||||||
|
|
||||||
|
// If we have not reached the max limit, play a new instance
|
||||||
|
if (this.soundInstances[key].length < maxInstances) {
|
||||||
|
const sound = this.sound.add(key, { volume: volume });
|
||||||
|
sound.play();
|
||||||
|
this.soundInstances[key].push(sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
playSoundtrack() {
|
||||||
|
if (this.trackQueue.length === 0) {
|
||||||
|
// Reinitialize queue if empty
|
||||||
|
this.initializeTrackQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.audioInterface) {
|
||||||
|
this.initializeInterface();
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentKey = this.trackQueue[this.currentTrackIndex];
|
||||||
|
|
||||||
|
// Play the current track
|
||||||
|
this.showTrack(currentKey);
|
||||||
|
const sound = this.sound.add(currentKey);
|
||||||
|
sound.play();
|
||||||
|
|
||||||
|
// Keep reference to current soundtrack for stopping
|
||||||
|
this.currentSoundtrack = sound;
|
||||||
|
|
||||||
|
// Set up callback for when track finishes
|
||||||
|
sound.on('complete', () => {
|
||||||
|
this.nextTrack();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move to next track in queue
|
||||||
|
this.currentTrackIndex = (this.currentTrackIndex + 1) % this.trackQueue.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleSoundtrackPause(pause = true) {
|
||||||
|
if (this.currentSoundtrack) {
|
||||||
|
if (pause && this.currentSoundtrack.isPlaying) {
|
||||||
|
this.currentSoundtrack.pause();
|
||||||
|
} else if (!pause && !this.currentSoundtrack.isPlaying) {
|
||||||
|
this.currentSoundtrack.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stopSoundtrack() {
|
||||||
|
if (this.currentSoundtrack) {
|
||||||
|
this.currentSoundtrack.stop();
|
||||||
|
this.currentSoundtrack = null;
|
||||||
|
|
||||||
|
// Hide the cassette interface if it's visible
|
||||||
|
if (this.cassette && this.cassette.alpha > 0) {
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.cassette,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 500,
|
||||||
|
onComplete: () => {
|
||||||
|
this.cassette.x = 1655;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeTrackQueue() {
|
||||||
|
// Create a copy of track keys and shuffle them
|
||||||
|
this.trackQueue = Object.keys(this.tracks);
|
||||||
|
this.shuffleArray(this.trackQueue);
|
||||||
|
this.isShuffled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
shuffleArray(array) {
|
||||||
|
for (let i = array.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
|
[array[i], array[j]] = [array[j], array[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextTrack() {
|
||||||
|
if (this.trackQueue.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentKey = this.trackQueue[this.currentTrackIndex];
|
||||||
|
|
||||||
|
// Play the next track
|
||||||
|
this.showTrack(currentKey);
|
||||||
|
const sound = this.sound.add(currentKey);
|
||||||
|
sound.play();
|
||||||
|
|
||||||
|
// Keep reference to current soundtrack for stopping
|
||||||
|
this.currentSoundtrack = sound;
|
||||||
|
|
||||||
|
// Set up callback for when track finishes
|
||||||
|
sound.on('complete', () => {
|
||||||
|
this.nextTrack();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move to next track in queue
|
||||||
|
this.currentTrackIndex = (this.currentTrackIndex + 1) % this.trackQueue.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeInterface() {
|
||||||
|
this.audioInterface = true;
|
||||||
|
this.cassette = this.add.container(1655, 675).setScrollFactor(0).setAlpha(0);
|
||||||
|
const cassetteSprite = this.add.sprite(0, 0, 'cassette', 0).setOrigin(0.5);//.setScale(.7);
|
||||||
|
this.cassette.add(cassetteSprite);
|
||||||
|
|
||||||
|
this.anims.create({
|
||||||
|
key: 'cassette-play',
|
||||||
|
frames: [
|
||||||
|
{ key: 'cassette', frame: 0 },
|
||||||
|
{ key: 'cassette', frame: 1 },
|
||||||
|
{ key: 'cassette', frame: 2 },
|
||||||
|
],
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
cassetteSprite.play('cassette-play', true);
|
||||||
|
|
||||||
|
this.trackTitle = this.add.text(-125, -88, 'Track Title Here', {
|
||||||
|
fontSize: '20px',
|
||||||
|
fill: '#000000ff',
|
||||||
|
stroke: '#8d3131ff',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 2,
|
||||||
|
offsetY: 2,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 4,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
}).setOrigin(0, 0.5);
|
||||||
|
this.cassette.add(this.trackTitle);
|
||||||
|
|
||||||
|
this.trackSub1 = this.add.text(-125, -78, 'By: Artist', {
|
||||||
|
fontSize: '18px',
|
||||||
|
fill: '#000000ff',
|
||||||
|
stroke: '#8d3131ff',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 2,
|
||||||
|
offsetY: 2,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 4,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.cassette.add(this.trackSub1);
|
||||||
|
}
|
||||||
|
|
||||||
|
showTrack(track) {
|
||||||
|
this.trackTitle.setText(this.tracks[track].title);
|
||||||
|
this.trackSub1.setText(`By: ${this.tracks[track].artist}`);
|
||||||
|
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.cassette,
|
||||||
|
alpha: 1,
|
||||||
|
x: 1355,
|
||||||
|
ease: 'Cubic.Out',
|
||||||
|
duration: 1000,
|
||||||
|
onComplete: () => {
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.cassette,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 2000,
|
||||||
|
delay: 5000,
|
||||||
|
onComplete: () => {
|
||||||
|
this.cassette.x = 1655;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
export const EVENT_CONFIG = {
|
||||||
|
'time_events': {
|
||||||
|
'nightfall': {
|
||||||
|
//'start': 16, // number of minutes into the game
|
||||||
|
//'end': 19, // number of minutes into the game
|
||||||
|
'waveStart': 11,
|
||||||
|
//'waveEnd': 2,
|
||||||
|
'bossEnd': 'bossGhould',
|
||||||
|
'event': 'evNightfall', // name of event function to start
|
||||||
|
},
|
||||||
|
'zoo': {
|
||||||
|
'waveStart': 14,
|
||||||
|
'bossEnd': 'bossBollini',
|
||||||
|
'event': 'evZoo'
|
||||||
|
},
|
||||||
|
'matrix': {
|
||||||
|
'waveStart': 9,
|
||||||
|
'bossEnd': 'bossJennifer',
|
||||||
|
'event': 'evMatrix'
|
||||||
|
},
|
||||||
|
'cyber': {
|
||||||
|
'waveStart': 16,
|
||||||
|
'bossEnd': 'bossBryce',
|
||||||
|
'event': 'evCyber'
|
||||||
|
},
|
||||||
|
'hiphop': {
|
||||||
|
'waveStart': 3,
|
||||||
|
'bossEnd': 'bossCraig',
|
||||||
|
'event': 'evHipHop'
|
||||||
|
},
|
||||||
|
'princess': {
|
||||||
|
'waveStart': 18,
|
||||||
|
'bossEnd': 'bossFreya',
|
||||||
|
'event': 'evPrincess'
|
||||||
|
},
|
||||||
|
'mechaKevin': {
|
||||||
|
'waveStart': 21,
|
||||||
|
'bossEnd': 'bossMechaKevin',
|
||||||
|
'event': 'evMechaKevin'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,755 @@
|
||||||
|
import { EVENT_CONFIG } from "./eventConfig.js";
|
||||||
|
|
||||||
|
export class EventManager extends Phaser.Scene {
|
||||||
|
constructor() {
|
||||||
|
super({ key: 'EventManager', active: true });
|
||||||
|
this.schedule = {};
|
||||||
|
this.triggers = [];
|
||||||
|
this.currentEvents = [];
|
||||||
|
this.levelSceneReference = null;
|
||||||
|
this.lightningTimer = 0;
|
||||||
|
this.lightningInterval = 2000;
|
||||||
|
this.evTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
for (let i = 1; i < 10; i++) {
|
||||||
|
this.load.audio(`zoo${i}`, `assets/sounds/zoo${i}.mp3`);
|
||||||
|
}
|
||||||
|
this.load.audio('zooOclockIntro', 'assets/sounds/zooOclockIntro.mp3');
|
||||||
|
this.load.audio('lightning-1', 'assets/sounds/lightning-1.mp3');
|
||||||
|
this.load.audio('lightning-2', 'assets/sounds/lightning-2.mp3');
|
||||||
|
this.load.audio('lightning-3', 'assets/sounds/lightning-3.mp3');
|
||||||
|
this.load.audio('cyberIntro', 'assets/sounds/cyberIntro.mp3');
|
||||||
|
this.load.audio('wolfHowl', 'assets/sounds/wolfHowl.mp3');
|
||||||
|
this.load.audio('hipHop', 'assets/sounds/hipHop.mp3');
|
||||||
|
this.load.audio('hipHopBeat', 'assets/sounds/hipHopBeat.mp3');
|
||||||
|
this.load.audio('princess', 'assets/sounds/princess.mp3');
|
||||||
|
this.load.image('evNightfall', 'assets/evNightfall.png');
|
||||||
|
this.load.image('ev2Zoo', 'assets/ev2Zoo.png');
|
||||||
|
this.load.image('ev2ZooSides', 'assets/ev2ZooSides.png');
|
||||||
|
this.load.image('evMatrix', 'assets/evMatrix.png');
|
||||||
|
this.load.image('evCyber', 'assets/evCyber.png');
|
||||||
|
this.load.image('evPrincess', 'assets/evPrincess.png');
|
||||||
|
this.load.image('blueParticle', 'assets/blueParticle.png');
|
||||||
|
this.load.spritesheet('graffiti', 'assets/graffiti.png', {
|
||||||
|
frameWidth: 400,
|
||||||
|
frameHeight: 250
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
// Build the Event Schedule
|
||||||
|
Object.values(EVENT_CONFIG.time_events).forEach(event => {
|
||||||
|
if (event.start) {
|
||||||
|
const start = event.start * 60 * 1000;
|
||||||
|
this.schedule[start] = [event.event, 'start'];
|
||||||
|
}
|
||||||
|
if (event.end) {
|
||||||
|
const end = event.end * 60 * 1000;
|
||||||
|
this.schedule[end] = [event.event, 'end'];
|
||||||
|
}
|
||||||
|
if (event.waveStart) {
|
||||||
|
this.triggers.push([event.waveStart, event.event, 'start']);
|
||||||
|
}
|
||||||
|
if (event.waveEnd) {
|
||||||
|
this.triggers.push([event.waveEnd, event.event, 'end']);
|
||||||
|
}
|
||||||
|
if (event.bossEnd) {
|
||||||
|
this.triggers.push([event.bossEnd, event.event, 'end']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store reference to Level scene for later use
|
||||||
|
this.levelSceneReference = this.scene.get('Level');
|
||||||
|
this.AudioManager = this.scene.get('AudioManager');
|
||||||
|
}
|
||||||
|
|
||||||
|
waveTrigger(wave) {
|
||||||
|
this.triggers.forEach((event) => {
|
||||||
|
if (event[0] === wave) {
|
||||||
|
const eventFunction = event[1];
|
||||||
|
const eventType = event[2];
|
||||||
|
if (typeof this[eventFunction] === 'function') {
|
||||||
|
this[eventFunction](eventType);
|
||||||
|
} else {
|
||||||
|
console.log('Not A Function', eventFunction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bossEndTrigger(boss) {
|
||||||
|
this.triggers.forEach((event) => {
|
||||||
|
if (event[0] === boss) {
|
||||||
|
const eventFunction = event[1];
|
||||||
|
const eventType = event[2];
|
||||||
|
if (typeof this[eventFunction] === 'function') {
|
||||||
|
this[eventFunction](eventType);
|
||||||
|
} else {
|
||||||
|
console.log('Not A Function', eventFunction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
evMechaKevin(event = 'start') {
|
||||||
|
if (event === 'start') {
|
||||||
|
this.levelSceneReference.UI.kevinFinal();
|
||||||
|
this.time.delayedCall(500, () => {
|
||||||
|
Object.values(this.levelSceneReference.player.weapons).forEach(weapon => {
|
||||||
|
weapon.destroy();
|
||||||
|
});
|
||||||
|
this.levelSceneReference.player.weapons = {};
|
||||||
|
this.levelSceneReference.drops.children.iterate(drop => {
|
||||||
|
if (drop && drop.active) {
|
||||||
|
drop.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.levelSceneReference.enemies.children.iterate(enemy => {
|
||||||
|
if (enemy && enemy.active) {
|
||||||
|
enemy.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.levelSceneReference.bonusManager.spawnMaxedWeapons();
|
||||||
|
this.levelSceneReference.waveManager.spawnMechaKevin();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
evPrincess(event = 'start') {
|
||||||
|
let levelScene = this.levelSceneReference || this.scene.get('Level');
|
||||||
|
|
||||||
|
if (levelScene && levelScene.mainLayer && levelScene.wallsLayer) {
|
||||||
|
if (event === 'start') {
|
||||||
|
this.currentEvents.push('princess');
|
||||||
|
|
||||||
|
// Create pink particle system for princess effect
|
||||||
|
this.princessParticles = this.add.particles(0, 0, 'blueParticle', {
|
||||||
|
speed: { min: -50, max: 50 },
|
||||||
|
angle: { min: 0, max: 360 },
|
||||||
|
scale: { start: 0.5, end: 0 },
|
||||||
|
quantity: 1,
|
||||||
|
lifespan: 1000,
|
||||||
|
emitZone: { type: 'random', source: new Phaser.Geom.Rectangle(0, 0, 1600, 900) },
|
||||||
|
blendMode: 'ADD',
|
||||||
|
tint: 0xff69b4
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create sparkle effects
|
||||||
|
this.sparkles = [];
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
const sparkle = this.add.circle(
|
||||||
|
Phaser.Math.Between(0, 1600),
|
||||||
|
Phaser.Math.Between(0, 900),
|
||||||
|
Phaser.Math.Between(2, 8),
|
||||||
|
0xff69b4,
|
||||||
|
0.8
|
||||||
|
);
|
||||||
|
sparkle.setOrigin(0.5);
|
||||||
|
this.sparkles.push(sparkle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create floating hearts
|
||||||
|
this.hearts = [];
|
||||||
|
for (let i = 0; i < 15; i++) {
|
||||||
|
const heart = this.add.circle(
|
||||||
|
Phaser.Math.Between(0, 1600),
|
||||||
|
Phaser.Math.Between(0, 900),
|
||||||
|
Phaser.Math.Between(10, 20),
|
||||||
|
0xff69b4,
|
||||||
|
0.6
|
||||||
|
);
|
||||||
|
heart.setOrigin(0.5);
|
||||||
|
this.hearts.push(heart);
|
||||||
|
}
|
||||||
|
|
||||||
|
const logo = this.add.image(800, 200, 'evPrincess').setOrigin(0.5);
|
||||||
|
this.tweens.add({
|
||||||
|
targets: logo,
|
||||||
|
delay: 2000,
|
||||||
|
duration: 5000,
|
||||||
|
scale: 0,
|
||||||
|
onComplete: () => {
|
||||||
|
logo.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set princess tint
|
||||||
|
levelScene.mainLayer.setTint(0xff69b4);
|
||||||
|
levelScene.wallsLayer.setTint(0xff69b4);
|
||||||
|
|
||||||
|
// Play princess sound effect
|
||||||
|
this.AudioManager.playManagedSound('princess', 1, 1.5);
|
||||||
|
|
||||||
|
// Start particle animation
|
||||||
|
this.princessTimer = 0;
|
||||||
|
this.princessInterval = 200;
|
||||||
|
|
||||||
|
} else if (event === 'end') {
|
||||||
|
this.currentEvents = this.currentEvents.filter(e => e !== 'princess');
|
||||||
|
|
||||||
|
// Clean up princess effects
|
||||||
|
levelScene.mainLayer.setTint(0xFFFFFF);
|
||||||
|
levelScene.wallsLayer.setTint(0xFFFFFF);
|
||||||
|
|
||||||
|
if (this.princessParticles) {
|
||||||
|
this.princessParticles.destroy();
|
||||||
|
this.princessParticles = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.sparkles) {
|
||||||
|
this.sparkles.forEach(sparkle => {
|
||||||
|
sparkle.destroy();
|
||||||
|
});
|
||||||
|
this.sparkles = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hearts) {
|
||||||
|
this.hearts.forEach(heart => {
|
||||||
|
heart.destroy();
|
||||||
|
});
|
||||||
|
this.hearts = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
evHipHop(event = 'start') {
|
||||||
|
let levelScene = this.levelSceneReference || this.scene.get('Level');
|
||||||
|
|
||||||
|
if (levelScene && levelScene.mainLayer && levelScene.wallsLayer) {
|
||||||
|
if (event === 'start') {
|
||||||
|
this.currentEvents.push('hiphop');
|
||||||
|
|
||||||
|
// Create beat drop effect
|
||||||
|
this.beatDrop = this.add.rectangle(0, 0, 1600, 900, 0x000000, 0.7);
|
||||||
|
this.beatDrop.setOrigin(0);
|
||||||
|
|
||||||
|
// Create beat pulse effect
|
||||||
|
this.beatPulse = this.add.circle(800, 450, 100, 0xffffff, 0.3);
|
||||||
|
this.beatPulse.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Animate beat drop
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.beatDrop,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 300,
|
||||||
|
ease: 'Linear',
|
||||||
|
onComplete: () => {
|
||||||
|
this.beatDrop.destroy();
|
||||||
|
this.beatDrop = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Animate beat pulse
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.beatPulse,
|
||||||
|
scale: 3,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 500,
|
||||||
|
ease: 'Linear',
|
||||||
|
onComplete: () => {
|
||||||
|
this.beatPulse.destroy();
|
||||||
|
this.beatPulse = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set hip hop tint
|
||||||
|
levelScene.mainLayer.setTint(0xff6600);
|
||||||
|
levelScene.wallsLayer.setTint(0xff6600);
|
||||||
|
|
||||||
|
// Create hip hop visual elements
|
||||||
|
this.hipHopElements = [];
|
||||||
|
this.graffitiTimer = 0;
|
||||||
|
|
||||||
|
// Create beat visualization
|
||||||
|
this.beatVisualizer = [];
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
const bar = this.add.rectangle(
|
||||||
|
100 + i * 30,
|
||||||
|
800,
|
||||||
|
20,
|
||||||
|
Phaser.Math.Between(20, 100),
|
||||||
|
0x00ffff
|
||||||
|
);
|
||||||
|
bar.setOrigin(0, 1);
|
||||||
|
this.beatVisualizer.push(bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
const logo = this.add.sprite(800, 200, 'graffiti', 5).setOrigin(0.5);
|
||||||
|
this.AudioManager.playManagedSound('hipHop', 1, 1.5);
|
||||||
|
this.tweens.add({
|
||||||
|
targets: logo,
|
||||||
|
delay: 2000,
|
||||||
|
duration: 5000,
|
||||||
|
scale: 0,
|
||||||
|
onComplete: () => {
|
||||||
|
logo.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start beat animation
|
||||||
|
this.beatTimer = 0;
|
||||||
|
this.beatInterval = 200;
|
||||||
|
|
||||||
|
} else if (event === 'end') {
|
||||||
|
this.currentEvents = this.currentEvents.filter(e => e !== 'hiphop');
|
||||||
|
|
||||||
|
// Clean up hip hop effects
|
||||||
|
levelScene.mainLayer.setTint(0xFFFFFF);
|
||||||
|
levelScene.wallsLayer.setTint(0xFFFFFF);
|
||||||
|
|
||||||
|
if (this.beatDrop) {
|
||||||
|
this.beatDrop.destroy();
|
||||||
|
this.beatDrop = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.beatPulse) {
|
||||||
|
this.beatPulse.destroy();
|
||||||
|
this.beatPulse = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hipHopElements) {
|
||||||
|
this.hipHopElements.forEach(element => {
|
||||||
|
element.destroy();
|
||||||
|
});
|
||||||
|
this.hipHopElements = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.beatVisualizer) {
|
||||||
|
this.beatVisualizer.forEach(bar => {
|
||||||
|
bar.destroy();
|
||||||
|
});
|
||||||
|
this.beatVisualizer = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
evCyber(event = 'start') {
|
||||||
|
if (event === 'start') {
|
||||||
|
this.currentEvents.push('cyber');
|
||||||
|
this.createVHSEffect();
|
||||||
|
this.AudioManager.playManagedSound('cyberIntro', 1, 1);
|
||||||
|
|
||||||
|
const logo = this.add.image(800, 300, 'evCyber').setOrigin(0.5);
|
||||||
|
this.tweens.add({
|
||||||
|
targets: logo,
|
||||||
|
delay: 2000,
|
||||||
|
duration: 5000,
|
||||||
|
scale: 0,
|
||||||
|
y: 200,
|
||||||
|
onComplete: () => {
|
||||||
|
logo.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.currentEvents = this.currentEvents.filter(e => e !== 'cyber');
|
||||||
|
|
||||||
|
// Remove VHS effect
|
||||||
|
if (this.vhsOverlay) {
|
||||||
|
this.vhsOverlay.destroy();
|
||||||
|
this.vhsOverlay = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove scanlines
|
||||||
|
if (this.scanlines && this.scanlines.length > 0) {
|
||||||
|
this.scanlines.forEach(scanline => {
|
||||||
|
if (scanline && scanline.destroy) {
|
||||||
|
scanline.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.scanlines = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove color fringing effect
|
||||||
|
if (this.colorFringing) {
|
||||||
|
this.colorFringing.destroy();
|
||||||
|
this.colorFringing = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove vignette
|
||||||
|
if (this.vignette) {
|
||||||
|
this.vignette.destroy();
|
||||||
|
this.vignette = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.levelSceneReference.mainLayer.setTint(0xffffff);
|
||||||
|
this.levelSceneReference.wallsLayer.setTint(0xffffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createVHSEffect() {
|
||||||
|
// Create overlay for VHS effect
|
||||||
|
this.vhsOverlay = this.add.rectangle(0, 0, 1600, 900, 0x000000, 0.1);
|
||||||
|
this.vhsOverlay.setOrigin(0);
|
||||||
|
|
||||||
|
// Create scanlines
|
||||||
|
this.scanlines = [];
|
||||||
|
const scanlineCount = 100;
|
||||||
|
for (let i = 0; i < scanlineCount; i++) {
|
||||||
|
const scanline = this.add.rectangle(0, i * (900 / scanlineCount), 1600, 1, 0x000000, 0.1);
|
||||||
|
scanline.setOrigin(0);
|
||||||
|
this.scanlines.push(scanline);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create color fringing effect
|
||||||
|
this.colorFringing = this.add.rectangle(0, 0, 1600, 900, 0x000000, 0);
|
||||||
|
this.colorFringing.setOrigin(0);
|
||||||
|
|
||||||
|
// Create vignette
|
||||||
|
this.vignette = this.add.rectangle(0, 0, 1600, 900, 0x000000, 0.3);
|
||||||
|
this.vignette.setOrigin(0);
|
||||||
|
|
||||||
|
// Add VHS distortion effect
|
||||||
|
this.vhsDistortion = 0;
|
||||||
|
this.vhsDistortionSpeed = 0.02;
|
||||||
|
|
||||||
|
// Start VHS animation
|
||||||
|
this.vhsTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
evMatrix(event = 'start') {
|
||||||
|
let levelScene = this.levelSceneReference || this.scene.get('Level');
|
||||||
|
|
||||||
|
if (levelScene && levelScene.mainLayer && levelScene.wallsLayer) {
|
||||||
|
if (event === 'start') {
|
||||||
|
this.currentEvents.push('matrix');
|
||||||
|
|
||||||
|
const matrixImage = this.add.image(800, 200, 'evMatrix').setOrigin(0.5).setScale(2);
|
||||||
|
this.tweens.add({
|
||||||
|
targets: matrixImage,
|
||||||
|
scale: 1,
|
||||||
|
duration: 1000,
|
||||||
|
onComplete: () => {
|
||||||
|
this.AudioManager.playManagedSound('thud', 1, 2);
|
||||||
|
this.tweens.add({
|
||||||
|
targets: matrixImage,
|
||||||
|
delay: 1000,
|
||||||
|
duration: 5000,
|
||||||
|
scale: 0,
|
||||||
|
onComplete: () => {
|
||||||
|
matrixImage.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
levelScene.mainLayer.setTint(0xc3ffcd);
|
||||||
|
levelScene.wallsLayer.setTint(0xc3ffcd);
|
||||||
|
|
||||||
|
// Create matrix rain effect
|
||||||
|
this.matrixChars = [];
|
||||||
|
this.matrixSpeed = 200;
|
||||||
|
this.matrixFontSize = 16;
|
||||||
|
|
||||||
|
// Create columns of characters
|
||||||
|
const columns = Math.ceil(1600 / this.matrixFontSize);
|
||||||
|
for (let i = 0; i < columns; i++) {
|
||||||
|
const column = {
|
||||||
|
x: i * this.matrixFontSize,
|
||||||
|
y: Phaser.Math.Between(-1000, 0),
|
||||||
|
speed: Phaser.Math.Between(2, 8),
|
||||||
|
chars: []
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a random number of characters for this column
|
||||||
|
const charCount = Phaser.Math.Between(10, 30);
|
||||||
|
for (let j = 0; j < charCount; j++) {
|
||||||
|
const char = this.add.text(column.x, column.y + (j * this.matrixFontSize),
|
||||||
|
this.getRandomMatrixChar(),
|
||||||
|
{
|
||||||
|
fontSize: this.matrixFontSize + 'px',
|
||||||
|
fill: '#00ff41',
|
||||||
|
stroke: '#000000',
|
||||||
|
strokeThickness: 2
|
||||||
|
}
|
||||||
|
);
|
||||||
|
char.setAlpha(0.8);
|
||||||
|
column.chars.push(char);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.matrixChars.push(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the animation
|
||||||
|
this.matrixTimer = 0;
|
||||||
|
} else if (event === 'end') {
|
||||||
|
this.currentEvents = this.currentEvents.filter(e => e !== 'matrix');
|
||||||
|
|
||||||
|
levelScene.mainLayer.setTint(0xFFFFFF);
|
||||||
|
levelScene.wallsLayer.setTint(0xFFFFFF);
|
||||||
|
|
||||||
|
if (this.matrixChars) {
|
||||||
|
this.matrixChars.forEach(column => {
|
||||||
|
column.chars.forEach(char => {
|
||||||
|
char.destroy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
evNightfall(event = 'start') {
|
||||||
|
// Use stored reference or get it dynamically
|
||||||
|
let levelScene = this.levelSceneReference || this.scene.get('Level');
|
||||||
|
|
||||||
|
if (levelScene && levelScene.mainLayer && levelScene.wallsLayer) {
|
||||||
|
if (event === 'start') {
|
||||||
|
this.currentEvents.push('nightfall');
|
||||||
|
levelScene.mainLayer.setTint(0x2f2f69);
|
||||||
|
levelScene.wallsLayer.setTint(0x2f2f69);
|
||||||
|
const nightfallImage = this.add.image(800, 200, 'evNightfall').setOrigin(0.5);
|
||||||
|
this.AudioManager.playManagedSound('wolfHowl', 1, 1);
|
||||||
|
this.tweens.add({
|
||||||
|
targets: nightfallImage,
|
||||||
|
delay: 2000,
|
||||||
|
duration: 5000,
|
||||||
|
scale: 0,
|
||||||
|
onComplete: () => {
|
||||||
|
nightfallImage.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (event === 'end') {
|
||||||
|
this.currentEvents = this.currentEvents.filter(e => e !== 'nightfall');
|
||||||
|
levelScene.mainLayer.setTint(0xFFFFFF);
|
||||||
|
levelScene.wallsLayer.setTint(0xFFFFFF);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('Level scene or layers not found for nightfall event');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
evZoo(event = 'start') {
|
||||||
|
let levelScene = this.levelSceneReference || this.scene.get('Level');
|
||||||
|
if (event === 'start') {
|
||||||
|
this.currentEvents.push('zoo');
|
||||||
|
levelScene.mainLayer.setTint(0xffcc92);
|
||||||
|
levelScene.wallsLayer.setTint(0xffcc92);
|
||||||
|
const zooImage = this.add.image(800, 200, 'ev2Zoo').setOrigin(0.5);
|
||||||
|
this.zooSide1 = this.add.image(-108, 450, 'ev2ZooSides').setOrigin(0.5);
|
||||||
|
this.zooSide2 = this.add.image(1708, 450, 'ev2ZooSides').setOrigin(0.5);
|
||||||
|
this.AudioManager.playManagedSound('zooOclockIntro', 1, 1);
|
||||||
|
this.zooTimer = 0;
|
||||||
|
this.tweens.add({
|
||||||
|
targets: zooImage,
|
||||||
|
delay: 2000,
|
||||||
|
duration: 5000,
|
||||||
|
scale: 0,
|
||||||
|
onComplete: () => {
|
||||||
|
zooImage.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.zooSide1,
|
||||||
|
delay: 2000,
|
||||||
|
duration: 5000,
|
||||||
|
x: 0
|
||||||
|
});
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.zooSide2,
|
||||||
|
delay: 2000,
|
||||||
|
duration: 5000,
|
||||||
|
x: 1600
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (event === 'end' && this.zooSide1 && this.zooSide2) {
|
||||||
|
levelScene.mainLayer.setTint(0xFFFFFF);
|
||||||
|
levelScene.wallsLayer.setTint(0xFFFFFF);
|
||||||
|
this.currentEvents = this.currentEvents.filter(e => e !== 'zoo');
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.zooSide1,
|
||||||
|
duration: 5000,
|
||||||
|
x: -108,
|
||||||
|
onComplete: () => {
|
||||||
|
this.zooSide1.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.zooSide2,
|
||||||
|
duration: 5000,
|
||||||
|
x: 1708,
|
||||||
|
onComplete: () => {
|
||||||
|
this.zooSide2.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(time, delta) {
|
||||||
|
// Create a copy of keys to avoid modification during iteration
|
||||||
|
const scheduleKeys = Object.keys(this.schedule);
|
||||||
|
|
||||||
|
scheduleKeys.forEach(schedule => {
|
||||||
|
if (time >= parseInt(schedule)) {
|
||||||
|
const details = this.schedule[schedule];
|
||||||
|
const eventFunction = details[0];
|
||||||
|
const eventType = details[1];
|
||||||
|
delete this.schedule[schedule];
|
||||||
|
|
||||||
|
if (typeof this[eventFunction] === 'function') {
|
||||||
|
this[eventFunction](eventType);
|
||||||
|
} else {
|
||||||
|
console.log('Not A Function', eventFunction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hip hop beat animation
|
||||||
|
if (this.currentEvents.includes('hiphop') && this.beatVisualizer) {
|
||||||
|
this.beatTimer += delta;
|
||||||
|
this.graffitiTimer += delta;
|
||||||
|
if (this.beatTimer > this.beatInterval) {
|
||||||
|
this.beatTimer = 0;
|
||||||
|
|
||||||
|
// Animate beat bars
|
||||||
|
this.beatVisualizer.forEach((bar, index) => {
|
||||||
|
const height = Phaser.Math.Between(20, 100);
|
||||||
|
this.tweens.add({
|
||||||
|
targets: bar,
|
||||||
|
height: height,
|
||||||
|
duration: 100,
|
||||||
|
ease: 'Power2'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.graffitiTimer > 5000) {
|
||||||
|
this.graffitiTimer = 0;
|
||||||
|
const frame = Phaser.Math.Between(0,4);
|
||||||
|
const quadrant = Phaser.Math.Between(1,4);
|
||||||
|
const quadCords = {
|
||||||
|
1: { 'x': 400, 'y': 225 },
|
||||||
|
2: { 'x': 1200, 'y': 225 },
|
||||||
|
3: { 'x': 400, 'y': 675 },
|
||||||
|
4: { 'x': 1200, 'y': 675 }
|
||||||
|
}
|
||||||
|
const quadX = Phaser.Math.Between(-100, 100);
|
||||||
|
const quadY = Phaser.Math.Between(-100, 100);
|
||||||
|
const graffiti = this.add.sprite(quadCords[quadrant].x + quadX, quadCords[quadrant].y + quadY, 'graffiti', frame)
|
||||||
|
.setOrigin(0.5).setAlpha(0.8);
|
||||||
|
this.hipHopElements.push(graffiti);
|
||||||
|
this.AudioManager.playManagedSound('hipHopBeat', 1, 1);
|
||||||
|
this.tweens.add({
|
||||||
|
targets: graffiti,
|
||||||
|
scale: { from: 1, to: .8 },
|
||||||
|
alpha: { from: 0.8, to: 0.4 },
|
||||||
|
duration: 500,
|
||||||
|
repeat: 3,
|
||||||
|
onComplete: () => {
|
||||||
|
if (graffiti && graffiti.active) {
|
||||||
|
this.tweens.add({
|
||||||
|
targets: graffiti,
|
||||||
|
scale: { from: 1, to: .2 },
|
||||||
|
alpha: 0,
|
||||||
|
duration: 5000,
|
||||||
|
onComplete: () => {
|
||||||
|
if (graffiti && graffiti.active) {
|
||||||
|
graffiti.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VHS effect update
|
||||||
|
if (this.currentEvents.includes('cyber') && this.vhsOverlay) {
|
||||||
|
this.vhsTimer += delta;
|
||||||
|
|
||||||
|
// Animate scanlines
|
||||||
|
this.scanlines.forEach((scanline, index) => {
|
||||||
|
scanline.y = (index * (900 / 100)) + (Math.sin(this.vhsTimer * 0.005 + index * 0.1) * 5);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Animate color fringing
|
||||||
|
if (this.vhsTimer % 200 < 100) {
|
||||||
|
this.colorFringing.setFillStyle(0xff0000, 0.02);
|
||||||
|
} else {
|
||||||
|
this.colorFringing.setFillStyle(0x0000ff, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Animate VHS distortion
|
||||||
|
this.vhsDistortion = Math.sin(this.vhsTimer * 0.01) * 0.5;
|
||||||
|
|
||||||
|
// Apply distortion to main layers
|
||||||
|
if (this.levelSceneReference && this.levelSceneReference.mainLayer) {
|
||||||
|
this.levelSceneReference.mainLayer.setTint(0x00ffff);
|
||||||
|
this.levelSceneReference.wallsLayer.setTint(0x00ffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nightfall Event
|
||||||
|
if (this.currentEvents.includes('nightfall')) {
|
||||||
|
this.lightningTimer += delta;
|
||||||
|
if (this.lightningTimer >= this.lightningInterval) {
|
||||||
|
this.lightningTimer = 0;
|
||||||
|
this.lightningInterval = Phaser.Math.Between(2000,5000);
|
||||||
|
this.createLightning();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zoo O'clock
|
||||||
|
if (this.currentEvents.includes('zoo')) {
|
||||||
|
this.zooTimer += delta;
|
||||||
|
if (this.zooTimer >= 1000) {
|
||||||
|
this.zooTimer = 0;
|
||||||
|
this.AudioManager.playManagedSound(`zoo${Phaser.Math.Between(1,9)}`, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matrix effect update
|
||||||
|
if (this.currentEvents.includes('matrix') && this.matrixChars) {
|
||||||
|
this.matrixTimer += delta;
|
||||||
|
if (this.matrixTimer > this.matrixSpeed) {
|
||||||
|
this.matrixTimer = 0;
|
||||||
|
|
||||||
|
this.matrixChars.forEach(column => {
|
||||||
|
column.y += column.speed;
|
||||||
|
|
||||||
|
// Reset column if it goes off screen
|
||||||
|
if (column.y > 900) {
|
||||||
|
column.y = Phaser.Math.Between(-1000, -100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update character positions
|
||||||
|
column.chars.forEach((char, index) => {
|
||||||
|
char.y = column.y + (index * this.matrixFontSize);
|
||||||
|
char.x = column.x;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createLightning() {
|
||||||
|
let levelScene = this.levelSceneReference || this.scene.get('Level');
|
||||||
|
|
||||||
|
if (levelScene && levelScene.mainLayer && levelScene.wallsLayer) {
|
||||||
|
levelScene.mainLayer.setTint(0xFFFFFF);
|
||||||
|
levelScene.wallsLayer.setTint(0xFFFFFF);
|
||||||
|
const lightningRand = Phaser.Math.Between(1,3);
|
||||||
|
this.AudioManager.playManagedSound(`lightning-${lightningRand}`, 2, 1);
|
||||||
|
|
||||||
|
this.time.delayedCall(Phaser.Math.Between(100, 300), () => {
|
||||||
|
if (this.currentEvents.includes('nightfall')) {
|
||||||
|
levelScene.mainLayer.setTint(0x2f2f69);
|
||||||
|
levelScene.wallsLayer.setTint(0x2f2f69);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getRandomMatrixChar() {
|
||||||
|
// Matrix-style characters (Latin, numbers, symbols)
|
||||||
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$#@%&*';
|
||||||
|
return chars.charAt(Phaser.Math.Between(0, chars.length - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
import { Faction } from '../faction/factions.js';
|
||||||
|
|
||||||
|
export class Level extends Phaser.Scene {
|
||||||
|
constructor() {
|
||||||
|
super({ key: 'Level' });
|
||||||
|
this.map = 'night-woods';
|
||||||
|
this.isDragging = false;
|
||||||
|
this.dragStartX = 0;
|
||||||
|
this.dragStartY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
init(data) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
// Map Stuff
|
||||||
|
this.load.tilemapTiledJSON('map', `./assets/${this.map}.json`);
|
||||||
|
this.load.image('terrain', './assets/terrain.png');
|
||||||
|
this.load.spritesheet('dark-ages', './assets/dark-ages.png', {
|
||||||
|
frameWidth: 64,
|
||||||
|
frameHeight: 64
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
const map = this.make.tilemap({ key: 'map' });
|
||||||
|
const tiles = map.addTilesetImage('terrain', 'terrain');
|
||||||
|
this.mainLayer = map.createLayer('main', tiles, 0, 0)
|
||||||
|
this.physics.world.setBounds(0, 0, this.mainLayer.width, this.mainLayer.height);
|
||||||
|
|
||||||
|
// Add input listeners for dragging
|
||||||
|
this.input.on('pointerdown', this.onPointerDown, this);
|
||||||
|
this.input.on('pointermove', this.onPointerMove, this);
|
||||||
|
this.input.on('pointerup', this.onPointerUp, this);
|
||||||
|
|
||||||
|
this.factionLeft = this.add.group();
|
||||||
|
this.factionRight = this.add.group();
|
||||||
|
|
||||||
|
const test = new Faction(this, 4*64, 5*64, 'dark-ages', 0, 'left', 1, 'dark-ages').setOrigin(0.5);
|
||||||
|
const test2 = new Faction(this, 27*64, 4*64, 'dark-ages', 0, 'right', 1, 'dark-ages').setOrigin(0.5);
|
||||||
|
|
||||||
|
// Add collision detection
|
||||||
|
this.physics.add.overlap(this.factionLeft, this.factionRight, this.handleFactionCollision, null, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(time, delta) {
|
||||||
|
this.factionLeft.getChildren().forEach(faction => {
|
||||||
|
if (faction.update) {
|
||||||
|
faction.update(time, delta);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.factionRight.getChildren().forEach(faction => {
|
||||||
|
if (faction.update) {
|
||||||
|
faction.update(time, delta);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFactionCollision(faction1, faction2) {
|
||||||
|
// Check if factions are on opposite sides
|
||||||
|
if (faction1.side !== faction2.side) {
|
||||||
|
// Calculate distance between factions
|
||||||
|
const distance = Phaser.Math.Distance.Between(faction1.x, faction1.y, faction2.x, faction2.y);
|
||||||
|
|
||||||
|
// If within attack range
|
||||||
|
if (distance < 150) {
|
||||||
|
// Pause path following and move towards each other
|
||||||
|
faction1.pausePath();
|
||||||
|
faction2.pausePath();
|
||||||
|
|
||||||
|
// Move towards each other
|
||||||
|
const angle = Phaser.Math.Angle.Between(faction1.x, faction1.y, faction2.x, faction2.y);
|
||||||
|
const speed = 50;
|
||||||
|
|
||||||
|
faction1.body.setVelocity(
|
||||||
|
Math.cos(angle) * speed,
|
||||||
|
Math.sin(angle) * speed
|
||||||
|
);
|
||||||
|
|
||||||
|
faction2.body.setVelocity(
|
||||||
|
Math.cos(angle + Math.PI) * speed,
|
||||||
|
Math.sin(angle + Math.PI) * speed
|
||||||
|
);
|
||||||
|
|
||||||
|
// Flip sprites based on movement direction
|
||||||
|
if (faction1.body.velocity.x > 0) {
|
||||||
|
faction1.setFlipX(true);
|
||||||
|
} else {
|
||||||
|
faction1.setFlipX(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (faction2.body.velocity.x > 0) {
|
||||||
|
faction2.setFlipX(true);
|
||||||
|
} else {
|
||||||
|
faction2.setFlipX(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If they're not close enough, resume normal path following
|
||||||
|
faction1.resumePath();
|
||||||
|
faction2.resumePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPointerDown(pointer) {
|
||||||
|
this.isDragging = true;
|
||||||
|
this.dragStartX = pointer.x;
|
||||||
|
this.dragStartY = pointer.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
onPointerMove(pointer) {
|
||||||
|
if (this.isDragging) {
|
||||||
|
const deltaX = pointer.x - this.dragStartX;
|
||||||
|
const deltaY = pointer.y - this.dragStartY;
|
||||||
|
|
||||||
|
// Update camera position
|
||||||
|
this.cameras.main.scrollX -= deltaX;
|
||||||
|
this.cameras.main.scrollY -= deltaY;
|
||||||
|
|
||||||
|
// Update drag start position for next move
|
||||||
|
this.dragStartX = pointer.x;
|
||||||
|
this.dragStartY = pointer.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPointerUp(pointer) {
|
||||||
|
this.isDragging = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,328 @@
|
||||||
|
import { PLAYER_CONFIG } from '../characters/playerConfig.js';
|
||||||
|
import { WEAPONS_CONFIG } from '../characters/weaponsConfig.js';
|
||||||
|
|
||||||
|
export class Menu extends Phaser.Scene {
|
||||||
|
constructor() {
|
||||||
|
super({ key: 'Menu' });
|
||||||
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
// Player
|
||||||
|
this.load.spritesheet('players', './assets/players.png', {
|
||||||
|
frameWidth: 200,
|
||||||
|
frameHeight: 200
|
||||||
|
});
|
||||||
|
|
||||||
|
// Weapons
|
||||||
|
this.load.image('chainWallet', 'assets/weapons/chainWallet.png');
|
||||||
|
this.load.image('monster', 'assets/weapons/monster.png');
|
||||||
|
this.load.image('hobbies', 'assets/weapons/hobbies.png');
|
||||||
|
this.load.spritesheet('hobbie-sprites', 'assets/weapons/hobbie-sprites.png', {
|
||||||
|
frameWidth: 100,
|
||||||
|
frameHeight: 100
|
||||||
|
});
|
||||||
|
this.load.image('catFight', 'assets/weapons/catFight.png');
|
||||||
|
this.load.image('bread', 'assets/weapons/bread.png');
|
||||||
|
this.load.image('leftovers', 'assets/weapons/leftovers.png');
|
||||||
|
this.load.spritesheet('catFight-sprites', 'assets/weapons/catFight-sprites.png', {
|
||||||
|
frameWidth: 100,
|
||||||
|
frameHeight: 100
|
||||||
|
});
|
||||||
|
this.load.spritesheet('leftovers-sprites', 'assets/weapons/leftovers-sprites.png', {
|
||||||
|
frameWidth: 100,
|
||||||
|
frameHeight: 100
|
||||||
|
});
|
||||||
|
this.load.spritesheet('bread-sprites', 'assets/weapons/bread-sprites.png', {
|
||||||
|
frameWidth: 100,
|
||||||
|
frameHeight: 100
|
||||||
|
});
|
||||||
|
this.load.image('freezeLaunch', 'assets/weapons/freezeLaunch.png');
|
||||||
|
this.load.spritesheet('freezeLaunch-sprites', 'assets/weapons/freezeLaunch-sprites.png', {
|
||||||
|
frameWidth: 200,
|
||||||
|
frameHeight: 100
|
||||||
|
});
|
||||||
|
this.load.image('pickles', 'assets/weapons/pickles.png');
|
||||||
|
this.load.image('pickleCloud1', 'assets/weapons/pickleCloud1.png');
|
||||||
|
this.load.image('pickleCloud2', 'assets/weapons/pickleCloud2.png');
|
||||||
|
this.load.image('banana', 'assets/weapons/banana.png');
|
||||||
|
this.load.spritesheet('banana-sprites', 'assets/weapons/banana-sprites.png', {
|
||||||
|
frameWidth: 100,
|
||||||
|
frameHeight: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
// Items
|
||||||
|
this.load.spritesheet('items', './assets/items.png', {
|
||||||
|
frameWidth: 100,
|
||||||
|
frameHeight: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
// Menu
|
||||||
|
this.load.image('menuLogo', 'assets/menuLogo.png');
|
||||||
|
this.load.font('Bitwise', 'assets/Bitwise.ttf');
|
||||||
|
this.load.video('menuVideo', 'assets/menuVideo.mp4');
|
||||||
|
this.load.audio('menuMusic', 'assets/menuMusic.mp3');
|
||||||
|
this.load.audio('menuInterface', 'assets/sounds/menuInterface.mp3');
|
||||||
|
this.load.audio('menuInterfaceUp', 'assets/sounds/menuInterfaceUp.mp3');
|
||||||
|
this.load.audio('select', 'assets/sounds/select.mp3');
|
||||||
|
this.load.image('menuKevin', 'assets/menuKevin.png');
|
||||||
|
this.load.image('menuPanel', 'assets/menuPanel.png');
|
||||||
|
this.load.image('arrow', 'assets/arrow.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
// Create video sprite that fills the screen
|
||||||
|
const video = this.add.video(0, 0, 'menuVideo');
|
||||||
|
video.setOrigin(0);
|
||||||
|
video.setScale(this.game.config.width / 848, this.game.config.height / 480);
|
||||||
|
video.setDepth(-1);
|
||||||
|
video.play(true);
|
||||||
|
|
||||||
|
// Create audio and play in a loop
|
||||||
|
this.bgMusic = this.sound.add('menuMusic');
|
||||||
|
this.bgMusic.loop = true;
|
||||||
|
this.bgMusic.play();
|
||||||
|
|
||||||
|
this.menuLogo = this.add.image(800, 350, 'menuLogo').setOrigin(0.5);
|
||||||
|
|
||||||
|
// Add start text
|
||||||
|
this.startPanel = this.add.image(500, 750, 'menuPanel').setOrigin(0.5).setInteractive();
|
||||||
|
this.startText = this.add.text(500, 750, 'Click Here to Start', {
|
||||||
|
fontSize: '32px',
|
||||||
|
fontFamily: 'Bitwise',
|
||||||
|
fill: '#ffffff',
|
||||||
|
align: 'center'
|
||||||
|
}).setOrigin(0.5);
|
||||||
|
|
||||||
|
// Add fullscreen text
|
||||||
|
this.fsPanel = this.add.image(1100, 750, 'menuPanel').setOrigin(0.5).setInteractive();
|
||||||
|
this.fullscreenText = this.add.text(1100, 750, 'Toggle Fullscreen', {
|
||||||
|
fontSize: '32px',
|
||||||
|
fontFamily: 'Bitwise',
|
||||||
|
fill: '#f6ff78ff',
|
||||||
|
align: 'center'
|
||||||
|
}).setOrigin(0.5);
|
||||||
|
|
||||||
|
// Add fullscreen functionality
|
||||||
|
this.fsPanel.on('pointerdown', () => {
|
||||||
|
if (this.scale.isFullscreen) {
|
||||||
|
this.scale.stopFullscreen();
|
||||||
|
} else {
|
||||||
|
this.scale.startFullscreen();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.fsPanel.on('pointerover', () => {
|
||||||
|
this.tweens.add({
|
||||||
|
targets: [this.fsPanel, this.fullscreenText],
|
||||||
|
scale: 1.1,
|
||||||
|
y: 730,
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.fsPanel.on('pointerout', () => {
|
||||||
|
this.tweens.add({
|
||||||
|
targets: [this.fsPanel, this.fullscreenText],
|
||||||
|
scale: 1,
|
||||||
|
y: 750,
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.characters = this.add.container();
|
||||||
|
this.menuBackground = this.add.rectangle(1000, 450, 1200, 800, 0xFFFFFF, 0.5).setOrigin(0.5);
|
||||||
|
this.menuCharacterText = this.add.text(425, 75, 'Choose Your Character', {
|
||||||
|
fontSize: '32px',
|
||||||
|
fontFamily: 'Bitwise',
|
||||||
|
fill: '#00a2ffff',
|
||||||
|
stroke: '#005e94ff',
|
||||||
|
align: 'left',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 2,
|
||||||
|
offsetY: 2,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 4,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.characters.add(this.menuBackground);
|
||||||
|
this.characters.add(this.menuCharacterText);
|
||||||
|
|
||||||
|
let i = 1;
|
||||||
|
let charX = 0;
|
||||||
|
let charY = 0;
|
||||||
|
Object.entries(PLAYER_CONFIG).forEach(([key, character]) => {
|
||||||
|
if (key === 'base') return;
|
||||||
|
|
||||||
|
const charContainer = this.add.container(425 + charX, 125 + charY);
|
||||||
|
const charBox = this.add.rectangle(0, 0, 370, 225, 0x000000, 0.6).setOrigin(0).setInteractive();
|
||||||
|
// Add hover effect
|
||||||
|
charBox.on('pointerover', () => {
|
||||||
|
charBox.setFillStyle(0x555555, 0.9);
|
||||||
|
});
|
||||||
|
|
||||||
|
charBox.on('pointerout', () => {
|
||||||
|
charBox.setFillStyle(0x333333, 0.9);
|
||||||
|
});
|
||||||
|
charBox.on('pointerdown', () => {
|
||||||
|
this.bgMusic.stop();
|
||||||
|
this.cameras.main.fadeOut();
|
||||||
|
this.sound.play('select');
|
||||||
|
this.time.delayedCall(1000, () => {
|
||||||
|
//this.sound.play('menuInterface');
|
||||||
|
this.scene.start('Level', {
|
||||||
|
character: key
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const charImage = this.add.sprite(-30, 12.5, character.texture, character.frame).setOrigin(0);
|
||||||
|
const charWeapon = this.add.image(80, 115, character.weapon).setOrigin(0).setDisplaySize(100, 100);
|
||||||
|
charWeapon.postFX.addGlow(0xff3c00);
|
||||||
|
const charName = this.add.text(130, 10, character.name, {
|
||||||
|
fontSize: '36px',
|
||||||
|
fontFamily: 'Bitwise',
|
||||||
|
fill: '#fffb00ff',
|
||||||
|
stroke: '#919400ff',
|
||||||
|
align: 'left',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 2,
|
||||||
|
offsetY: 2,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 4,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const charLikes = this.add.text(130, 60, `Likes:\n${character.likes}`, {
|
||||||
|
fontSize: '20px',
|
||||||
|
fontFamily: 'Bitwise',
|
||||||
|
fill: '#ffffffff',
|
||||||
|
stroke: '#2e2e2eff',
|
||||||
|
align: 'left',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 2,
|
||||||
|
offsetY: 2,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 4,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const charWeaponTitle = this.add.text(190, 110, 'Starting Weapon:', {
|
||||||
|
fontSize: '20px',
|
||||||
|
fontFamily: 'Bitwise',
|
||||||
|
fill: '#ff3c00',
|
||||||
|
stroke: '#8f2100ff',
|
||||||
|
align: 'left',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 2,
|
||||||
|
offsetY: 2,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 4,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const charWeaponInfo = this.add.text(190, 140, `${WEAPONS_CONFIG[character.weapon].info.name}`, {
|
||||||
|
fontSize: '20px',
|
||||||
|
fontFamily: 'Bitwise',
|
||||||
|
fill: '#ffffffff',
|
||||||
|
stroke: '#2e2e2eff',
|
||||||
|
align: 'left',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 2,
|
||||||
|
offsetY: 2,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 4,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const charWeaponInfo2 = this.add.text(190, 160, `${WEAPONS_CONFIG[character.weapon].info.desc}`, {
|
||||||
|
fontSize: '16px',
|
||||||
|
fontFamily: 'Bitwise',
|
||||||
|
fill: '#ffffffff',
|
||||||
|
stroke: '#2e2e2eff',
|
||||||
|
align: 'left',
|
||||||
|
strokeThickness: 2,
|
||||||
|
shadow: {
|
||||||
|
offsetX: 2,
|
||||||
|
offsetY: 2,
|
||||||
|
color: '#000000',
|
||||||
|
blur: 4,
|
||||||
|
fill: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
charContainer.add(charBox);
|
||||||
|
charContainer.add(charImage);
|
||||||
|
charContainer.add(charWeapon);
|
||||||
|
charContainer.add(charName);
|
||||||
|
charContainer.add(charLikes);
|
||||||
|
charContainer.add(charWeaponTitle);
|
||||||
|
charContainer.add(charWeaponInfo);
|
||||||
|
charContainer.add(charWeaponInfo2);
|
||||||
|
this.characters.add(charContainer);
|
||||||
|
charX += 390;
|
||||||
|
if (i % 3 === 0) {
|
||||||
|
charY += 245;
|
||||||
|
charX = 0;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
this.characters.y = 1000;
|
||||||
|
|
||||||
|
this.kevinMenu = this.add.image(-250, 550, 'menuKevin').setOrigin(0.5, 0.5).setScale(.8).setFlipX(true);
|
||||||
|
|
||||||
|
this.startPanel.on('pointerdown', () => {
|
||||||
|
this.sound.play('menuInterface');
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.kevinMenu,
|
||||||
|
x: 200,
|
||||||
|
duration: 2000,
|
||||||
|
scale: .5,
|
||||||
|
ease: 'Cubic.Out'
|
||||||
|
});
|
||||||
|
this.tweens.add({
|
||||||
|
targets: [this.startText, this.fullscreenText, this.startPanel, this.fsPanel],
|
||||||
|
alpha: 0,
|
||||||
|
duration: 1000,
|
||||||
|
onComplete: () => {
|
||||||
|
this.startText.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.menuLogo,
|
||||||
|
scale: .3,
|
||||||
|
x: 200,
|
||||||
|
y: 140,
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
this.tweens.add({
|
||||||
|
targets: this.characters,
|
||||||
|
y: 0,
|
||||||
|
delay: 500,
|
||||||
|
ease: 'Cubic.Out',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.startPanel.on('pointerover', () => {
|
||||||
|
this.tweens.add({
|
||||||
|
targets: [this.startPanel, this.startText],
|
||||||
|
scale: 1.1,
|
||||||
|
y: 730,
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.startPanel.on('pointerout', () => {
|
||||||
|
this.tweens.add({
|
||||||
|
targets: [this.startPanel, this.startText],
|
||||||
|
scale: 1,
|
||||||
|
y: 750,
|
||||||
|
duration: 200
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
update(time, delta) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1 @@
|
||||||
|
python -m http.server 8000
|
||||||
Loading…
Reference in New Issue