pico-8 cartridge // http://www.pico-8.com version 32 __lua__ #include ../pecs.lua --include"../pecs.lua" -- picotron -- A particle emitter example showing how to use PECS (PICO-8 Entity Component -- System) by Jess Telford: https://github.com/jesstelford/pico-8-pecs -- This example is optimised for readability, not token or character count. -- License: MIT Copyright (c) 2021 Jess Telford ------------------- --[[ ECS SETUP ]]-- -- Setup the world where all Components, Entities, and Systems will live local world = pecs() --[[ END ECS SETUP ]]-- ----------------------- ------------------------ --[[ ECS COMPONENTS ]]-- -- Create instantiable Components with default values -- These values will all be used later in the Systems -- Individual values can be overriden when instiating a Component local Position = world.component({ x= 0, y = 0 }) local Velocity = world.component({ x= 0, y = 0 }) local Acceleration = world.component({ x = 0, y = 60 }) local Renderable = world.component({ color = 7, size = 1 }) local Ttl = world.component({ ttlSeconds = 0 }) -- One Component to store general emitter data local Emitter = world.component({ isEmitting = false, emitAt = 0 }) -- Other components used to determine the exact type of emitter local FountainEmitter = world.component({ emitEverySeconds = 0.01 }) local RainfallEmitter = world.component({ emitEverySeconds = 0.01 }) local ExplosionEmitter = world.component({ emitEverySeconds = 0.01 }) --[[ END ECS COMPONENTS ]]-- ---------------------------- function _init() -- Setup our emitter. -- Systems which filter for these components will be automatically updated to -- include this new entity. world.entity( {}, Emitter(), -- Start with a Fountain, but it can be changed based on input FountainEmitter(), Position({ x = 64, y = 64 }), Renderable({ color = 7, size = 2 }) ) end --------------------- --[[ ECS SYSTEMS ]]-- -- A System for handling input. In this example, we only have a single entity -- which matches the filter { Emitter, Position }, so this System could be -- replaced with a regular function. -- But, as our world grows, we may want more than one emitter which responds to -- user input. All that's required is to call `world.entity` with at least -- the `Emitter` & `Position` components, then this System will automatically -- detect it and run the function. -- -- To try it out; duplicate the `world.entity` call in _init() above, but -- with a different type and x/y value. local handleEmitterInput = world.system({ Emitter, Position }, function(emitter, tickTime) -- Move the emitter around while keeping it on the screen if (btn(0)) then emitter[Position].x = (emitter[Position].x - 1) % 128 end if (btn(1)) then emitter[Position].x = (emitter[Position].x + 1) % 128 end if (btn(2)) then emitter[Position].y = (emitter[Position].y - 1) % 128 end if (btn(3)) then emitter[Position].y = (emitter[Position].y + 1) % 128 end -- Remove the current emitter and add a new emitter if (btnp(4)) then if (emitter[FountainEmitter]) then emitter -= FountainEmitter emitter += RainfallEmitter() elseif (emitter[RainfallEmitter]) then emitter -= RainfallEmitter emitter += ExplosionEmitter() elseif (emitter[ExplosionEmitter]) then emitter -= ExplosionEmitter emitter += FountainEmitter() end end -- Turn the emitter on if (btn(5)) then -- If it was previously not emitting if (not emitter[Emitter].isEmitting) then -- Reset the next emission time emitter[Emitter].emitAt = tickTime end emitter[Emitter].isEmitting = true else emitter[Emitter].isEmitting = false end end) -- The following Systems have a similar filter to the `handleEmitterInput` -- System, so why not combine them? -- Because they serve different purposes. -- In this example, the emitter is controlled with input, but in another -- program, the emitter might not be controllable at all, or there may be -- multiple emitters controlled differently (eg: A steam train puffing smoke -- goes past a camp fire). -- ie; this system shouldn't know or care about user input. There could be other -- systems that modify emitters (on/off, movement, etc) that have nothing to do -- with input. This system only cares about emitting. local emitFountain = world.system({ Emitter, FountainEmitter, Position }, function(emitter, tickTime) if (not emitter[Emitter].isEmitting) then return end -- Make sure enough time has elapsed to emit a new particle -- And keep emitting until we've caught up in time while (tickTime >= emitter[Emitter].emitAt) do emitter[Emitter].emitAt += emitter[FountainEmitter].emitEverySeconds -- 0.25 is 90deg counter-clockwise, so this points it straight up -- 0.125 is 45deg -- -0.0625 is to rotate it back by half that (-22.5deg) so it's not -- lop-sided local angle = 0.25 + rnd(0.125) - 0.0625 local speed = 50 + rnd(30) world.entity( {}, Position({ x=emitter[Position].x, y=emitter[Position].y }), Velocity({ x = cos(angle) * speed, y = sin(angle) * speed }), Acceleration(), -- Default accel values Renderable({ color = 8 + rnd(8) }), Ttl({ ttlSeconds = 2 + rnd(3) }) ) end end) local emitRainfall = world.system({ Emitter, RainfallEmitter, Position }, function(emitter, tickTime) if (not emitter[Emitter].isEmitting) then return end -- Make sure enough time has elapsed to emit a new particle -- And keep emitting until we've caught up in time while (tickTime >= emitter[Emitter].emitAt) do emitter[Emitter].emitAt += emitter[RainfallEmitter].emitEverySeconds world.entity( {}, Position({ x=emitter[Position].x + rnd(40) - 20, y=emitter[Position].y }), Velocity(), Acceleration(), -- Default accel values Renderable({ color = 8 + rnd(8) }), Ttl({ ttlSeconds = 2 + rnd(3) }) ) end end) local emitExplosion = world.system({ Emitter, ExplosionEmitter, Position }, function(emitter, tickTime) if (not emitter[Emitter].isEmitting) then return end -- Make sure enough time has elapsed to emit a new particle -- And keep emitting until we've caught up in time while (tickTime >= emitter[Emitter].emitAt) do emitter[Emitter].emitAt += emitter[ExplosionEmitter].emitEverySeconds local angle = rnd(1) local speed = 50 + rnd(30) world.entity( {}, Position({ x=emitter[Position].x, y=emitter[Position].y }), Velocity({ x = cos(angle) * speed, y = sin(angle) * speed }), Acceleration({ x = 0, y = 0 }),-- Overwrite the defaults Renderable({ color = 8 + rnd(8) }), Ttl({ ttlSeconds = 2 + rnd(3) }) ) end end) -- Particles don't live forever, so we give them a TTL local ttlUpdate = world.system({ Ttl }, function(item, tDiff) item[Ttl].ttlSeconds -= tDiff -- Once their remaining TTL is up if (item[Ttl].ttlSeconds <= 0) then -- Remove that entity from the world. -- All Systems will be automatically updated to exclude this item world.remove(item) end end) -- A mini physics system local moveItems = world.system({ Position, Velocity, Acceleration }, function(item, tDiff) item[Velocity].x += tDiff * item[Acceleration].x item[Velocity].y += tDiff * item[Acceleration].y item[Position].x += tDiff * item[Velocity].x item[Position].y += tDiff * item[Velocity].y end) -- Very naive rendering in this example. As complexity rises, it makes sense to -- create Components for each type of renderable, and the System which actually -- does the rendering. local drawRenderables = world.system({ Position, Renderable }, function(renderable) circfill( renderable[Position].x, renderable[Position].y, renderable[Renderable].size, renderable[Renderable].color ) end) --[[ END ECS SYSTEMS ]]-- ------------------------- --------------------- --[[ PICO8 LOOPS ]]-- local lastTickTime = time() function _update60() local tickTime = time() local tDiff = tickTime - lastTickTime -- Important to call .update() at the start of every loop, before any Systems world.update() -- The parameters passed in here will appear as the second argument in the -- System's function ttlUpdate(tDiff) handleEmitterInput(tickTime) emitFountain(tickTime) emitRainfall(tickTime) emitExplosion(tickTime) moveItems(tDiff) lastTickTime = tickTime end -- picotron if (_G) _update = _update60 function _draw() cls(0) drawRenderables() print("\f7 move emit type", 2, 2) print("\f7"..chr(139,145,148,131).." "..chr(151).." "..chr(142), 2) end --[[ END PICO8 LOOPS ]]-- ------------------------- __gfx__ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00077000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00700700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 __label__ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000007770077070707770000000000000777077707770777000007770707077707770000000000000000000000000000000000000000000000000000000 00000000007770707070707000000000000000700077700700070000000700707070707000000000000000000000000000000000000000000000000000000000 00000000007070707070707700000000000000770070700700070000000700777077707700000000000000000000000000000000000000000000000000000000 00000000007070707077707000000000000000700070700700070000000700007070007000000000000000000000000000000000000000000000000000000000 00000000007070770007007770000000000000777070707770070000000700777070007770000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00077777000777770007777700077777000000000007777700000000000000077777000000000000000000000000000000000000000000000000000000000000 00777007707700777077707770770007700000000077070770000000000000770007700000000000000000000000000000000000000000000000000000000000 00770007707700077077000770770007700000000077707770000000000000770707700000000000000000000000000000000000000000000000000000000000 00777007707700777077000770777077700000000077070770000000000000770007700000000000000000000000000000000000000000000000000000000000 00077777000777770007777700077777000000000007777700000000000000077777000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000088800000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000f000000000008000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000fff00000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000b0000000000000000800000000000f0000000c0000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000bbb0000000000000088800000000000000000ccc000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000b000000000000000080000000000000000000c0000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000aaa0000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000c0000000000000009990000000000000000000000000e000000000000000000000000000000000000000000 0000000000000000000000000000000000000000ccca000d0000090000900000000000000000f0000800eee00000000000000000000000000000000000000000 00000000000000000000000000000000000000000caaa0ddd0009990000000000000008e090fff0088800e0eb000000000000000000000000000000000000000 0000000000000000000000000000000000000000000a000d0000080000000800000b08eee990f000080000eeeb00000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008880a000888000bbb08e0b00000000b0000eb000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000e000080aaa0ff800000b0000bbb000000bbb00099900000000000000000000000000000000000000 00000000000000000000000000000000000000000000000ece000000c000fff0000000000bee000000b000009000000000000000000000000000000000000000 000000000000000000000000000000000000000000b0000ccc00090ccc000f000000000000e00000080000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000bbb0000caa09990c0000000000080000c000000a88000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000b000000a000900000000c000088800ccc0000aaa0000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000cbc000a800e0c000000a0b000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000cbbb00aca0eee0000c000bbb00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000cb880ccbbeee0f0ccc000b000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000008800000000d08dd0bbbbe0fff0c0a000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000008888b00f00ddd0d000bd0000f000aaa00000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000088bbbfff0bdee0000ddd000000eea000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000b00f0fbbe000000d000a0000e0000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000fff8080000c000aaa00000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000a0000f0088900ccc00ba000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000e00aaab00000099b00c00bbb000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000c0eee00aebb000000bbbc0008be000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000ccc0e000eee0000c000bccc08880000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000c0000000e0000dcc0000c99c800000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000ddd9c00009ccca0000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000d9ccc09008ca00000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000ccc999888000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000a0c0090080000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000aaa00000900000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000a0000a9990000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000ce009aa900000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000ceee9f90000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000ce8fff0000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000008888f00000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000088eee0000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000eeed0000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000faed00000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000aad000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000008ddd00000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000077d770000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000777770000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000777770000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000077700000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000