• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[WIP]ParticleSystem

Status
Not open for further replies.
Currently creating a Particle System that is master-slave based.

haven't added the main struct, but works :D

JASS:
library ParticleSystem uses Particle Vector ZLibrary MapBounds
    globals
        private constant real TIMEOUT = 0.03125
    endglobals
    
    struct ParticleData
        string MODEL = ""
        
        real PERIOD = TIMEOUT
        
        real LIFE_SPAN = 0.0
        real LIFE_SPAN_VARIANCE = 0.0
        
        real START_SIZE = 1.0
        real START_SIZE_VARIANCE = 0.0
        real END_SIZE = 1.0
        real END_SIZE_VARIANCE = 0.0
        
        real START_ANGLE = 0.0
        real START_ANGLE_VARIANCE = 0.0
        boolean LOCK_ANGLE = false
        
        real START_Z_ANGLE = 0.0
        real START_Z_ANGLE_VARIANCE = 0.0
        boolean LOCK_Z_ANGLE = false
        
        real START_DISTANCE = 0.0
        real START_DISTANCE_VARIANCE = 0.0
        real END_DISTANCE = 0.0
        real END_DISTANCE_VARIANCE = 0.0
        
        real SPEED = 0.0
        real SPEED_VARIANCE = 0.0
        
        real ACCEL = 0.0
        real ACCEL_VARIANCE = 0.0
        
        real GRAVITY_ACCEL = 0.0
        real GRAVITY_ANGLE = 0.0
        real GRAVITY_Z_ANGLE = 0.0
        
        integer START_ALPHA = 255
        integer START_RED = 255
        integer START_GREEN = 255
        integer START_BLUE = 255
        
        integer START_ALPHA_VARIANCE = 0
        integer START_RED_VARIANCE = 0
        integer START_GREEN_VARIANCE = 0
        integer START_BLUE_VARIANCE = 0
        
        integer END_ALPHA = 255
        integer END_RED = 255
        integer END_GREEN = 255
        integer END_BLUE = 255
        
        integer END_ALPHA_VARIANCE = 0
        integer END_RED_VARIANCE = 0
        integer END_GREEN_VARIANCE = 0
        integer END_BLUE_VARIANCE = 0
    endstruct
    
    private function GetVariance takes real base, real variance returns real
        if variance == 0.0 then
            return base
        endif
        return GetRandomReal(base - variance, base + variance)
    endfunction
    
    private function GetVariance2 takes integer base, integer variance returns integer
        if variance == 0 then
            return base
        endif
        return GetRandomInt(base - variance, base + variance)
    endfunction
    
    private function GetAngle3D takes vector v returns real
        local real l2d = SquareRoot(v.x*v.x + v.y*v.y)
        return Atan2(v.z, l2d)
    endfunction
    
    private function GetVector takes real dist, real angle, real angleZ returns vector
        local real z = dist*Sin(angleZ*bj_DEGTORAD)
        local real sz = dist*Cos(angleZ*bj_DEGTORAD)
        local real x = Cos(angle*bj_DEGTORAD)*sz
        local real y = Sin(angle*bj_DEGTORAD)*sz
        return vector.create(x, y, z)
    endfunction
    
    struct Particles extends Particle
        private Particle particle
        private vector velocity
        private vector gravity
        
        private real speed
        private real accel
    
        private real lifeSpan
        
        private integer addA
        private integer addR
        private integer addG
        private integer addB
        private real addS
        
        private real dist
        
        private boolean anglock
        private boolean zanglock
        
        private static constant timer t = CreateTimer()
        private static thistype array n
        private static thistype array p
        
        private method destroy takes nothing returns nothing
            set n[p[this]] = n[this]
            set p[n[this]] = p[this]
            call Particle(this).destroy()
            
            call velocity.destroy()
            call gravity.destroy()
        endmethod
        
        private static method period takes nothing returns nothing
            local thistype this = n[0]
            local real tz
            loop
                exitwhen 0 == this
                if lifeSpan > 0 then
                    set lifeSpan = lifeSpan - TIMEOUT
                    if dist > 0 then
                        set dist = dist - speed
                        set x = GetBoundedX(x + velocity.x)
                        set y = GetBoundedY(y + velocity.y)
                        set tz = GetSurfaceZ(x, y)
                        set z = (tz + z + velocity.z) - tz
                        
                        if not anglock then
                            set facing = Atan2(velocity.y, velocity.x)*bj_RADTODEG
                        endif
                        if not zanglock then
                            set pitch = GetAngle3D(velocity)
                        endif
                        set speed = speed + accel
                        call velocity.add(gravity)
                        call velocity.setLength(speed)
                    endif
                    
                    call setColor(alpha + addA, red + addR, green + addG, blue + addB)
                    
                    set scale = scale + addS
                else
                    call destroy()
                endif
                set this = n[this]
            endloop
        endmethod
        
        static method create takes real tx, real ty, real tz, ParticleData pd returns thistype
            local thistype this
            local real    newLifeSpan    = GetVariance( pd.LIFE_SPAN     , pd.LIFE_SPAN_VARIANCE     )
            local real    newStartSize   = GetVariance( pd.START_SIZE    , pd.START_SIZE_VARIANCE    )
            local real    newEndSize     = GetVariance( pd.END_SIZE      , pd.END_SIZE_VARIANCE      )
            local real    newStartAngle  = GetVariance( pd.START_ANGLE   , pd.START_ANGLE_VARIANCE   )
            local real    newStartZAngle = GetVariance( pd.START_Z_ANGLE , pd.START_Z_ANGLE_VARIANCE )
            local real    newStartDist   = GetVariance( pd.START_DISTANCE, pd.START_DISTANCE_VARIANCE)
            local real    newEndDist     = GetVariance( pd.END_DISTANCE  , pd.END_DISTANCE_VARIANCE  )
            local integer newStartAlpha  = GetVariance2(pd.START_ALPHA   , pd.START_ALPHA_VARIANCE   )
            local integer newStartRed    = GetVariance2(pd.START_RED     , pd.START_RED_VARIANCE     )
            local integer newStartGreen  = GetVariance2(pd.START_GREEN   , pd.START_GREEN_VARIANCE   )
            local integer newStartBlue   = GetVariance2(pd.START_BLUE    , pd.START_BLUE_VARIANCE    )
            
            local vector v = GetVector(newStartDist, newStartAngle, newStartZAngle)
            
            set this = Particle.create(pd.MODEL, v.x + tx, v.y + ty, v.z + tz - GetSurfaceZ(v.x + tx, v.y + ty), newStartAngle)
            
            if pd.LOCK_Z_ANGLE then
                set this.pitch = 0
            else
                set this.pitch = newStartZAngle
            endif
            set anglock = pd.LOCK_ANGLE
            set zanglock = pd.LOCK_Z_ANGLE
            
            call this.setColor(newStartAlpha, newStartRed, newStartGreen, newStartBlue)
            
            set this.scale = newStartSize
            
            set addA = R2I((I2R(GetVariance2(pd.END_ALPHA, pd.END_ALPHA_VARIANCE) - newStartAlpha)*TIMEOUT)/newLifeSpan)
            set addR = R2I((I2R(GetVariance2(pd.END_RED, pd.END_RED_VARIANCE    ) - newStartRed  )*TIMEOUT)/newLifeSpan)
            set addG = R2I((I2R(GetVariance2(pd.END_GREEN, pd.END_GREEN_VARIANCE) - newStartGreen)*TIMEOUT)/newLifeSpan)
            set addB = R2I((I2R(GetVariance2(pd.END_BLUE, pd.END_BLUE_VARIANCE  ) - newStartBlue)*TIMEOUT)/newLifeSpan)
            set addS = ((newEndSize - newStartSize)*TIMEOUT)/newLifeSpan
            set speed = GetVariance(pd.SPEED, pd.SPEED_VARIANCE)*TIMEOUT
            set velocity = GetVector(speed, newStartAngle, newStartZAngle)
            set accel = GetVariance(pd.ACCEL, pd.ACCEL_VARIANCE)*TIMEOUT
            
            set dist = newEndDist - newStartDist
            
            set gravity = GetVector(pd.GRAVITY_ACCEL*TIMEOUT,pd.GRAVITY_ANGLE, pd.GRAVITY_Z_ANGLE)
            
            set lifeSpan = newLifeSpan
            set n[this] = 0
            set p[this] = p[0]
            set n[p[0]] = this
            set p[0] = this
            
            if p[this] == 0 then
                call TimerStart(t, TIMEOUT, true, function thistype.period)
            endif
            return this
        endmethod
    endstruct
    
    
    struct ParticleEmitter
        private timer t
        private real x
        private real y
        private real z
        private real life
        private ParticleData pd
        
        method destroy takes nothing returns nothing
            call ReleaseTimer(t)
            
            set x = 0
            set y = 0
            set z = 0
            set life = 0
            set pd = 0
        endmethod
        
        private static method expire takes nothing returns nothing
            local timer tmp = GetExpiredTimer()
            local thistype this = GetTimerData(tmp)
            if life > 0 then
                call Particles.create(x, y, z, pd)
                set life = life - pd.PERIOD
            else
                call destroy()
            endif
        endmethod
        
        static method create takes ParticleData p, real tx, real ty, real tz, real duration returns thistype
            local thistype this = allocate()
            set t = NewTimerEx(this)
            set x = tx
            set y = ty
            set z = tz
            set life = duration
            set pd = p
            call TimerStart(t, pd.PERIOD, true, function thistype.expire)
            return this
        endmethod
        
        method move takes real tx, real ty, real tz returns nothing
            set x = tx
            set y = ty
            set z = tz
        endmethod
    endstruct
