Tutorial The Particle System

Chocobo

White-Flower
Reaction score
409
I don't have so much time now. So it's a work in progress (WIP as we call). There's a lot of errors, so don't worry, I will fix them later.

Credits : -
I've seen that thread some days ago. (or weeks?)

It's a work in progress (wip), but it seems it isn't being updated.

Just to know, do people wants to have a Particle System (I may do Vector System only for units and Particle System /w Linked Lists for trigger effects) tutorial?

-Anitarf for Vector System
-iNfraNe for Linked Lists and the Particle System


1. What is the Vector System?

What is it? All is in it's name. It is able to make realistic movement with Warcraft 3 Game Engine. The Vector System is able to handle 8191 pointers at same time, the interval defined by BouncyPeriod().


1.1 What do I need for the Vector System?

You need :
- The Custom Script in Map Header inside the map
- The Variables inside the map
- Some knowledge of JASS

1.2 How to use it?

We will start by learning from the demo vector inside the map. Here is the script.

Code:
constant function BouncyPeriod takes nothing returns real
    return 0.01
endfunction

function BouncyBallMove takes nothing returns nothing
    local integer array vectors
    local location stupid //required to get the terrainheight
    local real h
    local effect eff

  //  retrieve vector data from unit's custom value
    set vectors[1]=GetUnitUserData(udg_BouncyBall)
    set vectors[2]=R2I(VectorGetX(vectors[1]))
    set vectors[3]=R2I(VectorGetY(vectors[1]))
    set vectors[4]=R2I(VectorGetZ(vectors[1]))

  //  change the ball's position according to it's speed
    call VectorAdd(vectors[2], vectors[3])
  //  change the balls speed by the gravity acceleration
    call VectorAdd(vectors[3], vectors[4])

  //  get terrain height at the position of the ball
    set stupid = Location(VectorGetX(vectors[2]), VectorGetY(vectors[2]))
    set h = GetLocationZ(stupid)
    call RemoveLocation(stupid)
    set stupid = null

  //  verify terrain collision
    if h >= VectorGetZ(vectors[2]) then
      //  get terrain normal vector
        set vectors[5]=VectorGetTerrainNormal(VectorGetX(vectors[2]), VectorGetY(vectors[2]), 32.0)
      //  get the component of speed vector that is perpendicular to the terrain
        set vectors[6]=VectorProjectVector(vectors[3], vectors[5])
      //  invert the ball's speed component that's perpendicular to terrain
        call VectorScale(vectors[6], -2.0)
        call VectorAdd(vectors[3], vectors[6])
      //  cleanup the temporary vectors
        call VectorDestroy(vectors[5])
        call VectorDestroy(vectors[6])
      //  add land effect
        set eff = AddSpecialEffect("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl", VectorGetX(vectors[2]), VectorGetY(vectors[2]))
        call DestroyEffect(eff)
    endif

  //  move the ball
    call SetUnitX(udg_BouncyBall, VectorGetX(vectors[2]))
    call SetUnitY(udg_BouncyBall, VectorGetY(vectors[2]))
    call SetUnitFlyHeight(udg_BouncyBall, VectorGetZ(vectors[2])-h, 0.0)

endfunction

function BouncyBallCreate takes nothing returns nothing
    local integer array vectors
    local timer t
    set udg_BouncyBall = CreateUnit(Player(0), 'ewsp', 0.0,0.0,0.0)

  //  make it possible to change the unit's flyheight
    call UnitAddAbility(udg_BouncyBall, 'Amrf')
    call UnitRemoveAbility(udg_BouncyBall, 'Amrf')

  //  create the unit's position vector
    set vectors[1]=VectorCreate(0.0,0.0,100.0)

  //  create the unit's starting speed vector
    set vectors[2]=VectorCreate(GetRandomReal(-100.0, 100.0)*BouncyPeriod(),GetRandomReal(-100.0, 100.0)*BouncyPeriod(),500.0*BouncyPeriod())

  //  create the gravity acceleration vector
    set vectors[3]=VectorCreate(0.0, 0.0, -800.0*BouncyPeriod()*BouncyPeriod())

  //  to avoid having too many variables, we store these vectors into another vector
    set vectors[4]=VectorCreate(I2R(vectors[1]), I2R(vectors[2]), I2R(vectors[3]))
    call SetUnitUserData(udg_BouncyBall, vectors[4])

    set t = CreateTimer()
    call TimerStart(t, BouncyPeriod(), true, function BouncyBallMove )
endfunction



//===========================================================================
function InitTrig_Bouncy_Ball takes nothing returns nothing
    set gg_trg_Bouncy_Ball = CreateTrigger(  )
    call BouncyBallCreate()
endfunction

How do it works?

BouncyPeriod() is the periodic event timing, it means every 0.01 second, the function BouncyBallMove() is run.

