diff --git a/assets/Data/GameSettings.json b/assets/Data/GameSettings.json index 3b1741a..5bae5f7 100644 --- a/assets/Data/GameSettings.json +++ b/assets/Data/GameSettings.json @@ -59,6 +59,14 @@ "maxHaloProjectileUpgrades": 5, "maxRegenerationUpgrades": 5 }, + "metaUpgrades": { + "healthPointsPerLevel": 0, + "bonusDamagePerLevel": 0, + "projectilePiercingPerLevel": 0, + "movementSpeedPerLevel": 0, + "xpBonusPerLevel": 0, + "goldBonusPerLevel": 0 + }, "enemyManager": { "enemies": [ { diff --git a/assets/Scenes/Game.scene b/assets/Scenes/Game.scene index 77489d1..8a28e60 100644 --- a/assets/Scenes/Game.scene +++ b/assets/Scenes/Game.scene @@ -195,6 +195,12 @@ }, "_enabled": true, "__prefab": null, + "maxHpLevel": 0, + "bonusDamageLevel": 5, + "projectilePiercingLevel": 0, + "movementSpeedLevel": 0, + "xpGathererLevel": 0, + "goldGathererLevel": 0, "_id": "35CwPVksdGoJPgBRCGSH6m" }, { diff --git a/assets/Scripts/Game/Collision/PlayerProjectileCollisionSystem.ts b/assets/Scripts/Game/Collision/PlayerProjectileCollisionSystem.ts index aabe335..7d20591 100644 --- a/assets/Scripts/Game/Collision/PlayerProjectileCollisionSystem.ts +++ b/assets/Scripts/Game/Collision/PlayerProjectileCollisionSystem.ts @@ -10,6 +10,7 @@ export class PlayerProjectileCollisionSystem { } private onProjectileCollision(projectileCollision: ProjectileCollision): void { - projectileCollision.otherCollider.getComponent(Enemy).dealDamage(1); + projectileCollision.otherCollider.getComponent(Enemy).dealDamage(projectileCollision.projectile.Damage); + projectileCollision.projectile.pierce(); } } diff --git a/assets/Scripts/Game/Data/GameSettings.ts b/assets/Scripts/Game/Data/GameSettings.ts index fd50287..690a7fb 100644 --- a/assets/Scripts/Game/Data/GameSettings.ts +++ b/assets/Scripts/Game/Data/GameSettings.ts @@ -1,6 +1,7 @@ export class GameSettings { public player: PlayerSettings = new PlayerSettings(); public upgrades: UpgradeSettings = new UpgradeSettings(); + public metaUpgrades: MetaUpgradeSettings = new MetaUpgradeSettings(); public enemyManager: EnemyManagerSettings = new EnemyManagerSettings(); } @@ -48,6 +49,15 @@ export class UpgradeSettings { public maxRegenerationUpgrades = 0; } +export class MetaUpgradeSettings { + public healthPointsPerLevel = 0; + public bonusDamagePerLevel = 0; + public projectilePiercingPerLevel = 0; + public movementSpeedPerLevel = 0; + public xpBonusPerLevel = 0; + public goldBonusPerLevel = 0; +} + export class EnemyManagerSettings { public enemies: EnemySettings[] = [new EnemySettings()]; public individualEnemySpawners: IndividualEnemySpawnerSettings[] = [new IndividualEnemySpawnerSettings()]; diff --git a/assets/Scripts/Game/Data/UserData.ts b/assets/Scripts/Game/Data/UserData.ts index dc2b195..93ca860 100644 --- a/assets/Scripts/Game/Data/UserData.ts +++ b/assets/Scripts/Game/Data/UserData.ts @@ -11,7 +11,9 @@ export class GameData { export class MetaUpgradesData { public maxHpLevel = 0; - public overallDamageLevel = 0; + public bonusDamageLevel = 2; public projectilePiercingLevel = 0; public movementSpeedLevel = 0; + public xpGathererLevel = 0; + public goldGathererLevel = 0; } diff --git a/assets/Scripts/Game/Game.ts b/assets/Scripts/Game/Game.ts index c377460..33e5388 100644 --- a/assets/Scripts/Game/Game.ts +++ b/assets/Scripts/Game/Game.ts @@ -6,6 +6,7 @@ import { PlayerCollisionSystem } from "./Collision/PlayerCollisionSystem"; import { PlayerProjectileCollisionSystem } from "./Collision/PlayerProjectileCollisionSystem"; import { WeaponCollisionSystem } from "./Collision/WeaponCollisionSystem"; import { GameSettings } from "./Data/GameSettings"; +import { UserData } from "./Data/UserData"; import { KeyboardInput } from "./Input/KeyboardInput"; import { MultiInput } from "./Input/MultiInput"; import { VirtualJoystic } from "./Input/VirtualJoystic"; @@ -13,11 +14,13 @@ import { GameModalLauncher } from "./ModalWIndows/GameModalLauncher"; import { Pauser } from "./Pauser"; import { GameUI } from "./UI/GameUI"; import { EnemyManager } from "./Unit/Enemy/EnemyManager"; -import { Player } from "./Unit/Player/Player"; +import { MetaUpgrades } from "./Unit/MetaUpgrades/MetaUpgrades"; +import { Player, PlayerData } from "./Unit/Player/Player"; import { HaloProjectileLauncher } from "./Unit/Player/ProjectileLauncher/HaloProjectileLauncher"; -import { ProjectileLauncher } from "./Unit/Player/ProjectileLauncher/ProjectileLauncher"; +import { ProjectileData, ProjectileLauncher } from "./Unit/Player/ProjectileLauncher/ProjectileLauncher"; import { WaveProjectileLauncher } from "./Unit/Player/ProjectileLauncher/WaveProjectileLauncher"; import { Upgrader } from "./Upgrades/Upgrader"; +import { MetaUpgradeType } from "./Upgrades/UpgradeType"; const { ccclass, property } = _decorator; @@ -53,39 +56,54 @@ export class Game extends Component { this.gamePauser.pause(); } - public async playGame(): Promise { + public async playGame(userData: UserData): Promise { const settings: GameSettings = this.settingsAsset.json; + const metaUpgrades = new MetaUpgrades(userData.game.metaUpgrades, settings.metaUpgrades); this.virtualJoystic.init(); const wasd = new KeyboardInput(KeyCode.KEY_W, KeyCode.KEY_S, KeyCode.KEY_A, KeyCode.KEY_D); const arrowKeys = new KeyboardInput(KeyCode.ARROW_UP, KeyCode.ARROW_DOWN, KeyCode.ARROW_LEFT, KeyCode.ARROW_RIGHT); const multiInput: MultiInput = new MultiInput([this.virtualJoystic, wasd, arrowKeys]); - this.player.init(multiInput, settings.player); + + const playerData: PlayerData = Object.assign(new PlayerData(), settings.player); + playerData.bonusHp = metaUpgrades.getUpgradeValue(MetaUpgradeType.MaxHp); + playerData.bonusDamage = metaUpgrades.getUpgradeValue(MetaUpgradeType.OverallDamage); + playerData.bonusSpeed = metaUpgrades.getUpgradeValue(MetaUpgradeType.MovementSpeed); + playerData.bonusXP = metaUpgrades.getUpgradeValue(MetaUpgradeType.XPGatherer); + playerData.bonusGold = metaUpgrades.getUpgradeValue(MetaUpgradeType.GoldGatherer); + this.player.init(multiInput, playerData); this.playerCollisionSystem = new PlayerCollisionSystem(this.player, settings.player.collisionDelay); new WeaponCollisionSystem(this.player.Weapon); this.enemyManager.init(this.player.node, settings.enemyManager); + const projectileData = new ProjectileData(); + projectileData.damage = 1 + metaUpgrades.getUpgradeValue(MetaUpgradeType.OverallDamage); + projectileData.pierces = 1 + metaUpgrades.getUpgradeValue(MetaUpgradeType.ProjectilePiercing); + this.haloProjectileLauncher = new HaloProjectileLauncher( this.haloProjectileLauncherComponent, this.player.node, - settings.player.haloLauncher + settings.player.haloLauncher, + projectileData ); this.horizontalProjectileLauncher = new WaveProjectileLauncher( this.horizontalProjectileLauncherComponent, this.player.node, [new Vec2(-1, 0), new Vec2(1, 0)], - settings.player.horizontalLauncher + settings.player.horizontalLauncher, + projectileData ); this.diagonalProjectileLauncher = new WaveProjectileLauncher( this.diagonalProjectileLauncherComponent, this.player.node, [new Vec2(-0.5, -0.5), new Vec2(0.5, -0.5)], - settings.player.diagonalLauncher + settings.player.diagonalLauncher, + projectileData ); new PlayerProjectileCollisionSystem([this.haloProjectileLauncher, this.horizontalProjectileLauncher, this.diagonalProjectileLauncher]); diff --git a/assets/Scripts/Game/Projectile/Projectile.ts b/assets/Scripts/Game/Projectile/Projectile.ts index cf6712d..ecb7f75 100644 --- a/assets/Scripts/Game/Projectile/Projectile.ts +++ b/assets/Scripts/Game/Projectile/Projectile.ts @@ -7,20 +7,43 @@ const { ccclass, property } = _decorator; @ccclass("Projectile") export class Projectile extends Component { @property(CircleCollider2D) private collider: CircleCollider2D; - private contactBeginEvent: Signal = new Signal(); + private contactBeginEvent = new Signal(); + private piercesDepletedEvent = new Signal(); - private isInit = false; - public tryInit(): void { - if (this.isInit) return; - this.isInit = true; + private isContactListenerSet = false; - this.collider.on(Contact2DType.BEGIN_CONTACT, this.onColliderContactBegin, this); + private piercesLeft = 0; + private damage = 0; + + public init(damage: number, pierces: number): void { + this.piercesLeft = pierces; + this.damage = damage; + + if (!this.isContactListenerSet) { + this.isContactListenerSet = true; + this.collider.on(Contact2DType.BEGIN_CONTACT, this.onColliderContactBegin, this); + } + } + + public pierce(): void { + this.piercesLeft--; + if (this.piercesLeft <= 0) { + this.piercesDepletedEvent.trigger(this); + } + } + + public get Damage(): number { + return this.damage; } public get ContactBeginEvent(): ISignal { return this.contactBeginEvent; } + public get PiercesDepletedEvent(): ISignal { + return this.piercesDepletedEvent; + } + private onColliderContactBegin(thisCollider: Collider2D, otherCollider: Collider2D): void { this.contactBeginEvent.trigger({ otherCollider, projectile: this }); } diff --git a/assets/Scripts/Game/TestGameRunner.ts b/assets/Scripts/Game/TestGameRunner.ts index 6775e66..22824b8 100644 --- a/assets/Scripts/Game/TestGameRunner.ts +++ b/assets/Scripts/Game/TestGameRunner.ts @@ -1,11 +1,19 @@ -import { Component, _decorator } from "cc"; +import { CCInteger, Component, _decorator } from "cc"; import { GameRunner } from "../Menu/GameRunner"; import { delay } from "../Services/Utils/AsyncUtils"; +import { UserData } from "./Data/UserData"; import { Game } from "./Game"; -const { ccclass } = _decorator; +const { ccclass, property } = _decorator; @ccclass("TestGameRunner") export class TestGameRunner extends Component { + @property(CCInteger) private maxHpLevel = 0; + @property(CCInteger) private bonusDamageLevel = 0; + @property(CCInteger) private projectilePiercingLevel = 0; + @property(CCInteger) private movementSpeedLevel = 0; + @property(CCInteger) private xpGathererLevel = 0; + @property(CCInteger) private goldGathererLevel = 0; + public start(): void { if (GameRunner.Instance.IsRunning) return; this.playTestGameAsync(); @@ -13,6 +21,14 @@ export class TestGameRunner extends Component { public async playTestGameAsync(): Promise { while (Game.Instance == null) await delay(100); - Game.Instance.playGame(); + + const testUserData = new UserData(); + testUserData.game.metaUpgrades.maxHpLevel = this.maxHpLevel; + testUserData.game.metaUpgrades.bonusDamageLevel = this.bonusDamageLevel; + testUserData.game.metaUpgrades.projectilePiercingLevel = this.projectilePiercingLevel; + testUserData.game.metaUpgrades.movementSpeedLevel = this.movementSpeedLevel; + testUserData.game.metaUpgrades.xpGathererLevel = this.xpGathererLevel; + testUserData.game.metaUpgrades.goldGathererLevel = this.goldGathererLevel; + Game.Instance.playGame(testUserData); } } diff --git a/assets/Scripts/Game/Unit/MetaUpgrades.meta b/assets/Scripts/Game/Unit/MetaUpgrades.meta new file mode 100644 index 0000000..0831c7a --- /dev/null +++ b/assets/Scripts/Game/Unit/MetaUpgrades.meta @@ -0,0 +1,12 @@ +{ + "ver": "1.1.0", + "importer": "directory", + "imported": true, + "uuid": "675f0f72-bbed-4b01-a4af-80f77c27653e", + "files": [], + "subMetas": {}, + "userData": { + "compressionType": {}, + "isRemoteBundle": {} + } +} diff --git a/assets/Scripts/Game/Unit/MetaUpgrades/MetaUpgrades.ts b/assets/Scripts/Game/Unit/MetaUpgrades/MetaUpgrades.ts new file mode 100644 index 0000000..a95223d --- /dev/null +++ b/assets/Scripts/Game/Unit/MetaUpgrades/MetaUpgrades.ts @@ -0,0 +1,23 @@ +import { MetaUpgradeSettings } from "../../Data/GameSettings"; +import { MetaUpgradesData } from "../../Data/UserData"; +import { MetaUpgradeType } from "../../Upgrades/UpgradeType"; + +export class MetaUpgrades { + private upgradeTypeToValue = new Map(); + public constructor(data: MetaUpgradesData, settings: MetaUpgradeSettings) { + this.upgradeTypeToValue.set(MetaUpgradeType.MaxHp, data.maxHpLevel * settings.healthPointsPerLevel); + this.upgradeTypeToValue.set(MetaUpgradeType.OverallDamage, data.bonusDamageLevel * settings.bonusDamagePerLevel); + this.upgradeTypeToValue.set(MetaUpgradeType.ProjectilePiercing, data.projectilePiercingLevel * settings.projectilePiercingPerLevel); + this.upgradeTypeToValue.set(MetaUpgradeType.MovementSpeed, data.movementSpeedLevel * settings.movementSpeedPerLevel); + this.upgradeTypeToValue.set(MetaUpgradeType.XPGatherer, data.xpGathererLevel * settings.xpBonusPerLevel); + this.upgradeTypeToValue.set(MetaUpgradeType.GoldGatherer, data.goldGathererLevel * settings.goldBonusPerLevel); + } + + public getUpgradeValue(type: MetaUpgradeType): number { + if (!this.upgradeTypeToValue.has(type)) { + throw new Error("Does not have meta upgrade set up " + type); + } + + return this.upgradeTypeToValue.get(type); + } +} diff --git a/assets/Scripts/Game/Unit/MetaUpgrades/MetaUpgrades.ts.meta b/assets/Scripts/Game/Unit/MetaUpgrades/MetaUpgrades.ts.meta new file mode 100644 index 0000000..e6e482d --- /dev/null +++ b/assets/Scripts/Game/Unit/MetaUpgrades/MetaUpgrades.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "50863e3a-1339-4a3a-aa58-74f316b3344a", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/Scripts/Game/Unit/Player/Player.ts b/assets/Scripts/Game/Unit/Player/Player.ts index 378f46e..0c5ac85 100644 --- a/assets/Scripts/Game/Unit/Player/Player.ts +++ b/assets/Scripts/Game/Unit/Player/Player.ts @@ -21,7 +21,7 @@ export class Player extends Component { private level: UnitLevel; private regeneration: PlayerRegeneration; - public init(input: IInput, settings: PlayerSettings): void { + public init(input: IInput, settings: PlayerData): void { this.input = input; this.health = new UnitHealth(settings.defaultHP); this.level = new UnitLevel(settings.requiredXP); @@ -30,6 +30,8 @@ export class Player extends Component { this.weapon.init(settings.weapon); this.playerUI.init(this.health); + + console.log("Bonus damage " + settings.bonusDamage); } public get Health(): UnitHealth { @@ -67,3 +69,11 @@ export class Player extends Component { this.regeneration.gameTick(deltaTime); } } + +export class PlayerData extends PlayerSettings { + public bonusDamage = 0; + public bonusHp = 0; + public bonusSpeed = 0; + public bonusXP = 0; + public bonusGold = 0; +} diff --git a/assets/Scripts/Game/Unit/Player/ProjectileLauncher/HaloProjectileLauncher.ts b/assets/Scripts/Game/Unit/Player/ProjectileLauncher/HaloProjectileLauncher.ts index 0a7eb9d..1965136 100644 --- a/assets/Scripts/Game/Unit/Player/ProjectileLauncher/HaloProjectileLauncher.ts +++ b/assets/Scripts/Game/Unit/Player/ProjectileLauncher/HaloProjectileLauncher.ts @@ -4,14 +4,14 @@ import { roundToOneDecimal } from "../../../../Services/Utils/MathUtils"; import { HaloLauncherSettings } from "../../../Data/GameSettings"; import { ProjectileCollision } from "../../../Projectile/ProjectileCollision"; import { IProjectileCollisionSignaler } from "../../../Projectile/IProjectileCollisionSignaler"; -import { ProjectileLauncher } from "./ProjectileLauncher"; +import { ProjectileData, ProjectileLauncher } from "./ProjectileLauncher"; export class HaloProjectileLauncher implements IProjectileCollisionSignaler { private currentUpgrade = 0; private defaultCooldown = 0; private cooldownDivisorPerUpgrade = 0; - public constructor(private launcher: ProjectileLauncher, playerNode: Node, settings: HaloLauncherSettings) { + public constructor(private launcher: ProjectileLauncher, playerNode: Node, settings: HaloLauncherSettings, projectileData: ProjectileData) { this.defaultCooldown = settings.launcher.cooldown; this.cooldownDivisorPerUpgrade = settings.cooldownDivisorPerUpgrade; @@ -24,7 +24,7 @@ export class HaloProjectileLauncher implements IProjectileCollisionSignaler { directions.push(new Vec2(x, y).normalize()); } - launcher.init(playerNode, directions, settings.launcher); + launcher.init(playerNode, directions, settings.launcher, projectileData); } public get ProjectileCollisionEvent(): ISignal { @@ -39,6 +39,6 @@ export class HaloProjectileLauncher implements IProjectileCollisionSignaler { public upgrade(): void { this.currentUpgrade++; - this.launcher.Cooldown = (this.defaultCooldown / this.cooldownDivisorPerUpgrade) * this.currentUpgrade; + this.launcher.Cooldown = this.defaultCooldown / (this.cooldownDivisorPerUpgrade * this.currentUpgrade); } } diff --git a/assets/Scripts/Game/Unit/Player/ProjectileLauncher/ProjectileLauncher.ts b/assets/Scripts/Game/Unit/Player/ProjectileLauncher/ProjectileLauncher.ts index a337d52..8badb4c 100644 --- a/assets/Scripts/Game/Unit/Player/ProjectileLauncher/ProjectileLauncher.ts +++ b/assets/Scripts/Game/Unit/Player/ProjectileLauncher/ProjectileLauncher.ts @@ -14,7 +14,7 @@ const { ccclass, property } = _decorator; export class ProjectileLauncher extends Component implements IProjectileCollisionSignaler { @property(Prefab) private projectilePrefab: Prefab; private projectileCollisionEvent: Signal = new Signal(); - + private projectileData: ProjectileData; private projectilePool: ObjectPool; private fireTimer: GameTimer; private projectileLifetime: number; @@ -53,7 +53,8 @@ export class ProjectileLauncher extends Component implements IProjectileCollisio return this.projectileCollisionEvent; } - public init(playerNode: Node, fireDirections: Vec2[], settings: ProjectileLauncherSettings): void { + public init(playerNode: Node, fireDirections: Vec2[], settings: ProjectileLauncherSettings, projectileData: ProjectileData): void { + this.projectileData = projectileData; this.projectileLifetime = settings.projectileLifetime; this.speed = settings.projectileSpeed; this.wavesToShoot = settings.wavesToShoot; @@ -89,10 +90,11 @@ export class ProjectileLauncher extends Component implements IProjectileCollisio private fireProjectile(direction: Vec2): void { const projectile: Projectile = this.projectilePool.borrow(); - projectile.tryInit(); + projectile.init(this.projectileData.damage, this.projectileData.pierces); projectile.node.setWorldPosition(this.playerNode.worldPosition); projectile.node.active = true; projectile.ContactBeginEvent.on(this.onProjectileCollision, this); + projectile.PiercesDepletedEvent.on(this.onPiercesDepleted, this); this.projectiles.push(projectile); this.directions.push(direction); @@ -104,16 +106,31 @@ export class ProjectileLauncher extends Component implements IProjectileCollisio if (this.currentTime < this.expireTimes[i]) break; // the oldest particles are at the start of the array const projectile: Projectile = this.projectiles[i]; - projectile.ContactBeginEvent.off(this.onProjectileCollision); - this.projectilePool.return(projectile); - - this.projectiles.splice(i, 1); - this.directions.splice(i, 1); - this.expireTimes.splice(i, 1); + this.removeProjectile(projectile, i); i--; // Check the same index } } + private onPiercesDepleted(projectile: Projectile): void { + const index = this.projectiles.indexOf(projectile); + if (index === -1) { + throw new Error("Projectile not found!"); + } + + this.removeProjectile(projectile, index); + } + + private removeProjectile(projectile: Projectile, index: number): void { + projectile.ContactBeginEvent.off(this.onProjectileCollision); + projectile.PiercesDepletedEvent.off(this.onPiercesDepleted); + + this.projectilePool.return(projectile); + + this.projectiles.splice(index, 1); + this.directions.splice(index, 1); + this.expireTimes.splice(index, 1); + } + private moveAllProjectiles(deltaTime: number): void { for (let i = 0; i < this.projectiles.length; i++) { const newPosition: Vec3 = this.projectiles[i].node.worldPosition; @@ -128,3 +145,8 @@ export class ProjectileLauncher extends Component implements IProjectileCollisio this.projectileCollisionEvent.trigger(projectlieCollision); } } + +export class ProjectileData { + public pierces = 0; + public damage = 0; +} diff --git a/assets/Scripts/Game/Unit/Player/ProjectileLauncher/WaveProjectileLauncher.ts b/assets/Scripts/Game/Unit/Player/ProjectileLauncher/WaveProjectileLauncher.ts index 069728e..b52df9c 100644 --- a/assets/Scripts/Game/Unit/Player/ProjectileLauncher/WaveProjectileLauncher.ts +++ b/assets/Scripts/Game/Unit/Player/ProjectileLauncher/WaveProjectileLauncher.ts @@ -3,15 +3,21 @@ import { ISignal } from "../../../../Services/EventSystem/ISignal"; import { WaveLauncherSettings } from "../../../Data/GameSettings"; import { IProjectileCollisionSignaler } from "../../../Projectile/IProjectileCollisionSignaler"; import { ProjectileCollision } from "../../../Projectile/ProjectileCollision"; -import { ProjectileLauncher } from "./ProjectileLauncher"; +import { ProjectileData, ProjectileLauncher } from "./ProjectileLauncher"; export class WaveProjectileLauncher implements IProjectileCollisionSignaler { private currentUpgrade = 0; private wavesToShootPerUpgrade = 0; - public constructor(private launcher: ProjectileLauncher, playerNode: Node, directions: Vec2[], settings: WaveLauncherSettings) { + public constructor( + private launcher: ProjectileLauncher, + playerNode: Node, + directions: Vec2[], + settings: WaveLauncherSettings, + projectileData: ProjectileData + ) { this.wavesToShootPerUpgrade = settings.wavesToShootPerUpgrade; - launcher.init(playerNode, directions, settings.launcher); + launcher.init(playerNode, directions, settings.launcher, projectileData); } public get ProjectileCollisionEvent(): ISignal {