feat: Implement basic level 1 with tilemap, enemies, pathfinding and wave system
- Added level 1 assets (tilemap, terrain, enemy sprites) - Implemented Level1 scene with tilemap loading and collision detection - Integrated EasyStar.js for enemy pathfinding between spawn and end points - Created wave manager system to handle enemy spawning schedules - Added basic enemy configuration and animation support - Set up game structure with Phaser 3 framework - Added web server startup script for local development This commit establishes the foundational level 1 gameplay including map rendering, collision detection, enemy spawning mechanics, and pathfinding behavior using EasyStar.js for AI movement.
This commit is contained in:
commit
9bf0b55f33
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -0,0 +1,111 @@
|
|||
{ "compressionlevel":-1,
|
||||
"height":9,
|
||||
"infinite":true,
|
||||
"layers":[
|
||||
{
|
||||
"chunks":[
|
||||
{
|
||||
"data":[2, 1, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 1, 2, 1, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 1, 1, 1, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 2, 2, 2, 2, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"height":16,
|
||||
"width":16,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"height":16,
|
||||
"id":1,
|
||||
"name":"main",
|
||||
"opacity":1,
|
||||
"startx":0,
|
||||
"starty":0,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":16,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"chunks":[
|
||||
{
|
||||
"data":[0, 0, 16, 0, 16, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 16, 16, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"height":16,
|
||||
"width":16,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"height":16,
|
||||
"id":2,
|
||||
"name":"platforms",
|
||||
"opacity":1,
|
||||
"startx":0,
|
||||
"starty":0,
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":16,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":3,
|
||||
"nextobjectid":1,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"1.11.2",
|
||||
"tileheight":200,
|
||||
"tilesets":[
|
||||
{
|
||||
"columns":5,
|
||||
"firstgid":1,
|
||||
"image":"terrain.png",
|
||||
"imageheight":1000,
|
||||
"imagewidth":1000,
|
||||
"margin":0,
|
||||
"name":"terrain",
|
||||
"spacing":0,
|
||||
"tilecount":25,
|
||||
"tileheight":200,
|
||||
"tiles":[
|
||||
{
|
||||
"id":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"collides",
|
||||
"type":"bool",
|
||||
"value":true
|
||||
}]
|
||||
}],
|
||||
"tilewidth":200
|
||||
}],
|
||||
"tilewidth":200,
|
||||
"type":"map",
|
||||
"version":"1.10",
|
||||
"width":16
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 213 KiB |
Binary file not shown.
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.11.2" orientation="orthogonal" renderorder="right-down" width="16" height="9" tilewidth="200" tileheight="200" infinite="1" nextlayerid="3" nextobjectid="1">
|
||||
<editorsettings>
|
||||
<export target="../level1.json" format="json"/>
|
||||
</editorsettings>
|
||||
<tileset firstgid="1" name="terrain" tilewidth="200" tileheight="200" tilecount="25" columns="5">
|
||||
<image source="../terrain.png" width="1000" height="1000"/>
|
||||
<tile id="1">
|
||||
<properties>
|
||||
<property name="collides" type="bool" value="true"/>
|
||||
</properties>
|
||||
</tile>
|
||||
</tileset>
|
||||
<layer id="1" name="main" width="16" height="9">
|
||||
<data encoding="csv">
|
||||
<chunk x="0" y="0" width="16" height="16">
|
||||
2,1,2,2,2,2,2,2,0,0,0,0,0,0,0,0,
|
||||
2,1,2,1,1,1,2,2,0,0,0,0,0,0,0,0,
|
||||
2,1,1,1,2,1,1,2,0,0,0,0,0,0,0,0,
|
||||
2,2,2,2,2,2,1,2,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</chunk>
|
||||
</data>
|
||||
</layer>
|
||||
<layer id="2" name="platforms" width="16" height="9">
|
||||
<data encoding="csv">
|
||||
<chunk x="0" y="0" width="16" height="16">
|
||||
0,0,16,0,16,0,16,0,0,0,0,0,0,0,0,0,
|
||||
0,0,16,0,0,0,16,0,0,0,0,0,0,0,0,0,
|
||||
16,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,16,16,0,16,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</chunk>
|
||||
</data>
|
||||
</layer>
|
||||
</map>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Alien Rush</title>
|
||||
<style>
|
||||
body { margin: 0; background-color: black; }
|
||||
canvas { display: block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="game-container"></div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/phaser@v3.90.0/dist/phaser.min.js"></script>
|
||||
<script src="./src/EasyStar.js"></script>
|
||||
<script type="module" src="./src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,60 @@
|
|||
import { WaveManager } from '../support/waveManager.js';
|
||||
|
||||
export class Level1 extends Phaser.Scene {
|
||||
constructor() {
|
||||
super({ key: 'Level1' });
|
||||
}
|
||||
|
||||
init(data) {
|
||||
|
||||
}
|
||||
|
||||
preload() {
|
||||
this.load.tilemapTiledJSON('level1', 'assets/level1.json');
|
||||
this.load.image('terrain', 'assets/terrain.png');
|
||||
this.load.spritesheet('basic-enemies', 'assets/basic-enemies.png', {
|
||||
frameWidth: 50,
|
||||
frameHeight: 50
|
||||
});
|
||||
}
|
||||
|
||||
create() {
|
||||
this.levelMap = this.make.tilemap({ key: 'level1' });
|
||||
const terrainTiles = this.levelMap.addTilesetImage('terrain', 'terrain');
|
||||
this.mainLayer = this.levelMap.createLayer('main', terrainTiles)
|
||||
.setCollisionByProperty({ collides: true });
|
||||
this.platformsLayer = this.levelMap.createLayer('platforms', terrainTiles);
|
||||
|
||||
this.waveManager = new WaveManager(this, 1, 1);
|
||||
|
||||
this.enemies = this.physics.add.group();
|
||||
|
||||
this.physics.add.collider(this.enemies, this.mainLayer);
|
||||
this.physics.add.collider(this.enemies, this.platformsLayer);
|
||||
}
|
||||
|
||||
moveJoshAlongPath(path) {
|
||||
let currentIndex = 0;
|
||||
|
||||
const moveNextStep = () => {
|
||||
if (currentIndex >= path.length - 1) return; // Reached target
|
||||
|
||||
const nextPoint = path[++currentIndex];
|
||||
|
||||
// Move josh to the next point
|
||||
this.tweens.add({
|
||||
targets: this.josh,
|
||||
x: nextPoint.x * 200 + 100,
|
||||
y: nextPoint.y * 200 + 100,
|
||||
duration: 2000,
|
||||
onComplete: moveNextStep
|
||||
});
|
||||
};
|
||||
|
||||
moveNextStep();
|
||||
}
|
||||
|
||||
update(time, delta) {
|
||||
this.waveManager.update(time, delta);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import { Level1 } from './levels/level1.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: [
|
||||
Level1
|
||||
],
|
||||
physics: {
|
||||
default: 'arcade',
|
||||
arcade: {
|
||||
gravity: { y: 0 },
|
||||
debug: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Create the game instance
|
||||
const game = new Phaser.Game(GAME_CONFIG);
|
||||
|
||||
console.log('Alien Rush game initialized successfully!');
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
import { ENEMIES_CONFIG } from "./enemiesConfig.js";
|
||||
|
||||
export class Enemies {
|
||||
|
||||
constructor(scene, type, x, y, path) {
|
||||
this.scene = scene;
|
||||
this.type = type;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.path = path;
|
||||
this.spread = ENEMIES_CONFIG[type].spread;
|
||||
this.speedLow = ENEMIES_CONFIG[type].speedLow;
|
||||
this.speedHigh = ENEMIES_CONFIG[type].speedHigh;
|
||||
this.baseSprite = ENEMIES_CONFIG[type].spriteStart;
|
||||
|
||||
this.spawnEnemy();
|
||||
}
|
||||
|
||||
spawnEnemy() {
|
||||
const randX = Phaser.Math.Between(-this.spread, this.spread);
|
||||
const randY = Phaser.Math.Between(-this.spread, this.spread);
|
||||
const randSpeed = Phaser.Math.Between(this.speedLow, this.speedHigh);
|
||||
const spawnX = (this.x * 200) + 100 + randX;
|
||||
const spawnY = (this.y * 200) + 100 + randY;
|
||||
|
||||
// Create enemy and store reference
|
||||
const enemy = this.scene.add.sprite(spawnX, spawnY, ENEMIES_CONFIG[this.type].spriteSheet, ENEMIES_CONFIG[this.type].spriteStart);
|
||||
|
||||
// Create Animations
|
||||
this.createAnim('side', ENEMIES_CONFIG[this.type].spriteStart, ENEMIES_CONFIG[this.type].spriteStart+2);
|
||||
this.createAnim('up', ENEMIES_CONFIG[this.type].spriteStart+6, ENEMIES_CONFIG[this.type].spriteStart+7);
|
||||
this.createAnim('down', ENEMIES_CONFIG[this.type].spriteStart+3, ENEMIES_CONFIG[this.type].spriteStart+5);
|
||||
this.createAnim('die', ENEMIES_CONFIG[this.type].spriteStart+8, ENEMIES_CONFIG[this.type].spriteStart+9, 0);
|
||||
|
||||
enemy.props = {
|
||||
'offsetX': randX,
|
||||
'offsetY': randY,
|
||||
'path': this.path,
|
||||
'pathPhase': 0,
|
||||
'speed': randSpeed,
|
||||
'health': ENEMIES_CONFIG[this.type].health,
|
||||
'type': this.type
|
||||
};
|
||||
|
||||
this.scene.enemies.add(enemy);
|
||||
|
||||
enemy.play(`${this.type}-side`);
|
||||
}
|
||||
|
||||
createAnim(type, start, end, repeat = -1) {
|
||||
if (!this.scene.anims.get(`${this.type}-${type}`)) {
|
||||
this.scene.anims.create({
|
||||
key: `${this.type}-${type}`,
|
||||
frames: this.scene.anims.generateFrameNumbers(ENEMIES_CONFIG[this.type].spriteSheet, {
|
||||
start: start,
|
||||
end: end,
|
||||
}),
|
||||
frameRate: 5,
|
||||
repeat: repeat
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
export const ENEMIES_CONFIG = {
|
||||
'basic1': {
|
||||
'spread': 25,
|
||||
'health': 100,
|
||||
'speedLow': 25,
|
||||
'speedHigh': 35,
|
||||
'spriteStart': 0,
|
||||
'spriteSheet': 'basic-enemies'
|
||||
},
|
||||
'basic2': {
|
||||
'spread': 0,
|
||||
'health': 300,
|
||||
'speedLow': 45,
|
||||
'speedHigh': 55,
|
||||
'spriteStart': 0,
|
||||
'spriteSheet': 'basic-enemies'
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
export const WAVE_CONFIG = {
|
||||
// Level
|
||||
1: {
|
||||
//Spawn Point
|
||||
spawnX: 1,
|
||||
spawnY: 0,
|
||||
endX: 6,
|
||||
endY: 3,
|
||||
// Wave
|
||||
1: {
|
||||
// Schedule
|
||||
1: {
|
||||
begin: 0,
|
||||
basic1: 5
|
||||
},
|
||||
2: {
|
||||
begin: 15,
|
||||
basic1: 1
|
||||
},
|
||||
3: {
|
||||
begin: 30,
|
||||
basic1: 5
|
||||
}
|
||||
},
|
||||
// Wave
|
||||
2: {
|
||||
// Schedule
|
||||
1: {
|
||||
begin: 0,
|
||||
basic1: 5
|
||||
},
|
||||
2: {
|
||||
begin: 15,
|
||||
basic1: 5
|
||||
},
|
||||
3: {
|
||||
begin: 30,
|
||||
basic1: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
import { WAVE_CONFIG } from './waveConfig.js'
|
||||
import { Enemies } from './enemies.js'
|
||||
|
||||
export class WaveManager {
|
||||
|
||||
constructor(scene, level, wave) {
|
||||
this.scene = scene;
|
||||
this.level = level;
|
||||
this.wave = wave;
|
||||
this.schedule = 0;
|
||||
this.scheduleInfo = null;
|
||||
this.spawnX = WAVE_CONFIG[this.level].spawnX;
|
||||
this.spawnY = WAVE_CONFIG[this.level].spawnY;
|
||||
this.endX = WAVE_CONFIG[this.level].endX;
|
||||
this.endY = WAVE_CONFIG[this.level].endY;
|
||||
this.path = null;
|
||||
|
||||
this.waveTimer = 0;
|
||||
this.waveScheduleStartTime();
|
||||
}
|
||||
|
||||
waveScheduleStartTime() {
|
||||
this.schedule++;
|
||||
this.scheduleInfo = WAVE_CONFIG[this.level][this.wave][this.schedule]
|
||||
this.waveStart = this.scheduleInfo.begin * 1000;
|
||||
}
|
||||
|
||||
nextWave() {
|
||||
this.wave++;
|
||||
this.waveTimer = 0;
|
||||
this.schedule = 0;
|
||||
this.waveScheduleStartTime();
|
||||
}
|
||||
|
||||
gridToLocation(num, offset = 0) {
|
||||
return num * 200 + 100 + offset;
|
||||
}
|
||||
|
||||
update(time, delta) {
|
||||
this.waveTimer += delta;
|
||||
|
||||
// Handle Enemy Pathing
|
||||
this.scene.enemies.children.iterate((enemy) => {
|
||||
const path = enemy.props.path;
|
||||
const pathPhase = enemy.props.pathPhase;
|
||||
const speed = enemy.props.speed;
|
||||
const offsetX = enemy.props.offsetX;
|
||||
const offsetY = enemy.props.offsetY;
|
||||
|
||||
// Only move if we have a valid path and pathPhase
|
||||
if (path && pathPhase !== undefined) {
|
||||
// Calculate movement for this frame
|
||||
const segmentSpeed = speed; // Normalize by delta time
|
||||
|
||||
// Get current and next points in the path
|
||||
const currentPoint = path[pathPhase];
|
||||
const nextPoint = path[pathPhase + 1];
|
||||
|
||||
if (currentPoint && nextPoint) {
|
||||
// Calculate direction vector from current to next point
|
||||
const dx = this.gridToLocation(nextPoint.x, offsetX) - this.gridToLocation(currentPoint.x, offsetX);
|
||||
const dy = this.gridToLocation(nextPoint.y, offsetY) - this.gridToLocation(currentPoint.y, offsetY);
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
// Normalize the direction
|
||||
if (distance > 0) {
|
||||
const normalizedDx = dx / distance;
|
||||
const normalizedDy = dy / distance;
|
||||
|
||||
const velocX = normalizedDx * segmentSpeed;
|
||||
const velocY = normalizedDy * segmentSpeed;
|
||||
// Move towards next point
|
||||
enemy.body.setVelocity(velocX, velocY);
|
||||
|
||||
if (Math.abs(velocY) > Math.abs(velocX)) {
|
||||
if (velocY > 0) {
|
||||
enemy.play(`${enemy.props.type}-down`, true);
|
||||
} else {
|
||||
enemy.play(`${enemy.props.type}-up`, true);
|
||||
}
|
||||
} else {
|
||||
if (velocX > 0) {
|
||||
enemy.play(`${enemy.props.type}-side`, true);
|
||||
enemy.setFlipX(true);
|
||||
} else {
|
||||
enemy.play(`${enemy.props.type}-side`, true);
|
||||
enemy.setFlipX(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we've reached the next point
|
||||
const distToNextPoint = Math.sqrt(
|
||||
Math.pow(enemy.x - this.gridToLocation(nextPoint.x, offsetX), 2) +
|
||||
Math.pow(enemy.y - this.gridToLocation(nextPoint.y, offsetY), 2)
|
||||
);
|
||||
|
||||
if (distToNextPoint < segmentSpeed * 0.5) { // Threshold for reaching point
|
||||
enemy.props.pathPhase++; // Move to next path segment
|
||||
|
||||
// If we've reached the end of the path, remove the enemy or handle accordingly
|
||||
if (enemy.props.pathPhase >= path.length - 1) {
|
||||
// Enemy reached destination - you might want to handle this differently
|
||||
enemy.body.setVelocity(0, 0);
|
||||
// Remove enemy from scene or mark for removal
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We're at the last point in the path
|
||||
enemy.body.setVelocity(0, 0);
|
||||
}
|
||||
} else if (currentPoint && !nextPoint) {
|
||||
// Last point in path - stop moving
|
||||
enemy.body.setVelocity(0, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle Waves and Schedules
|
||||
if (this.waveTimer >= this.waveStart) {
|
||||
console.log('Wave',this.wave,'Schedule',this.schedule);
|
||||
// Make path synchronous
|
||||
this.makePath().then(() => {
|
||||
// Spawn enemies after path is ready
|
||||
this.spawnSchedule();
|
||||
|
||||
if (WAVE_CONFIG[this.level][this.wave].hasOwnProperty(this.schedule + 1)) {
|
||||
this.waveScheduleStartTime();
|
||||
} else if (WAVE_CONFIG[this.level].hasOwnProperty(this.wave+1)) {
|
||||
this.nextWave();
|
||||
} else {
|
||||
console.log('LEVEL COMPLETE');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
spawnSchedule() {
|
||||
if (this.scheduleInfo.hasOwnProperty('basic1')) {
|
||||
console.log('Spawn',this.scheduleInfo.basic1,'Basic1 enemies');
|
||||
for (let e = 0; e < this.scheduleInfo.basic1; e++) {
|
||||
const enemy = new Enemies(this.scene, 'basic1', this.spawnX, this.spawnY, this.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
makePath() {
|
||||
return new Promise((resolve) => {
|
||||
this.easyStar = new EasyStar.js();
|
||||
|
||||
// Set up the grid for pathfinding
|
||||
const width = this.scene.levelMap.width;
|
||||
const height = this.scene.levelMap.height;
|
||||
const grid = [];
|
||||
|
||||
// Create a grid based on collision data
|
||||
for (let y = 0; y < height; y++) {
|
||||
grid[y] = [];
|
||||
for (let x = 0; x < width; x++) {
|
||||
// Check if the tile at this position is colliding
|
||||
const tile = this.scene.mainLayer.getTileAt(x, y);
|
||||
if (tile && tile.properties.collides) {
|
||||
grid[y][x] = 1; // Blocked
|
||||
} else {
|
||||
grid[y][x] = 0; // Free space
|
||||
}
|
||||
}
|
||||
}
|
||||
this.easyStar.setGrid(grid);
|
||||
|
||||
this.easyStar.setAcceptableTiles([0]); // Only allow movement on tiles with value 0
|
||||
|
||||
this.easyStar.findPath(
|
||||
this.spawnX,
|
||||
this.spawnY,
|
||||
this.endX,
|
||||
this.endY,
|
||||
(path) => {
|
||||
if (path === null) {
|
||||
console.log("No path found");
|
||||
this.path = null;
|
||||
} else {
|
||||
this.path = path;
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
|
||||
this.easyStar.calculate();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
python -m http.server 8000
|
||||
Loading…
Reference in New Issue