diff --git a/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt b/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt index f25eb0b..72e9e24 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt @@ -27,6 +27,37 @@ import net.minecraft.world.World import java.util.* +// TODO: +// Allowing the use of regular Minecraft particles instead of just BDEs. +// Better command auto-completion. (and change names of args) + // force field "config" option + // blockCurve array not needing "minecraft:" + +// Adding a parameter for an initial velocity from an origin point (you currently have to use force fields) + // Pair, Pair> + // "min center vel", "max center vel", "min edge vel", "max edge vel" + +// Parameters + // localOffset (Vec3f) + // velocity based, relative coordinate based, or rotation based + // localOffsetCurve (curve) + // spawnOffset (Vec3f) + // velRot (bool) + // rotates the particle to face the velocity + // spawnChance (Float) + +// Move most (if not all) particle params to emitters. +// 3D curves (curves for all X Y Z) +// Custom curve equation command args (parse from strings) +// Cylinder and cone force field shape. +// Better particle performance. +// Global max particles variable. + // gamerule max particles + +// Emitter groups (multiple emitters for EmitterTool) +// Private functions/classes + + var ALL_PARTICLE_EMITTERS: Array = emptyArray() val sessionUuid: UUID = UUID.randomUUID() diff --git a/src/main/kotlin/com/bytedice/bde_particles/Math.kt b/src/main/kotlin/com/bytedice/bde_particles/Math.kt index 8418ac1..85e0e32 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/Math.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/Math.kt @@ -12,18 +12,18 @@ import kotlin.math.* import kotlin.random.Random -class InterpolationCurves(val function: (Float) -> Float) { +class LerpCurves(val function: (Float) -> Float) { companion object { - val LINEAR = InterpolationCurves { y -> y } - val SQRT = InterpolationCurves { y -> sqrt(y) } - val EXPONENT = InterpolationCurves { y -> y.pow(2.0f) } - val CUBIC = InterpolationCurves { y -> y.pow(3.0f) } - val SINE = InterpolationCurves { y -> sin(y * PI.toFloat() / 2) } - val COSINE = InterpolationCurves { y -> 1 - cos(y * PI.toFloat() / 2) } - val INVERSE = InterpolationCurves { y -> 1 - y } - val LOG = InterpolationCurves { y -> if (y > 0) ln(y + 1) else 0f } - val EXP = InterpolationCurves { y -> exp(y) - 1 } - val BOUNCE = InterpolationCurves { y -> + val Linear = LerpCurves { y -> y } + val Sqrt = LerpCurves { y -> sqrt(y) } + val Exponent = LerpCurves { y -> y.pow(2.0f) } + val Cubic = LerpCurves { y -> y.pow(3.0f) } + val Sine = LerpCurves { y -> sin(y * PI.toFloat() / 2) } + val Cosine = LerpCurves { y -> 1 - cos(y * PI.toFloat() / 2) } + val Inverse = LerpCurves { y -> 1 - y } + val Log = LerpCurves { y -> if (y > 0) ln(y + 1) else 0f } + val Exp = LerpCurves { y -> exp(y) - 1 } + val Bounce = LerpCurves { y -> val n1 = 7.5625f val d1 = 2.75f when { @@ -43,7 +43,7 @@ class InterpolationCurves(val function: (Float) -> Float) { } } - fun custom(equation: (Float) -> Float) = InterpolationCurves(equation) + fun custom(equation: (Float) -> Float) = LerpCurves(equation) } } @@ -209,7 +209,7 @@ fun lerp(x: Float, y: Float, t: Float) : Float { } -fun interpolateCurve(start: Vector3f, end: Vector3f, t: Float, curve: InterpolationCurves): Vector3f { +fun interpolateCurve(start: Vector3f, end: Vector3f, t: Float, curve: LerpCurves): Vector3f { val clampedT = t.coerceIn(0.0f, 1.0f) val curvedT = curve.function(clampedT) diff --git a/src/main/kotlin/com/bytedice/bde_particles/commands/ManageConfigArgs.kt b/src/main/kotlin/com/bytedice/bde_particles/commands/ManageConfigArgs.kt index c2f045e..d0be586 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/commands/ManageConfigArgs.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/commands/ManageConfigArgs.kt @@ -1,6 +1,6 @@ package com.bytedice.bde_particles.commands -import com.bytedice.bde_particles.InterpolationCurves +import com.bytedice.bde_particles.LerpCurves import com.bytedice.bde_particles.particles.* import com.mojang.brigadier.Command import com.mojang.brigadier.arguments.BoolArgumentType @@ -127,7 +127,7 @@ class ArgConfigParticleKeys { .then(CommandManager.argument("Radius", FloatArgumentType.floatArg()) .executes { context -> val radius = FloatArgumentType.getFloat(context, "Radius") - val feedback = updateParticleParam(context, "shape", SpawningShape.CIRCLE(radius)) + val feedback = updateParticleParam(context, "shape", SpawningShape.Circle(radius)) context.source.sendFeedback( { feedback }, false) Command.SINGLE_SUCCESS } @@ -139,7 +139,7 @@ class ArgConfigParticleKeys { .executes { context -> val w = FloatArgumentType.getFloat(context, "Width") val h = FloatArgumentType.getFloat(context, "Height") - val feedback = updateParticleParam(context, "shape", SpawningShape.RECT(Vector2f(w, h))) + val feedback = updateParticleParam(context, "shape", SpawningShape.Rect(Vector2f(w, h))) context.source.sendFeedback( { feedback }, false) Command.SINGLE_SUCCESS } @@ -154,7 +154,7 @@ class ArgConfigParticleKeys { val x = FloatArgumentType.getFloat(context, "X") val y = FloatArgumentType.getFloat(context, "Y") val z = FloatArgumentType.getFloat(context, "Z") - val feedback = updateParticleParam(context, "shape", SpawningShape.CUBE(Vector3f(x, y, z))) + val feedback = updateParticleParam(context, "shape", SpawningShape.Cube(Vector3f(x, y, z))) context.source.sendFeedback( { feedback }, false) Command.SINGLE_SUCCESS } @@ -166,7 +166,7 @@ class ArgConfigParticleKeys { .then(CommandManager.argument("Radius", FloatArgumentType.floatArg()) .executes { context -> val radius = FloatArgumentType.getFloat(context, "Radius") - val feedback = updateParticleParam(context, "shape", SpawningShape.SPHERE(radius)) + val feedback = updateParticleParam(context, "shape", SpawningShape.Sphere(radius)) context.source.sendFeedback( { feedback }, false) Command.SINGLE_SUCCESS } @@ -174,7 +174,7 @@ class ArgConfigParticleKeys { ) .then(CommandManager.literal("point") .executes { context -> - val feedback = updateParticleParam(context, "shape", SpawningShape.POINT) + val feedback = updateParticleParam(context, "shape", SpawningShape.Point) context.source.sendFeedback( { feedback }, false) Command.SINGLE_SUCCESS } @@ -415,19 +415,19 @@ class ArgConfigParticleKeys { } -fun getCurveByString(str: String) : InterpolationCurves { +fun getCurveByString(str: String) : LerpCurves { return when (str) { - "LINEAR" -> InterpolationCurves.LINEAR - "SQRT" -> InterpolationCurves.SQRT - "EXPONENT" -> InterpolationCurves.EXPONENT - "CUBIC" -> InterpolationCurves.CUBIC - "SINE" -> InterpolationCurves.SINE - "COSINE" -> InterpolationCurves.COSINE - "INVERSE" -> InterpolationCurves.INVERSE - "LOG" -> InterpolationCurves.LOG - "EXP" -> InterpolationCurves.EXP - "BOUNCE" -> InterpolationCurves.BOUNCE - else -> InterpolationCurves.LINEAR + "LINEAR" -> LerpCurves.Linear + "SQRT" -> LerpCurves.Sqrt + "EXPONENT" -> LerpCurves.Exponent + "CUBIC" -> LerpCurves.Cubic + "SINE" -> LerpCurves.Sine + "COSINE" -> LerpCurves.Cosine + "INVERSE" -> LerpCurves.Inverse + "LOG" -> LerpCurves.Log + "EXP" -> LerpCurves.Exp + "BOUNCE" -> LerpCurves.Bounce + else -> LerpCurves.Linear } } @@ -538,7 +538,7 @@ fun forceFieldAddSphereExec(context: CommandContext) : Int val minForce = FloatArgumentType.getFloat(context, "Min Force") val maxForce = FloatArgumentType.getFloat(context, "Max Force") - val shape = ForceFieldShape.SPHERE(radius, Pair(minForce, maxForce)) + val shape = ForceFieldShape.Sphere(radius, Pair(minForce, maxForce)) val forceField = forceFieldGenericParams(context, shape) val currentParams = getEmitterParams(emitterIdVal) @@ -567,7 +567,7 @@ fun forceFieldAddCubeExec(context: CommandContext) : Int { val zForce = FloatArgumentType.getFloat(context, "Z Force") val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID") - val shape = ForceFieldShape.CUBE(Vector3f(xSize, ySize, zSize), Vector3f(xForce, yForce, zForce)) + val shape = ForceFieldShape.Cube(Vector3f(xSize, ySize, zSize), Vector3f(xForce, yForce, zForce)) val forceField = forceFieldGenericParams(context, shape) val currentParams = getEmitterParams(emitterIdVal) diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterParams.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterParams.kt index 414c932..bb18d2c 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterParams.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterParams.kt @@ -1,42 +1,60 @@ package com.bytedice.bde_particles.particles +import com.bytedice.bde_particles.LerpCurves +import org.joml.Vector3f + + /** * EmitterParams defines the parameters for controlling how particles are emitted, * including settings for looping, spawn frequency, and maximum particle count. * - * @param maxCount The maximum number of particles that can exist. If set to 0 or below, no particles will spawn. - * @param spawnsPerTick The number of particles spawned per tick. If set to 0 or below, no particles will spawn. - * @param loopDur The duration for which the loop runs, in ticks. A value 0 or below means the loop is infinite, and `loopDelay` and `loopCount` will be ignored. - * @param loopDelay The delay between each loop cycle, in ticks. Negative values are treated as 0, meaning no delay. - * @param loopCount The number of times the loop will repeat. 0 means it will shoot a single burst of particles. A value below 0 means it will repeat indefinitely. - * @param particle The particle params of the particle that will spawn. + * @param maxCount The maximum number of particles that can exist at any time. If set to 0 or below, no particles will spawn. + * @param spawnRate The number of particles to spawn each tick. If set to 0 or below, no particles will spawn. + * @param spawnChance The chance for a particle to spawn. 0.5 means a particle has a 50% chance of spawning. Values are between 0.0 and 1.0. + * @param loopDur The duration, in ticks, that each emission loop lasts. A value of 0 or below makes the loop infinite, ignoring `loopDelay` and `loopCount`. + * @param loopDelay The delay, in ticks, between consecutive loops. Negative values are treated as 0 (no delay). + * @param loopCount The number of times the loop repeats. A value of 0 results in a single burst of particles. Values below 0 make the loop repeat indefinitely. + * @param shape The spawning shape for the particles, such as `SpawningShape.Sphere()`. + * @param initRot Specifies the initial random rotation range for the particles, in degrees, for the X, Y, and Z axes. + * @param rotVel Specifies the random range for rotational velocity, in degrees per tick, for the X, Y, and Z axes. + * @param rotTowardVel If true, particles will face the direction of velocity. It uses `initRot` as an offset rotation and ignores `rotVel`. + * @param initVel Specifies the random range for the initial velocity, in units per tick, for the X, Y, and Z axes. + * @param initScale Defines the random range for the initial particle size. + * @param scaleTowardVel If true, particles will scale to the direction of velocity. + * @param forceFields An array of force fields applied to particles, affecting their motion during their lifetime. + * @param constVel A constant velocity vector applied to particles each tick, useful for effects like gravity. + * @param drag A drag coefficient that slows down particle velocity over time. Calculated as `velocity * (1.0 - drag)`. + * @param minVel The minimum speed a particle must maintain. Particles slower than this value are stopped. Values <= 0 disable this check. + * @param lifeTime Specifies the range for particle lifetime, in ticks. Values below 1 prevent particles from spawning. + * @param rotVelCurve A curve defining how rotational velocity evolves during the particle's lifetime. Multiplies the `rotVel` values. + * @param sizeCurve A curve defining how the particle's size evolves over its lifetime. Multiplies the `initScale` values. + * @param blockCurve Specifies an array of block names that the particle transitions through during its lifetime, combined with a curve to control transitions. Defaults to "minecraft:air" if empty. */ data class EmitterParams ( - var maxCount: Int = 200, - var spawnsPerTick: Int = 1, - var loopDur: Int = 25, - var loopDelay: Int = 0, - var loopCount: Int = 0, - var particle: ParticleParams = ParticleParams.DEFAULT, + var maxCount: Int = 200, + var spawnRate: Int = 1, + var spawnChance: Float = 1.0f, + var loopDur: Int = 25, + var loopDelay: Int = 0, + var loopCount: Int = 0, + var shape: SpawningShape = SpawningShape.Circle(3.0f), + var initRot: ParamClasses.PairVec3f = ParamClasses.PairVec3f(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), + var rotVel: ParamClasses.PairVec3f = ParamClasses.PairVec3f(-0.2f, -0.2f, -0.2f, 0.2f, 0.2f, 0.2f), + var rotTowardVel: Boolean = true, + var initVel: ParamClasses.PairVec3f = ParamClasses.PairVec3f(-0.1f, 0.3f, -0.1f, 0.1f, 0.6f, 0.1f), + var initScale: ParamClasses.RandScale = ParamClasses.RandScale.Uniform(), + var scaleTowardVel: Boolean = true, + var forceFields: Array = emptyArray(), + var constVel: Vector3f = Vector3f(0.0f, -0.01f, 0.0f), + var drag: Float = 0.075f, + var minVel: Float = 0.0f, + var lifeTime: ParamClasses.PairVec2i = ParamClasses.PairVec2i(0, 0, 1, 1), + var rotVelCurve: ParamClasses.LerpVal = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Sqrt), + var sizeCurve: ParamClasses.LerpVal = ParamClasses.LerpVal.LerpUniform(1.0f, 0.5f, LerpCurves.Linear), + var blockCurve: Pair, LerpCurves> = Pair(arrayOf("minecraft:purple_concrete", "minecraft:purple_stained_glass"), LerpCurves.Sqrt), ) { companion object Presets { val DEFAULT = EmitterParams() - val FIRE_GEYSER = EmitterParams( - 200, - 1, - 25, - 0, - 0, - ParticleParams.FIRE_GEYSER - ) - val RING_EXPLOSION = EmitterParams( - 200, - 150, - 1, - 0, - 0, - ParticleParams.RING_EXPLOSION - ) } } \ No newline at end of file diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/ForceFields.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/ForceFields.kt index ec77bf3..e399407 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/ForceFields.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/ForceFields.kt @@ -5,5 +5,5 @@ import org.joml.Vector3f data class ForceField ( val name: String = "DEFAULT", val pos: Vector3f = Vector3f(0.0f, 5.0f, 0.0f), - val shape: ForceFieldShape = ForceFieldShape.SPHERE() + val shape: ForceFieldShape = ForceFieldShape.Sphere() ) \ No newline at end of file diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/ParamClasses.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/ParamClasses.kt new file mode 100644 index 0000000..67d166c --- /dev/null +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/ParamClasses.kt @@ -0,0 +1,110 @@ +package com.bytedice.bde_particles.particles + +import com.bytedice.bde_particles.LerpCurves +import com.bytedice.bde_particles.randomFloatBetween +import com.bytedice.bde_particles.randomIntBetween +import org.joml.Vector3f + +class ParamClasses { + class PairVec3f ( + private val minX: Float = 0.0f, + private val minY: Float = 0.0f, + private val minZ: Float = 0.0f, + private val maxX: Float = 1.0f, + private val maxY: Float = 1.0f, + private val maxZ: Float = 1.0f, + ) { + fun randomize() : Vector3f { + return Vector3f( + randomFloatBetween(minX, maxX), + randomFloatBetween(minY, maxY), + randomFloatBetween(minZ, maxZ), + ) + } + } + sealed class RandScale { + class Uniform ( + private val min: Float = 0.0f, + private val max: Float = 1.0f, + ) : RandScale() { + fun randomize() : Vector3f { + val x = randomFloatBetween(min, max) + return Vector3f(x, x, x) + } + } + class NonUniform ( + private val minX: Float = 0.0f, + private val minY: Float = 0.0f, + private val minZ: Float = 0.0f, + private val maxX: Float = 1.0f, + private val maxY: Float = 1.0f, + private val maxZ: Float = 1.0f + ) : RandScale() { + fun randomize(): Vector3f { + return Vector3f( + randomFloatBetween(minX, maxX), + randomFloatBetween(minY, maxY), + randomFloatBetween(minZ, maxZ), + ) + } + } + } + class PairVec2i ( + private val minX: Int = 0, + private val minY: Int = 0, + private val maxX: Int = 1, + private val maxY: Int = 1, + ) { + fun randomize() : Pair { + return Pair( + randomIntBetween(minX, maxX), + randomIntBetween(minY, maxY), + ) + } + } + sealed class LerpVal { + class LerpVec3f( + private val fromX: Float = 0.0f, + private val fromY: Float = 0.0f, + private val fromZ: Float = 0.0f, + private val toX: Float = 1.0f, + private val toY: Float = 1.0f, + private val toZ: Float = 1.0f, + private val curve: LerpCurves = LerpCurves.Linear, + ) : LerpVal() { + fun lerp(t: Float): Vector3f { + val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curve.function(t) + val y = com.bytedice.bde_particles.lerp(fromY, toY, t) * curve.function(t) + val z = com.bytedice.bde_particles.lerp(fromZ, toZ, t) * curve.function(t) + return Vector3f(x, y, z) + } + } + class MultiLerpVec3f( + private val fromX: Float = 0.0f, + private val fromY: Float = 0.0f, + private val fromZ: Float = 0.0f, + private val toX: Float = 1.0f, + private val toY: Float = 1.0f, + private val toZ: Float = 1.0f, + private val curveX: LerpCurves = LerpCurves.Linear, + private val curveY: LerpCurves = LerpCurves.Linear, + private val curveZ: LerpCurves = LerpCurves.Linear + ) : LerpVal() { + fun lerp(t: Float): Vector3f { + val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curveX.function(t) + val y = com.bytedice.bde_particles.lerp(fromY, toY, t) * curveY.function(t) + val z = com.bytedice.bde_particles.lerp(fromZ, toZ, t) * curveZ.function(t) + return Vector3f(x, y, z) + } + } + class LerpUniform( + private val from: Float = 0.0f, + private val to: Float = 1.0f, + private val curve: LerpCurves = LerpCurves.Linear, + ) : LerpVal() { + fun lerp(t: Float): Float { + return com.bytedice.bde_particles.lerp(from, to, t) * curve.function(t) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/Particle.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/Particle.kt index 3e34bfe..33e0cc2 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/Particle.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/Particle.kt @@ -11,7 +11,7 @@ import kotlin.math.* // TODO: consider moving most params to emitter (such as shape, and forceFields) to store less data -class Particle(private val particleParams: ParticleParams) { +class Particle(private val emitterParams: EmitterParams) { private val initOffset = Vector3f(-0.5f, -0.5f, -0.5f) private var offset = Vector3f(0.0f, 0.0f, 0.0f) private var pos = Vec3d(0.0, 0.0, 0.0) @@ -44,11 +44,11 @@ class Particle(private val particleParams: ParticleParams) { val newSpawnPos: Vector3f when (shape) { - is SpawningShape.CIRCLE -> { val posInCircle = randomInCircle(shape.radius); newSpawnPos = Vector3f(posInCircle.x, 0.0f, posInCircle.y) } - is SpawningShape.SPHERE -> { newSpawnPos = randomInSphere(shape.radius) } - is SpawningShape.RECT -> { val posInRect = randomInRect(shape.size); newSpawnPos = Vector3f(posInRect.x, 0.0f, posInRect.y) } - is SpawningShape.CUBE -> { newSpawnPos = randomInCube(shape.size) } - is SpawningShape.POINT -> { newSpawnPos = Vector3f(0.0f, 0.0f, 0.0f) } + is SpawningShape.Circle -> { val posInCircle = randomInCircle(shape.radius); newSpawnPos = Vector3f(posInCircle.x, 0.0f, posInCircle.y) } + is SpawningShape.Sphere -> { newSpawnPos = randomInSphere(shape.radius) } + is SpawningShape.Rect -> { val posInRect = randomInRect(shape.size); newSpawnPos = Vector3f(posInRect.x, 0.0f, posInRect.y) } + is SpawningShape.Cube -> { newSpawnPos = randomInCube(shape.size) } + is SpawningShape.Point -> { newSpawnPos = Vector3f(0.0f, 0.0f, 0.0f) } } offset = newSpawnPos @@ -110,7 +110,7 @@ class Particle(private val particleParams: ParticleParams) { } fun sphereSdfVel(forceField: ForceField) : Vector3f { - if (forceField.shape !is ForceFieldShape.SPHERE) { return Vector3f(0.0f, 0.0f, 0.0f) } + if (forceField.shape !is ForceFieldShape.Sphere) { return Vector3f(0.0f, 0.0f, 0.0f) } val shape = forceField.shape val sdfVal = sdfSphere(forceField.pos, shape.radius, offset) @@ -123,7 +123,7 @@ class Particle(private val particleParams: ParticleParams) { } fun cubeSdfVel(forceField: ForceField) : Vector3f { - if (forceField.shape !is ForceFieldShape.CUBE) { return Vector3f(0.0f, 0.0f, 0.0f) } + if (forceField.shape !is ForceFieldShape.Cube) { return Vector3f(0.0f, 0.0f, 0.0f) } val shape = forceField.shape val sdfVal = sdfCube(forceField.pos, shape.size, offset) @@ -176,8 +176,8 @@ class Particle(private val particleParams: ParticleParams) { rot = newRot for (forceField in particleParams.forceFields) { - if (forceField.shape is ForceFieldShape.SPHERE) { vel.add(sphereSdfVel(forceField)) } - else if (forceField.shape is ForceFieldShape.CUBE) { vel.add(cubeSdfVel(forceField)) } + if (forceField.shape is ForceFieldShape.Sphere) { vel.add(sphereSdfVel(forceField)) } + else if (forceField.shape is ForceFieldShape.Cube) { vel.add(cubeSdfVel(forceField)) } } val (quatRot, transformOffset) = calcTransformOffset(newRot, initOffset, newScale) diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleIdRegister.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleIdRegister.kt index 211198b..ebf089a 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleIdRegister.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleIdRegister.kt @@ -2,7 +2,7 @@ package com.bytedice.bde_particles.particles -import com.bytedice.bde_particles.InterpolationCurves +import com.bytedice.bde_particles.LerpCurves import org.joml.Vector3f @@ -103,8 +103,8 @@ fun updateSingleParticleParam(params: ParticleParams, paramName: String, paramVa "drag" -> paramValue as Float "minVel" -> paramValue as Float "lifeTime" -> paramValue as Pair - "rotVelCurve" -> paramValue as Triple - "sizeCurve" -> paramValue as Triple + "rotVelCurve" -> paramValue as Triple + "sizeCurve" -> paramValue as Triple else -> null } @@ -125,8 +125,8 @@ fun updateSingleParticleParam(params: ParticleParams, paramName: String, paramVa "drag" -> newParams.drag = value as Float "minVel" -> newParams.minVel = value as Float "lifeTime" -> newParams.lifeTime = value as Pair - "rotVelCurve" -> newParams.rotVelCurve = value as Triple - "sizeCurve" -> newParams.sizeCurve = value as Triple + "rotVelCurve" -> newParams.rotVelCurve = value as Triple + "sizeCurve" -> newParams.sizeCurve = value as Triple else -> return Pair(params, false) } diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleParams.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleParams.kt deleted file mode 100644 index b7b05b2..0000000 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleParams.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.bytedice.bde_particles.particles - -import com.bytedice.bde_particles.InterpolationCurves -import org.joml.Vector3f - -/** - * ParticleParams defines the parameters for particle behavior, including shape, size, velocity, and other physics properties. - * - * @param shape The shape of the particle's spawning area, `null` is a single point. - * @param blockCurve An array of block names that gets cycled through during the particle's lifetime. Empty defaults to "minecraft:air". - * @param rotRandom The random ***initial*** rotation range for the particle's rotation in X, Y, and Z axes. - * @param rotVelRandom The random velocity for particle rotation in the X, Y, and Z axes. - * @param sizeRandom The random ***initial*** size range for the particle. If `uniformSize` is true, this will be uniform (cubic). - * @param uniformSize If true, particles will have a uniform (cubic) size. Otherwise, their sizes on different axis can vary. - * @param velRandom The random ***initial*** velocity range for the particle in the X, Y, and Z axes. - * @param forceFields An array of force fields applied to the particle. - * @param gravity A constant force applied to the particle every tick. It's often used as gravity. - * @param drag A drag force that affects the speed overtime. The formula is (velocity * (1.0 - drag)) - * @param minVel If particles travel slower than this their speed is automatically 0. Values less than or equal to 0 mean the particle can travel at any speed. - * @param lifeTime A range for the particle's lifetime in ticks. A value below 1 will result in the particle not spawning. - * @param rotVelCurve A curve which the rotation velocity gets multiplied by during the particle's lifetime. - * @param sizeCurve A curve which the size gets multiplied by during the particle's lifetime. - */ -data class ParticleParams ( - var shape: SpawningShape = SpawningShape.CIRCLE(3.0f), - var blockCurve: Array = arrayOf("minecraft:purple_concrete", "minecraft:purple_stained_glass"), - var rotRandom: Pair = Pair(Vector3f(0.0f, 0.0f, 0.0f), Vector3f(360.0f, 360.0f, 360.0f)), - var rotVelRandom: Pair = Pair(Vector3f(-0.2f, -0.2f, -0.2f), Vector3f(0.2f, 0.2f, 0.2f)), - var sizeRandom: Pair = Pair(Vector3f(0.5f, 0.5f, 0.5f), Vector3f(1.0f, 1.0f, 1.0f)), - var uniformSize: Boolean = true, - var velRandom: Pair = Pair(Vector3f(-0.1f, 0.3f, -0.1f), Vector3f(0.1f, 0.6f, 0.1f)), - var forceFields: Array = emptyArray(), - var gravity: Vector3f = Vector3f(0.0f, -0.01f, 0.0f), - var drag: Float = 0.075f, - var minVel: Float = 0.0f, - var lifeTime: Pair = Pair(15, 45), - var rotVelCurve: Triple = Triple(Vector3f(1.0f, 1.0f, 1.0f), Vector3f(0.0f, 0.0f, 0.0f), InterpolationCurves.SQRT), - var sizeCurve: Triple = Triple(Vector3f(1.0f, 1.0f, 1.0f), Vector3f(0.5f, 0.5f, 0.5f), InterpolationCurves.LINEAR), -) { - companion object Presets { - val DEFAULT = ParticleParams() - val FIRE_GEYSER = ParticleParams( - SpawningShape.POINT, - arrayOf("minecraft:shroomlight", "minecraft:orange_concrete", "minecraft:orange_stained_glass", "minecraft:gray_stained_glass", "minecraft:light_gray_stained_glass"), - Pair(Vector3f(0.0f, 0.0f, 0.0f), Vector3f(360.0f, 360.0f, 360.0f)), - Pair(Vector3f(-0.2f, -0.2f, -0.2f), Vector3f(0.2f, 0.2f, 0.2f)), - Pair(Vector3f(0.5f, 0.5f, 0.5f), Vector3f(1.0f, 1.0f, 1.0f)), - true, - Pair(Vector3f(-0.1f, 0.4f, -0.1f), Vector3f(0.1f, 0.8f, 0.1f)), - emptyArray(), - Vector3f(0.0f, -0.01f, 0.0f), - 0.075f, - 0.0f, - Pair(15, 45), - Triple(Vector3f(1.0f, 1.0f, 1.0f), Vector3f(0.0f, 0.0f, 0.0f), InterpolationCurves.SQRT), - Triple(Vector3f(1.0f, 1.0f, 1.0f), Vector3f(0.5f, 0.5f, 0.5f), InterpolationCurves.SQRT) - ) - val RING_EXPLOSION = ParticleParams( - SpawningShape.CIRCLE(0.1f), - arrayOf("minecraft:shroomlight", "minecraft:orange_concrete", "minecraft:orange_stained_glass", "minecraft:gray_stained_glass", "minecraft:light_gray_stained_glass"), - Pair(Vector3f(0.0f, 0.0f, 0.0f), Vector3f(360.0f, 360.0f, 360.0f)), - Pair(Vector3f(-0.2f, -0.2f, -0.2f), Vector3f(0.2f, 0.2f, 0.2f)), - Pair(Vector3f(10.0f, 10.0f, 10.0f), Vector3f(15.0f, 15.0f, 15.0f)), - true, - Pair(Vector3f(0.0f, 0.0f, 0.0f), Vector3f(0.0f, 0.0f, 0.0f)), - arrayOf(ForceField("init", Vector3f(0.0f, -0.0001f, 0.0f), ForceFieldShape.SPHERE(0.1f, Pair(4.0f, 4.0f)))), - Vector3f(0.0f, 0.0f, 0.0f), - 0.0075f, - 0.0f, - Pair(50, 100), - Triple(Vector3f(1.0f, 1.0f, 1.0f), Vector3f(0.0f, 0.0f, 0.0f), InterpolationCurves.SQRT), - Triple(Vector3f(0.0f, 0.0f, 0.0f), Vector3f(3.0f, 3.0f, 3.0f), InterpolationCurves.SQRT) - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt index e185c39..66576d8 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt @@ -4,20 +4,31 @@ import org.joml.Vector2f import org.joml.Vector3f sealed class SpawningShape { - data class CIRCLE(val radius: Float = 1.0f) : SpawningShape() - data class RECT (val size: Vector2f = Vector2f(1.0f, 1.0f)) : SpawningShape() - data class CUBE (val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f)) : SpawningShape() - data class SPHERE(val radius: Float = 1.0f) : SpawningShape() - data object POINT : SpawningShape() + data class Circle(val radius: Float = 1.0f) : SpawningShape() + data class Rect (val size: Vector2f = Vector2f(1.0f, 1.0f)) : SpawningShape() + data class Cube (val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f)) : SpawningShape() + data class Sphere(val radius: Float = 1.0f) : SpawningShape() + data object Point : SpawningShape() } sealed class ForceFieldShape { - data class SPHERE( + data class Sphere( val radius: Float = 3.0f, val force: Pair = Pair(0.0f, 0.02f), ) : ForceFieldShape() - data class CUBE( - val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f), - val forceDir: Vector3f = Vector3f(0.0f, 0.0f, 0.0f) + data class Cube( + val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f), + val dir: Vector3f = Vector3f(0.0f, 0.0f, -1.0f), + val force: Pair = Pair(0.0f, 0.02f) ) : ForceFieldShape() + data class Cone( + val size: Vector2f = Vector2f(1.0f, 1.0f), + val dir: Vector3f = Vector3f(0.0f, 0.0f, -1.0f), + val force: Pair = Pair(0.0f, 0.02f) + ) + data class Cylinder( + val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f), + val dir: Vector3f = Vector3f(0.0f, 0.0f, -1.0f), + val force: Pair = Pair(0.0f, 0.02f) + ) } \ No newline at end of file