mirror of
https://github.com/MartinKral/Slash-The-Hordes
synced 2025-10-10 09:06:03 +00:00
Moving projectile launcher
This commit is contained in:
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "f996de47-37ab-489b-820f-fe7a38c09c64",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"compressionType": {},
|
||||
"isRemoteBundle": {}
|
||||
}
|
||||
}
|
@@ -1,69 +0,0 @@
|
||||
import { Node, Vec2 } from "cc";
|
||||
import { ISignal } from "../../../../Services/EventSystem/ISignal";
|
||||
import { Signal } from "../../../../Services/EventSystem/Signal";
|
||||
import { GameTimer } from "../../../../Services/GameTimer";
|
||||
import { roundToOneDecimal } from "../../../../Services/Utils/MathUtils";
|
||||
import { HaloLauncherSettings } from "../../../Data/GameSettings";
|
||||
import { IProjectileLauncherSignaler } from "../../../Projectile/IProjectileLauncherSignaler";
|
||||
import { ProjectileCollision } from "../../../Projectile/ProjectileCollision";
|
||||
import { ProjectileData } from "./ProjectileData";
|
||||
import { ProjectileLauncher } from "./ProjectileLauncher";
|
||||
|
||||
export class HaloProjectileLauncher implements IProjectileLauncherSignaler {
|
||||
private currentUpgrade = 0;
|
||||
private defaultCooldown = 0;
|
||||
private cooldownDivisorPerUpgrade = 0;
|
||||
private directions: Vec2[] = [];
|
||||
private fireTimer = new GameTimer(0);
|
||||
|
||||
private projectilesLaunchedEvent = new Signal();
|
||||
|
||||
public constructor(
|
||||
private launcher: ProjectileLauncher,
|
||||
private playerNode: Node,
|
||||
settings: HaloLauncherSettings,
|
||||
projectileData: ProjectileData
|
||||
) {
|
||||
this.defaultCooldown = settings.launcher.cooldown;
|
||||
this.cooldownDivisorPerUpgrade = settings.cooldownDivisorPerUpgrade;
|
||||
|
||||
const angle: number = (2 * Math.PI) / settings.projectilesToSpawn;
|
||||
|
||||
for (let i = 0; i < settings.projectilesToSpawn; i++) {
|
||||
const x: number = roundToOneDecimal(Math.sin(angle * i));
|
||||
const y: number = roundToOneDecimal(Math.cos(angle * i));
|
||||
this.directions.push(new Vec2(x, y).normalize());
|
||||
}
|
||||
|
||||
launcher.init(settings.launcher.projectileLifetime, settings.launcher.projectileSpeed, projectileData.damage, projectileData.pierces);
|
||||
}
|
||||
|
||||
public get ProjectileCollisionEvent(): ISignal<ProjectileCollision> {
|
||||
return this.launcher.ProjectileCollisionEvent;
|
||||
}
|
||||
|
||||
public get ProjectileLaunchedEvent(): ISignal {
|
||||
return this.launcher.ProjectileLaunchedEvent;
|
||||
}
|
||||
|
||||
public get ProjectilesLaunchedEvent(): ISignal {
|
||||
return this.projectilesLaunchedEvent;
|
||||
}
|
||||
|
||||
public gameTick(deltaTime: number): void {
|
||||
if (this.currentUpgrade == 0) return;
|
||||
|
||||
this.launcher.gameTick(deltaTime);
|
||||
this.fireTimer.gameTick(deltaTime);
|
||||
|
||||
if (this.fireTimer.tryFinishPeriod()) {
|
||||
this.launcher.fireProjectiles(this.playerNode.worldPosition, this.directions);
|
||||
this.projectilesLaunchedEvent.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
public upgrade(): void {
|
||||
this.currentUpgrade++;
|
||||
this.fireTimer = new GameTimer(this.defaultCooldown / (this.cooldownDivisorPerUpgrade * this.currentUpgrade));
|
||||
}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "422b46ec-3e15-437d-97fc-7f44a277c3be",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
export class ProjectileData {
|
||||
public pierces = 0;
|
||||
public damage = 0;
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "a4a076f3-e9fa-4838-bc7c-886d9aac8f60",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
@@ -1,118 +0,0 @@
|
||||
import { _decorator, Component, Prefab, Vec2, Vec3 } from "cc";
|
||||
import { Empty } from "../../../../Menu/ModalWindows/Upgrades/UpgradesModalWindow";
|
||||
import { ISignal } from "../../../../Services/EventSystem/ISignal";
|
||||
import { Signal } from "../../../../Services/EventSystem/Signal";
|
||||
import { ObjectPool } from "../../../../Services/ObjectPool";
|
||||
import { getDegreeAngleFromDirection } from "../../../../Services/Utils/MathUtils";
|
||||
import { IProjectileLauncherSignaler } from "../../../Projectile/IProjectileLauncherSignaler";
|
||||
import { Projectile } from "../../../Projectile/Projectile";
|
||||
import { ProjectileCollision } from "../../../Projectile/ProjectileCollision";
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass("ProjectileLauncher")
|
||||
export class ProjectileLauncher extends Component implements IProjectileLauncherSignaler {
|
||||
@property(Prefab) private projectilePrefab: Prefab;
|
||||
private projectileCollisionEvent = new Signal<ProjectileCollision>();
|
||||
private projectileLaunchedEvent = new Signal();
|
||||
|
||||
private projectileDamage: number;
|
||||
private projectilePierces: number;
|
||||
private projectileLifetime: number;
|
||||
private projectileSpeed: number;
|
||||
|
||||
private projectilePool: ObjectPool<Projectile>;
|
||||
|
||||
private projectiles: Projectile[] = [];
|
||||
private directions: Vec2[] = [];
|
||||
private expireTimes: number[] = [];
|
||||
private currentTime = 0;
|
||||
|
||||
public get ProjectileCollisionEvent(): ISignal<ProjectileCollision> {
|
||||
return this.projectileCollisionEvent;
|
||||
}
|
||||
|
||||
public get ProjectileLaunchedEvent(): ISignal {
|
||||
return this.projectileLaunchedEvent;
|
||||
}
|
||||
|
||||
public init(projectileLifetime: number, projectileSpeed: number, projectileDamage: number, projectilePierces: number): void {
|
||||
this.projectileLifetime = projectileLifetime;
|
||||
this.projectileSpeed = projectileSpeed;
|
||||
this.projectileDamage = projectileDamage;
|
||||
this.projectilePierces = projectilePierces;
|
||||
|
||||
this.projectilePool = new ObjectPool<Projectile>(this.projectilePrefab, this.node, 6, "Projectile");
|
||||
}
|
||||
|
||||
public gameTick(deltaTime: number): void {
|
||||
this.currentTime += deltaTime;
|
||||
this.tryRemoveExpiredProjectiles();
|
||||
this.moveAllProjectiles(deltaTime);
|
||||
}
|
||||
|
||||
public fireProjectiles(startPosition: Vec3, fireDirections: Vec2[]): void {
|
||||
for (const direction of fireDirections) {
|
||||
this.fireProjectile(startPosition, direction);
|
||||
}
|
||||
}
|
||||
|
||||
private fireProjectile(startPosition: Vec3, direction: Vec2): void {
|
||||
direction = direction.normalize();
|
||||
const projectile: Projectile = this.projectilePool.borrow();
|
||||
projectile.setup(this.projectileDamage, this.projectilePierces, getDegreeAngleFromDirection(direction.x, direction.y));
|
||||
projectile.node.setWorldPosition(startPosition);
|
||||
projectile.node.active = true;
|
||||
projectile.ContactBeginEvent.on(this.onProjectileCollision, this);
|
||||
projectile.PiercesDepletedEvent.on(this.onPiercesDepleted, this);
|
||||
|
||||
this.projectiles.push(projectile);
|
||||
this.directions.push(direction);
|
||||
this.expireTimes.push(this.currentTime + this.projectileLifetime);
|
||||
|
||||
this.projectileLaunchedEvent.trigger();
|
||||
}
|
||||
|
||||
private tryRemoveExpiredProjectiles(): void {
|
||||
for (let i = 0; i < this.projectiles.length; i++) {
|
||||
if (this.currentTime < this.expireTimes[i]) break; // the oldest particles are at the start of the array
|
||||
|
||||
const projectile: Projectile = this.projectiles[i];
|
||||
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;
|
||||
newPosition.x += this.directions[i].x * deltaTime * this.projectileSpeed;
|
||||
newPosition.y += this.directions[i].y * deltaTime * this.projectileSpeed;
|
||||
|
||||
this.projectiles[i].node.setWorldPosition(newPosition);
|
||||
}
|
||||
}
|
||||
|
||||
private onProjectileCollision(projectlieCollision: ProjectileCollision): void {
|
||||
this.projectileCollisionEvent.trigger(projectlieCollision);
|
||||
}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "e3d06e80-f1ec-4505-a596-9f6831e1ce23",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
import { Node, Vec2 } from "cc";
|
||||
import { Empty } from "../../../../Menu/ModalWindows/Upgrades/UpgradesModalWindow";
|
||||
import { ISignal } from "../../../../Services/EventSystem/ISignal";
|
||||
import { GameTimer } from "../../../../Services/GameTimer";
|
||||
import { delay } from "../../../../Services/Utils/AsyncUtils";
|
||||
import { WaveLauncherSettings } from "../../../Data/GameSettings";
|
||||
import { IProjectileLauncherSignaler } from "../../../Projectile/IProjectileLauncherSignaler";
|
||||
import { ProjectileCollision } from "../../../Projectile/ProjectileCollision";
|
||||
import { ProjectileData } from "./ProjectileData";
|
||||
import { ProjectileLauncher } from "./ProjectileLauncher";
|
||||
|
||||
export class WaveProjectileLauncher implements IProjectileLauncherSignaler {
|
||||
private currentUpgrade = 0;
|
||||
private wavesToShootPerUpgrade = 0;
|
||||
private fireTimer: GameTimer;
|
||||
private wavesToShoot: number;
|
||||
private wavesDelayMs: number;
|
||||
|
||||
public constructor(
|
||||
private launcher: ProjectileLauncher,
|
||||
private playerNode: Node,
|
||||
private directions: Vec2[],
|
||||
settings: WaveLauncherSettings,
|
||||
projectileData: ProjectileData
|
||||
) {
|
||||
this.wavesToShootPerUpgrade = settings.wavesToShootPerUpgrade;
|
||||
|
||||
this.fireTimer = new GameTimer(settings.launcher.cooldown);
|
||||
this.wavesToShoot = settings.launcher.wavesToShoot;
|
||||
this.wavesDelayMs = settings.launcher.wavesDelayMs;
|
||||
|
||||
launcher.init(settings.launcher.projectileLifetime, settings.launcher.projectileSpeed, projectileData.damage, projectileData.pierces);
|
||||
}
|
||||
|
||||
public get ProjectileCollisionEvent(): ISignal<ProjectileCollision> {
|
||||
return this.launcher.ProjectileCollisionEvent;
|
||||
}
|
||||
|
||||
public get ProjectileLaunchedEvent(): ISignal {
|
||||
return this.launcher.ProjectileLaunchedEvent;
|
||||
}
|
||||
|
||||
public gameTick(deltaTime: number): void {
|
||||
if (this.currentUpgrade == 0) return;
|
||||
|
||||
this.launcher.gameTick(deltaTime);
|
||||
this.fireTimer.gameTick(deltaTime);
|
||||
|
||||
if (this.fireTimer.tryFinishPeriod()) {
|
||||
this.fireProjectiles();
|
||||
}
|
||||
}
|
||||
|
||||
public upgrade(): void {
|
||||
this.currentUpgrade++;
|
||||
this.wavesToShoot += this.wavesToShootPerUpgrade;
|
||||
}
|
||||
|
||||
private async fireProjectiles(): Promise<void> {
|
||||
for (let i = 0; i < this.wavesToShoot; i++) {
|
||||
this.launcher.fireProjectiles(this.playerNode.worldPosition, this.directions);
|
||||
|
||||
await delay(this.wavesDelayMs);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "1ed6eff1-da2e-4727-8f44-2e802848719c",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
Reference in New Issue
Block a user