diff --git a/src/Wolfie2D/AI/GoapActionPlanner.ts b/src/Wolfie2D/AI/GoapActionPlanner.ts index c8743ea..71c225f 100644 --- a/src/Wolfie2D/AI/GoapActionPlanner.ts +++ b/src/Wolfie2D/AI/GoapActionPlanner.ts @@ -24,7 +24,6 @@ export default class GoapActionPlanner { //Build tree from 0 to 1 this.buildTree(0, goal, possibleActions, currentStatus); - console.log(this.graph.toString()); //Run djikstra to find shortest path this.path = GraphUtils.djikstra(this.graph, 0); @@ -34,7 +33,6 @@ export default class GoapActionPlanner { let i = 1; while(this.path[i] !== -1){ - console.log(this.path[i]); if (this.path[i] !== 0){ plan.push(this.mapping.get(this.path[i])); } @@ -47,9 +45,6 @@ export default class GoapActionPlanner { buildTree(root: number, goal:string, possibleActions: Array, currentStatus: Array): void { //For each possible action possibleActions.forEach(action => { - console.log("root:" + root + ",action precons:" + action.preconditions.toString() - + ", action effects:" + action.effects.toString() + ", current Status:" + currentStatus.toString()) - //Can it be performed? if (action.checkPreconditions(currentStatus)){ //This action can be performed @@ -59,7 +54,6 @@ export default class GoapActionPlanner { //Check if the new node is the goal if (newStatus.includes(goal)){ - console.log("AT GOAL"); let newNode = this.graph.addNode() - 1; this.mapping.set(newNode, action); this.graph.addEdge(root, newNode, action.cost); @@ -73,7 +67,6 @@ export default class GoapActionPlanner { this.graph.addEdge(root, newNode, action.cost); //Recursive call - console.log(possibleActions.indexOf(action)) let newActions = possibleActions.filter(act => act !== action) this.buildTree(newNode, goal, newActions, action.effects); } diff --git a/src/Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap.ts b/src/Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap.ts index 9b9703e..730155c 100644 --- a/src/Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap.ts +++ b/src/Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap.ts @@ -86,8 +86,8 @@ export default class OrthogonalTilemap extends Tilemap { let row = Math.floor(index / this.numCols); // Get the world position - let x = col * this.tileSize.x; - let y = row * this.tileSize.y; + let x = col * this.tileSize.x * this.scale.x; + let y = row * this.tileSize.y * this.scale.y; return new Vec2(x, y); } diff --git a/src/Wolfie2D/Physics/BasicPhysicsManager.ts b/src/Wolfie2D/Physics/BasicPhysicsManager.ts index 0b5086a..df2374a 100644 --- a/src/Wolfie2D/Physics/BasicPhysicsManager.ts +++ b/src/Wolfie2D/Physics/BasicPhysicsManager.ts @@ -264,7 +264,7 @@ export default class BasicPhysicsManager extends PhysicsManager { // Also check for triggers for(let overlap of overlaps){ // Check for a trigger. If we care about the trigger, react - if(overlap.other.isTrigger && (overlap.other.triggerMask & node.group)){ + if(overlap.other.isTrigger && (overlap.other.triggerMask & node.group) && node.group != -1){ // Get the bit that this group is represented by let index = Math.floor(Math.log2(node.group)); diff --git a/src/Wolfie2D/Rendering/Animations/AnimationTypes.ts b/src/Wolfie2D/Rendering/Animations/AnimationTypes.ts index 5f172de..ffd4067 100644 --- a/src/Wolfie2D/Rendering/Animations/AnimationTypes.ts +++ b/src/Wolfie2D/Rendering/Animations/AnimationTypes.ts @@ -49,6 +49,9 @@ export class TweenData { loop: boolean; /** The name of the event to send (if any) when the tween finishes playing */ onEnd: string + + /** Extra data to be sent when the onEnd event is fired. Keys with the name 'key' or 'node' are reserved and can't be used as names for your extra data */ + onEndData: Record; // Members for management by the tween manager /** The progress of this tween through its effects */ diff --git a/src/Wolfie2D/Rendering/Animations/ParticleSystem.ts b/src/Wolfie2D/Rendering/Animations/ParticleSystem.ts index ea7810f..c682087 100644 --- a/src/Wolfie2D/Rendering/Animations/ParticleSystem.ts +++ b/src/Wolfie2D/Rendering/Animations/ParticleSystem.ts @@ -6,65 +6,97 @@ import Scene from "../../Scene/Scene"; import Timer from "../../Timing/Timer"; import Color from "../../Utils/Color"; import { EaseFunctionType } from "../../Utils/EaseFunctions"; +import MathUtils from "../../Utils/MathUtils"; import RandUtils from "../../Utils/RandUtils"; import ParticleSystemManager from "./ParticleSystemManager"; -/* --Move particle system to HW#4, particle class and particle manager(object pool), source, randomized period of decay, - semi-randomized approach for spawning, should be general purpose - and load some settings from a json (location, states, colors, randomization). - Should be effect when balloon is popped -*/ - export default class ParticleSystem implements Updateable { + /** Pool for all particles */ protected particlePool: Array; + /** Lifetime for each particle */ protected lifetime: number; - protected liveParticles: number; - - protected maxLiveParticles: number; - protected sourcePoint: Vec2; protected particleSize: Vec2; + /** Timer for how long a particle system lasts before being turned off */ protected systemLifetime: Timer; protected systemRunning: boolean; protected color: Color = new Color(255, 0, 0); - constructor(poolSize: number, sourcePoint: Vec2, lifetime: number, size: number, maxParticles: number) { + /** Particles that can be rendered per frame */ + protected particlesPerFrame: number; + + /** Total number of particles to render, this will be incremented overtime by particlesPerFrame */ + protected particlesToRender: number; + + protected particleMass: number; + + /** + * Construct a particle system + * + * @param poolSize The pool size, i.e the total number of particles that will be created + * @param sourcePoint The initial source point each particle will start at when the system is running, can be changed + * @param lifetime Lifetime of each particle before they are set inactive + * @param size Size of each particle + * @param mass Initial mass of each particle, can be changed + * @param maxParticlesPerFrame Total number of particles that can be created during a given frame. + */ + constructor(poolSize: number, sourcePoint: Vec2, lifetime: number, size: number, mass: number, maxParticlesPerFrame: number) { this.particlePool = new Array(poolSize); this.sourcePoint = sourcePoint; this.lifetime = lifetime; this.particleSize = new Vec2(size, size); - this.maxLiveParticles = maxParticles; this.systemRunning = false; + this.particlesPerFrame = maxParticlesPerFrame; + this.particlesToRender = this.particlesPerFrame; + this.particleMass = mass; ParticleSystemManager.getInstance().registerParticleSystem(this); } - initalizePool(scene: Scene, layer: string, type: ParticleSystemType, mass: number) { + /** Initialize the pool of all particles, creating the assets in advance */ + initializePool(scene: Scene, layer: string) { for (let i = 0; i < this.particlePool.length; i++) { this.particlePool[i] = scene.add.graphic(GraphicType.PARTICLE, layer, - { position: this.sourcePoint.clone(), size: this.particleSize.clone(), mass: mass }); + { position: this.sourcePoint.clone(), size: this.particleSize.clone(), mass: this.particleMass }); this.particlePool[i].addPhysics(); this.particlePool[i].isCollidable = false; this.particlePool[i].visible = false; } } - startSystem(time: number, startPoint?: Vec2) { + /** + * Start up the particle system to run for a set amount of time + * @param time Time for the particle systme to run + * @param mass Optional change of mass for each particle + * @param startPoint Optional change of start position for each particle + */ + startSystem(time: number, mass?: number, startPoint?: Vec2) { + //Stop the system to reset all particles + this.stopSystem(); + + //Set the timer this.systemLifetime = new Timer(time); + + //Update optional parameters + if (mass !== undefined) + this.particleMass = mass; + + if (startPoint !== undefined) + this.sourcePoint = startPoint; + + //Start the timer, set flags, and give the initial amount of particles to render this.systemLifetime.start(); this.systemRunning = true; - this.sourcePoint = startPoint; + this.particlesToRender = this.particlesPerFrame; } stopSystem() { - console.log(this); this.systemRunning = false; for (let particle of this.particlePool) { if (particle.inUse) { @@ -77,15 +109,35 @@ export default class ParticleSystem implements Updateable { this.color = color; } + /** + * Default implementation of setParticleAnimation, no tween animations occur, but each particle is given a random + * velocity. It's encouraged for you to override this function and implement your own tween animations. + * + * @param particle + */ + setParticleAnimation(particle: Particle) { + particle.vel = RandUtils.randVec(-50, 50, -100, 100); + particle.tweens.add("active", { + startDelay: 0, + duration: this.lifetime, + effects: [] + }); + } + update(deltaT: number) { + // Exit if the system isn't currently running if (!this.systemRunning) { return; } + // Stop the system if our timer is up if (this.systemLifetime.isStopped()) { this.stopSystem(); } else { - for (let particle of this.particlePool) { + for (let i = 0; i < this.particlesToRender; i++) { + let particle = this.particlePool[i]; + + // If a particle is in use, decrease it's age and update it's velocity, if it has one if (particle.inUse) { particle.decrementAge(deltaT * 1000); @@ -93,71 +145,27 @@ export default class ParticleSystem implements Updateable { particle.setParticleInactive(); } - //particle.vel.y += 200*deltaT; particle.move(particle.vel.scaled(deltaT)); } else { + // Set the particle to active particle.setParticleActive(this.lifetime, this.sourcePoint.clone()); + // Update particle color, mass, and alpha particle.color = this.color; particle.alpha = 1; - //particle.size.set(1) - particle.vel = RandUtils.randVec(-50, 50, -100, 100); - - particle.tweens.add("active", { - startDelay: 0, - duration: 2000, - effects: [ - { - property: "alpha", - resetOnComplete: true, - start: 1, - end: 0, - ease: EaseFunctionType.IN_OUT_SINE - }, - /*{ - property: "colorR", - resetOnComplete: true, - start: particle.color.r, - end: 255, - ease: EaseFunctionType.IN_OUT_SINE - }, - { - property: "colorG", - resetOnComplete: true, - start: particle.color.g, - end: 255, - ease: EaseFunctionType.IN_OUT_SINE - }, - { - property: "colorB", - resetOnComplete: true, - start: particle.color.b, - end: 255, - ease: EaseFunctionType.IN_OUT_SINE - },*/ - { - property: "velY", - resetOnComplete: true, - start: particle.vel.y, - end: particle.vel.y + ((this.lifetime * particle.mass)/2), - ease: EaseFunctionType.IN_OUT_SINE - } - ] - }); + particle.mass = this.particleMass; + + // Give particle tween animations + this.setParticleAnimation(particle); particle.tweens.play("active"); - - //particle.vel = RandUtils.randVec(-150, 150, -100, 100); - //console.log(particle.vel.toString()); } } + // Update the amount of particles that can be rendered based on the particles per frame, clamping if we go over the total number + // of particles in our pool + this.particlesToRender = MathUtils.clamp(this.particlesToRender+this.particlesPerFrame, 0, this.particlePool.length); } } } - -export enum ParticleSystemType { - emitter = "emitter", - burst = "burst" -} diff --git a/src/Wolfie2D/Rendering/Animations/TweenController.ts b/src/Wolfie2D/Rendering/Animations/TweenController.ts index 082208d..b409216 100644 --- a/src/Wolfie2D/Rendering/Animations/TweenController.ts +++ b/src/Wolfie2D/Rendering/Animations/TweenController.ts @@ -143,7 +143,16 @@ export default class TweenController { // If it has an onEnd, send an event if(tween.onEnd){ - this.emitter.fireEvent(tween.onEnd, {key: key, node: this.owner.id}); + let data: Record = {key: key, node: this.owner.id} + // If it has onEnd event data, add each entry, as long as the key is not named 'key' or 'node' + if (tween.onEndData) { + Object.keys(tween.onEndData).forEach(key => { + if (key !== "key" && key !== "node") { + data[key] = tween.onEndData[key]; + } + }) + } + this.emitter.fireEvent(tween.onEnd, data); } } }