mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2026-02-20 13:11:02 +00:00
Add particlesystem stuff
This commit is contained in:
parent
cc706f8cbb
commit
f88433ea26
11 changed files with 553 additions and 2 deletions
|
|
@ -3,5 +3,6 @@
|
|||
-lib hlsdl
|
||||
-lib polygonal-ds
|
||||
-hl marblegame.hl
|
||||
-D windowSize=1280x720
|
||||
--main Main
|
||||
-debug
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package src;
|
||||
|
||||
import shaders.Billboard;
|
||||
import collision.BoxCollisionEntity;
|
||||
import shaders.DtsTexture;
|
||||
import h3d.shader.AlphaMult;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package src;
|
||||
|
||||
import shaders.Billboard;
|
||||
import shaders.DtsTexture;
|
||||
import h3d.mat.Pass;
|
||||
import h3d.shader.AlphaMult;
|
||||
|
|
|
|||
45
src/Main.hx
45
src/Main.hx
|
|
@ -1,5 +1,12 @@
|
|||
package;
|
||||
|
||||
import h3d.mat.Data.Blend;
|
||||
import src.ParticleSystem.ParticleEmitterOptions;
|
||||
import src.ParticleSystem.ParticleEmitter;
|
||||
import src.ParticleSystem.Particle;
|
||||
import src.ParticleSystem.ParticleManager;
|
||||
import src.ParticleSystem.ParticleData;
|
||||
import src.ParticleSystem.ParticleData;
|
||||
import shapes.Helicopter;
|
||||
import shapes.ShockAbsorber;
|
||||
import shapes.SuperBounce;
|
||||
|
|
@ -116,7 +123,45 @@ class Main extends hxd.App {
|
|||
ag.y = 6;
|
||||
world.addDtsObject(ag);
|
||||
|
||||
// var le:ParticleEmitterOptions = {
|
||||
// ejectionPeriod: 0.01,
|
||||
// ambientVelocity: new Vector(0, 0, 0),
|
||||
// ejectionVelocity: 0.5,
|
||||
// velocityVariance: 0.25,
|
||||
// emitterLifetime: 1e8,
|
||||
// inheritedVelFactor: 0.2,
|
||||
// particleOptions: {
|
||||
// texture: 'particles/smoke.png',
|
||||
// blending: Add,
|
||||
// spinSpeed: 40,
|
||||
// spinRandomMin: -90,
|
||||
// spinRandomMax: 90,
|
||||
// lifetime: 1,
|
||||
// lifetimeVariance: 0.15,
|
||||
// dragCoefficient: 0.8,
|
||||
// acceleration: 0,
|
||||
// colors: [new Vector(0.56, 0.36, 0.26, 1), new Vector(0.56, 0.36, 0.26, 0)],
|
||||
// sizes: [0.5, 1],
|
||||
// times: [0, 1]
|
||||
// }
|
||||
// };
|
||||
|
||||
// var p1 = new ParticleData();
|
||||
// p1.identifier = "testparticle";
|
||||
// p1.texture = ResourceLoader.getTexture("data/particles/smoke.png");
|
||||
|
||||
// // var emitter = new ParticleEmitter(le, p1, world.particleManager); // var p = new Particle();
|
||||
// world.particleManager.createEmitter(le, p1, new Vector());
|
||||
|
||||
// p.position = new Vector();
|
||||
// p.color = new Vector(255, 255, 255);
|
||||
// p.rotation = Math.PI;
|
||||
// p.scale = 5;
|
||||
|
||||
// world.particleManager.addParticle(p1, p);
|
||||
|
||||
// for (i in 0...10) {
|
||||
|
||||
// for (j in 0...10) {
|
||||
// var trapdoor = new Tornado();
|
||||
// trapdoor.x = i * 2;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package src;
|
||||
|
||||
import src.ParticleSystem.ParticleData;
|
||||
import src.ParticleSystem.ParticleEmitterOptions;
|
||||
import src.DtsObject;
|
||||
import sdl.Cursor;
|
||||
import hxd.Cursor;
|
||||
|
|
@ -36,6 +38,29 @@ class Move {
|
|||
public function new() {}
|
||||
}
|
||||
|
||||
final bounceParticleOptions:ParticleEmitterOptions = {
|
||||
ejectionPeriod: 1,
|
||||
ambientVelocity: new Vector(0, 0, 0.0),
|
||||
ejectionVelocity: 2.6,
|
||||
velocityVariance: 0.25 * 0.5,
|
||||
emitterLifetime: 4,
|
||||
inheritedVelFactor: 0,
|
||||
particleOptions: {
|
||||
texture: 'particles/star.png',
|
||||
blending: Alpha,
|
||||
spinSpeed: 90,
|
||||
spinRandomMin: -90,
|
||||
spinRandomMax: 90,
|
||||
lifetime: 500,
|
||||
lifetimeVariance: 100,
|
||||
dragCoefficient: 0.5,
|
||||
acceleration: -2,
|
||||
colors: [new Vector(0.9, 0, 0, 1), new Vector(0.9, 0.9, 0, 1), new Vector(0.9, 0.9, 0, 0)],
|
||||
sizes: [0.25, 0.25, 0.25],
|
||||
times: [0, 0.75, 1]
|
||||
}
|
||||
};
|
||||
|
||||
class Marble extends GameObject {
|
||||
public var camera:CameraController;
|
||||
public var cameraObject:Object;
|
||||
|
|
@ -86,6 +111,8 @@ class Marble extends GameObject {
|
|||
var shockAbsorberEnableTime:Float = -1e8;
|
||||
var helicopterEnableTime:Float = -1e8;
|
||||
|
||||
var bounceEmitterData:ParticleData;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
var geom = Sphere.defaultUnitSphere();
|
||||
|
|
@ -100,6 +127,10 @@ class Marble extends GameObject {
|
|||
this.camera = new CameraController(cast this);
|
||||
|
||||
this.collider = new SphereCollisionEntity(cast this);
|
||||
|
||||
this.bounceEmitterData = new ParticleData();
|
||||
this.bounceEmitterData.identifier = "MarbleBounceParticle";
|
||||
this.bounceEmitterData.texture = ResourceLoader.getTexture("data/particles/star.png");
|
||||
}
|
||||
|
||||
public function init(level:MarbleWorld) {
|
||||
|
|
@ -307,6 +338,7 @@ class Marble extends GameObject {
|
|||
var velocityAdd = surfaceVel.multiply(-(1 + restitution));
|
||||
var vAtC = sVel.add(this.omega.cross(contacts[i].normal.multiply(-this._radius)));
|
||||
var normalVel = -contacts[i].normal.dot(sVel);
|
||||
bounceEmitter(sVel.length() * restitution, contacts[i].normal);
|
||||
vAtC = vAtC.sub(contacts[i].normal.multiply(contacts[i].normal.dot(sVel)));
|
||||
var vAtCMag = vAtC.length();
|
||||
if (vAtCMag != 0) {
|
||||
|
|
@ -473,6 +505,10 @@ class Marble extends GameObject {
|
|||
return [A, a];
|
||||
}
|
||||
|
||||
function bounceEmitter(speed:Float, normal:Vector) {
|
||||
this.level.particleManager.createEmitter(bounceParticleOptions, this.bounceEmitterData, this.getAbsPos().getPosition());
|
||||
}
|
||||
|
||||
function ReportBounce(pos:Vector, normal:Vector, speed:Float) {
|
||||
if (this._bounceYet && speed < this._bounceSpeed) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package src;
|
||||
|
||||
import src.ParticleSystem.ParticleManager;
|
||||
import src.Util;
|
||||
import h3d.Quat;
|
||||
import shapes.PowerUp;
|
||||
|
|
@ -21,6 +22,7 @@ import src.Marble;
|
|||
class MarbleWorld {
|
||||
public var collisionWorld:CollisionWorld;
|
||||
public var instanceManager:InstanceManager;
|
||||
public var particleManager:ParticleManager;
|
||||
|
||||
public var interiors:Array<InteriorObject> = [];
|
||||
public var pathedInteriors:Array<PathedInterior> = [];
|
||||
|
|
@ -49,6 +51,7 @@ class MarbleWorld {
|
|||
this.collisionWorld = new CollisionWorld();
|
||||
this.scene = scene;
|
||||
this.instanceManager = new InstanceManager(scene);
|
||||
this.particleManager = new ParticleManager(cast this);
|
||||
this.sky = new Sky();
|
||||
sky.dmlPath = "data/skies/sky_day.dml";
|
||||
sky.init(cast this);
|
||||
|
|
@ -112,6 +115,7 @@ class MarbleWorld {
|
|||
marble.update(currentTime, dt, collisionWorld, this.pathedInteriors);
|
||||
}
|
||||
this.instanceManager.update(dt);
|
||||
this.particleManager.update(1000 * currentTime, dt);
|
||||
currentTime += dt;
|
||||
if (this.marble != null) {
|
||||
callCollisionHandlers(marble);
|
||||
|
|
|
|||
363
src/ParticleSystem.hx
Normal file
363
src/ParticleSystem.hx
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
package src;
|
||||
|
||||
import h3d.prim.UV;
|
||||
import h3d.parts.Data.BlendMode;
|
||||
import src.MarbleWorld;
|
||||
import src.Util;
|
||||
import h3d.mat.Data.Wrap;
|
||||
import shaders.Billboard;
|
||||
import hxd.IndexBuffer;
|
||||
import h3d.col.Point;
|
||||
import h3d.prim.Polygon;
|
||||
import h3d.prim.MeshPrimitive;
|
||||
import h3d.mat.Texture;
|
||||
import h3d.scene.Scene;
|
||||
import h3d.mat.Material;
|
||||
import h3d.Vector;
|
||||
import h3d.scene.MeshBatch;
|
||||
import h3d.scene.Mesh;
|
||||
|
||||
@:publicFields
|
||||
class ParticleData {
|
||||
var texture:Texture;
|
||||
var identifier:String;
|
||||
|
||||
public function new() {}
|
||||
}
|
||||
|
||||
@:publicFields
|
||||
class Particle {
|
||||
var data:ParticleData;
|
||||
var manager:ParticleManager;
|
||||
var o:ParticleOptions;
|
||||
var position:Vector;
|
||||
var vel:Vector;
|
||||
var rotation:Float;
|
||||
var color:Vector;
|
||||
var scale:Float;
|
||||
var lifeTime:Float;
|
||||
var initialSpin:Float;
|
||||
var spawnTime:Float;
|
||||
var currentAge:Float = 0;
|
||||
var acc:Vector = new Vector();
|
||||
|
||||
public function new(options:ParticleOptions, manager:ParticleManager, data:ParticleData, spawnTime:Float, pos:Vector, vel:Vector) {
|
||||
this.o = options;
|
||||
this.manager = manager;
|
||||
this.data = data;
|
||||
this.spawnTime = spawnTime;
|
||||
this.position = pos;
|
||||
this.vel = vel;
|
||||
this.acc = this.vel.multiply(options.acceleration);
|
||||
|
||||
this.lifeTime = this.o.lifetime + this.o.lifetimeVariance * (Math.random() * 2 - 1);
|
||||
this.initialSpin = Util.lerp(this.o.spinRandomMin, this.o.spinRandomMax, Math.random());
|
||||
}
|
||||
|
||||
public function update(time:Float, dt:Float) {
|
||||
var t = dt;
|
||||
var a = this.acc;
|
||||
a = a.sub(this.vel.multiply(this.o.dragCoefficient));
|
||||
this.vel = this.vel.add(a.multiply(dt));
|
||||
this.position = this.position.add(this.vel.multiply(dt));
|
||||
|
||||
this.currentAge += dt;
|
||||
|
||||
var elapsed = time - this.spawnTime;
|
||||
var completion = Util.clamp(elapsed / this.lifeTime, 0, 1);
|
||||
|
||||
if (currentAge > this.lifeTime) // Again, rewind needs this
|
||||
{
|
||||
this.manager.removeParticle(this.data, this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (completion == 1) {
|
||||
// The particle can die
|
||||
this.manager.removeParticle(this.data, this);
|
||||
return;
|
||||
}
|
||||
|
||||
// var velElapsed = elapsed / 1000;
|
||||
// velElapsed *= 0.001;
|
||||
// velElapsed = Math.pow(velElapsed, (1 - this.o.dragCoefficient)); // Somehow slow down velocity over time based on the drag coefficient
|
||||
|
||||
// // Compute the position
|
||||
// var pos = this.position.add(this.vel.multiply(velElapsed + this.o.acceleration * (velElapsed * velElapsed) / 2));
|
||||
// this.position = pos;
|
||||
|
||||
this.rotation = (this.initialSpin + this.o.spinSpeed * elapsed / 1000) * Math.PI / 180;
|
||||
|
||||
// Check where we are in the times array
|
||||
var indexLow = 0;
|
||||
var indexHigh = 1;
|
||||
for (i in 2...this.o.times.length) {
|
||||
if (this.o.times[indexHigh] >= completion)
|
||||
break;
|
||||
|
||||
indexLow = indexHigh;
|
||||
indexHigh = i;
|
||||
}
|
||||
|
||||
if (this.o.times.length == 1)
|
||||
indexHigh = indexLow;
|
||||
var t = (completion - this.o.times[indexLow]) / (this.o.times[indexHigh] - this.o.times[indexLow]);
|
||||
|
||||
// Adjust color
|
||||
var color = Util.lerpThreeVectors(this.o.colors[indexLow], this.o.colors[indexHigh], t);
|
||||
this.color = color;
|
||||
// this.material.opacity = color.a * * 1.5; // Adjusted because additive mixing can be kind of extreme
|
||||
|
||||
// Adjust sizing
|
||||
this.scale = Util.lerp(this.o.sizes[indexLow], this.o.sizes[indexHigh], t);
|
||||
}
|
||||
}
|
||||
|
||||
typedef ParticleBatch = {
|
||||
var instances:Array<Particle>;
|
||||
var meshBatch:MeshBatch;
|
||||
}
|
||||
|
||||
/** The options for a single particle. */
|
||||
typedef ParticleOptions = {
|
||||
var texture:String;
|
||||
|
||||
/** Which blending mode to use. */
|
||||
var blending:h3d.mat.BlendMode;
|
||||
|
||||
/** The spinning speed in degrees per second. */
|
||||
var spinSpeed:Float;
|
||||
|
||||
var spinRandomMin:Float;
|
||||
var spinRandomMax:Float;
|
||||
var lifetime:Float;
|
||||
var lifetimeVariance:Float;
|
||||
var dragCoefficient:Float;
|
||||
|
||||
/** Acceleration along the velocity vector. */
|
||||
var acceleration:Float;
|
||||
|
||||
var colors:Array<Vector>;
|
||||
var sizes:Array<Float>;
|
||||
|
||||
/** Determines at what percentage of lifetime the corresponding colors and sizes are in effect. */
|
||||
var times:Array<Float>;
|
||||
};
|
||||
|
||||
/** The options for a particle emitter. */
|
||||
typedef ParticleEmitterOptions = {
|
||||
/** The time between particle ejections. */
|
||||
var ejectionPeriod:Float; /** A fixed velocity to add to each particle. */
|
||||
|
||||
var ambientVelocity:Vector; /** The particle is ejected in a random direction with this velocity. */
|
||||
|
||||
var ejectionVelocity:Float;
|
||||
|
||||
var velocityVariance:Float;
|
||||
var emitterLifetime:Float;
|
||||
|
||||
/** How much of the emitter's own velocity the particle should inherit. */
|
||||
var inheritedVelFactor:Float; /** Computes a spawn offset for each particle. */
|
||||
|
||||
var ?spawnOffset:Void->Vector;
|
||||
|
||||
var particleOptions:ParticleOptions;
|
||||
}
|
||||
|
||||
@:publicFields
|
||||
class ParticleEmitter {
|
||||
var o:ParticleEmitterOptions;
|
||||
var data:ParticleData;
|
||||
var manager:ParticleManager;
|
||||
var spawnTime:Float;
|
||||
var lastEmitTime:Float;
|
||||
var currentWaitPeriod:Float;
|
||||
var lastPos:Vector;
|
||||
var lastPosTime:Float;
|
||||
var currPos:Vector;
|
||||
var currPosTime:Float;
|
||||
var creationTime:Float;
|
||||
var vel = new Vector();
|
||||
var getPos:Void->Vector;
|
||||
|
||||
public function new(options:ParticleEmitterOptions, data:ParticleData, manager:ParticleManager, ?getPos:Void->Vector) {
|
||||
this.o = options;
|
||||
this.manager = manager;
|
||||
this.getPos = getPos;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public function spawn(time:Float) {
|
||||
this.spawnTime = time;
|
||||
this.emit(time);
|
||||
}
|
||||
|
||||
public function tick(time:Float) {
|
||||
// Cap the amount of particles emitted in such a case to prevent lag
|
||||
if (time - this.lastEmitTime >= 1000)
|
||||
this.lastEmitTime = time - 1000;
|
||||
// Spawn as many particles as needed
|
||||
while (this.lastEmitTime + this.currentWaitPeriod <= time) {
|
||||
this.emit(this.lastEmitTime + this.currentWaitPeriod);
|
||||
var completion = Util.clamp((this.lastEmitTime - this.spawnTime) / this.o.emitterLifetime, 0, 1);
|
||||
if (completion == 1) {
|
||||
this.manager.removeEmitter(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Emit a single particle. */
|
||||
public function emit(time:Float) {
|
||||
this.lastEmitTime = time;
|
||||
this.currentWaitPeriod = this.o.ejectionPeriod;
|
||||
var pos = this.getPosAtTime(time).clone();
|
||||
if (this.o.spawnOffset != null)
|
||||
pos.add(this.o.spawnOffset()); // Call the spawnOffset function if it's there
|
||||
// This isn't necessarily uniform but it's fine for the purpose.
|
||||
var randomPointOnSphere = new Vector(Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1).normalized();
|
||||
// Compute the total velocity
|
||||
var vel = this.vel.multiply(this.o.inheritedVelFactor)
|
||||
.add(randomPointOnSphere.multiply(this.o.ejectionVelocity + this.o.velocityVariance * (Math.random() * 2 - 1)))
|
||||
.add(this.o.ambientVelocity);
|
||||
var particle = new Particle(this.o.particleOptions, this.manager, this.data, time, pos, vel);
|
||||
this.manager.addParticle(data, particle);
|
||||
}
|
||||
|
||||
/** Computes the interpolated emitter position at a point in time. */
|
||||
public function getPosAtTime(time:Float) {
|
||||
if (this.lastPos == null)
|
||||
return this.currPos;
|
||||
var completion = Util.clamp((time - this.lastPosTime) / (this.currPosTime - this.lastPosTime), 0, 1);
|
||||
return Util.lerpThreeVectors(this.lastPos, this.currPos, completion);
|
||||
}
|
||||
|
||||
public function setPos(pos:Vector, time:Float) {
|
||||
this.lastPos = this.currPos;
|
||||
this.lastPosTime = this.currPosTime;
|
||||
this.currPos = pos.clone();
|
||||
this.currPosTime = time;
|
||||
this.vel = this.currPos.sub(this.lastPos).multiply(1000 / (this.currPosTime - this.lastPosTime));
|
||||
}
|
||||
}
|
||||
|
||||
class ParticleManager {
|
||||
var particlebatches:Map<String, ParticleBatch> = new Map();
|
||||
var level:MarbleWorld;
|
||||
var scene:Scene;
|
||||
var currentTime:Float;
|
||||
|
||||
var emitters:Array<ParticleEmitter> = [];
|
||||
|
||||
public function new(level:MarbleWorld) {
|
||||
this.level = level;
|
||||
this.scene = level.scene;
|
||||
}
|
||||
|
||||
public function update(currentTime:Float, dt:Float) {
|
||||
this.tick();
|
||||
this.currentTime = currentTime;
|
||||
for (obj => batch in particlebatches) {
|
||||
for (instance in batch.instances)
|
||||
instance.update(currentTime, dt);
|
||||
}
|
||||
for (obj => batch in particlebatches) {
|
||||
batch.meshBatch.begin(batch.instances.length);
|
||||
for (instance in batch.instances) {
|
||||
if (instance.currentAge != 0) {
|
||||
batch.meshBatch.setPosition(instance.position.x, instance.position.y, instance.position.z);
|
||||
var particleShader = batch.meshBatch.material.mainPass.getShader(Billboard);
|
||||
particleShader.scale = instance.scale;
|
||||
particleShader.rotation = instance.rotation;
|
||||
batch.meshBatch.material.blendMode = instance.o.blending;
|
||||
batch.meshBatch.material.color.load(instance.color);
|
||||
batch.meshBatch.shadersChanged = true;
|
||||
batch.meshBatch.setScale(instance.scale);
|
||||
batch.meshBatch.emitInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addParticle(particleData:ParticleData, particle:Particle) {
|
||||
if (particlebatches.exists(particleData.identifier)) {
|
||||
particlebatches.get(particleData.identifier).instances.push(particle);
|
||||
} else {
|
||||
var pts = [
|
||||
new Point(-0.5, -0.5, 0),
|
||||
new Point(-0.5, 0.5, 0),
|
||||
new Point(0.5, -0.5, 0),
|
||||
new Point(0.5, 0.5)
|
||||
];
|
||||
var prim = new Polygon(pts);
|
||||
prim.idx = new IndexBuffer();
|
||||
prim.idx.push(0);
|
||||
prim.idx.push(1);
|
||||
prim.idx.push(2);
|
||||
prim.idx.push(1);
|
||||
prim.idx.push(3);
|
||||
prim.idx.push(2);
|
||||
prim.uvs = [new UV(0, 0), new UV(0, 1), new UV(1, 0), new UV(1, 1)];
|
||||
prim.addNormals();
|
||||
var mat = Material.create(particleData.texture);
|
||||
mat.mainPass.addShader(new h3d.shader.pbr.PropsValues(1, 0, 0, 1));
|
||||
mat.texture.wrap = Wrap.Repeat;
|
||||
mat.blendMode = Alpha;
|
||||
var billboardShader = new Billboard();
|
||||
mat.mainPass.addShader(billboardShader);
|
||||
var mb = new MeshBatch(prim, mat, this.scene);
|
||||
var batch:ParticleBatch = {
|
||||
instances: [particle],
|
||||
meshBatch: mb
|
||||
};
|
||||
particlebatches.set(particleData.identifier, batch);
|
||||
}
|
||||
}
|
||||
|
||||
public function removeParticle(particleData:ParticleData, particle:Particle) {
|
||||
if (particlebatches.exists(particleData.identifier)) {
|
||||
particlebatches.get(particleData.identifier).instances.remove(particle);
|
||||
}
|
||||
}
|
||||
|
||||
public function getTime() {
|
||||
return this.currentTime;
|
||||
}
|
||||
|
||||
public function createEmitter(options:ParticleEmitterOptions, data:ParticleData, initialPos:Vector, ?getPos:Void->Vector) {
|
||||
var emitter = new ParticleEmitter(options, data, cast this, getPos);
|
||||
emitter.currPos = (getPos != null) ? getPos() : initialPos.clone();
|
||||
if (emitter.currPos == null)
|
||||
emitter.currPos = initialPos.clone();
|
||||
emitter.currPosTime = this.getTime();
|
||||
emitter.creationTime = this.getTime();
|
||||
emitter.spawn(this.getTime());
|
||||
this.emitters.push(emitter);
|
||||
return emitter;
|
||||
}
|
||||
|
||||
public function removeEmitter(emitter:ParticleEmitter) {
|
||||
this.emitters.remove(emitter);
|
||||
}
|
||||
|
||||
public function removeEverything() {
|
||||
for (particle in this.particlebatches) {
|
||||
particle.instances = [];
|
||||
}
|
||||
for (emitter in this.emitters)
|
||||
this.removeEmitter(emitter);
|
||||
}
|
||||
|
||||
public function tick() {
|
||||
var time = this.getTime();
|
||||
for (emitter in this.emitters) {
|
||||
if (emitter.getPos != null)
|
||||
emitter.setPos(emitter.getPos(), time);
|
||||
emitter.tick(time);
|
||||
// Remove the artifact that was created in a different future cause we rewinded and now we shifted timelines
|
||||
if (emitter.creationTime > time) {
|
||||
this.removeEmitter(emitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ class Util {
|
|||
}
|
||||
|
||||
public static function lerpThreeVectors(v1:Vector, v2:Vector, t:Float) {
|
||||
return new Vector(lerp(v1.x, v2.x, t), lerp(v1.y, v2.y, t), lerp(v1.z, v2.z, t));
|
||||
return new Vector(lerp(v1.x, v2.x, t), lerp(v1.y, v2.y, t), lerp(v1.z, v2.z, t), lerp(v1.w, v2.w, t));
|
||||
}
|
||||
|
||||
public static function rotateImage(bitmap:BitmapData, angle:Float) {
|
||||
|
|
|
|||
33
src/shaders/Billboard.hx
Normal file
33
src/shaders/Billboard.hx
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package shaders;
|
||||
|
||||
class Billboard extends hxsl.Shader {
|
||||
static var SRC = {
|
||||
@input var input:{
|
||||
var uv:Vec2;
|
||||
};
|
||||
@global var camera:{
|
||||
var view:Mat4;
|
||||
var proj:Mat4;
|
||||
};
|
||||
@global var global:{
|
||||
@perObject var modelView:Mat4;
|
||||
};
|
||||
@param var scale:Float;
|
||||
@param var rotation:Float;
|
||||
var relativePosition:Vec3;
|
||||
var projectedPosition:Vec4;
|
||||
var calculatedUV:Vec2;
|
||||
function vertex() {
|
||||
var mid = 0.5;
|
||||
var uv = input.uv;
|
||||
calculatedUV.x = cos(rotation) * (uv.x - mid) + sin(rotation) * (uv.y - mid) + mid;
|
||||
calculatedUV.y = cos(rotation) * (uv.y - mid) - sin(rotation) * (uv.x - mid) + mid;
|
||||
}
|
||||
function billboard(pos:Vec2, scale:Vec2):Vec4 {
|
||||
return (vec4(0, 0, 0, 1) * (global.modelView * camera.view) + vec4(pos * scale, 0, 0));
|
||||
}
|
||||
function __init__() {
|
||||
projectedPosition = billboard(relativePosition.xy, vec2(scale, scale)) * camera.proj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,45 @@
|
|||
package shapes;
|
||||
|
||||
import src.ResourceLoader;
|
||||
import src.ParticleSystem.ParticleData;
|
||||
import h3d.Vector;
|
||||
import src.DtsObject;
|
||||
|
||||
final superJumpParticleOptions:src.ParticleSystem.ParticleEmitterOptions = {
|
||||
ejectionPeriod: 10,
|
||||
ambientVelocity: new Vector(0, 0, 0.05),
|
||||
ejectionVelocity: 1 * 0.5,
|
||||
velocityVariance: 0.25 * 0.5,
|
||||
emitterLifetime: 1000,
|
||||
inheritedVelFactor: 0.1,
|
||||
particleOptions: {
|
||||
texture: 'particles/twirl.png',
|
||||
blending: Add,
|
||||
spinSpeed: 90,
|
||||
spinRandomMin: -90,
|
||||
spinRandomMax: 90,
|
||||
lifetime: 1000,
|
||||
lifetimeVariance: 150,
|
||||
dragCoefficient: 0.25,
|
||||
acceleration: 0,
|
||||
colors: [new Vector(0, 0.5, 1, 0), new Vector(0, 0.6, 1, 1), new Vector(0, 0.5, 1, 0)],
|
||||
sizes: [0.25, 0.25, 0.5],
|
||||
times: [0, 0.75, 1]
|
||||
}
|
||||
};
|
||||
|
||||
class SuperJump extends PowerUp {
|
||||
var sjEmitterParticleData:ParticleData;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
this.dtsPath = "data/shapes/items/superjump.dts";
|
||||
this.isCollideable = false;
|
||||
this.isTSStatic = false;
|
||||
this.identifier = "SuperJump";
|
||||
sjEmitterParticleData = new ParticleData();
|
||||
sjEmitterParticleData.identifier = "superJumpParticle";
|
||||
sjEmitterParticleData.texture = ResourceLoader.getTexture("data/particles/twirl.png");
|
||||
}
|
||||
|
||||
public function pickUp():Bool {
|
||||
|
|
@ -18,6 +49,7 @@ class SuperJump extends PowerUp {
|
|||
public function use(time:Float) {
|
||||
var marble = this.level.marble;
|
||||
marble.velocity = marble.velocity.add(this.level.currentUp.multiply(20));
|
||||
this.level.particleManager.createEmitter(superJumpParticleOptions, this.sjEmitterParticleData, null, () -> marble.getAbsPos().getPosition());
|
||||
// marble.body.addLinearVelocity(this.level.currentUp.scale(20)); // Simply add to vertical velocity
|
||||
// if (!this.level.rewinding)
|
||||
// AudioManager.play(this.sounds[1]);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,42 @@
|
|||
package shapes;
|
||||
|
||||
import src.ResourceLoader;
|
||||
import src.ParticleSystem.ParticleData;
|
||||
import src.ParticleSystem.ParticleEmitterOptions;
|
||||
import h3d.Quat;
|
||||
import h3d.Vector;
|
||||
import src.DtsObject;
|
||||
|
||||
final superSpeedParticleOptions:ParticleEmitterOptions = {
|
||||
ejectionPeriod: 5,
|
||||
ambientVelocity: new Vector(0, 0, 0.2),
|
||||
ejectionVelocity: 1 * 0.5,
|
||||
velocityVariance: 0.25 * 0.5,
|
||||
emitterLifetime: 1100,
|
||||
inheritedVelFactor: 0.25,
|
||||
particleOptions: {
|
||||
texture: 'particles/spark.png',
|
||||
blending: Add,
|
||||
spinSpeed: 0,
|
||||
spinRandomMin: 0,
|
||||
spinRandomMax: 0,
|
||||
lifetime: 1500,
|
||||
lifetimeVariance: 150,
|
||||
dragCoefficient: 0.25,
|
||||
acceleration: 0,
|
||||
colors: [
|
||||
new Vector(0.8, 0.8, 0, 0),
|
||||
new Vector(0.8, 0.8, 0, 1),
|
||||
new Vector(0.8, 0.8, 0, 0)
|
||||
],
|
||||
sizes: [0.25, 0.25, 1],
|
||||
times: [0, 0.25, 1]
|
||||
}
|
||||
};
|
||||
|
||||
class SuperSpeed extends PowerUp {
|
||||
var ssEmitterParticleData:ParticleData;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
this.dtsPath = "data/shapes/items/superspeed.dts";
|
||||
|
|
@ -12,6 +44,9 @@ class SuperSpeed extends PowerUp {
|
|||
this.isTSStatic = false;
|
||||
this.identifier = "SuperSpeed";
|
||||
this.useInstancing = true;
|
||||
ssEmitterParticleData = new ParticleData();
|
||||
ssEmitterParticleData.identifier = "superSpeedParticle";
|
||||
ssEmitterParticleData.texture = ResourceLoader.getTexture("data/particles/spark.png");
|
||||
}
|
||||
|
||||
public function pickUp():Bool {
|
||||
|
|
@ -37,7 +72,7 @@ class SuperSpeed extends PowerUp {
|
|||
// marble.body.addLinearVelocity(this.level.currentUp.scale(20)); // Simply add to vertical velocity
|
||||
// if (!this.level.rewinding)
|
||||
// AudioManager.play(this.sounds[1]);
|
||||
// this.level.particles.createEmitter(superJumpParticleOptions, null, () => Util.vecOimoToThree(marble.body.getPosition()));
|
||||
this.level.particleManager.createEmitter(superSpeedParticleOptions, this.ssEmitterParticleData, null, () -> marble.getAbsPos().getPosition());
|
||||
// this.level.deselectPowerUp();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue