diff --git a/.vscode/launch.json b/.vscode/launch.json index 925af83..a5fdd85 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,14 +4,14 @@ "configurations": [ { "name": "ng serve", - "type": "chrome", + "type": "firefox", "request": "launch", "preLaunchTask": "npm: start", "url": "http://localhost:4200/" }, { "name": "ng test", - "type": "chrome", + "type": "firefox", "request": "launch", "preLaunchTask": "npm: test", "url": "http://localhost:9876/debug.html" diff --git a/angular.json b/angular.json index 82daac1..09c3703 100644 --- a/angular.json +++ b/angular.json @@ -1,96 +1,83 @@ { - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "HexTowerDefense": { - "projectType": "application", - "schematics": {}, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:application", - "options": { - "outputPath": "dist/hex-tower-defense", - "index": "src/index.html", - "browser": "src/main.ts", - "polyfills": [ - "zone.js" - ], - "tsConfig": "tsconfig.app.json", - "assets": [ - { - "glob": "**/*", - "input": "public" - } - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kB", - "maximumError": "1MB" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "4kB", - "maximumError": "8kB" - } + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "HexTowerDefense": { + "projectType": "application", + "schematics": {}, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:application", + "options": { + "outputPath": "dist/hex-tower-defense", + "index": "src/index.html", + "browser": "src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "tsconfig.app.json", + "assets": [ + "src/assets", + "src/favicon.ico" ], - "outputHashing": "all" + "styles": ["src/styles.css"], + "scripts": [] }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "HexTowerDefense:build:production" - }, - "development": { - "buildTarget": "HexTowerDefense:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n" - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "polyfills": [ - "zone.js", - "zone.js/testing" - ], - "tsConfig": "tsconfig.spec.json", - "assets": [ - { - "glob": "**/*", - "input": "public" + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kB", + "maximumError": "1MB" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kB", + "maximumError": "8kB" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true } - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "HexTowerDefense:build:production" + }, + "development": { + "buildTarget": "HexTowerDefense:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "polyfills": ["zone.js", "zone.js/testing"], + "tsConfig": "tsconfig.spec.json", + "assets": [ + "src/assets", + "src/favicon.ico" + ], + "styles": ["src/styles.css"], + "scripts": [] + } } } } } - } -} + } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index fd71f4b..2e3cbc9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "hex-tower-defense", "version": "0.0.0", "dependencies": { + "@angular/animations": "^19.2.9", "@angular/common": "^19.2.0", "@angular/compiler": "^19.2.0", "@angular/core": "^19.2.0", @@ -306,6 +307,22 @@ "tslib": "^2.1.0" } }, + "node_modules/@angular/animations": { + "version": "19.2.9", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-19.2.9.tgz", + "integrity": "sha512-Xg/JD8GyeUpBwno51iuK/iJnbSVc6A+THyP+2ScNVdWFdLyuCiEr9EbIHdeGDnhK1f/MVjRKbkrN6OElkxCx8A==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/common": "19.2.9", + "@angular/core": "19.2.9" + } + }, "node_modules/@angular/build": { "version": "19.2.10", "resolved": "https://registry.npmjs.org/@angular/build/-/build-19.2.10.tgz", diff --git a/package.json b/package.json index 5ecec6b..808f1b2 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,15 @@ "version": "0.0.0", "scripts": { "ng": "ng", - "start": "ng serve", - "build": "ng build", - "watch": "ng build --watch --configuration development", - "test": "ng test" + "prebuild": "node tools/generateAssetManifest.js", + "start": "npm run prebuild && ng serve", + "build": "npm run prebuild && ng build", + "watch": "npm run prebuild && ng build --watch --configuration development", + "test": "npm run prebuild && ng test" }, "private": true, "dependencies": { + "@angular/animations": "^19.2.9", "@angular/common": "^19.2.0", "@angular/compiler": "^19.2.0", "@angular/core": "^19.2.0", diff --git a/src/.prettierrc b/src/.prettierrc new file mode 100644 index 0000000..dfcc0e9 --- /dev/null +++ b/src/.prettierrc @@ -0,0 +1,4 @@ +{ + "tabWidth": 4, + "useTabs": true +} diff --git a/src/app/app.component.html b/src/app/app.component.html deleted file mode 100644 index 36093e1..0000000 --- a/src/app/app.component.html +++ /dev/null @@ -1,336 +0,0 @@ - - - - - - - - - - - -
-
-
- -

Hello, {{ title }}

-

Congratulations! Your app is running. 🎉

-
- -
-
- @for (item of [ - { title: 'Explore the Docs', link: 'https://angular.dev' }, - { title: 'Learn with Tutorials', link: 'https://angular.dev/tutorials' }, - { title: 'CLI Docs', link: 'https://angular.dev/tools/cli' }, - { title: 'Angular Language Service', link: 'https://angular.dev/tools/language-service' }, - { title: 'Angular DevTools', link: 'https://angular.dev/tools/devtools' }, - ]; track item.title) { - - {{ item.title }} - - - - - } -
- -
-
-
- - - - - - - - - - - diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts deleted file mode 100644 index fc81f81..0000000 --- a/src/app/app.component.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [AppComponent], - }).compileComponents(); - }); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have the 'HexTowerDefense' title`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('HexTowerDefense'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain('Hello, HexTowerDefense'); - }); -}); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 09cc525..6f7d69c 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,12 +1,28 @@ import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; +import { trigger, transition, style, animate } from '@angular/animations'; @Component({ selector: 'app-root', + standalone: true, imports: [RouterOutlet], - templateUrl: './app.component.html', - styleUrl: './app.component.css' + template: ` +
+ +
+ `, + animations: [ + trigger('routeAnimations', [ + transition('* <=> *', [ + style({ transform: 'translateX(100%)', opacity: 0 }), + animate('300ms ease-in-out', style({ transform: 'translateX(0)', opacity: 1 })) + ]) + ]) + + ] }) export class AppComponent { - title = 'HexTowerDefense'; + getRoute(outlet: RouterOutlet) { + return outlet?.activatedRouteData?.['animation'] || ''; + } } diff --git a/src/app/app.config.ts b/src/app/app.config.ts index a1e7d6f..6499f8e 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,8 +1,13 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; +import { provideAnimations } from '@angular/platform-browser/animations'; import { routes } from './app.routes'; export const appConfig: ApplicationConfig = { - providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)] + providers: [ + provideZoneChangeDetection({ eventCoalescing: true }), + provideRouter(routes), + provideAnimations() + ], }; diff --git a/src/app/app.module.ts b/src/app/app.module.ts new file mode 100644 index 0000000..9845426 --- /dev/null +++ b/src/app/app.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { RouterModule } from "@angular/router"; +import { routes } from "./app.routes"; + +@NgModule({ + imports: [BrowserModule, RouterModule.forRoot(routes)], + }) + export class AppModule {} + \ No newline at end of file diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index dc39edb..3fdce61 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,3 +1,12 @@ import { Routes } from '@angular/router'; +import { SplashComponent } from './components/splash/splash.component'; +import { MenuComponent } from './components/menu/menu.component'; +import { GameComponent } from './components/game/game.component'; +import { OptionsComponent } from './components/options/options.component'; -export const routes: Routes = []; +export const routes: Routes = [ + { path: '', component: SplashComponent, data: { animation: 'Splash' } }, + { path: 'menu', component: MenuComponent, data: { animation: 'Menu' } }, + { path: 'game', component: GameComponent, data: { animation: 'Game' } }, + { path: 'options', component: OptionsComponent }, // for full-page options +]; diff --git a/src/app/assetPreloaderService.ts b/src/app/assetPreloaderService.ts new file mode 100644 index 0000000..28a75f0 --- /dev/null +++ b/src/app/assetPreloaderService.ts @@ -0,0 +1,71 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; + +interface AssetEntry { + path: string; + type: 'image' | 'audio'; + size: number; +} + +@Injectable({ providedIn: 'root' }) +export class AssetPreloaderService { + private totalBytes = 0; + private loadedBytes = 0; + + private _progress = new BehaviorSubject(0); + progress$ = this._progress.asObservable(); + + private images = new Map(); + private audio = new Map(); + + async preload(): Promise { + const manifest: AssetEntry[] = await fetch( + '/assets/manifest.json' + ).then((res) => res.json()); + this.totalBytes = manifest.reduce((sum, asset) => sum + asset.size, 0); + + const loadTasks = manifest.map((entry) => + this.loadAsset(entry).then((blob) => { + const url = URL.createObjectURL(blob); + if (entry.type === 'image') { + const img = new Image(); + img.src = url; + this.images.set(entry.path, img); + } else if (entry.type === 'audio') { + const audio = new Audio(); + audio.src = url; + this.audio.set(entry.path, audio); + } + }) + ); + + await Promise.all(loadTasks); + } + + private async loadAsset(entry: AssetEntry): Promise { + const response = await fetch(`/assets/${entry.path}`); + const reader = response.body?.getReader(); + let loaded = 0; + const chunks = []; + + while (true) { + const { done, value } = await reader!.read(); + if (done) + break; + chunks.push(value); + loaded += value.length; + this.loadedBytes += value.length; + this._progress.next(this.loadedBytes / this.totalBytes); + } + + return new Blob(chunks); + } + + getImage(name: string): HTMLImageElement { + return this.images.get(name)!; + } + + getAudio(name: string): HTMLAudioElement { + return this.audio.get(name)!; + } +} diff --git a/src/app/components/game/command.ts b/src/app/components/game/command.ts new file mode 100644 index 0000000..9773fe5 --- /dev/null +++ b/src/app/components/game/command.ts @@ -0,0 +1,5 @@ +export interface Command { + step: number; + type: string; + payload: any; +} diff --git a/src/app/components/game/game.component.css b/src/app/components/game/game.component.css new file mode 100644 index 0000000..3580d03 --- /dev/null +++ b/src/app/components/game/game.component.css @@ -0,0 +1,40 @@ +.game-layout { + display: flex; + height: 100vh; + overflow: hidden; +} + +.left-panel { + width: 250px; /* resizable width later */ + background-color: #222; + color: white; + flex-shrink: 0; +} + +.main-area { + flex: 1; + display: flex; + flex-direction: column; +} + +.canvas-wrapper { + flex: 1; + position: relative; + display: flex; + align-items: center; + justify-content: center; + background: black; +} + +canvas { + display: block; +} + +.bottom-panel { + height: 80px; + background-color: #444; + color: white; + display: flex; + align-items: center; + padding: 0 16px; +} diff --git a/src/app/components/game/game.component.html b/src/app/components/game/game.component.html new file mode 100644 index 0000000..5c2ccd7 --- /dev/null +++ b/src/app/components/game/game.component.html @@ -0,0 +1,25 @@ +
+
Sidebar content
+ +
+
+ +
+
+ + + + + +
Step: {{ engine.currentStep }}
+ + +
+
+
+ + diff --git a/src/app/components/game/game.component.ts b/src/app/components/game/game.component.ts new file mode 100644 index 0000000..f4e082d --- /dev/null +++ b/src/app/components/game/game.component.ts @@ -0,0 +1,154 @@ +import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { OptionsComponent } from '../options/options.component'; +import { GameState } from './gameState'; +import { SimulationEngine } from './simulationEngine'; +import { GameRules } from './gameRules'; +import { Command } from './command'; + +@Component({ + selector: 'app-game', + templateUrl: './game.component.html', + styleUrls: ['./game.component.css'], + imports: [OptionsComponent], +}) +export class GameComponent implements OnInit { + engine!: SimulationEngine; + private optionsOpen = false; + private isPaused = false; + private lastFrameTime = 0; + + @ViewChild('gameCanvas') canvasRef!: ElementRef; + @ViewChild('canvasWrapper') wrapperRef!: ElementRef; + private logicalWidth = 800; + private logicalHeight = 600; + scaleX: number = 1; + scaleY: number = 1; + pixelScale: number = 1; + + async ngOnInit() { + const initialState: GameState = { + tick: 0, + units: [{ id: 'u1', x: 0, y: 0 }], + commandHistory: [] + }; + + const json = await fetch('/assets/gameData.json').then(r => r.json()); + this.engine = new SimulationEngine(initialState, GameRules, json); + requestAnimationFrame(this.gameLoop.bind(this)); + } + + start() { + this.engine.start(); + } + + stop() { + this.engine.stop(); + } + + step() { + this.engine.step(); + } + + rewind() { + this.engine.rewindToZero(); + } + + fastForward() { + this.engine.fastForwardToEnd(); + } + + async reloadGameData() { + const json = await fetch('/assets/gameData.json').then(r => r.json()); + this.engine.reinitializeWithNewData(json); + } + + issueMove() { + const cmd: Command = { + step: this.engine.currentStep + 1, + type: 'move', + payload: { id: 'u1', dx: 1, dy: 0 } + }; + this.engine.issueCommand(cmd); + } + + + ngAfterViewInit(): void { + this.resizeCanvas(); + window.addEventListener('resize', this.resizeCanvas.bind(this)); + } + + resizeCanvas(): void { + const wrapper = this.wrapperRef.nativeElement; + const canvas = this.canvasRef.nativeElement; + + const targetAspect = this.logicalWidth / this.logicalHeight; + const maxW = wrapper.clientWidth; + const maxH = wrapper.clientHeight; + + let width = maxW; + let height = width / targetAspect; + + if (height > maxH) { + height = maxH; + width = height * targetAspect; + } + + canvas.width = width; + canvas.height = height; + + this.scaleX = canvas.width / this.logicalWidth; // e.g. 800 + this.scaleY = canvas.height / this.logicalHeight; // e.g. 600 + + // Optionally use the smaller of the two for uniform scaling + this.pixelScale = Math.min(this.scaleX, this.scaleY); + } + + toScreen(x: number, y: number): [number, number] { + return [x * this.pixelScale, y * this.pixelScale]; + } + + fromScreen(px: number, py: number): [number, number] { + return [px / this.pixelScale, py / this.pixelScale]; + } + + private gameLoop(currentTime: number): void { + if (this.lastFrameTime === 0) { + this.lastFrameTime = currentTime; + } + const deltaTime = (currentTime - this.lastFrameTime) / 1000; + this.lastFrameTime = currentTime; + + // Only update the game state if not paused + if (!this.isPaused) { + this.updateGame(deltaTime); + requestAnimationFrame(this.gameLoop.bind(this)); + } + } + + private updateGame(deltaTime: number): void { + // Implement your game update logic here using deltaTime + } + + // Called when opening options: pause the game + public openOptions(): void { + this.optionsOpen = true; + this.pauseGame(); + } + + // Called when closing options: resume the game + public closeOptions(): void { + this.optionsOpen = false; + this.resumeGame(); + } + + private pauseGame(): void { + this.isPaused = true; + } + + private resumeGame(): void { + this.isPaused = false; + // Reset the lastFrameTime to avoid a huge delta on resume + this.lastFrameTime = performance.now(); + requestAnimationFrame(this.gameLoop.bind(this)); + } +} diff --git a/src/app/components/game/gameData.ts b/src/app/components/game/gameData.ts new file mode 100644 index 0000000..93a2711 --- /dev/null +++ b/src/app/components/game/gameData.ts @@ -0,0 +1,6 @@ +export interface GameData { + unitSpeed: number; + maxUnits: number; + enemySpawnRate: number; + // anything else that's tunable +} diff --git a/src/app/components/game/gameRules.ts b/src/app/components/game/gameRules.ts new file mode 100644 index 0000000..6381f3e --- /dev/null +++ b/src/app/components/game/gameRules.ts @@ -0,0 +1,37 @@ +import { Command } from './command'; +import { GameData } from './gameData'; +import { GameState } from './gameState'; + +export const GameRules = { + step(state: GameState, data: GameData): GameState { + const nextTick = state.tick + 1; + + // Get all commands for this step + const commands = state.commandHistory.filter( + (c) => c.step === nextTick + ); + // Clone and update + const newState: GameState = { + ...state, + tick: state.tick + 1, + units: state.units.map((u) => ({ + ...u, + x: u.x + 1, // Simple movement + })), + }; + for (const cmd of commands) { + this.applyCommand(newState, cmd, data); + } + return newState; + }, + + applyCommand(state: GameState, cmd: Command, data: GameData): void { + if (cmd.type === 'move') { + const unit = state.units.find((u) => u.id === cmd.payload.id); + if (unit) { + unit.x += cmd.payload.dx * data.unitSpeed; + unit.y += cmd.payload.dy * data.unitSpeed; + } + } + }, +}; diff --git a/src/app/components/game/gameState.ts b/src/app/components/game/gameState.ts new file mode 100644 index 0000000..1c2933e --- /dev/null +++ b/src/app/components/game/gameState.ts @@ -0,0 +1,7 @@ +import { Command } from "./command"; + +export interface GameState { + tick: number; + units: { id: string; x: number; y: number }[]; + commandHistory: Command[]; +} diff --git a/src/app/components/game/simulationEngine.ts b/src/app/components/game/simulationEngine.ts new file mode 100644 index 0000000..b9e78f3 --- /dev/null +++ b/src/app/components/game/simulationEngine.ts @@ -0,0 +1,97 @@ +import { Command } from './command'; +import { GameData } from './gameData'; +import { GameRules } from './gameRules'; +import { GameState } from './gameState'; + +export class SimulationEngine { + private interval = 50; // ms per step + private lastTime = 0; + private frameRequestId: number | null = null; + private data: GameData; + + currentStep = 0; + initialState: GameState; + state: GameState; + isRunning = false; + + constructor( + initialState: GameState, + private rules: typeof GameRules, + initialData: GameData + ) { + this.initialState = JSON.parse(JSON.stringify(initialState)); + this.state = JSON.parse(JSON.stringify(initialState)); + this.data = initialData; + } + + setGameData(newData: GameData) { + this.data = newData; + } + + reinitializeWithNewData(data: GameData) { + this.setGameData(data); + const rewound = JSON.parse(JSON.stringify(this.initialState)); + rewound.tick = this.state.tick; + rewound.commandHistory = this.state.commandHistory.filter( + (c) => c.step <= rewound.tick + ); + this.state = rewound; + this.fastForwardTo(this.currentStep); + } + + fastForwardToEnd() { + this.fastForwardTo(this.state.commandHistory[this.state.commandHistory.length - 1].step); + } + + private fastForwardTo(target: number) { + this.state.tick = 0; + while (this.state.tick < target) { + this.step(); + } + } + + step() { + this.state = this.rules.step(this.state, this.data); + this.currentStep++; + } + + start() { + if (this.isRunning) return; + this.isRunning = true; + this.lastTime = performance.now(); + this.loop(); + } + + stop() { + this.isRunning = false; + if (this.frameRequestId) { + cancelAnimationFrame(this.frameRequestId); + this.frameRequestId = null; + } + } + + rewindToZero() { + this.stop(); + this.state = JSON.parse(JSON.stringify(this.initialState)); + this.currentStep = 0; + } + + issueCommand(command: Command) { + // Purge future commands + this.state.commandHistory = this.state.commandHistory.filter( + (c) => c.step < command.step + ); + this.state.commandHistory.push(command); + } + + private loop = () => { + const now = performance.now(); + while (now - this.lastTime >= this.interval) { + this.step(); + this.lastTime += this.interval; + } + if (this.isRunning) { + this.frameRequestId = requestAnimationFrame(this.loop); + } + }; +} diff --git a/src/app/app.component.css b/src/app/components/menu/menu.component.css similarity index 100% rename from src/app/app.component.css rename to src/app/components/menu/menu.component.css diff --git a/src/app/components/menu/menu.component.html b/src/app/components/menu/menu.component.html new file mode 100644 index 0000000..67f61e6 --- /dev/null +++ b/src/app/components/menu/menu.component.html @@ -0,0 +1,4 @@ +

Menu Page

+

Select an option:

+ + \ No newline at end of file diff --git a/src/app/components/menu/menu.component.ts b/src/app/components/menu/menu.component.ts new file mode 100644 index 0000000..31900e7 --- /dev/null +++ b/src/app/components/menu/menu.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-menu', + templateUrl: './menu.component.html', + styleUrls: ['./menu.component.css'], +}) +export class MenuComponent { + constructor(private router: Router) {} + + navigateToGame(): void { + this.router.navigate(['/game']); + } + + navigateToOptions(): void { + this.router.navigate(['/options'], { state: { mode: 'full' } }); + } +} \ No newline at end of file diff --git a/src/app/components/options/options.component.css b/src/app/components/options/options.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/components/options/options.component.html b/src/app/components/options/options.component.html new file mode 100644 index 0000000..d0726db --- /dev/null +++ b/src/app/components/options/options.component.html @@ -0,0 +1,2 @@ +

Options Page

+

Configure your preferences here.

\ No newline at end of file diff --git a/src/app/components/options/options.component.ts b/src/app/components/options/options.component.ts new file mode 100644 index 0000000..b8057e1 --- /dev/null +++ b/src/app/components/options/options.component.ts @@ -0,0 +1,19 @@ +import { Component, Input } from '@angular/core'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-options', + templateUrl: './options.component.html', + styleUrls: ['./options.component.css'], +}) +export class OptionsComponent { + @Input() mode: 'modal' | 'full' = 'full'; + + constructor(private router: Router) {} + + ngOnInit(): void { + const nav = this.router.getCurrentNavigation(); + const state = nav?.extras?.state as { mode: 'modal' | 'full' }; + this.mode = state?.mode || 'full'; + } +} diff --git a/src/app/components/splash/splash.component.css b/src/app/components/splash/splash.component.css new file mode 100644 index 0000000..1637aa7 --- /dev/null +++ b/src/app/components/splash/splash.component.css @@ -0,0 +1,4 @@ +h1 { + color: blue; + text-align: center; + } \ No newline at end of file diff --git a/src/app/components/splash/splash.component.html b/src/app/components/splash/splash.component.html new file mode 100644 index 0000000..d7b55ea --- /dev/null +++ b/src/app/components/splash/splash.component.html @@ -0,0 +1 @@ +

Welcome to the Splash Page!

\ No newline at end of file diff --git a/src/app/components/splash/splash.component.ts b/src/app/components/splash/splash.component.ts new file mode 100644 index 0000000..de80360 --- /dev/null +++ b/src/app/components/splash/splash.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { AssetPreloaderService } from '../../assetPreloaderService'; + +@Component({ + selector: 'app-splash', + templateUrl: './splash.component.html', + styleUrls: ['./splash.component.css'], +}) +export class SplashComponent { + show: boolean = true; + assetPreloader: AssetPreloaderService = new AssetPreloaderService(); + progress: number = 0; + + constructor(private router: Router) { + this.assetPreloader.progress$.subscribe(p => this.progress = p); + this.assetPreloader.preload().then(() => this.router.navigate(['/menu'])); + } +} diff --git a/src/assets/audio/Cosmic Reflections.mp3 b/src/assets/audio/Cosmic Reflections.mp3 new file mode 100644 index 0000000..6dc5097 Binary files /dev/null and b/src/assets/audio/Cosmic Reflections.mp3 differ diff --git a/src/assets/audio/Premonition.mp3 b/src/assets/audio/Premonition.mp3 new file mode 100644 index 0000000..2cfe76a Binary files /dev/null and b/src/assets/audio/Premonition.mp3 differ diff --git a/src/assets/audio/Uncover.mp3 b/src/assets/audio/Uncover.mp3 new file mode 100644 index 0000000..bdb15af Binary files /dev/null and b/src/assets/audio/Uncover.mp3 differ diff --git a/src/assets/audio/Violet moon.mp3 b/src/assets/audio/Violet moon.mp3 new file mode 100644 index 0000000..9b1e119 Binary files /dev/null and b/src/assets/audio/Violet moon.mp3 differ diff --git a/src/assets/gameData.json b/src/assets/gameData.json new file mode 100644 index 0000000..3a27dde --- /dev/null +++ b/src/assets/gameData.json @@ -0,0 +1,5 @@ +{ + "unitSpeed": 1, + "maxUnits": 10, + "enemySpawnRate": 1 +} diff --git a/src/assets/images/cell-blocked-0.svg b/src/assets/images/cell-blocked-0.svg new file mode 100644 index 0000000..a1275c5 --- /dev/null +++ b/src/assets/images/cell-blocked-0.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-1.svg b/src/assets/images/cell-blocked-1.svg new file mode 100644 index 0000000..b849289 --- /dev/null +++ b/src/assets/images/cell-blocked-1.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-10.svg b/src/assets/images/cell-blocked-10.svg new file mode 100644 index 0000000..7778e08 --- /dev/null +++ b/src/assets/images/cell-blocked-10.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-11.svg b/src/assets/images/cell-blocked-11.svg new file mode 100644 index 0000000..6f043b0 --- /dev/null +++ b/src/assets/images/cell-blocked-11.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-12.svg b/src/assets/images/cell-blocked-12.svg new file mode 100644 index 0000000..8b0dc18 --- /dev/null +++ b/src/assets/images/cell-blocked-12.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-13.svg b/src/assets/images/cell-blocked-13.svg new file mode 100644 index 0000000..39f7ed0 --- /dev/null +++ b/src/assets/images/cell-blocked-13.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-14.svg b/src/assets/images/cell-blocked-14.svg new file mode 100644 index 0000000..870b1ab --- /dev/null +++ b/src/assets/images/cell-blocked-14.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-15.svg b/src/assets/images/cell-blocked-15.svg new file mode 100644 index 0000000..e3dd318 --- /dev/null +++ b/src/assets/images/cell-blocked-15.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-16.svg b/src/assets/images/cell-blocked-16.svg new file mode 100644 index 0000000..76bc6c8 --- /dev/null +++ b/src/assets/images/cell-blocked-16.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-17.svg b/src/assets/images/cell-blocked-17.svg new file mode 100644 index 0000000..8b7bcb3 --- /dev/null +++ b/src/assets/images/cell-blocked-17.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-18.svg b/src/assets/images/cell-blocked-18.svg new file mode 100644 index 0000000..dfc74b7 --- /dev/null +++ b/src/assets/images/cell-blocked-18.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-19.svg b/src/assets/images/cell-blocked-19.svg new file mode 100644 index 0000000..2ca75b2 --- /dev/null +++ b/src/assets/images/cell-blocked-19.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-2.svg b/src/assets/images/cell-blocked-2.svg new file mode 100644 index 0000000..287fab2 --- /dev/null +++ b/src/assets/images/cell-blocked-2.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-20.svg b/src/assets/images/cell-blocked-20.svg new file mode 100644 index 0000000..4265e4f --- /dev/null +++ b/src/assets/images/cell-blocked-20.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-21.svg b/src/assets/images/cell-blocked-21.svg new file mode 100644 index 0000000..86b0a83 --- /dev/null +++ b/src/assets/images/cell-blocked-21.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-22.svg b/src/assets/images/cell-blocked-22.svg new file mode 100644 index 0000000..09538c6 --- /dev/null +++ b/src/assets/images/cell-blocked-22.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-23.svg b/src/assets/images/cell-blocked-23.svg new file mode 100644 index 0000000..a11ecc3 --- /dev/null +++ b/src/assets/images/cell-blocked-23.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-24.svg b/src/assets/images/cell-blocked-24.svg new file mode 100644 index 0000000..61798b7 --- /dev/null +++ b/src/assets/images/cell-blocked-24.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-25.svg b/src/assets/images/cell-blocked-25.svg new file mode 100644 index 0000000..009144c --- /dev/null +++ b/src/assets/images/cell-blocked-25.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-26.svg b/src/assets/images/cell-blocked-26.svg new file mode 100644 index 0000000..7ffe3c4 --- /dev/null +++ b/src/assets/images/cell-blocked-26.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-27.svg b/src/assets/images/cell-blocked-27.svg new file mode 100644 index 0000000..6eaf325 --- /dev/null +++ b/src/assets/images/cell-blocked-27.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-28.svg b/src/assets/images/cell-blocked-28.svg new file mode 100644 index 0000000..007a014 --- /dev/null +++ b/src/assets/images/cell-blocked-28.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-29.svg b/src/assets/images/cell-blocked-29.svg new file mode 100644 index 0000000..0af565c --- /dev/null +++ b/src/assets/images/cell-blocked-29.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-3.svg b/src/assets/images/cell-blocked-3.svg new file mode 100644 index 0000000..1fa058b --- /dev/null +++ b/src/assets/images/cell-blocked-3.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-30.svg b/src/assets/images/cell-blocked-30.svg new file mode 100644 index 0000000..2dea5ae --- /dev/null +++ b/src/assets/images/cell-blocked-30.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-31.svg b/src/assets/images/cell-blocked-31.svg new file mode 100644 index 0000000..6295e21 --- /dev/null +++ b/src/assets/images/cell-blocked-31.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-32.svg b/src/assets/images/cell-blocked-32.svg new file mode 100644 index 0000000..f3dffe9 --- /dev/null +++ b/src/assets/images/cell-blocked-32.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-33.svg b/src/assets/images/cell-blocked-33.svg new file mode 100644 index 0000000..bca3ef9 --- /dev/null +++ b/src/assets/images/cell-blocked-33.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-34.svg b/src/assets/images/cell-blocked-34.svg new file mode 100644 index 0000000..7cef6ca --- /dev/null +++ b/src/assets/images/cell-blocked-34.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-35.svg b/src/assets/images/cell-blocked-35.svg new file mode 100644 index 0000000..fbec7ad --- /dev/null +++ b/src/assets/images/cell-blocked-35.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-36.svg b/src/assets/images/cell-blocked-36.svg new file mode 100644 index 0000000..1c5bd10 --- /dev/null +++ b/src/assets/images/cell-blocked-36.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-37.svg b/src/assets/images/cell-blocked-37.svg new file mode 100644 index 0000000..e411a7f --- /dev/null +++ b/src/assets/images/cell-blocked-37.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-38.svg b/src/assets/images/cell-blocked-38.svg new file mode 100644 index 0000000..22621f9 --- /dev/null +++ b/src/assets/images/cell-blocked-38.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-39.svg b/src/assets/images/cell-blocked-39.svg new file mode 100644 index 0000000..ba35f4b --- /dev/null +++ b/src/assets/images/cell-blocked-39.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-4.svg b/src/assets/images/cell-blocked-4.svg new file mode 100644 index 0000000..7a116cc --- /dev/null +++ b/src/assets/images/cell-blocked-4.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-40.svg b/src/assets/images/cell-blocked-40.svg new file mode 100644 index 0000000..a866958 --- /dev/null +++ b/src/assets/images/cell-blocked-40.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-41.svg b/src/assets/images/cell-blocked-41.svg new file mode 100644 index 0000000..99288c5 --- /dev/null +++ b/src/assets/images/cell-blocked-41.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-42.svg b/src/assets/images/cell-blocked-42.svg new file mode 100644 index 0000000..c07f9e6 --- /dev/null +++ b/src/assets/images/cell-blocked-42.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-43.svg b/src/assets/images/cell-blocked-43.svg new file mode 100644 index 0000000..a309a9c --- /dev/null +++ b/src/assets/images/cell-blocked-43.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-44.svg b/src/assets/images/cell-blocked-44.svg new file mode 100644 index 0000000..8db7ec7 --- /dev/null +++ b/src/assets/images/cell-blocked-44.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-45.svg b/src/assets/images/cell-blocked-45.svg new file mode 100644 index 0000000..f7afb9f --- /dev/null +++ b/src/assets/images/cell-blocked-45.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-46.svg b/src/assets/images/cell-blocked-46.svg new file mode 100644 index 0000000..15e0af2 --- /dev/null +++ b/src/assets/images/cell-blocked-46.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-47.svg b/src/assets/images/cell-blocked-47.svg new file mode 100644 index 0000000..908130e --- /dev/null +++ b/src/assets/images/cell-blocked-47.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-48.svg b/src/assets/images/cell-blocked-48.svg new file mode 100644 index 0000000..5e644ab --- /dev/null +++ b/src/assets/images/cell-blocked-48.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-49.svg b/src/assets/images/cell-blocked-49.svg new file mode 100644 index 0000000..4068bbc --- /dev/null +++ b/src/assets/images/cell-blocked-49.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-5.svg b/src/assets/images/cell-blocked-5.svg new file mode 100644 index 0000000..0e6575c --- /dev/null +++ b/src/assets/images/cell-blocked-5.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-50.svg b/src/assets/images/cell-blocked-50.svg new file mode 100644 index 0000000..dcb2b6e --- /dev/null +++ b/src/assets/images/cell-blocked-50.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-51.svg b/src/assets/images/cell-blocked-51.svg new file mode 100644 index 0000000..fb0e795 --- /dev/null +++ b/src/assets/images/cell-blocked-51.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-52.svg b/src/assets/images/cell-blocked-52.svg new file mode 100644 index 0000000..2ee9e16 --- /dev/null +++ b/src/assets/images/cell-blocked-52.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-53.svg b/src/assets/images/cell-blocked-53.svg new file mode 100644 index 0000000..b96d6e2 --- /dev/null +++ b/src/assets/images/cell-blocked-53.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-54.svg b/src/assets/images/cell-blocked-54.svg new file mode 100644 index 0000000..f9af589 --- /dev/null +++ b/src/assets/images/cell-blocked-54.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-55.svg b/src/assets/images/cell-blocked-55.svg new file mode 100644 index 0000000..0023239 --- /dev/null +++ b/src/assets/images/cell-blocked-55.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-56.svg b/src/assets/images/cell-blocked-56.svg new file mode 100644 index 0000000..1cb0ff5 --- /dev/null +++ b/src/assets/images/cell-blocked-56.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-57.svg b/src/assets/images/cell-blocked-57.svg new file mode 100644 index 0000000..f1c20f0 --- /dev/null +++ b/src/assets/images/cell-blocked-57.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-58.svg b/src/assets/images/cell-blocked-58.svg new file mode 100644 index 0000000..94847a4 --- /dev/null +++ b/src/assets/images/cell-blocked-58.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-59.svg b/src/assets/images/cell-blocked-59.svg new file mode 100644 index 0000000..2cb793f --- /dev/null +++ b/src/assets/images/cell-blocked-59.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-6.svg b/src/assets/images/cell-blocked-6.svg new file mode 100644 index 0000000..7c99d34 --- /dev/null +++ b/src/assets/images/cell-blocked-6.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-60.svg b/src/assets/images/cell-blocked-60.svg new file mode 100644 index 0000000..8f7be1f --- /dev/null +++ b/src/assets/images/cell-blocked-60.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-61.svg b/src/assets/images/cell-blocked-61.svg new file mode 100644 index 0000000..3516d9a --- /dev/null +++ b/src/assets/images/cell-blocked-61.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-62.svg b/src/assets/images/cell-blocked-62.svg new file mode 100644 index 0000000..8974086 --- /dev/null +++ b/src/assets/images/cell-blocked-62.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-63.svg b/src/assets/images/cell-blocked-63.svg new file mode 100644 index 0000000..6d48818 --- /dev/null +++ b/src/assets/images/cell-blocked-63.svg @@ -0,0 +1,79 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-7.svg b/src/assets/images/cell-blocked-7.svg new file mode 100644 index 0000000..ac0e6a5 --- /dev/null +++ b/src/assets/images/cell-blocked-7.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-8.svg b/src/assets/images/cell-blocked-8.svg new file mode 100644 index 0000000..efc2415 --- /dev/null +++ b/src/assets/images/cell-blocked-8.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-blocked-9.svg b/src/assets/images/cell-blocked-9.svg new file mode 100644 index 0000000..257f076 --- /dev/null +++ b/src/assets/images/cell-blocked-9.svg @@ -0,0 +1,73 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-1.svg b/src/assets/images/cell-entry-1.svg new file mode 100644 index 0000000..73f4cb6 --- /dev/null +++ b/src/assets/images/cell-entry-1.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-12.svg b/src/assets/images/cell-entry-12.svg new file mode 100644 index 0000000..9c40802 --- /dev/null +++ b/src/assets/images/cell-entry-12.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-16.svg b/src/assets/images/cell-entry-16.svg new file mode 100644 index 0000000..e6146b9 --- /dev/null +++ b/src/assets/images/cell-entry-16.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-2.svg b/src/assets/images/cell-entry-2.svg new file mode 100644 index 0000000..306e9e9 --- /dev/null +++ b/src/assets/images/cell-entry-2.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-24.svg b/src/assets/images/cell-entry-24.svg new file mode 100644 index 0000000..83ec2e9 --- /dev/null +++ b/src/assets/images/cell-entry-24.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-3.svg b/src/assets/images/cell-entry-3.svg new file mode 100644 index 0000000..afebbe7 --- /dev/null +++ b/src/assets/images/cell-entry-3.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-32.svg b/src/assets/images/cell-entry-32.svg new file mode 100644 index 0000000..a69fc85 --- /dev/null +++ b/src/assets/images/cell-entry-32.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-33.svg b/src/assets/images/cell-entry-33.svg new file mode 100644 index 0000000..4552e46 --- /dev/null +++ b/src/assets/images/cell-entry-33.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-4.svg b/src/assets/images/cell-entry-4.svg new file mode 100644 index 0000000..4512d4c --- /dev/null +++ b/src/assets/images/cell-entry-4.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-48.svg b/src/assets/images/cell-entry-48.svg new file mode 100644 index 0000000..d24ad44 --- /dev/null +++ b/src/assets/images/cell-entry-48.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-6.svg b/src/assets/images/cell-entry-6.svg new file mode 100644 index 0000000..b765475 --- /dev/null +++ b/src/assets/images/cell-entry-6.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-entry-8.svg b/src/assets/images/cell-entry-8.svg new file mode 100644 index 0000000..65e6ac7 --- /dev/null +++ b/src/assets/images/cell-entry-8.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/assets/images/cell-highlighted.svg b/src/assets/images/cell-highlighted.svg new file mode 100644 index 0000000..dead9f5 --- /dev/null +++ b/src/assets/images/cell-highlighted.svg @@ -0,0 +1,97 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/assets/images/cell.svg b/src/assets/images/cell.svg new file mode 100644 index 0000000..4fa3ce7 --- /dev/null +++ b/src/assets/images/cell.svg @@ -0,0 +1,97 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/assets/images/enemy-0.svg b/src/assets/images/enemy-0.svg new file mode 100644 index 0000000..d1afb20 --- /dev/null +++ b/src/assets/images/enemy-0.svg @@ -0,0 +1,109 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/src/assets/images/projectile.svg b/src/assets/images/projectile.svg new file mode 100644 index 0000000..bd1759b --- /dev/null +++ b/src/assets/images/projectile.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/tower-0.svg b/src/assets/images/tower-0.svg new file mode 100644 index 0000000..0b76469 --- /dev/null +++ b/src/assets/images/tower-0.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/assets/images/wall.png b/src/assets/images/wall.png new file mode 100644 index 0000000..1f72498 Binary files /dev/null and b/src/assets/images/wall.png differ diff --git a/src/assets/manifest.json b/src/assets/manifest.json new file mode 100644 index 0000000..bf7f4c8 --- /dev/null +++ b/src/assets/manifest.json @@ -0,0 +1,442 @@ +[ + { + "path": "audio/Cosmic Reflections.mp3", + "type": "audio", + "size": 5118331 + }, + { + "path": "audio/Premonition.mp3", + "type": "audio", + "size": 5472139 + }, + { + "path": "audio/Uncover.mp3", + "type": "audio", + "size": 5525515 + }, + { + "path": "audio/Violet moon.mp3", + "type": "audio", + "size": 5622381 + }, + { + "path": "gameData.json", + "type": "other", + "size": 68 + }, + { + "path": "images/cell-blocked-0.svg", + "type": "image", + "size": 2241 + }, + { + "path": "images/cell-blocked-1.svg", + "type": "image", + "size": 2279 + }, + { + "path": "images/cell-blocked-10.svg", + "type": "image", + "size": 2322 + }, + { + "path": "images/cell-blocked-11.svg", + "type": "image", + "size": 2360 + }, + { + "path": "images/cell-blocked-12.svg", + "type": "image", + "size": 2322 + }, + { + "path": "images/cell-blocked-13.svg", + "type": "image", + "size": 2364 + }, + { + "path": "images/cell-blocked-14.svg", + "type": "image", + "size": 2308 + }, + { + "path": "images/cell-blocked-15.svg", + "type": "image", + "size": 2414 + }, + { + "path": "images/cell-blocked-16.svg", + "type": "image", + "size": 2274 + }, + { + "path": "images/cell-blocked-17.svg", + "type": "image", + "size": 2315 + }, + { + "path": "images/cell-blocked-18.svg", + "type": "image", + "size": 2333 + }, + { + "path": "images/cell-blocked-19.svg", + "type": "image", + "size": 2373 + }, + { + "path": "images/cell-blocked-2.svg", + "type": "image", + "size": 2280 + }, + { + "path": "images/cell-blocked-20.svg", + "type": "image", + "size": 2317 + }, + { + "path": "images/cell-blocked-21.svg", + "type": "image", + "size": 2358 + }, + { + "path": "images/cell-blocked-22.svg", + "type": "image", + "size": 2373 + }, + { + "path": "images/cell-blocked-23.svg", + "type": "image", + "size": 2359 + }, + { + "path": "images/cell-blocked-24.svg", + "type": "image", + "size": 2323 + }, + { + "path": "images/cell-blocked-25.svg", + "type": "image", + "size": 2367 + }, + { + "path": "images/cell-blocked-26.svg", + "type": "image", + "size": 2376 + }, + { + "path": "images/cell-blocked-27.svg", + "type": "image", + "size": 2426 + }, + { + "path": "images/cell-blocked-28.svg", + "type": "image", + "size": 2314 + }, + { + "path": "images/cell-blocked-29.svg", + "type": "image", + "size": 2352 + }, + { + "path": "images/cell-blocked-3.svg", + "type": "image", + "size": 2320 + }, + { + "path": "images/cell-blocked-30.svg", + "type": "image", + "size": 2362 + }, + { + "path": "images/cell-blocked-31.svg", + "type": "image", + "size": 2401 + }, + { + "path": "images/cell-blocked-32.svg", + "type": "image", + "size": 2275 + }, + { + "path": "images/cell-blocked-33.svg", + "type": "image", + "size": 2331 + }, + { + "path": "images/cell-blocked-34.svg", + "type": "image", + "size": 2317 + }, + { + "path": "images/cell-blocked-35.svg", + "type": "image", + "size": 2317 + }, + { + "path": "images/cell-blocked-36.svg", + "type": "image", + "size": 2333 + }, + { + "path": "images/cell-blocked-37.svg", + "type": "image", + "size": 2381 + }, + { + "path": "images/cell-blocked-38.svg", + "type": "image", + "size": 2383 + }, + { + "path": "images/cell-blocked-39.svg", + "type": "image", + "size": 2349 + }, + { + "path": "images/cell-blocked-4.svg", + "type": "image", + "size": 2279 + }, + { + "path": "images/cell-blocked-40.svg", + "type": "image", + "size": 2313 + }, + { + "path": "images/cell-blocked-41.svg", + "type": "image", + "size": 2363 + }, + { + "path": "images/cell-blocked-42.svg", + "type": "image", + "size": 2364 + }, + { + "path": "images/cell-blocked-43.svg", + "type": "image", + "size": 2340 + }, + { + "path": "images/cell-blocked-44.svg", + "type": "image", + "size": 2377 + }, + { + "path": "images/cell-blocked-45.svg", + "type": "image", + "size": 2419 + }, + { + "path": "images/cell-blocked-46.svg", + "type": "image", + "size": 2359 + }, + { + "path": "images/cell-blocked-47.svg", + "type": "image", + "size": 2389 + }, + { + "path": "images/cell-blocked-48.svg", + "type": "image", + "size": 2311 + }, + { + "path": "images/cell-blocked-49.svg", + "type": "image", + "size": 2296 + }, + { + "path": "images/cell-blocked-5.svg", + "type": "image", + "size": 2318 + }, + { + "path": "images/cell-blocked-50.svg", + "type": "image", + "size": 2375 + }, + { + "path": "images/cell-blocked-51.svg", + "type": "image", + "size": 2335 + }, + { + "path": "images/cell-blocked-52.svg", + "type": "image", + "size": 2362 + }, + { + "path": "images/cell-blocked-53.svg", + "type": "image", + "size": 2352 + }, + { + "path": "images/cell-blocked-54.svg", + "type": "image", + "size": 2403 + }, + { + "path": "images/cell-blocked-55.svg", + "type": "image", + "size": 2390 + }, + { + "path": "images/cell-blocked-56.svg", + "type": "image", + "size": 2295 + }, + { + "path": "images/cell-blocked-57.svg", + "type": "image", + "size": 2408 + }, + { + "path": "images/cell-blocked-58.svg", + "type": "image", + "size": 2352 + }, + { + "path": "images/cell-blocked-59.svg", + "type": "image", + "size": 2378 + }, + { + "path": "images/cell-blocked-6.svg", + "type": "image", + "size": 2316 + }, + { + "path": "images/cell-blocked-60.svg", + "type": "image", + "size": 2341 + }, + { + "path": "images/cell-blocked-61.svg", + "type": "image", + "size": 2380 + }, + { + "path": "images/cell-blocked-62.svg", + "type": "image", + "size": 2404 + }, + { + "path": "images/cell-blocked-63.svg", + "type": "image", + "size": 2503 + }, + { + "path": "images/cell-blocked-7.svg", + "type": "image", + "size": 2305 + }, + { + "path": "images/cell-blocked-8.svg", + "type": "image", + "size": 2279 + }, + { + "path": "images/cell-blocked-9.svg", + "type": "image", + "size": 2318 + }, + { + "path": "images/cell-entry-1.svg", + "type": "image", + "size": 2901 + }, + { + "path": "images/cell-entry-12.svg", + "type": "image", + "size": 2932 + }, + { + "path": "images/cell-entry-16.svg", + "type": "image", + "size": 2882 + }, + { + "path": "images/cell-entry-2.svg", + "type": "image", + "size": 2894 + }, + { + "path": "images/cell-entry-24.svg", + "type": "image", + "size": 2937 + }, + { + "path": "images/cell-entry-3.svg", + "type": "image", + "size": 2866 + }, + { + "path": "images/cell-entry-32.svg", + "type": "image", + "size": 2889 + }, + { + "path": "images/cell-entry-33.svg", + "type": "image", + "size": 2908 + }, + { + "path": "images/cell-entry-4.svg", + "type": "image", + "size": 2965 + }, + { + "path": "images/cell-entry-48.svg", + "type": "image", + "size": 2901 + }, + { + "path": "images/cell-entry-6.svg", + "type": "image", + "size": 2855 + }, + { + "path": "images/cell-entry-8.svg", + "type": "image", + "size": 2885 + }, + { + "path": "images/cell-highlighted.svg", + "type": "image", + "size": 3580 + }, + { + "path": "images/cell.svg", + "type": "image", + "size": 3576 + }, + { + "path": "images/enemy-0.svg", + "type": "image", + "size": 3836 + }, + { + "path": "images/projectile.svg", + "type": "image", + "size": 13184 + }, + { + "path": "images/tower-0.svg", + "type": "image", + "size": 3758 + }, + { + "path": "images/wall.png", + "type": "image", + "size": 310712 + }, + { + "path": "manifest.json", + "type": "other", + "size": 7721 + } +] \ No newline at end of file diff --git a/public/favicon.ico b/src/favicon.ico similarity index 100% rename from public/favicon.ico rename to src/favicon.ico diff --git a/src/index.html b/src/index.html index a549e93..bf8bd2c 100644 --- a/src/index.html +++ b/src/index.html @@ -1,13 +1,13 @@ - + - - - HexTowerDefense - - - - - - - + + + HexTowerDefense + + + + + + + diff --git a/tools/generateAssetManifest.js b/tools/generateAssetManifest.js new file mode 100644 index 0000000..2033658 --- /dev/null +++ b/tools/generateAssetManifest.js @@ -0,0 +1,37 @@ +const fs = require("fs"); +const path = require("path"); + +const basePath = path.join(__dirname, "../src/assets"); + +function detectType(filepath) { + const ext = path.extname(filepath).toLowerCase(); + if ([".svg", ".png", ".jpg"].includes(ext)) return "image"; + if ([".mp3", ".ogg", ".wav"].includes(ext)) return "audio"; + return "other"; +} + +function walk(dir, acc = []) { + const entries = fs.readdirSync(dir); + for (const entry of entries) { + const fullPath = path.join(dir, entry); + const relPath = path.relative(basePath, fullPath).replace(/\\/g, "/"); + const stat = fs.statSync(fullPath); + + if (stat.isDirectory()) { + walk(fullPath, acc); + } else { + acc.push({ + path: relPath, + type: detectType(fullPath), + size: stat.size, + }); + } + } + return acc; +} + +const assets = walk(basePath); +fs.writeFileSync( + path.join(basePath, "manifest.json"), + JSON.stringify(assets, null, 2) +);