Projectile piercing, meta upgrades

This commit is contained in:
Martin 2022-12-13 11:58:40 +01:00
parent e626d493d2
commit 39775b2a65
15 changed files with 201 additions and 35 deletions

View File

@ -59,6 +59,14 @@
"maxHaloProjectileUpgrades": 5,
"maxRegenerationUpgrades": 5
},
"metaUpgrades": {
"healthPointsPerLevel": 0,
"bonusDamagePerLevel": 0,
"projectilePiercingPerLevel": 0,
"movementSpeedPerLevel": 0,
"xpBonusPerLevel": 0,
"goldBonusPerLevel": 0
},
"enemyManager": {
"enemies": [
{

View File

@ -195,6 +195,12 @@
},
"_enabled": true,
"__prefab": null,
"maxHpLevel": 0,
"bonusDamageLevel": 5,
"projectilePiercingLevel": 0,
"movementSpeedLevel": 0,
"xpGathererLevel": 0,
"goldGathererLevel": 0,
"_id": "35CwPVksdGoJPgBRCGSH6m"
},
{

View File

@ -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();
}
}

View File

@ -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()];

View File

@ -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;
}

View File

@ -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<number> {
public async playGame(userData: UserData): Promise<number> {
const settings: GameSettings = <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]);

View File

@ -7,20 +7,43 @@ const { ccclass, property } = _decorator;
@ccclass("Projectile")
export class Projectile extends Component {
@property(CircleCollider2D) private collider: CircleCollider2D;
private contactBeginEvent: Signal<ProjectileCollision> = new Signal<ProjectileCollision>();
private contactBeginEvent = new Signal<ProjectileCollision>();
private piercesDepletedEvent = new Signal<Projectile>();
private isInit = false;
public tryInit(): void {
if (this.isInit) return;
this.isInit = true;
private isContactListenerSet = false;
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<ProjectileCollision> {
return this.contactBeginEvent;
}
public get PiercesDepletedEvent(): ISignal<Projectile> {
return this.piercesDepletedEvent;
}
private onColliderContactBegin(thisCollider: Collider2D, otherCollider: Collider2D): void {
this.contactBeginEvent.trigger({ otherCollider, projectile: this });
}

View File

@ -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<void> {
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);
}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "675f0f72-bbed-4b01-a4af-80f77c27653e",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@ -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<MetaUpgradeType, number>();
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);
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "50863e3a-1339-4a3a-aa58-74f316b3344a",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@ -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;
}

View File

@ -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<ProjectileCollision> {
@ -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);
}
}

View File

@ -14,7 +14,7 @@ const { ccclass, property } = _decorator;
export class ProjectileLauncher extends Component implements IProjectileCollisionSignaler {
@property(Prefab) private projectilePrefab: Prefab;
private projectileCollisionEvent: Signal<ProjectileCollision> = new Signal<ProjectileCollision>();
private projectileData: ProjectileData;
private projectilePool: ObjectPool<Projectile>;
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;
}

View File

@ -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<ProjectileCollision> {