diff --git a/src/shattered_sword/AI/EnemyAI.ts b/src/shattered_sword/AI/EnemyAI.ts index 1214910..3779494 100644 --- a/src/shattered_sword/AI/EnemyAI.ts +++ b/src/shattered_sword/AI/EnemyAI.ts @@ -1,12 +1,6 @@ -import GoapActionPlanner from "../../Wolfie2D/AI/GoapActionPlanner"; import StateMachineAI from "../../Wolfie2D/AI/StateMachineAI"; -import StateMachineGoapAI from "../../Wolfie2D/AI/StateMachineGoapAI"; -import GoapAction from "../../Wolfie2D/DataTypes/Interfaces/GoapAction"; import AABB from "../../Wolfie2D/DataTypes/Shapes/AABB"; -import Stack from "../../Wolfie2D/DataTypes/Stack"; -import State from "../../Wolfie2D/DataTypes/State/State"; import Vec2 from "../../Wolfie2D/DataTypes/Vec2"; -import GameEvent from "../../Wolfie2D/Events/GameEvent"; import GameNode from "../../Wolfie2D/Nodes/GameNode"; import AnimatedSprite from "../../Wolfie2D/Nodes/Sprites/AnimatedSprite"; import OrthogonalTilemap from "../../Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap"; @@ -19,15 +13,13 @@ import { GameState, Statuses } from "../sword_enums"; import Sprite from "../../Wolfie2D/Nodes/Sprites/Sprite"; -import MathUtils from "../../Wolfie2D/Utils/MathUtils"; - import { Player_Events } from "../sword_enums"; import InputWrapper from "../Tools/InputWrapper"; import Timer from "../../Wolfie2D/Timing/Timer"; import PlayerController from "../Player/PlayerController"; import Rect from "../../Wolfie2D/Nodes/Graphics/Rect"; import Color from "../../Wolfie2D/Utils/Color"; -export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { +export default class EnemyAI extends StateMachineAI implements BattlerAI { /** The owner of this AI */ owner: AnimatedSprite; @@ -52,9 +44,6 @@ export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { // The last known position of the player lastPlayerPos: Vec2; - // Attack range - inRange: number; - // Path to player //path: NavigationPath; @@ -91,7 +80,8 @@ export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { //add states // Patrol mode - this.addState(EnemyStates.DEFAULT, new Patrol(this, owner)); + this.addState(EnemyStates.PATROL, new Patrol(this, owner)); + // this.addState(EnemyStates.ALERT,) this.maxHealth = options.health; @@ -101,22 +91,10 @@ export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { this.player = options.player; - this.inRange = options.inRange; - - this.goal = options.goal; - - this.currentStatus = options.status; - - this.possibleActions = options.actions; - - this.plan = new Stack(); - - this.planner = new GoapActionPlanner(); - //TODO - get correct tilemap this.tilemap = this.owner.getScene().getLayer("Wall").getItems()[0]; // Initialize to the default state - this.initialize(EnemyStates.DEFAULT); + this.initialize(EnemyStates.PATROL); this.direction = 1; //default moving to the right @@ -131,8 +109,6 @@ export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { this.attackTimer = new Timer(2500); } - activate(options: Record): void { } - damage(damage: number): void { // enemy already dead, do not send new event if (this.CURRENT_HP <= 0) { @@ -144,11 +120,6 @@ export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { this.owner.animation.play("HURT",false); console.log(damage +" damage taken, "+this.CURRENT_HP+" hp left"); - // If we're low enough, add Low Health status to enemy - if (this.CURRENT_HP <= Math.floor(this.maxHealth/2)) { - - } - // If health goes below 0, disable AI and fire enemyDied event if (this.CURRENT_HP <= 0) { this.owner.setAIActive(false, {}); @@ -172,17 +143,10 @@ export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { } this.emitter.fireEvent(Player_Events.ENEMY_KILLED, {owner: this.owner.id, ai:this}); - - - if (Math.random() < 0.05) { - // give buff maybe - //this.emitter.fireEvent("giveBuff", { position: this.owner.position }); - } } } //TODO - need to modify for side view - isPlayerVisible(pos: Vec2): Vec2{ //Check ifplayer is visible, taking into account walls @@ -235,12 +199,9 @@ export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { * @returns position of the player if visible, else null */ getPlayerPosition(): Vec2 { - //TODO - check if player is visible - if(this.isPlayerVisible(this.player.position)) - return this.player.position; - else - return null; + return this.isPlayerVisible(this.player.position); } + update(deltaT: number){ if (InputWrapper.getState() != GameState.GAMING) { this.owner.animation.pause(); @@ -249,22 +210,6 @@ export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { this.owner.animation.resume(); super.update(deltaT); - // This is the plan that is executed in the Active state, so whenever we don't have a plan, acquire a new one given the current statuses the enemy has - /* - if (this.plan.isEmpty()) { - //get a new plan - if(this.possibleActions === undefined){ - console.log("undefined possiblse actions"); - } - - if(this.currentState === undefined){ - console.log("undefined current status"); - } - this.plan = this.planner.plan(Statuses.REACHED_GOAL, this.possibleActions, this.currentStatus, null); - } - */ - - //TODO if(this.burnTimer.isStopped() && this.burnCounter >0){ this.burnCounter --; this.burnTimer.start(); @@ -281,10 +226,6 @@ export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { this.damage(5 + (this.player._ai).extraDotDmg + (this.player._ai).CURRENT_ATK * .08); } - - - - if (this.healthBar) { this.healthBar.position = this.owner.collisionShape.center.clone().add(new Vec2(0, -((this.owner.collisionShape).hh+5))); this.healthBar.fillWidth = this.CURRENT_HP/this.maxHealth * this.owner.collisionShape.hw * 3; @@ -314,7 +255,7 @@ export default class EnemyAI extends StateMachineGoapAI implements BattlerAI { } export enum EnemyStates { - DEFAULT = "default", + PATROL = "patrol", ALERT = "alert", - PREVIOUS = "previous" -} + ATTACK = "attack" +} \ No newline at end of file diff --git a/src/shattered_sword/AI/EnemyActions/AttackAction.ts b/src/shattered_sword/AI/EnemyActions/AttackAction.ts deleted file mode 100644 index 9f414ab..0000000 --- a/src/shattered_sword/AI/EnemyActions/AttackAction.ts +++ /dev/null @@ -1,47 +0,0 @@ -import StateMachineGoapAI from "../../../Wolfie2D/AI/StateMachineGoapAI"; -import GoapAction from "../../../Wolfie2D/DataTypes/Interfaces/GoapAction"; -import Vec2 from "../../../Wolfie2D/DataTypes/Vec2"; -import Emitter from "../../../Wolfie2D/Events/Emitter"; -import GameNode from "../../../Wolfie2D/Nodes/GameNode"; -import EnemyAI from "../EnemyAI"; - -export default class AttackAction extends GoapAction { - protected emitter: Emitter; - - constructor(cost: number, preconditions: Array, effects: Array, options?: Record) { - super(); - this.cost = cost; - this.preconditions = preconditions; - this.effects = effects; - } - - performAction(statuses: Array, actor: StateMachineGoapAI, deltaT: number, target?: StateMachineGoapAI): Array { - //Check if preconditions are met for this action to be performed - if (this.checkPreconditions(statuses)){ - let enemy = actor; - - //If the player is out of sight, don't bother attacking - if (enemy.getPlayerPosition() == null){ - return null; - } - - //Randomize attack direction, gives the enemy gun users stormtrooper aim - let dir = enemy.getPlayerPosition().clone().sub(enemy.owner.position).normalize(); - dir.rotateCCW(Math.PI / 4 * Math.random() - Math.PI/8); - if(enemy.weapon.use(enemy.owner, "enemy", dir)){ - // If we fired, face that direction - enemy.owner.rotation = Vec2.UP.angleToCCW(dir); - } - - return this.effects; - } - return null; - } - - updateCost(options: Record): void {} - - toString(): string { - return "(AttackAction)"; - } - -} \ No newline at end of file diff --git a/src/shattered_sword/AI/EnemyActions/Move.ts b/src/shattered_sword/AI/EnemyActions/Move.ts deleted file mode 100644 index 664e9a0..0000000 --- a/src/shattered_sword/AI/EnemyActions/Move.ts +++ /dev/null @@ -1,47 +0,0 @@ -import StateMachineGoapAI from "../../../Wolfie2D/AI/StateMachineGoapAI"; -import GoapAction from "../../../Wolfie2D/DataTypes/Interfaces/GoapAction"; -import Vec2 from "../../../Wolfie2D/DataTypes/Vec2"; -import Emitter from "../../../Wolfie2D/Events/Emitter"; -import NavigationPath from "../../../Wolfie2D/Pathfinding/NavigationPath"; -import EnemyAI from "../EnemyAI"; - -export default class Move extends GoapAction { - private inRange: number; - - private path: NavigationPath; - protected emitter: Emitter; - - constructor(cost: number, preconditions: Array, effects: Array, options?: Record) { - super(); - this.cost = cost; - this.preconditions = preconditions; - this.effects = effects; - this.loopAction = true; - this.inRange = options.inRange; - } - - performAction(statuses: Array, actor: StateMachineGoapAI, deltaT: number, target?: StateMachineGoapAI): Array { - if (this.checkPreconditions(statuses)){ - //Check distance from player - let enemy = actor; - let playerPos = enemy.lastPlayerPos; - let distance = enemy.owner.position.distanceTo(playerPos); - - //If close enough, we've moved far enough and this loop action is done - if (distance <= this.inRange){ - return this.effects; - } - - //Otherwise move - return null; - } - return this.effects; - } - - updateCost(options: Record): void {} - - toString(): string { - return "(Move)"; - } - -} \ No newline at end of file diff --git a/src/shattered_sword/AI/EnemyStates/EnemyState.ts b/src/shattered_sword/AI/EnemyStates/EnemyState.ts index 0e10f2e..7c310a4 100644 --- a/src/shattered_sword/AI/EnemyStates/EnemyState.ts +++ b/src/shattered_sword/AI/EnemyStates/EnemyState.ts @@ -1,23 +1,32 @@ +import AABB from "../../../Wolfie2D/DataTypes/Shapes/AABB"; import State from "../../../Wolfie2D/DataTypes/State/State"; +import Vec2 from "../../../Wolfie2D/DataTypes/Vec2"; +import GameEvent from "../../../Wolfie2D/Events/GameEvent"; import GameNode from "../../../Wolfie2D/Nodes/GameNode"; import EnemyAI from "../EnemyAI"; export default abstract class EnemyState extends State { - protected parent: EnemyAI; - protected owner: GameNode; - gravity: number = 1500; //TODO - can change later + protected parent: EnemyAI; + protected owner: GameNode; + gravity: number = 1500; //TODO - can change later - constructor(parent: EnemyAI, owner: GameNode){ - super(parent); - this.owner = owner; - } + constructor(parent: EnemyAI, owner: GameNode) { + super(parent); + this.owner = owner; + } + handleInput(event: GameEvent): void { } - - update(deltaT: number): void { - // Do gravity - this.parent.velocity.y += this.gravity*deltaT; - } - + canWalk() { + let collision = this.owner.collisionShape; + let colrow = this.parent.tilemap.getColRowAt(collision.center.clone().add(new Vec2(this.parent.direction * (collision.hw+2)))); + return !this.parent.tilemap.isTileCollidable(colrow.x, colrow.y) && this.parent.tilemap.isTileCollidable(colrow.x,colrow.y+1); + } + + update(deltaT: number): void { + // Do gravity + this.parent.velocity.y += this.gravity * deltaT; + this.owner.move(this.parent.velocity.scaled(deltaT)); + } } diff --git a/src/shattered_sword/AI/EnemyStates/Patrol.ts b/src/shattered_sword/AI/EnemyStates/Patrol.ts index 68005b9..173159a 100644 --- a/src/shattered_sword/AI/EnemyStates/Patrol.ts +++ b/src/shattered_sword/AI/EnemyStates/Patrol.ts @@ -8,63 +8,27 @@ import EnemyState from "./EnemyState"; import Sprite from "../../../Wolfie2D/Nodes/Sprites/Sprite"; import MathUtils from "../../../Wolfie2D/Utils/MathUtils"; import AnimatedSprite from "../../../Wolfie2D/Nodes/Sprites/AnimatedSprite"; +import AABB from "../../../Wolfie2D/DataTypes/Shapes/AABB"; export default class Patrol extends EnemyState { - - - - // A return object for exiting this state - protected retObj: Record; - - constructor(parent: EnemyAI, owner: GameNode){ - super(parent, owner); - - } - onEnter(options: Record): void { - //this.currentPath = this.getNextPath(); - //if(!(this.owner).animation.isPlaying("DYING")){ - //(this.owner).animation.queue("IDLE", true); - //} - //else{ - (this.owner).animation.playIfNotAlready("IDLE", true); - //} + (this.owner).animation.playIfNotAlready("IDLE", true); } - handleInput(event: GameEvent): void { } - update(deltaT: number): void { - super.update(deltaT); - - //no goap rn, just adding some moving - let colrow = this.parent.tilemap.getColRowAt(this.owner.position.clone()); - - //check if next tile on walking path is collidable - if(this.parent.tilemap.isTileCollidable(colrow.x+this.parent.direction,colrow.y) || this.parent.tilemap.isTileCollidable(colrow.x+this.parent.direction,colrow.y-1)){ - //turn around - this.parent.direction *= -1; - } - //check if next ground tile is collidable - else if(!this.parent.tilemap.isTileCollidable(colrow.x+this.parent.direction,colrow.y+1)){ - //turn around - this.parent.direction *=-1; - } - else{ - //keep moving + if(!this.canWalk()){ + this.parent.direction *= -1; } + //move this.parent.velocity.x = this.parent.direction * this.parent.speed; - (this.owner).invertX = this.parent.direction ==1? true: false ; + (this.owner).invertX = this.parent.direction === 1 ? true : false ; - //move this elsewhere later - this.owner.move(this.parent.velocity.scaled(deltaT)); - //console.log("enemy moving"); + super.update(deltaT); } onExit(): Record { - return this.retObj; + (this.owner).animation.stop(); + return null; } - - - } \ No newline at end of file diff --git a/src/shattered_sword/Scenes/GameLevel.ts b/src/shattered_sword/Scenes/GameLevel.ts index f2849b5..7f24f6e 100644 --- a/src/shattered_sword/Scenes/GameLevel.ts +++ b/src/shattered_sword/Scenes/GameLevel.ts @@ -34,8 +34,6 @@ import Story from "../Tools/DataTypes/Story"; import Sprite from "../../Wolfie2D/Nodes/Sprites/Sprite"; import TextInput from "../../Wolfie2D/Nodes/UIElements/TextInput"; import { TiledTilemapData } from "../../Wolfie2D/DataTypes/Tilesets/TiledData"; -import AttackAction from "../AI/EnemyActions/AttackAction"; -import Move from "../AI/EnemyActions/Move"; import GameOver from "./GameOver"; import Porcelain from "./Porcelain"; import Tutorial from "./Tutorial"; @@ -867,19 +865,7 @@ export default class GameLevel extends Scene { (enemy._ai).bleedStat.scale.set(1, 1); enemy.setGroup("Enemy"); enemy.setTrigger("player", Player_Events.PLAYER_COLLIDE, null); - let actionsDefault = [new AttackAction(3, [Statuses.IN_RANGE], [Statuses.REACHED_GOAL]), - new Move(2, [], [Statuses.IN_RANGE], {inRange: 60}), - ]; - let statusArray : Array = [Statuses.CAN_RETREAT, Statuses.CAN_BERSERK]; - - //TODO - not working correctly - if ( "status" !in aiOptions ){ - aiOptions["status"] = statusArray; - } - if( "actions" !in aiOptions){ - aiOptions["actions"] = actionsDefault; - } //add enemy to the enemy array this.enemies.push(enemy); //this.battleManager.setEnemies(this.enemies.map(enemy => enemy._ai)); @@ -889,34 +875,13 @@ export default class GameLevel extends Scene { //TODO - give each enemy unique weapon protected initializeEnemies( enemies: Enemy[]){ - let actionsDefault = [new AttackAction(3, [Statuses.IN_RANGE], [Statuses.REACHED_GOAL]), - new Move(2, [], [Statuses.IN_RANGE], {inRange: 60}), - ]; - - let statusArray : Array = [Statuses.CAN_RETREAT, Statuses.CAN_BERSERK]; - for (let enemy of enemies) { switch (enemy.type) { - case "test_dummy": - this.addEnemy("test_dummy", enemy.position.scale(32), { - player: this.player, - health: 100, - tilemap: "Main", - actions: actionsDefault, - status: statusArray, - goal: Statuses.REACHED_GOAL, - //size: new AABB(Vec2.ZERO, new Vec2(16, 25)), - exp: 100, - weapon : this.createWeapon("knife") - }) - break; case "Snake": //Snake enemies drop from sky("trees")? or could just be very abundant this.addEnemy("Snake", enemy.position.scale(32), { player: this.player, health: 50, tilemap: "Main", - actions: actionsDefault, - status: statusArray, goal: Statuses.REACHED_GOAL, size: new Vec2(14,10), offset : new Vec2(0, 22), @@ -929,11 +894,8 @@ export default class GameLevel extends Scene { player: this.player, health: 200, tilemap: "Main", - goal: Statuses.REACHED_GOAL, exp: 100, weapon : this.createWeapon("knife"), - actions: actionsDefault, - status: statusArray, }) break; @@ -943,11 +905,8 @@ export default class GameLevel extends Scene { health: 200, tilemap: "Main", //actions:actions, - goal: Statuses.REACHED_GOAL, exp: 50, weapon : this.createWeapon("knife"), - actions: actionsDefault, - status: statusArray, }) break; case "black_pudding": @@ -956,14 +915,11 @@ export default class GameLevel extends Scene { health: 200, tilemap: "Main", //actions:actions, - goal: Statuses.REACHED_GOAL, scale: .25, size: new Vec2(16,10), offset : new Vec2(0,6), exp: 50, weapon : this.createWeapon("knife"), - actions: actionsDefault, - status: statusArray, }) break; default: diff --git a/src/shattered_sword/Scenes/Tutorial.ts b/src/shattered_sword/Scenes/Tutorial.ts index d34fbb4..bdb213e 100644 --- a/src/shattered_sword/Scenes/Tutorial.ts +++ b/src/shattered_sword/Scenes/Tutorial.ts @@ -11,8 +11,6 @@ import { Statuses } from "../sword_enums"; import AABB from "../../Wolfie2D/DataTypes/Shapes/AABB"; import EnemyAI from "../AI/EnemyAI"; import BattlerAI from "../AI/BattlerAI"; -import AttackAction from "../AI/EnemyActions/AttackAction"; -import Move from "../AI/EnemyActions/Move"; import Porcelain from "./Porcelain"; import MainMenu from "./MainMenu"; @@ -45,13 +43,9 @@ export default class Tutorial extends GameLevel { player: this.player, health: 50, tilemap: "Main", - goal: Statuses.REACHED_GOAL, size: new Vec2(14,10), offset : new Vec2(0, 22), exp: 50, - actions: [new AttackAction(3, [Statuses.IN_RANGE], [Statuses.REACHED_GOAL]), - new Move(2, [], [Statuses.IN_RANGE], {inRange: 60})], - status : [Statuses.CAN_RETREAT, Statuses.CAN_BERSERK], weapon : this.createWeapon("knife") }) }