diff --git a/assets/Scripts/Game/Enemy/Enemy.ts b/assets/Scripts/Game/Enemy/Enemy.ts index 1cab894..72e316c 100644 --- a/assets/Scripts/Game/Enemy/Enemy.ts +++ b/assets/Scripts/Game/Enemy/Enemy.ts @@ -1,4 +1,4 @@ -import { BoxCollider2D, Component, _decorator } from "cc"; +import { BoxCollider2D, Component, Vec2, Vec3, _decorator } from "cc"; import { ISignal } from "../../Services/EventSystem/ISignal"; import { Signal } from "../../Services/EventSystem/Signal"; import { UnitHealth } from "../Player/UnitHealth"; @@ -38,6 +38,14 @@ export class Enemy extends Component implements IDamageDealing { this.deathEvent.trigger(this); } } + + public moveBy(move: Vec3): void { + const newPosition: Vec3 = this.node.worldPosition; + newPosition.x += move.x; + newPosition.y += move.y; + + this.node.setWorldPosition(newPosition); + } } export interface IDamageDealing { diff --git a/assets/Scripts/Game/Enemy/EnemyMover.ts b/assets/Scripts/Game/Enemy/EnemyMover.ts new file mode 100644 index 0000000..779185f --- /dev/null +++ b/assets/Scripts/Game/Enemy/EnemyMover.ts @@ -0,0 +1,28 @@ +import { Node, Vec3 } from "cc"; +import { Enemy } from "./Enemy"; + +export class EnemyMover { + private targetNode: Node; + private enemies: Enemy[] = []; + public constructor(targetNode: Node) { + this.targetNode = targetNode; + } + public addEnemy(enemy: Enemy): void { + this.enemies.push(enemy); + } + + public removeEnemy(enemy: Enemy): void { + const index: number = this.enemies.indexOf(enemy); + if (index != -1) { + this.enemies.splice(index, 1); + } + } + + public gameTick(deltaTime: number): void { + this.enemies.forEach((enemy) => { + let direction: Vec3 = new Vec3(); + direction = Vec3.subtract(direction, this.targetNode.position, enemy.node.position); + enemy.moveBy(direction.multiplyScalar(deltaTime).normalize()); + }); + } +} diff --git a/assets/Scripts/Game/Enemy/EnemyMover.ts.meta b/assets/Scripts/Game/Enemy/EnemyMover.ts.meta new file mode 100644 index 0000000..ecd740b --- /dev/null +++ b/assets/Scripts/Game/Enemy/EnemyMover.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "50aa2052-8c6f-4405-8732-346ac2a942c9", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/Scripts/Game/Enemy/EnemySpawner.ts b/assets/Scripts/Game/Enemy/EnemySpawner.ts index 369aab5..14c257a 100644 --- a/assets/Scripts/Game/Enemy/EnemySpawner.ts +++ b/assets/Scripts/Game/Enemy/EnemySpawner.ts @@ -2,6 +2,7 @@ import { Component, Prefab, randomRange, Vec3, _decorator } from "cc"; import { GameTimer } from "../../Services/GameTimer"; import { ObjectPool } from "../../Services/ObjectPool"; import { Enemy } from "./Enemy"; +import { EnemyMover } from "./EnemyMover"; const { ccclass, property } = _decorator; @ccclass("EnemySpawner") @@ -10,10 +11,12 @@ export class EnemySpawner extends Component { private enemyPool: ObjectPool; private spawnTimer: GameTimer; + private enemyMover: EnemyMover; - public init(): void { + public init(enemyMover: EnemyMover): void { this.enemyPool = new ObjectPool(this.enemies[0], this.node, 5, Enemy); - this.spawnTimer = new GameTimer(5); + this.spawnTimer = new GameTimer(1); + this.enemyMover = enemyMover; } public gameTick(deltaTime: number): void { @@ -21,6 +24,8 @@ export class EnemySpawner extends Component { if (this.spawnTimer.tryFinishPeriod()) { this.spawnNewEnemy(); } + + this.enemyMover.gameTick(deltaTime); } private spawnNewEnemy(): void { @@ -31,11 +36,14 @@ export class EnemySpawner extends Component { enemy.setup(); enemy.DeathEvent.on(this.returnEnemyToPool, this); + + this.enemyMover.addEnemy(enemy); } private returnEnemyToPool(enemy: Enemy): void { - console.log("Return to enemy pool"); enemy.DeathEvent.off(this.returnEnemyToPool); this.enemyPool.return(enemy); + + this.enemyMover.removeEnemy(enemy); } } diff --git a/assets/Scripts/Game/GameBootstrapper.ts b/assets/Scripts/Game/GameBootstrapper.ts index b0031c1..defae38 100644 --- a/assets/Scripts/Game/GameBootstrapper.ts +++ b/assets/Scripts/Game/GameBootstrapper.ts @@ -1,10 +1,13 @@ -import { Component, _decorator } from "cc"; +import { Component, KeyCode, _decorator } from "cc"; import { PlayerCollisionSystem } from "./Collision/PlayerCollisionSystem"; import { WeaponCollisionSystem } from "./Collision/WeaponCollisionSystem"; import { EnemySpawner } from "./Enemy/EnemySpawner"; +import { MultiInput } from "./Input/MultiInput"; import { VirtualJoystic } from "./Input/VirtualJoystic"; +import { KeyboardInput } from "./Input/KeyboardInput"; import { Player } from "./Player/Player"; import { Weapon } from "./Weapon"; +import { EnemyMover } from "./Enemy/EnemyMover"; const { ccclass, property } = _decorator; @ccclass("GameBootstrapper") @@ -20,8 +23,13 @@ export class GameBootstrapper extends Component { public start(): void { this.virtualJoystic.init(); this.weapon.init(this.strikeDelay); - this.player.init(this.virtualJoystic, this.weapon, 50); - this.enemySpawner.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 dualInput: MultiInput = new MultiInput([this.virtualJoystic, wasd, arrowKeys]); + this.player.init(dualInput, this.weapon, 50); + + const enemyMover = new EnemyMover(this.player.node); + this.enemySpawner.init(enemyMover); this.playerCollisionSystem = new PlayerCollisionSystem(this.player, this.collisionDelay); new WeaponCollisionSystem(this.weapon); } diff --git a/assets/Scripts/Game/Input/IInput.ts b/assets/Scripts/Game/Input/IInput.ts new file mode 100644 index 0000000..a036e56 --- /dev/null +++ b/assets/Scripts/Game/Input/IInput.ts @@ -0,0 +1,5 @@ +import { Vec2 } from "cc"; + +export interface IInput { + getAxis: () => Vec2; +} diff --git a/assets/Scripts/Game/Input/IInput.ts.meta b/assets/Scripts/Game/Input/IInput.ts.meta new file mode 100644 index 0000000..9e7b5cf --- /dev/null +++ b/assets/Scripts/Game/Input/IInput.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "b82ab67e-d720-4feb-ada9-07b6704a2b88", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/Scripts/Game/Input/KeyboardInput.ts b/assets/Scripts/Game/Input/KeyboardInput.ts new file mode 100644 index 0000000..cf42fbf --- /dev/null +++ b/assets/Scripts/Game/Input/KeyboardInput.ts @@ -0,0 +1,60 @@ +import { EventKeyboard, Input, input, KeyCode, Vec2 } from "cc"; +import { IInput } from "./IInput"; + +export class KeyboardInput implements IInput { + private xAxis = 0; + private yAxis = 0; + + private up: KeyCode; + private down: KeyCode; + private left: KeyCode; + private right: KeyCode; + + public constructor(up: KeyCode, down: KeyCode, left: KeyCode, right: KeyCode) { + this.up = up; + this.down = down; + this.left = left; + this.right = right; + + input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this); + input.on(Input.EventType.KEY_UP, this.onKeyUp, this); + } + + public getAxis(): Vec2 { + return new Vec2(this.xAxis, this.yAxis).normalize(); + } + + private onKeyDown(event: EventKeyboard): void { + switch (event.keyCode) { + case this.up: + this.yAxis += 1; + break; + case this.down: + this.yAxis += -1; + break; + case this.left: + this.xAxis += -1; + break; + case this.right: + this.xAxis += 1; + break; + } + } + + private onKeyUp(event: EventKeyboard): void { + switch (event.keyCode) { + case this.up: + this.yAxis -= 1; + break; + case this.down: + this.yAxis -= -1; + break; + case this.left: + this.xAxis -= -1; + break; + case this.right: + this.xAxis -= 1; + break; + } + } +} diff --git a/assets/Scripts/Game/Input/KeyboardInput.ts.meta b/assets/Scripts/Game/Input/KeyboardInput.ts.meta new file mode 100644 index 0000000..c5b2a26 --- /dev/null +++ b/assets/Scripts/Game/Input/KeyboardInput.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "14d4988b-08bc-4a0e-97e7-b06b78b1a180", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/Scripts/Game/Input/MultiInput.ts b/assets/Scripts/Game/Input/MultiInput.ts new file mode 100644 index 0000000..8a939fe --- /dev/null +++ b/assets/Scripts/Game/Input/MultiInput.ts @@ -0,0 +1,20 @@ +import { Vec2 } from "cc"; +import { IInput } from "./IInput"; + +export class MultiInput implements IInput { + private inputs: IInput[]; + + public constructor(inputs: IInput[]) { + this.inputs = inputs; + } + + public getAxis(): Vec2 { + for (let i = 0; i < this.inputs.length; i++) { + if (!this.inputs[i].getAxis().equals(Vec2.ZERO)) { + return this.inputs[i].getAxis(); + } + } + + return new Vec2(); + } +} diff --git a/assets/Scripts/Game/Input/MultiInput.ts.meta b/assets/Scripts/Game/Input/MultiInput.ts.meta new file mode 100644 index 0000000..adce9d5 --- /dev/null +++ b/assets/Scripts/Game/Input/MultiInput.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "679d7c05-dfb4-43e8-8115-9af235222733", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/Scripts/Game/Input/VirtualJoystic.ts b/assets/Scripts/Game/Input/VirtualJoystic.ts index deed54b..193bc8c 100644 --- a/assets/Scripts/Game/Input/VirtualJoystic.ts +++ b/assets/Scripts/Game/Input/VirtualJoystic.ts @@ -1,8 +1,9 @@ import { _decorator, Component, Node, Vec3, input, Input, EventMouse, Vec2, EventTouch } from "cc"; +import { IInput } from "./IInput"; const { ccclass, property } = _decorator; @ccclass("VirtualJoystic") -export class VirtualJoystic extends Component { +export class VirtualJoystic extends Component implements IInput { @property(Number) private maxDistance = 10; @property(Node) private knob: Node; diff --git a/assets/Scripts/Game/Player/Player.ts b/assets/Scripts/Game/Player/Player.ts index 1cb39e9..07683ea 100644 --- a/assets/Scripts/Game/Player/Player.ts +++ b/assets/Scripts/Game/Player/Player.ts @@ -1,8 +1,8 @@ import { BoxCollider2D, Collider2D, Component, Vec2, Vec3, _decorator } from "cc"; -import { VirtualJoystic } from "../Input/VirtualJoystic"; +import { IInput } from "../Input/IInput"; import { Weapon } from "../Weapon"; -import { UnitHealth } from "./UnitHealth"; import { PlayerUI } from "./PlayerUI/PlayerUI"; +import { UnitHealth } from "./UnitHealth"; const { ccclass, property } = _decorator; @ccclass("Player") @@ -11,12 +11,12 @@ export class Player extends Component { @property(BoxCollider2D) private collider: BoxCollider2D; @property(PlayerUI) private playerUI: PlayerUI; - private virtualJoystic: VirtualJoystic; + private input: IInput; private weapon: Weapon; private health: UnitHealth; - public init(virtualJoystic: VirtualJoystic, weapon: Weapon, maxHp: number): void { - this.virtualJoystic = virtualJoystic; + public init(input: IInput, weapon: Weapon, maxHp: number): void { + this.input = input; this.weapon = weapon; this.health = new UnitHealth(maxHp); @@ -35,7 +35,7 @@ export class Player extends Component { } public gameTick(deltaTime: number): void { - const movement: Vec2 = this.virtualJoystic.getAxis(); + const movement: Vec2 = this.input.getAxis(); movement.x *= deltaTime * this.speed; movement.y *= deltaTime * this.speed; diff --git a/assets/Scripts/Game/Weapon.ts b/assets/Scripts/Game/Weapon.ts index 8052ff6..b94c30a 100644 --- a/assets/Scripts/Game/Weapon.ts +++ b/assets/Scripts/Game/Weapon.ts @@ -1,5 +1,6 @@ import { Animation, BoxCollider2D, Collider2D, Component, Vec2, Vec3, _decorator } from "cc"; import { GameTimer } from "../Services/GameTimer"; +import { delay } from "../Services/Utils/AsyncUtils"; const { ccclass, property } = _decorator; @ccclass("Weapon") @@ -8,15 +9,24 @@ export class Weapon extends Component { @property(BoxCollider2D) private collider: BoxCollider2D; private strikeTimer: GameTimer; + private lastDirection = new Vec2(); public init(strikeDelay: number): void { this.strikeTimer = new GameTimer(strikeDelay); + this.node.active = false; } public gameTick(deltaTime: number, movement: Vec2): void { + let direction: Vec2 = movement.normalize(); + if (direction.x == 0 && direction.y == 0) { + direction = this.lastDirection; + } else { + this.lastDirection = direction; + } + this.strikeTimer.gameTick(deltaTime); if (this.strikeTimer.tryFinishPeriod()) { - this.strike(movement); + this.strike(direction); } } @@ -28,12 +38,16 @@ export class Weapon extends Component { return 5; } - private strike(movement: Vec2): void { - const direction: Vec2 = movement.normalize(); - const angle: number = (Math.atan2(direction.y, direction.x) * 180) / Math.PI; + private async strike(direction: Vec2): Promise { + this.node.active = true; + + const angle: number = (Math.atan2(direction.y, direction.x) * 180) / Math.PI - 45; this.node.eulerAngles = new Vec3(0, 0, angle); this.weaponAnimation.getState("WeaponSwing").speed = 4; this.weaponAnimation.play("WeaponSwing"); + + await delay(1000); + this.node.active = false; } } diff --git a/assets/Scripts/Services/EventSystem/ISignal.ts b/assets/Scripts/Services/EventSystem/ISignal.ts index a6eebca..bbd0c63 100644 --- a/assets/Scripts/Services/EventSystem/ISignal.ts +++ b/assets/Scripts/Services/EventSystem/ISignal.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ export interface ISignal { on(handler: (data: T) => void, thisArg: any): void; off(handler: (data: T) => void): void; diff --git a/assets/Scripts/Services/EventSystem/Signal.ts b/assets/Scripts/Services/EventSystem/Signal.ts index bcbdf74..86e480f 100644 --- a/assets/Scripts/Services/EventSystem/Signal.ts +++ b/assets/Scripts/Services/EventSystem/Signal.ts @@ -1,3 +1,5 @@ +// Need to capture *this* +/* eslint-disable @typescript-eslint/no-explicit-any */ import { ISignal } from "./ISignal"; export class Signal implements ISignal { @@ -9,14 +11,12 @@ export class Signal implements ISignal { this.thisArgs.push(thisArg); } public off(handler: (data: T) => void): void { - console.log("[OFF] " + this.handlers.length); - this.handlers = this.handlers.filter((h) => h !== handler); - console.log("[OFF] >> " + this.handlers.length); + const index: number = this.handlers.indexOf(handler); + this.handlers.splice(index, 1); + this.thisArgs.splice(index, 1); } public trigger(data: T): void { - //[...this.handlers].forEach((handler) => handler(data)); - for (let i = 0; i < this.handlers.length; i++) { this.handlers[i].call(this.thisArgs[i], data); }