Log In  


After some time of figuring everything out (including what I want to do in the future regarding the path of my life), I finally finished another snippet. This lets you efficiently create particles, as seen in this gif here:

DOCUMENTATION:

IMPORTING

Assuming you've placed the downloaded file into a folder called src, import with

#include src/ptc_x.lua

The compressed version doesn't have an extension, so just use src/ptc_x_c without .lua


CREATE A GROUP

You can create a particle group like so.

g_smp=_pgrp(64,64)

now, g_smp will become a particle group and will be positioned at 64/64 (center of screen with unmodded camera).

GROUP TABLE VALUES

  • x/y
    • X and Y location of the group
  • _ary
    • table that contains the particles
  • _tk
    • Tick value. Increases by 1 per .tick() call.
  • max
    • Allows you to limit how many particles the group can create/have.
  • linkcam

    • Links a camera to the particle group.

    CAMERA LINK

To link a camera, you'll need to use the collowing code in _init(). This code will set the groups camera to your own camera. This is needed because the particles will delete themselves when off camera.

g_smp.linkcam=cam

This assumes your cam has x and y values.
cam={x=0,y=0}

Alternatively, if you have a different setup, you can set the specifics for x/y...

g_smp.linkcam.x=cam_x
g_smp.linkcam.y=cam_y

PARTICLE TYPES

Particle Types need to be functions that return an object. This is needed because of the possibility of randomization.

	--create lava eruption
fx1=function()
	return	{
		--location
		x=rnd(8),
		y=-rnd(4),

		--initial velocity
		--and gaining velocity
		xv={
			rnd(4)-rnd(4),
			rnd(0.01)-rnd(0.01)
		},
		yv={
			-3+rnd(1),
			0.1
		},

		--colors (shifts through
		--array per tick)
		c={8,2,4,1},

		--collision flag, nil for
		--no map collision.
		cflg=1,

		--life length
		l=200-rnd(30),

		--weight (for collision)
			--[x and y]
			--effects bounce rate
		w={1.4,3-rnd(1)},

		-----optional parts here----
		--setting size and size-gain
		--will make it a puff particle.

	 	s=0.5+rnd(2),
		sg=-rnd(0.1),
	}
end

Values:

  • x/y
    • X and Y location of spawn (arranged by x/y of particle group)
  • xv/yv
    • Xvelocity and Yvelocity of spawn. The first value is the initial velocity, and the second value is how much that value increases per frame. Setting the second value to 0.1 for the yv for example will cause the particles to continously increase their yvelocity. In the gif, notice how they start launching up then fall as if gravity is affecting them.
  • c

    • Color array. Every tick of the particles lifespan will increment through the color array. Use only 1 value for a solid color, or make up your own patterns.
  • cflg

    • Collision Flag. This means that the particles will have physics if they come in contact with a sprite that has the set ID. Set to nil to skip collision checking, or just don't add this property to save yourself some tokens.
  • l

    • Life. This is how many frames the particles will stay alive for.
  • w
    • Weight. This is a Table and contains 2 values. One for calculating the division(slowdown) of the xvelocity and another for calculating the slowdown of the yvelocity. You only need this if you're using collision. This is also ignorable if you want to save tokens.
  • s
    • Optional, sets the size of the particle. If its less than or equal to 1, it'll use pset instead of circfill. Otherwise, it becomes a "puff particle", which is a type of particle that flips patterns (between 0b1010010110100101.1 and 0b0101101001011010.1) to create a simi-transparent circle creating the illusion of a blending effect. This is ignorable
  • sg

    • Optional, sets the size-gain. The size of the particle will increase by this value per frame.

    Emitting particles

To create particles, you'll need to use the emit function. For example:

g_smp.emit(fx1, 90)

The first value is the particle group we've created earlier. The second value is how many particles it'll create per frame (or per call).


DISPLAYING A GROUP

To actually get your particles to draw on screen, use the .tick command in _draw().

g_smp.tick()

That should be about it. If I missed anything, I'll add it later.


NON-DOWNLOAD VERSION