endlibrary

Examples:

JASS:
struct Tester extends array
    private static ParticleData pdata
    private static integer counts = 30
    private static timer t = CreateTimer()
    private static method pd takes nothing returns nothing
        local Particles p = Particles.create(0, 0, 200, pdata)
    endmethod
    private static method onInit takes nothing returns nothing
        call FogEnable(false)
        call FogMaskEnable(false)
        set pdata = ParticleData.create()
        set pdata.MODEL =  "Abilities\Spells\Other\Parasite\ParasiteMissile.mdl"
        set pdata.LIFE_SPAN = 2.0
        set pdata.SPEED = 10
        set pdata.ACCEL = 9.6
        set pdata.START_DISTANCE = 0
        set pdata.END_DISTANCE = 100000
        set pdata.START_Z_ANGLE = 90
        set pdata.START_Z_ANGLE_VARIANCE = 180
        set pdata.START_ANGLE = 90
        set pdata.START_ANGLE_VARIANCE = 180
        set pdata.GRAVITY_ACCEL = 9.6
        set pdata.GRAVITY_ANGLE = 0
        set pdata.GRAVITY_Z_ANGLE = 90
        set pdata.START_ALPHA = 255
        set pdata.END_ALPHA = 0
        call SetCameraPosition(0, 0)
        call TimerStart(t, 0.03125, true, function thistype.pd) 
    endmethod