How to create a realistic movement with a vector? You need 14 lines for.

Code:
function BouncyBallCreate takes nothing returns nothing
    local integer array vectors
    local timer t
    set udg_BouncyBall = CreateUnit(Player(0), 'ewsp', 0.0,0.0,0.0)

  //  make it possible to change the unit's flyheight
    call UnitAddAbility(udg_BouncyBall, 'Amrf')
    call UnitRemoveAbility(udg_BouncyBall, 'Amrf')

  //  create the unit's position vector
    set vectors[1]=VectorCreate(0.0,0.0,100.0)

  //  create the unit's starting speed vector
    set vectors[2]=VectorCreate(GetRandomReal(-100.0, 100.0)*BouncyPeriod(),GetRandomReal(-100.0, 100.0)*BouncyPeriod(),500.0*BouncyPeriod())

  //  create the gravity acceleration vector
    set vectors[3]=VectorCreate(0.0, 0.0, -800.0*BouncyPeriod()*BouncyPeriod())

  //  to avoid having too many variables, we store these vectors into another vector
    set vectors[4]=VectorCreate(I2R(vectors[1]), I2R(vectors[2]), I2R(vectors[3]))
    call SetUnitUserData(udg_BouncyBall, vectors[4])

    set t = CreateTimer()
    call TimerStart(t, BouncyPeriod(), true, function BouncyBallMove )
endfunction