--[[DEPENDANCIES
    cdec.lua
     •Col.Detection

--]]
    --[[cdec.lua]]
function cdec(mx, my, xl, yl, flg)
    local _=function(x,y,f)
        return fget(mget(x/8,y/8),f)
    end

    if _(mx+xl, my+yl, flg) or _(mx, my, flg) then
        return true
    end

    return false
end
--[[end of cdec.lua]]

--[[main]]
    --particle patterns for puff particles
ptc_pats={0b1010010110100101.1, 0b0101101001011010.1}
--create a new particle grou[
function _pgrp(x,y)
    local a={
        x=x,
        y=y,
        --particle array
        _ary={},
        --tick, can be used for custom code
        _tk=0,
        --max particle limit
        max=500,
        linkcam={x=0,y=0}
    }

    a.emit=function(dt, rpt)
        for i=1,rpt do
            if #a._ary<a.max then

                local _a=dt()
                _a.lc=0
                _a.w=_a.w or {1,1}

                add(a._ary, _a)
            else
                return
            end
        end
    end

    a.tick=function()
        a._tk+=1
        for i=1, #a._ary do
            local s=a._ary[i]
            if not s then goto e end
            local _={
                s.x+a.x,
                s.y+a.y
            }

            ::r::
            s.lc+=1
            if s.lc>=s.l or stat(1)>0.9 then
                del(a._ary, a._ary[i])
                if stat(1)>0.9 then break end
            end

            s.x+=s.xv[1]+s.xv[2]
            s.y+=s.yv[1]+s.yv[2]
            s.xv[1]+=s.xv[2]
            s.yv[1]+=s.yv[2]

            if not s.cflg then goto d end
            if cdec(_[1], _[2], s.xv[1], s.yv[1], s.cflg) then
                if not cdec(_[1]+s.xv[1], _[2]-s.yv[1], s.xv[1], 0, s.cflg) then
                    s.y-=(s.yv[1]*2)
                    s.yv[1]=-s.yv[1]
                    s.yv[1]/=s.w[2]
                    s.xv[1]/=s.w[1]
                else
                    s.x-=(s.xv[1]*2)
                    s.xv[1]=-s.xv[1]
                    s.xv[1]/=s.w[1]
                end
            end

            ::d::
            local color=s.c[1+s.lc%#s.c]

            if _[1]-a.linkcam.x>128 or _[1]-a.linkcam.x<0 or _[2]-a.linkcam.y>128 or _[2]-a.linkcam.y<0 then s.lc=s.l goto e end
            if not s.s then
                fillp()
                goto px
            else
                s.s+=s.sg
                if s.s<=1 then fillp() goto px end
                fillp(ptc_pats[1+(a._tk%#ptc_pats)])
                goto cl
            end

            --set pixel
            ::px::
            pset(_[1], _[2], color)
            goto e
            --set circle
            ::cl::
            circfill(_[1], _[2], s.s, color)
            goto e
            ::e::
        end
        fillp()
    end

    return a
end
5


couple of coding style comments:

  • too many goto! goto jumping makes a code difficult to follow and can hide control path optimizations
  • too many _ variables: variables/functions should have a clear name
  • cdec function used in inner loop should not create a local function (performance)
  • separate velocity and acceleration (clearer)
  • split tick into update/draw (remember that pico can skip draw calls if game is too slow
  • stat(1) check is actually going to have a very bizarre effect of particle no longer moving?!?

keep up with the good work!


Freds72
Thank you for your feedback! I'll take all of it into consideration when developing in the future. The stat(1) check was to make sure the particles didn't get created if the CPU usage was above 90% (to prevent lag), and if the CPU should go above 90% at any time, the particles (which usually don't have much of an effect other than visual stimuli) would start deleting themselves to increase performance, keeping the game running smooth.

However, yes it does cause jankyness without a separate update/draw function but I was going for a method of saving tokens. However, I've realized late-dev that saving tokens alone isn't really what you want to go for, there are other aspects to take note of that make the extra tokens worthit



[Please log in to post a comment]