endstruct
gif1.jpg



JASS:
struct Tester extends array
    private static ParticleData pdata
    private static integer counts = 30
    private static timer t = CreateTimer()
    private static method pd takes nothing returns nothing
        local Particles p = Particles.create(0, 0, 200, pdata)
    endmethod
    private static method onInit takes nothing returns nothing
        call FogEnable(false)
        call FogMaskEnable(false)
        set pdata = ParticleData.create()
        set pdata.MODEL = "Abilities\\Spells\\Undead\\Possession\\PossessionTarget.mdl"
        set pdata.LIFE_SPAN = 2.0
        set pdata.SPEED = 10
        set pdata.ACCEL = 9.6
        set pdata.START_DISTANCE = 0
        set pdata.END_DISTANCE = 100000
        set pdata.START_Z_ANGLE = 90
        set pdata.START_Z_ANGLE_VARIANCE = 180
        set pdata.START_ANGLE = 90
        set pdata.START_ANGLE_VARIANCE = 180
        set pdata.GRAVITY_ACCEL = 4.8
        set pdata.GRAVITY_ANGLE = 0
        set pdata.GRAVITY_Z_ANGLE = 270
        set pdata.START_ALPHA = 255
        set pdata.END_ALPHA = 0
        call SetCameraPosition(0, 0)
        call TimerStart(t, 0.03125, true, function thistype.pd) 
    endmethod
