2022-04-03 18:07:45 -04:00
|
|
|
import AABB from "../../Wolfie2D/DataTypes/Shapes/AABB";
|
|
|
|
import Vec2 from "../../Wolfie2D/DataTypes/Vec2";
|
|
|
|
import Debug from "../../Wolfie2D/Debug/Debug";
|
|
|
|
import { GameEventType } from "../../Wolfie2D/Events/GameEventType";
|
|
|
|
import Input from "../../Wolfie2D/Input/Input";
|
|
|
|
import { TweenableProperties } from "../../Wolfie2D/Nodes/GameNode";
|
|
|
|
import { GraphicType } from "../../Wolfie2D/Nodes/Graphics/GraphicTypes";
|
|
|
|
import Point from "../../Wolfie2D/Nodes/Graphics/Point";
|
|
|
|
import Rect from "../../Wolfie2D/Nodes/Graphics/Rect";
|
|
|
|
import AnimatedSprite from "../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
|
|
|
|
import Label from "../../Wolfie2D/Nodes/UIElements/Label";
|
|
|
|
import { UIElementType } from "../../Wolfie2D/Nodes/UIElements/UIElementTypes";
|
|
|
|
import Scene from "../../Wolfie2D/Scene/Scene";
|
|
|
|
import Timer from "../../Wolfie2D/Timing/Timer";
|
|
|
|
import Color from "../../Wolfie2D/Utils/Color";
|
|
|
|
import { EaseFunctionType } from "../../Wolfie2D/Utils/EaseFunctions";
|
|
|
|
import PlayerController from "../Player/PlayerController";
|
|
|
|
import MainMenu from "./MainMenu";
|
|
|
|
import { Player_Events } from "../sword_enums";
|
2022-04-08 18:01:21 -04:00
|
|
|
import RegistryManager from "../../Wolfie2D/Registry/RegistryManager";
|
|
|
|
import WeaponType from "../GameSystems/items/WeaponTypes/WeaponType";
|
|
|
|
import Weapon from "../GameSystems/items/Weapon";
|
|
|
|
import BattleManager from "../GameSystems/BattleManager";
|
|
|
|
//import EnemyAI from "../AI/EnemyAI";
|
|
|
|
import BattlerAI from "../AI/BattlerAI";
|
2022-04-09 04:49:30 -04:00
|
|
|
import InventoryManager from "../GameSystems/InventoryManager";
|
|
|
|
import Item from "../GameSystems/items/Item";
|
|
|
|
|
|
|
|
|
2022-04-08 18:01:21 -04:00
|
|
|
|
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
|
|
|
|
// TODO
|
|
|
|
/**
|
|
|
|
* Add in some level music.
|
|
|
|
* This can be done here in the base GameLevel class or individual level files
|
|
|
|
*/
|
|
|
|
export default class GameLevel extends Scene {
|
|
|
|
// Every level will have a player, which will be an animated sprite
|
|
|
|
protected playerSpawn: Vec2;
|
|
|
|
protected player: AnimatedSprite;
|
|
|
|
protected respawnTimer: Timer;
|
|
|
|
|
|
|
|
// Labels for the UI
|
|
|
|
protected static livesCount: number = 3;
|
|
|
|
protected livesCountLabel: Label;
|
|
|
|
|
|
|
|
// Stuff to end the level and go to the next level
|
|
|
|
protected levelEndArea: Rect;
|
|
|
|
protected nextLevel: new (...args: any) => GameLevel;
|
|
|
|
protected levelEndTimer: Timer;
|
|
|
|
protected levelEndLabel: Label;
|
|
|
|
|
|
|
|
// Screen fade in/out for level start and end
|
|
|
|
protected levelTransitionTimer: Timer;
|
|
|
|
protected levelTransitionScreen: Rect;
|
2022-04-08 18:01:21 -04:00
|
|
|
|
|
|
|
// The battle manager for the scene
|
|
|
|
private battleManager: BattleManager;
|
2022-04-06 22:24:08 -04:00
|
|
|
|
|
|
|
// Health UI
|
|
|
|
protected healthLabel: Label;
|
2022-04-09 04:49:30 -04:00
|
|
|
|
|
|
|
// A list of items in the scene
|
|
|
|
private items: Array<Item>;
|
2022-04-06 22:24:08 -04:00
|
|
|
|
2022-04-08 18:01:21 -04:00
|
|
|
loadScene(): void {
|
|
|
|
//can load player sprite here
|
|
|
|
|
|
|
|
//can load enemy sprite here
|
2022-04-06 22:24:08 -04:00
|
|
|
|
2022-04-08 18:01:21 -04:00
|
|
|
// Load the scene info
|
2022-04-09 04:49:30 -04:00
|
|
|
this.load.object("weaponData", "shattered_sword_assets/data/weaponData.json");
|
2022-04-08 18:01:21 -04:00
|
|
|
|
|
|
|
// Load in the enemy info
|
|
|
|
//this.load.object("enemyData", "shattered_sword_assets/data/enemy.json");
|
|
|
|
|
|
|
|
// Load in item info
|
|
|
|
//this.load.object("itemData", "shattered_sword_assets/data/items.json");
|
2022-04-09 04:49:30 -04:00
|
|
|
|
|
|
|
|
|
|
|
this.load.image("knife", "shattered_sword_assets/sprites/knife.png");
|
|
|
|
this.load.spritesheet("slice", "shattered_sword_assets/spritesheets/slice.json");
|
|
|
|
this.load.image("inventorySlot", "shattered_sword_assets/sprites/inventory.png");
|
2022-04-08 18:01:21 -04:00
|
|
|
}
|
2022-04-06 22:24:08 -04:00
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
startScene(): void {
|
|
|
|
|
2022-04-09 04:49:30 -04:00
|
|
|
|
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
// Do the game level standard initializations
|
|
|
|
this.initLayers();
|
|
|
|
this.initViewport();
|
2022-04-09 04:49:30 -04:00
|
|
|
|
|
|
|
// Create the battle manager
|
|
|
|
this.battleManager = new BattleManager();
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
this.initializeWeapons();
|
|
|
|
// Initialize the items array - this represents items that are in the game world
|
|
|
|
this.items = new Array();
|
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
this.initPlayer();
|
|
|
|
this.subscribeToEvents();
|
|
|
|
this.addUI();
|
|
|
|
|
2022-04-09 04:49:30 -04:00
|
|
|
|
|
|
|
// Send the player and enemies to the battle manager
|
|
|
|
this.battleManager.setPlayers([<PlayerController>this.player._ai]);
|
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
// Initialize the timers
|
|
|
|
this.respawnTimer = new Timer(1000, () => {
|
|
|
|
if(GameLevel.livesCount === 0){
|
|
|
|
this.sceneManager.changeToScene(MainMenu);
|
|
|
|
} else {
|
|
|
|
this.respawnPlayer();
|
|
|
|
this.player.enablePhysics();
|
|
|
|
this.player.unfreeze();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.levelTransitionTimer = new Timer(500);
|
|
|
|
this.levelEndTimer = new Timer(3000, () => {
|
|
|
|
// After the level end timer ends, fade to black and then go to the next scene
|
|
|
|
this.levelTransitionScreen.tweens.play("fadeIn");
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2022-04-09 04:49:30 -04:00
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
// Start the black screen fade out
|
|
|
|
this.levelTransitionScreen.tweens.play("fadeOut");
|
|
|
|
|
2022-04-04 03:23:10 -04:00
|
|
|
//TODO - uncomment when done testing
|
2022-04-03 18:07:45 -04:00
|
|
|
// Initially disable player movement
|
2022-04-04 03:23:10 -04:00
|
|
|
//Input.disableInput();
|
|
|
|
Input.enableInput();
|
2022-04-03 18:07:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
updateScene(deltaT: number){
|
|
|
|
// Handle events and update the UI if needed
|
|
|
|
while(this.receiver.hasNextEvent()){
|
|
|
|
let event = this.receiver.getNextEvent();
|
|
|
|
|
|
|
|
switch(event.type){
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 04:49:30 -04:00
|
|
|
//update health UI
|
|
|
|
let playerAI = (<PlayerController>this.player.ai);
|
|
|
|
this.healthLabel.text = "Player Health: "+ playerAI.CURRENT_HP +'/' + (playerAI.MAX_HP );
|
2022-04-06 22:54:57 -04:00
|
|
|
|
2022-04-09 04:49:30 -04:00
|
|
|
//handle collisions - may be in battle manager instead
|
2022-04-06 22:54:57 -04:00
|
|
|
|
|
|
|
|
|
|
|
//move background
|
|
|
|
|
|
|
|
|
|
|
|
// Get the viewport center and padded size
|
|
|
|
const viewportCenter = this.viewport.getCenter().clone();
|
|
|
|
const baseViewportSize = this.viewport.getHalfSize().scaled(2);
|
|
|
|
//check position of player
|
|
|
|
this.playerFalloff(viewportCenter, baseViewportSize);
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-04-09 04:49:30 -04:00
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialzes the layers
|
|
|
|
*/
|
|
|
|
protected initLayers(): void {
|
|
|
|
// Add a layer for UI
|
|
|
|
this.addUILayer("UI");
|
|
|
|
|
|
|
|
// Add a layer for players and enemies
|
|
|
|
this.addLayer("primary", 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the viewport
|
|
|
|
*/
|
|
|
|
protected initViewport(): void {
|
|
|
|
this.viewport.setZoomLevel(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handles all subscriptions to events
|
|
|
|
*/
|
|
|
|
protected subscribeToEvents(){
|
|
|
|
this.receiver.subscribe([
|
|
|
|
Player_Events.PLAYER_HIT_ENEMY,
|
|
|
|
Player_Events.ENEMY_KILLED,
|
|
|
|
Player_Events.LEVEL_START,
|
|
|
|
Player_Events.LEVEL_END,
|
|
|
|
Player_Events.PLAYER_KILLED
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO -
|
|
|
|
/**
|
|
|
|
* Adds in any necessary UI to the game
|
|
|
|
*/
|
|
|
|
protected addUI(){
|
|
|
|
// In-game labels
|
2022-04-06 22:24:08 -04:00
|
|
|
this.healthLabel = <Label> this.add.uiElement(UIElementType.LABEL, "UI",{position: new Vec2(80, 30), text: "Player Health: "+ (<PlayerController>this.player.ai).CURRENT_HP });
|
|
|
|
this.healthLabel.textColor = Color.WHITE;
|
|
|
|
this.healthLabel.font = "PixelSimple";
|
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
|
|
|
|
// End of level label (start off screen)
|
|
|
|
this.levelEndLabel = <Label>this.add.uiElement(UIElementType.LABEL, "UI", {position: new Vec2(-300, 200), text: "Level Complete"});
|
|
|
|
this.levelEndLabel.size.set(1200, 60);
|
|
|
|
this.levelEndLabel.borderRadius = 0;
|
|
|
|
this.levelEndLabel.backgroundColor = new Color(34, 32, 52);
|
|
|
|
this.levelEndLabel.textColor = Color.WHITE;
|
|
|
|
this.levelEndLabel.fontSize = 48;
|
|
|
|
this.levelEndLabel.font = "PixelSimple";
|
|
|
|
|
|
|
|
// Add a tween to move the label on screen
|
|
|
|
this.levelEndLabel.tweens.add("slideIn", {
|
|
|
|
startDelay: 0,
|
|
|
|
duration: 1000,
|
|
|
|
effects: [
|
|
|
|
{
|
|
|
|
property: TweenableProperties.posX,
|
|
|
|
start: -300,
|
|
|
|
end: 300,
|
|
|
|
ease: EaseFunctionType.OUT_SINE
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
2022-04-04 03:23:10 -04:00
|
|
|
this.levelTransitionScreen = <Rect>this.add.graphic(GraphicType.RECT, "UI", {position: new Vec2(300, 200), size: new Vec2(600, 400)});
|
|
|
|
this.levelTransitionScreen.color = new Color(34, 32, 52);
|
|
|
|
this.levelTransitionScreen.alpha = 1;
|
|
|
|
|
|
|
|
this.levelTransitionScreen.tweens.add("fadeIn", {
|
|
|
|
startDelay: 0,
|
|
|
|
duration: 1000,
|
|
|
|
effects: [
|
|
|
|
{
|
|
|
|
property: TweenableProperties.alpha,
|
|
|
|
start: 0,
|
|
|
|
end: 1,
|
|
|
|
ease: EaseFunctionType.IN_OUT_QUAD
|
|
|
|
}
|
|
|
|
],
|
|
|
|
onEnd: Player_Events.LEVEL_END
|
|
|
|
});
|
|
|
|
|
|
|
|
this.levelTransitionScreen.tweens.add("fadeOut", {
|
|
|
|
startDelay: 0,
|
|
|
|
duration: 1000,
|
|
|
|
effects: [
|
|
|
|
{
|
|
|
|
property: TweenableProperties.alpha,
|
|
|
|
start: 1,
|
|
|
|
end: 0,
|
|
|
|
ease: EaseFunctionType.IN_OUT_QUAD
|
|
|
|
}
|
|
|
|
],
|
|
|
|
onEnd: Player_Events.LEVEL_START
|
|
|
|
});
|
2022-04-03 18:07:45 -04:00
|
|
|
|
|
|
|
|
2022-04-08 18:01:21 -04:00
|
|
|
// Initialize all enemies
|
|
|
|
//this.initializeEnemies();
|
|
|
|
|
|
|
|
// Send the player and enemies to the battle manager
|
|
|
|
//this.battleManager.setPlayers([<BattlerAI>this.player._ai]);
|
|
|
|
//this.battleManager.setEnemies(this.enemies.map(enemy => <BattlerAI>enemy._ai));
|
|
|
|
|
|
|
|
// Subscribe to relevant events
|
|
|
|
//this.receiver.subscribe("");
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
}
|
|
|
|
|
2022-04-09 04:49:30 -04:00
|
|
|
//TODO - determine whether we will have weapon datatype
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Creates and returns a new weapon
|
|
|
|
* @param type The weaponType of the weapon, as a string
|
|
|
|
*/
|
|
|
|
createWeapon(type: string): Weapon {
|
|
|
|
let weaponType = <WeaponType>RegistryManager.getRegistry("weaponTypes").get(type);
|
|
|
|
|
|
|
|
let sprite = this.add.sprite(weaponType.spriteKey, "primary");
|
|
|
|
|
|
|
|
return new Weapon(sprite, weaponType, this.battleManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initalizes all weapon types based of data from weaponData.json
|
|
|
|
*/
|
|
|
|
initializeWeapons(): void{
|
|
|
|
let weaponData = this.load.getObject("weaponData");
|
|
|
|
|
|
|
|
for(let i = 0; i < weaponData.numWeapons; i++){
|
|
|
|
let weapon = weaponData.weapons[i];
|
|
|
|
|
|
|
|
// Get the constructor of the prototype
|
|
|
|
let constr = RegistryManager.getRegistry("weaponTemplates").get(weapon.weaponType);
|
|
|
|
|
|
|
|
// Create a weapon type
|
|
|
|
let weaponType = new constr();
|
|
|
|
|
|
|
|
// Initialize the weapon type
|
|
|
|
weaponType.initialize(weapon);
|
|
|
|
|
|
|
|
// Register the weapon type
|
|
|
|
RegistryManager.getRegistry("weaponTypes").registerItem(weapon.name, weaponType)
|
|
|
|
}
|
|
|
|
}
|
2022-04-03 18:07:45 -04:00
|
|
|
/**
|
|
|
|
* Initializes the player
|
|
|
|
*/
|
|
|
|
protected initPlayer(): void {
|
2022-04-09 04:49:30 -04:00
|
|
|
|
|
|
|
|
|
|
|
//create the inventory
|
|
|
|
let inventory = new InventoryManager(this, 1, "inventorySlot", new Vec2(16, 16), 4, "slots1", "items1");
|
|
|
|
|
|
|
|
|
|
|
|
//add starting weapon to inventory
|
|
|
|
let startingWeapon = this.createWeapon("knife");
|
|
|
|
inventory.addItem(startingWeapon); //using slice to test right now
|
|
|
|
|
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
// Add the player
|
|
|
|
this.player = this.add.animatedSprite("player", "primary");
|
|
|
|
this.player.scale.set(2, 2);
|
|
|
|
if(!this.playerSpawn){
|
|
|
|
console.warn("Player spawn was never set - setting spawn to (0, 0)");
|
|
|
|
this.playerSpawn = Vec2.ZERO;
|
|
|
|
}
|
|
|
|
this.player.position.copy(this.playerSpawn);
|
2022-04-06 21:44:44 -04:00
|
|
|
this.player.addPhysics(new AABB(Vec2.ZERO, new Vec2(32, 32))); //sets the collision shape
|
2022-04-03 18:07:45 -04:00
|
|
|
this.player.colliderOffset.set(0, 2);
|
2022-04-09 04:49:30 -04:00
|
|
|
this.player.addAI(PlayerController, {
|
|
|
|
playerType: "platformer",
|
|
|
|
tilemap: "Main",
|
|
|
|
speed: 100,
|
|
|
|
health: 10,
|
|
|
|
inventory: inventory,
|
|
|
|
items: this.items,
|
|
|
|
inputEnabled: false,
|
|
|
|
range: 100
|
|
|
|
});
|
2022-04-03 18:07:45 -04:00
|
|
|
|
|
|
|
this.player.setGroup("player");
|
|
|
|
|
|
|
|
this.viewport.follow(this.player);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//TODO -
|
|
|
|
/**
|
|
|
|
* Adds an Enemy into the game
|
|
|
|
* @param spriteKey The key of the Enemy sprite
|
|
|
|
* @param tilePos The tilemap position to add the Enemy to
|
|
|
|
* @param aiOptions The options for the Enemy AI
|
|
|
|
*/
|
2022-04-09 04:49:30 -04:00
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
protected addEnemy(spriteKey: string, tilePos: Vec2, aiOptions: Record<string, any>): void {
|
|
|
|
let enemy = this.add.animatedSprite(spriteKey, "primary");
|
|
|
|
enemy.position.set(tilePos.x*32, tilePos.y*32);
|
|
|
|
enemy.scale.set(2, 2);
|
|
|
|
enemy.addPhysics();
|
2022-04-09 04:49:30 -04:00
|
|
|
//enemy.addAI(EnemyAI, aiOptions); //TODO - add individual enemy AI
|
2022-04-03 18:07:45 -04:00
|
|
|
enemy.setGroup("Enemy");
|
|
|
|
|
|
|
|
enemy.setTrigger("player",Player_Events.PLAYER_HIT_ENEMY, null);
|
|
|
|
|
|
|
|
}
|
2022-04-09 04:49:30 -04:00
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
|
|
|
|
|
|
|
|
protected handlePlayerEnemyCollision(player: AnimatedSprite, enemy: AnimatedSprite) {
|
2022-04-08 18:01:21 -04:00
|
|
|
//collisions are handled by the battleManager - no need for this in gamelevel for now
|
2022-04-03 18:07:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Increments the amount of life the player has
|
|
|
|
* @param amt The amount to add to the player life
|
|
|
|
*/
|
|
|
|
protected incPlayerLife(amt: number): void {
|
|
|
|
GameLevel.livesCount += amt;
|
|
|
|
this.livesCountLabel.text = "Lives: " + GameLevel.livesCount;
|
|
|
|
if (GameLevel.livesCount == 0){
|
|
|
|
Input.disableInput();
|
|
|
|
this.player.disablePhysics();
|
|
|
|
this.emitter.fireEvent(GameEventType.PLAY_SOUND, {key: "player_death", loop: false, holdReference: false});
|
|
|
|
this.player.tweens.play("death");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the player to spawn
|
|
|
|
*/
|
|
|
|
protected respawnPlayer(): void {
|
|
|
|
GameLevel.livesCount = 3;
|
|
|
|
this.emitter.fireEvent(GameEventType.STOP_SOUND, {key: "level_music"});
|
|
|
|
this.sceneManager.changeToScene(MainMenu, {});
|
|
|
|
Input.enableInput();
|
|
|
|
}
|
2022-04-06 22:54:57 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* handles the player falling off the map
|
|
|
|
*
|
|
|
|
* @param viewportCenter The center of the viewport
|
|
|
|
* @param viewportSize The size of the viewport
|
|
|
|
*/
|
|
|
|
playerFalloff(viewportCenter: Vec2, viewportSize: Vec2):void{
|
|
|
|
if(this.player.position.y >= viewportCenter.y +viewportSize.y/2.0){
|
|
|
|
|
|
|
|
this.player.position.set(this.playerSpawn.x,this.playerSpawn.y);
|
|
|
|
}
|
|
|
|
}
|
2022-04-08 18:01:21 -04:00
|
|
|
|
2022-04-09 04:49:30 -04:00
|
|
|
|
2022-04-03 18:07:45 -04:00
|
|
|
}
|