The first line declares an array integer called vectors, the second line a timer called t, and the third is a pointer (global variable) that handles a unit created with the integerId (unitId) 'ewsp'. (Night Elves - Wisp)
The 4st, and 5st, make the unit able to move via the Crow Form bug ('Amrf').
The set vectors[1] creates a main vector for location at point 0.00,0.00, at height 100.00. You can change these values.
The set vectors[2] creates a new vector, the main for the speed. You can change RandomReal thing to a new value, to change the target point.
The set vectors[3] creates a vector for the accelaration of the gravity when the ball falls or go higher, at -800.00(Pow(BouncyPeriod()). Remember to keep the "-", else the vector unit will keep flying. That vector is set as a Custom Unit Value for the udg_BouncyBall.
The 2 last lines creates a timer, and runs it every BouncyPeriod().

This is how, this system is used in the demo map.

You need inspiration to get what you want with this, because you may say : "I don't want to use globals ffsbbqhaxomg and I want it MUI rofl!"

To solve this problem, use KaTTaNa's Handle Vars, and to know at least how to use it :

Code:
// ===========================
function H2I takes handle h returns integer
    return h
    return 0
endfunction

// ===========================
function LocalVars takes nothing returns gamecache
    return udg_GameCache
endfunction

function SetHandleHandle takes handle subject, string name, handle value returns nothing
    if value==null then
        call FlushStoredInteger(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreInteger(LocalVars(), I2S(H2I(subject)), name, H2I(value))
    endif
endfunction

function SetHandleInt takes handle subject, string name, integer value returns nothing
    if value==0 then
        call FlushStoredInteger(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreInteger(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function SetHandleBoolean takes handle subject, string name, boolean value returns nothing
    if value==false then
        call FlushStoredBoolean(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreBoolean(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function SetHandleReal takes handle subject, string name, real value returns nothing
    if value==0 then
        call FlushStoredReal(LocalVars(), I2S(H2I(subject)), name)
    else
        call StoreReal(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function SetHandleString takes handle subject, string name, string value returns nothing
    if value==null then
        call FlushStoredString(LocalVars(), I2S(H2I(subject)), name)
    else
        call StoreString(LocalVars(), I2S(H2I(subject)), name, value)
    endif
endfunction

function GetHandleHandle takes handle subject, string name returns handle
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleInt takes handle subject, string name returns integer
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
endfunction
function GetHandleBoolean takes handle subject, string name returns boolean
    return GetStoredBoolean(LocalVars(), I2S(H2I(subject)), name)
endfunction
function GetHandleReal takes handle subject, string name returns real
    return GetStoredReal(LocalVars(), I2S(H2I(subject)), name)
endfunction
function GetHandleString takes handle subject, string name returns string
    return GetStoredString(LocalVars(), I2S(H2I(subject)), name)
endfunction

function GetHandleUnit takes handle subject, string name returns unit
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleTimer takes handle subject, string name returns timer
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleTrigger takes handle subject, string name returns trigger
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleEffect takes handle subject, string name returns effect
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleGroup takes handle subject, string name returns group
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleLightning takes handle subject, string name returns lightning
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleWidget takes handle subject, string name returns widget
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction

function FlushHandleLocals takes handle subject returns nothing
    call FlushStoredMission(LocalVars(), I2S(H2I(subject)) )
endfunction

Use a global gamecache called GameCache.

Since the Vector System uses a Timer, we will use SetHandleUnit and to retreive the unit that is bouncing attached to the timer.

Here is our new trigger with the handle vars (and also without the integer array vectors) :

Code:
constant function BouncyPeriod takes nothing returns real
    return 0.01
endfunction

function BouncyBallMove takes nothing returns nothing
[B]    local integer vector1
    local integer vector2
    local integer vector3
    local integer vector4
    local integer vector5
    local integer vector6[/B]
    local location stupid
    local real h
    local effect eff
    [B]local unit u=GetHandleUnit(GetExpiredTimer(),"unit")[/B] //get "unit" from t
    set vector1=GetUnitUserData(u)
    set vector2=R2I(VectorGetX(vector1))
    set vector3=R2I(VectorGetY(vector1))
    set vector4=R2I(VectorGetZ(vector1))
    call VectorAdd(vector2, vector3)
    call VectorAdd(vector3, vector4)
    set stupid = Location(VectorGetX(vector2), VectorGetY(vector2))
    set h = GetLocationZ(stupid)
    call RemoveLocation(stupid)
    set stupid = null
    if h >= VectorGetZ(vector2) then
        set vector5=VectorGetTerrainNormal(VectorGetX(vector2), VectorGetY(vector2), 32.0)
        set vector6=VectorProjectVector(vector3, vector5)
        call VectorScale(vector6, -2.0)
        call VectorAdd(vector3, vector6)
        call VectorDestroy(vector5)
        call VectorDestroy(vector6)
        set eff = AddSpecialEffect("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl", VectorGetX(vector2), VectorGetY(vector2))
        call DestroyEffect(eff)
    endif
    call SetUnitX(u, VectorGetX(vector2))
    call SetUnitY(u, VectorGetY(vector2))
    call SetUnitFlyHeight(u, VectorGetZ(vector2)-h, 0.0)
endfunction

function BouncyBallCreate takes nothing returns nothing
[B]    local integer vector1
    local integer vector2
    local integer vector3
    local integer vector4[/B]
    local timer t
    local unit u = CreateUnit(Player(0), 'ewsp', 0.0,0.0,0.0)
    call UnitAddAbility(u, 'Amrf')
    call UnitRemoveAbility(u, 'Amrf')
    set vector1=VectorCreate(0.0,0.0,100.0)
    set vector2=VectorCreate(GetRandomReal(-100.0, 100.0)*BouncyPeriod(),GetRandomReal(-100.0, 100.0)*BouncyPeriod(),500.0*BouncyPeriod())
    set vector3=VectorCreate(0.0, 0.0, -800.0*BouncyPeriod()*BouncyPeriod())
    set vector4=VectorCreate(I2R(vectors[1]), I2R(vectors[2]), I2R(vector3))
    call SetUnitUserData(u, vector4)
    set t = CreateTimer()
[B]    call SetHandleUnit(t,"unit",u)[/B] //attach u to timer as "unit"
    call TimerStart(t, BouncyPeriod(), true, function BouncyBallMove )
endfunction
//===========================================================================
function InitTrig_Bouncy_Ball takes nothing returns nothing
    set gg_trg_Bouncy_Ball = CreateTrigger(  )
    call BouncyBallCreate()
endfunction

Here is a Multi-Instanceable bouncy ball trigger. And you can customize it to create lot of bouncy balls, that deals damage when units are close to them.

Here is the Function list of the Vector System (Vector Functions Documentation\Functions list

constant function VectorGetX takes integer vector returns real
Returns the x coordinate of a vector.

constant function VectorGetY takes integer vector returns real
Returns the y coordinate of a vector.

constant function VectorGetZ takes integer vector returns real
Returns the z coordinate of a vector.

function VectorGetLength takes integer vector returns real
Returns the length of a vector.

function VectorSetX takes integer vector, real x returns boolean
Sets the x coordinate of a vector to the given value.
Returns false if an invalid ID is given for the vector.

function VectorSetY takes integer vector, real y returns boolean
Sets the y coordinate of a vector to the given value.
Returns false if an invalid ID is given for the vector.

function VectorSetZ takes integer vector, real z returns boolean
Sets the z coordinate of a vector to the given value.
Returns false if an invalid ID is given for the vector.

function VectorCreate takes real x, real y, real z returns integer
Creates a new vector with the given coordinates, and returns it's ID.

function VectorDestroy takes integer vector returns boolean
Destroys a vector, allowing it's ID to be recycled; since the amount of vectors you can have is limited, make sure you destroy all vectors which you no longer need.
Returns false if invalid ID is given for the vector.

function VectorSum takes integer augendV, integer addendV returns integer
Returns the sum of two vectors as a new vector.
Returns 0 if invalid ID is given for any of the vectors.

function VectorAdd takes integer increasedV, integer addedV returns boolean
Similar to VectorSum, except that it doesn't create a new vector for the result, but changes the increasedV by adding the addedV to it
Returns false if invalid ID is given for any of the vectors.

function VectorDifference takes integer minuendV, integer subtrahendV returns integer
Returns the difference between two vectors as a new vector.
Returns 0 if invalid ID is given for any of the vectors.

function VectorSubtract takes integer decreasedV, integer subtractedV returns boolean
Similar to VectorDifference, except that it doesn't create a new vector for the result, but changes the decreasedV by subtracting the subtractedV from it.
Returns false if invalid ID is given for any of the vectors.

function VectorAmplify takes integer vector1, real factor returns integer
Returns a new vector that has the same direction as vector1, and length equal to that of vector1 multiplied by factor.
Returns 0 if invalid ID is given for the vector.

function VectorScale takes integer vector1, real factor returns boolean
Similar to VectorAmplify, except that it doesn't create a new vector for the result,
but changes the vector1 by multiplying it with the factor
Returns false if invalid ID is given for the vector.

function VectorProductScalar takes integer vector1, integer vector2 returns real
Calculates the scalar product of two vectors.
Returns 0.0 if invalid ID is given for any of the vectors.

function VectorProductVector takes integer vector1, integer vector2 returns integer
Calculates the vector product of two vectors and returns it as a new vector.
Returns 0 if invalid ID is given for any of the vectors.

function VectorProjectVector takes integer projectedV, integer directionV returns integer
Calculates the projection of the projectedV onto the directionV and returns it
as a new vector
Returns 0 if the vector directionV has 0 length or if invalid ID is given for any of the vectors.

function VectorProjectPlane takes integer projectedV, integer planeNormalV returns integer
Calculates the projection of the projectedV onto a plane defined by it's normal vector and returns it as a new vector
Returns 0 if the vector planeNormalV has 0 length or if invalid ID is given for any of the vectors.

function VectorSetLength takes integer vector1, real length returns boolean
Modifies vector1 to keep the same direction, but change it's length
Returns false if vector1 is 0 units long or if invalid ID is given for the vector.

function VectorGetAngle takes integer vector1, integer vector2 returns real
Returns the angle between two vectors, in radians, returns a value between 0 and pi.
Returns 0.0 if any of the vectors are 0 units long or if invalid ID is given for any of the vectors.

function VectorGetAngleDeg takes integer vector1, integer vector2 returns real
Same as VectorGetAngle, except that it returns the angle in degrees.

function VectorRotate takes integer rotatedV, integer axisV, real angle returns integer
Returns a new vector that you get if you rotate rotatedV around the axis defined by the vector axisV by the given angle, which should be input in radians.
Returns 0 if axisV is 0 units long or if invalid ID is given for any of the vectors.

function VectorRotateDeg takes integer rotatedV, integer axisV, real angle returns integer
Same as VectorRotate, except that it takes the angle argument in degrees.

function VectorGetTerrainPosition takes real x, real y returns integer
Creates a vector to the given terrain coordinate, taking it's z height into account.

function VectorGetTerrainNormal takes real x, real y, real sampleRadius returns integer
Gets the normal vector of the terrain at given coordinates. sampleRadius defines how far apart the reference points will be, if they are further apart, the result will be an impression of smoother terrain; normaly the value should be between 0 and 128.


function IsPointInCylinder takes integer pointV, integer cylinderOriginV, integer cylinderHeightV, real cylinderRadius returns boolean
Determines if a point is within a given cylinder. The cylinder's origin vector points to the center of one of the two paralel circular sides, and the height vector points from the origin point to the center of the other of the two paralel circular sides.
Returns false if the point is not in the cylinder, or if an invalid ID is given for any of the vectors, or if the cylinderHeightV is 0 units long.

function IsPointInCone takes integer pointV, integer coneOriginV, integer coneHeightV, real coneRadius returns boolean
Determines if a point is within a given cone. The cone's origin vector points to the center of the circular side, and the height vector points from the origin point to the tip of the cone.
Returns false if the point is not in the cylinder, or if an invalid ID is given for any of the vectors, or if the cylinderHeightV is 0 units long.

function IsPointInSphere takes integer pointV, integer sphereOriginV, real sphereRadius returns boolean
Determines if a point is within a give sphere. The sphere's origin vector points to the center of the sphere.
Returns false if the point is not in the sphere, or if an invalid ID is given for any of the vectors.

When using it, remember to clean up all the unused vectors using VectorDestroy(vectorinteger).




More to come later. (bolded + underlined if people does not see it)
- Particle System
- How to use it
- How to use Linked Lists
- and all the blabla you can find
- and maybe the Physic System

Download the Particle System there.


See also the The Index for Tutorials by Amfidament,
or my JASS Tutorial.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top