395 lines
12 KiB
TypeScript
395 lines
12 KiB
TypeScript
import Layer from "./Layer";
|
|
import Viewport from "../SceneGraph/Viewport";
|
|
import Vec2 from "../DataTypes/Vec2";
|
|
import SceneGraph from "../SceneGraph/SceneGraph";
|
|
import PhysicsManager from "../Physics/PhysicsManager";
|
|
import BasicPhysicsManager from "../Physics/BasicPhysicsManager";
|
|
import SceneGraphArray from "../SceneGraph/SceneGraphArray";
|
|
import FactoryManager from "./Factories/FactoryManager";
|
|
import Tilemap from "../Nodes/Tilemap";
|
|
import ResourceManager from "../ResourceManager/ResourceManager";
|
|
import Game from "../Loop/Game";
|
|
import SceneManager from "./SceneManager";
|
|
import Receiver from "../Events/Receiver";
|
|
import Emitter from "../Events/Emitter";
|
|
import Updateable from "../DataTypes/Interfaces/Updateable";
|
|
import NavigationManager from "../Pathfinding/NavigationManager";
|
|
import AIManager from "../AI/AIManager";
|
|
import Map from "../DataTypes/Map";
|
|
import ParallaxLayer from "./Layers/ParallaxLayer";
|
|
import UILayer from "./Layers/UILayer";
|
|
import CanvasNode from "../Nodes/CanvasNode";
|
|
import GameNode from "../Nodes/GameNode";
|
|
import SceneOptions from "./SceneOptions";
|
|
import RenderingManager from "../Rendering/RenderingManager";
|
|
import Debug from "../Debug/Debug";
|
|
|
|
/**
|
|
* Scenes are the main container in the game engine.
|
|
* Your main scene is the current level or menu of the game, and will contain all of the GameNodes needed.
|
|
* Scenes provide an easy way to load assets, add assets to the game world, and unload assets,
|
|
* and have lifecycle methods exposed for these functions.
|
|
*/
|
|
export default class Scene implements Updateable {
|
|
/** The size of the game world. */
|
|
protected worldSize: Vec2;
|
|
|
|
/** The viewport. */
|
|
protected viewport: Viewport;
|
|
|
|
/** A flag that represents whether this scene is running or not. */
|
|
protected running: boolean;
|
|
|
|
/** The manager of this scene. */
|
|
protected sceneManager: SceneManager;
|
|
|
|
/** The receiver for this scene. */
|
|
protected receiver: Receiver;
|
|
|
|
/** The emitter for this scene. */
|
|
protected emitter: Emitter;
|
|
|
|
/** This list of tilemaps in this scene. */
|
|
protected tilemaps: Array<Tilemap>;
|
|
|
|
/** A map from layer names to the layers themselves */
|
|
protected layers: Map<Layer>;
|
|
|
|
/** A map from parallax layer names to the parallax layers themselves */
|
|
protected parallaxLayers: Map<ParallaxLayer>;
|
|
|
|
/** A map from uiLayer names to the uiLayers themselves */
|
|
protected uiLayers: Map<UILayer>;
|
|
|
|
/** The scene graph of the Scene*/
|
|
protected sceneGraph: SceneGraph;
|
|
|
|
/** The physics manager of the Scene */
|
|
protected physicsManager: PhysicsManager;
|
|
|
|
/** The navigation manager of the Scene */
|
|
protected navManager: NavigationManager;
|
|
|
|
/** The AI manager of the Scene */
|
|
protected aiManager: AIManager;
|
|
|
|
/** The renderingManager of the scene */
|
|
protected renderingManager: RenderingManager;
|
|
|
|
/** An interface that allows the adding of different nodes to the scene */
|
|
public add: FactoryManager;
|
|
|
|
/** An interface that allows the loading of different files for use in the scene */
|
|
public load: ResourceManager;
|
|
|
|
/** The configuration options for this scene */
|
|
public sceneOptions: SceneOptions;
|
|
|
|
/**
|
|
* Creates a new Scene. To add a new Scene in your game, use addScene() in @reference[SceneManager]
|
|
* @param viewport The viewport of the game
|
|
* @param sceneManager The SceneManager that owns this Scene
|
|
* @param renderingManager The RenderingManager that will handle this Scene's rendering
|
|
* @param game The instance of the Game
|
|
* @param options The options for Scene initialization
|
|
*/
|
|
constructor(viewport: Viewport, sceneManager: SceneManager, renderingManager: RenderingManager, options: Record<string, any>){
|
|
this.sceneOptions = SceneOptions.parse(options);
|
|
|
|
this.worldSize = new Vec2(500, 500);
|
|
this.viewport = viewport;
|
|
this.viewport.setBounds(0, 0, 2560, 1280);
|
|
this.running = false;
|
|
this.sceneManager = sceneManager;
|
|
this.receiver = new Receiver();
|
|
this.emitter = new Emitter();
|
|
|
|
this.tilemaps = new Array();
|
|
this.sceneGraph = new SceneGraphArray(this.viewport, this);
|
|
|
|
this.layers = new Map();
|
|
this.uiLayers = new Map();
|
|
this.parallaxLayers = new Map();
|
|
|
|
this.physicsManager = new BasicPhysicsManager(this.sceneOptions.physics);
|
|
this.navManager = new NavigationManager();
|
|
this.aiManager = new AIManager();
|
|
this.renderingManager = renderingManager;
|
|
|
|
this.add = new FactoryManager(this, this.tilemaps);
|
|
|
|
this.load = ResourceManager.getInstance();
|
|
}
|
|
|
|
/** A lifecycle method that gets called when a new scene is created. Load all files you wish to access in the scene here. */
|
|
loadScene(): void {}
|
|
|
|
/** A lifecycle method that gets called on scene destruction. Specify which files you no longer need for garbage collection. */
|
|
unloadScene(): void {}
|
|
|
|
/** A lifecycle method called strictly after loadScene(). Create any game objects you wish to use in the scene here. */
|
|
startScene(): void {}
|
|
|
|
/**
|
|
* A lifecycle method called every frame of the game. This is where you can dynamically do things like add in new enemies
|
|
* @param delta The time this frame represents
|
|
*/
|
|
updateScene(deltaT: number): void {}
|
|
|
|
update(deltaT: number): void {
|
|
this.updateScene(deltaT);
|
|
|
|
// Do all AI updates
|
|
this.aiManager.update(deltaT);
|
|
|
|
// Update all physics objects
|
|
this.physicsManager.update(deltaT);
|
|
|
|
// Update all canvas objects
|
|
this.sceneGraph.update(deltaT);
|
|
|
|
// Update all tilemaps
|
|
this.tilemaps.forEach(tilemap => {
|
|
if(!tilemap.getLayer().isPaused()){
|
|
tilemap.update(deltaT);
|
|
}
|
|
});
|
|
|
|
// Update viewport
|
|
this.viewport.update(deltaT);
|
|
}
|
|
|
|
/**
|
|
* Collects renderable sets and coordinates with the RenderingManager to draw the Scene
|
|
*/
|
|
render(): void {
|
|
// Get the visible set of nodes
|
|
let visibleSet = this.sceneGraph.getVisibleSet();
|
|
|
|
// Add parallax layer items to the visible set (we're rendering them all for now)
|
|
this.parallaxLayers.forEach(key => {
|
|
let pLayer = this.parallaxLayers.get(key);
|
|
for(let node of pLayer.getItems()){
|
|
if(node instanceof CanvasNode){
|
|
visibleSet.push(node);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Send the visible set, tilemaps, and uiLayers to the renderer
|
|
this.renderingManager.render(visibleSet, this.tilemaps, this.uiLayers);
|
|
|
|
let nodes = this.sceneGraph.getAllNodes();
|
|
this.tilemaps.forEach(tilemap => tilemap.visible && tilemap.debugRender());
|
|
Debug.setNodes(nodes);
|
|
}
|
|
|
|
/**
|
|
* Sets the scene as running or not
|
|
* @param running True if the Scene should be running, false if not
|
|
*/
|
|
setRunning(running: boolean): void {
|
|
this.running = running;
|
|
}
|
|
|
|
/**
|
|
* Returns whether or not the Scene is running
|
|
* @returns True if the scene is running, false otherwise
|
|
*/
|
|
isRunning(): boolean {
|
|
return this.running;
|
|
}
|
|
|
|
/**
|
|
* Adds a new layer to the scene and returns it
|
|
* @param name The name of the new layer
|
|
* @param depth The depth of the layer
|
|
* @returns The newly created Layer
|
|
*/
|
|
addLayer(name: string, depth?: number): Layer {
|
|
if(this.layers.has(name) || this.parallaxLayers.has(name) || this.uiLayers.has(name)){
|
|
throw `Layer with name ${name} already exists`;
|
|
}
|
|
|
|
let layer = new Layer(this, name);
|
|
|
|
this.layers.add(name, layer);
|
|
|
|
if(depth){
|
|
layer.setDepth(depth);
|
|
}
|
|
|
|
return layer;
|
|
}
|
|
|
|
/**
|
|
* Adds a new parallax layer to this scene and returns it
|
|
* @param name The name of the parallax layer
|
|
* @param parallax The parallax level
|
|
* @param depth The depth of the layer
|
|
* @returns The newly created ParallaxLayer
|
|
*/
|
|
addParallaxLayer(name: string, parallax: Vec2, depth?: number): ParallaxLayer {
|
|
if(this.layers.has(name) || this.parallaxLayers.has(name) || this.uiLayers.has(name)){
|
|
throw `Layer with name ${name} already exists`;
|
|
}
|
|
|
|
let layer = new ParallaxLayer(this, name, parallax);
|
|
|
|
this.parallaxLayers.add(name, layer);
|
|
|
|
if(depth){
|
|
layer.setDepth(depth);
|
|
}
|
|
|
|
return layer;
|
|
}
|
|
|
|
/**
|
|
* Adds a new UILayer to the scene
|
|
* @param name The name of the new UIlayer
|
|
* @returns The newly created UILayer
|
|
*/
|
|
addUILayer(name: string): UILayer {
|
|
if(this.layers.has(name) || this.parallaxLayers.has(name) || this.uiLayers.has(name)){
|
|
throw `Layer with name ${name} already exists`;
|
|
}
|
|
|
|
let layer = new UILayer(this, name);
|
|
|
|
this.uiLayers.add(name, layer);
|
|
|
|
return layer;
|
|
}
|
|
|
|
/**
|
|
* Gets a layer from the scene by name if it exists.
|
|
* This can be a Layer or any of its subclasses
|
|
* @param name The name of the layer
|
|
* @returns The Layer found with that name
|
|
*/
|
|
getLayer(name: string): Layer {
|
|
if(this.layers.has(name)){
|
|
return this.layers.get(name);
|
|
} else if(this.parallaxLayers.has(name)){
|
|
return this.parallaxLayers.get(name);
|
|
} else if(this.uiLayers.has(name)){
|
|
return this.uiLayers.get(name);
|
|
} else {
|
|
throw `Requested layer ${name} does not exist.`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true if this layer is a ParallaxLayer
|
|
* @param name The name of the layer
|
|
* @returns True if this layer is a ParallaxLayer
|
|
*/
|
|
isParallaxLayer(name: string): boolean {
|
|
return this.parallaxLayers.has(name);
|
|
}
|
|
|
|
/**
|
|
* Returns true if this layer is a UILayer
|
|
* @param name The name of the layer
|
|
* @returns True if this layer is ParallaxLayer
|
|
*/
|
|
isUILayer(name: string): boolean {
|
|
return this.uiLayers.has(name);
|
|
}
|
|
|
|
/**
|
|
* Returns the translation of this node with respect to camera space (due to the viewport moving).
|
|
* This value is affected by the parallax level of the @reference[Layer] the node is on.
|
|
* @param node The node to check the viewport with respect to
|
|
* @returns A Vec2 containing the translation of viewport with respect to this node.
|
|
*/
|
|
getViewTranslation(node: GameNode): Vec2 {
|
|
let layer = node.getLayer();
|
|
|
|
if(layer instanceof ParallaxLayer || layer instanceof UILayer){
|
|
return this.viewport.getOrigin().mult(layer.parallax);
|
|
} else {
|
|
return this.viewport.getOrigin();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the scale level of the view
|
|
* @returns The zoom level of the viewport
|
|
*/
|
|
getViewScale(): number {
|
|
return this.viewport.getZoomLevel();
|
|
}
|
|
|
|
/**
|
|
* Returns the Viewport associated with this scene
|
|
* @returns The current Viewport
|
|
*/
|
|
getViewport(): Viewport {
|
|
return this.viewport;
|
|
}
|
|
|
|
/**
|
|
* Gets the world size of this Scene
|
|
* @returns The world size in a Vec2
|
|
*/
|
|
getWorldSize(): Vec2 {
|
|
return this.worldSize;
|
|
}
|
|
|
|
/**
|
|
* Gets the SceneGraph associated with this Scene
|
|
* @returns The SceneGraph
|
|
*/
|
|
getSceneGraph(): SceneGraph {
|
|
return this.sceneGraph;
|
|
}
|
|
|
|
/**
|
|
* Gets the PhysicsManager associated with this Scene
|
|
* @returns The PhysicsManager
|
|
*/
|
|
getPhysicsManager(): PhysicsManager {
|
|
return this.physicsManager;
|
|
}
|
|
|
|
/**
|
|
* Gets the NavigationManager associated with this Scene
|
|
* @returns The NavigationManager
|
|
*/
|
|
getNavigationManager(): NavigationManager {
|
|
return this.navManager;
|
|
}
|
|
|
|
/**
|
|
* Gets the AIManager associated with this Scene
|
|
* @returns The AIManager
|
|
*/
|
|
getAIManager(): AIManager {
|
|
return this.aiManager;
|
|
}
|
|
|
|
/**
|
|
* Generates an ID for a GameNode
|
|
* @returns The new ID
|
|
*/
|
|
generateId(): number {
|
|
return this.sceneManager.generateId();
|
|
}
|
|
|
|
/**
|
|
* Retrieves a Tilemap in this Scene
|
|
* @param name The name of the Tilemap
|
|
* @returns The Tilemap, if one this name exists, otherwise null
|
|
*/
|
|
getTilemap(name: string): Tilemap {
|
|
for(let tilemap of this .tilemaps){
|
|
if(tilemap.name === name){
|
|
return tilemap;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
} |