endstruct
gif2.jpg




JASS:
struct Tester extends array
    private static ParticleData pdata
    private static integer counts = 30
    private static timer t = CreateTimer()
    private static method pd takes nothing returns nothing
        local Particles p = Particles.create(0, 0, 200, pdata)
    endmethod
    private static method onInit takes nothing returns nothing
        call FogEnable(false)
        call FogMaskEnable(false)
        set pdata = ParticleData.create()
        set pdata.MODEL = "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl"
        set pdata.LIFE_SPAN = 2.0
        set pdata.SPEED = 5
        set pdata.ACCEL = 9.6
        set pdata.START_DISTANCE = 0
        set pdata.END_DISTANCE = 100000
        set pdata.START_Z_ANGLE = 90
        set pdata.START_Z_ANGLE_VARIANCE = 180
        set pdata.START_ANGLE = 90
        set pdata.START_ANGLE_VARIANCE = 180
        set pdata.GRAVITY_ACCEL = 4.8
        set pdata.GRAVITY_ANGLE = 0
        set pdata.GRAVITY_Z_ANGLE = 270
        set pdata.START_ALPHA = 255
        set pdata.END_ALPHA = 0
        call SetCameraPosition(0, 0)
        call TimerStart(t, 0.03125, true, function thistype.pd) 
    endmethod
endstruct
gif3.jpg



JASS:
struct Tester extends array
    private static ParticleData pdata
    private static integer counts = 30
    private static timer t = CreateTimer()
    private static method pd takes nothing returns nothing
        local Particles p = Particles.create(0, 0, 200, pdata)
    endmethod
    private static method onInit takes nothing returns nothing
        call FogEnable(false)
        call FogMaskEnable(false)
        set pdata = ParticleData.create()
        set pdata.MODEL = "Abilities\\Weapons\\WitchDoctorMissile\\WitchDoctorMissile.mdl"
        set pdata.LIFE_SPAN = 2.0
        set pdata.SPEED = 100
        set pdata.ACCEL = 0
        set pdata.START_DISTANCE = 0
        set pdata.END_DISTANCE = 100000
        set pdata.START_Z_ANGLE = 90
        set pdata.START_Z_ANGLE_VARIANCE = 180
        set pdata.START_ANGLE = 90
        set pdata.START_ANGLE_VARIANCE = 180
        set pdata.GRAVITY_ACCEL = 9.6
        set pdata.GRAVITY_ANGLE = 0
        set pdata.GRAVITY_Z_ANGLE = 90
        set pdata.START_ALPHA = 255
        set pdata.END_ALPHA = 0
        set pdata.START_GREEN = 0
        set pdata.END_GREEN = 0
        call SetCameraPosition(0, 0)
        call TimerStart(t, 0.03125, true, function thistype.pd) 
    endmethod
endstruct
gif4.jpg



JASS:
struct Tester extends array
    private static ParticleData pdata
    private static integer counts = 30
    private static timer t = CreateTimer()
    private static method pd takes nothing returns nothing
        local Particles p = Particles.create(0, 0, 200, pdata)
    endmethod
    private static method onInit takes nothing returns nothing
        call FogEnable(false)
        call FogMaskEnable(false)
        set pdata = ParticleData.create()
        set pdata.MODEL = "Abilities\\Spells\\Human\\ManaFlare\\ManaFlareTarget.mdl"
        set pdata.LIFE_SPAN = 2.0
        set pdata.SPEED = 10
        set pdata.ACCEL = 9.6
        set pdata.START_DISTANCE = 0
        set pdata.END_DISTANCE = 100000
        set pdata.START_Z_ANGLE = 90
        set pdata.START_Z_ANGLE_VARIANCE = 180
        set pdata.START_ANGLE = 90
        set pdata.START_ANGLE_VARIANCE = 180
        set pdata.GRAVITY_ACCEL = 9.6
        set pdata.GRAVITY_ANGLE = 0
        set pdata.GRAVITY_Z_ANGLE = 90
        set pdata.START_ALPHA = 255
        set pdata.END_ALPHA = 0
        call SetCameraPosition(0, 0)
        call TimerStart(t, 0.03125, true, function thistype.pd) 
    endmethod
endstruct

gif5.jpg



TestMap
 
Last edited:
Updated.
Added ParticleEmitter struct with lifespan :D

Here is some pixie dust:
JASS:
struct Tester extends array
    private static ParticleData pdata
    private static timer t = CreateTimer()
    
    private static real dist = 512
    private static real angle = 0
    private static real aspeed = (bj_PI/4)*0.03125
    private static ParticleEmitter rotate
    private static method pd takes nothing returns nothing
        set angle = angle + aspeed
        call rotate.move(dist*Cos(angle), dist*Sin(angle), 250)
    endmethod
    
    private static method onInit takes nothing returns nothing
        call FogEnable(false)
        call FogMaskEnable(false)
        set pdata = ParticleData.create()
        //set pdata.PERIOD = 0.1
        set pdata.MODEL = "Abilities\\Spells\\Undead\\Possession\\PossessionTarget.mdl"
        set pdata.LIFE_SPAN = 2.0
        set pdata.SPEED = 10
        set pdata.ACCEL = 9.6
        set pdata.START_DISTANCE = 0
        set pdata.END_DISTANCE = 100000
        set pdata.START_Z_ANGLE = 90
        set pdata.START_Z_ANGLE_VARIANCE = 180
        set pdata.START_ANGLE = 90
        set pdata.START_ANGLE_VARIANCE = 180
        set pdata.GRAVITY_ACCEL = 9.6
        set pdata.GRAVITY_ANGLE = 0
        set pdata.GRAVITY_Z_ANGLE = 270
        
        set pdata.START_SIZE = 1.0
        set pdata.END_SIZE =0.0
        call SetCameraPosition(0, 0)
        
        //call ParticleEmitter.create(pdata, 0, 0, 250, 10)
        //call ParticleEmitter.create(pdata, 256, 0, 250, 10)
        set rotate = ParticleEmitter.create(pdata, -256, 0, 250, 20)
        
        call TimerStart(t, 0.03125, true, function thistype.pd)
    endmethod
endstruct

attachment.php
 

Attachments

  • huehue.png
    huehue.png
    1.6 MB · Views: 160
Fancy. Is each particle a unit?
Yes.



I did something like this some time ago - and while it's neat, it doesn't really serve much purpose. For any effect like this, that is purely visual (no collision or acting forces) you would simply create it as a model to save/gain 99% performance.
looks sweet nonetheless.

I agree to your point, creating the model saves a lot, but modders like me who doesn't know how to create models, we tend to use such things like this :D

Thanks for the feedbacks :D
 
I agree to your point, creating the model saves a lot, but modders like me who doesn't know how to create models, we tend to use such things like this :D

This is the logic behind my first mod. Nothing but a ton of dummy units and an excessive amount of trial and error until I got the dummy in the right position at the right height. I don't recommended this practice :p
 
Status
Not open for further replies.
Top