Pico-8 coroutines are occasionally dead - lua

I was trying to replace a for-loop with coroutines to move the stars:
--fine
function _update()
for c in all(boids) do
move_boid(c)
end
end
--broken
function _update()
for c in all(boids) do
coresume(cocreate(move_boid),c)
end
end
Notice that a fixed number of stars are frozen (I'm pretty sure the number is fixed):
But why? How can I handle this? The complete code is on itch.

Thanks for #Vald and #Egor's comments. Seems the problem is caused by "too-long coroutines" to finish in a PICO-8 cycle. So the solution is that I store unfinished coroutines in a table and resume them if not finished. But somehow the movement is changed, kinda like "lost frame".
Here's my edited code:
function _init()
-- code
cors={}
end
function _update()
for i=1,#boids do
local co=cocreate(move_boid)
local c=boids[i]
add(cors,co)
coresume(co,c)
end
for co in all(cors) do
if (co and costatus(co)!="dead") then
coresume(co)
else
del(cors,co)
end
end
end
And also modify the calculation function, adding a new line in the middle:
function move_boid(c)
-- code
yield()
-- code
end
Just to yield before it's completed.
Update: another way to do it is reusing coroutines.
function _init()
-- code
-- create coroutines
cors={}
for i=1,#boids do
local co=cocreate(move_boid)
local c=boids[i]
add(cors,co)
coresume(co,c)
end
end
function _update()
foreach(cors,coresume)
end
-- and wrap the move function with a loop
function move_boid(c)
while true do
-- code
yield()
-- code
yield()
end
end

Related

having problems getting keyboard input in LÖVE

heyo!
I'm trying to get input from my keyboard in LOVE2D but no input is being registered. getting no errors.
here's the code:
ESCdown=love.keyboard.isDown('escape')
function love.update()
if ESCdown then
love.event.quit()
end
end
love.update is called every frame.
ESCdown is assigned a value once and then never changes.
Consider using keyboard events:
https://love2d.org/wiki/love.keypressed
It even gives an example for what you want to do:
function love.keypressed(key, scancode, isrepeat)
if key == "escape" then
love.event.quit()
end
end

Coding error in Pico 8 code (lua). (Newbie here)

I have recently started coding and wanted to try out Pico-8. A game development platform that uses Lua. I watched tutorials on how to create a platformer and have run into an obstacle with my code. Spid in the code is the name of my main sprite and i have organized some of the code into sections: init, update, draw, collisions and player. if anyone can help me with my error please may you keep in mind that i have little to no experience with coding.
Error message:
Runtime error line 26 tab 4
If spid.dy>0 then
attempt to index global 'spid' (a nil value)
at line 26 tab 4
Cart code
pico-8 cartridge // http://www.pico-8.com
version 18
__lua__
--init
function _init()
spid={
sp=1,
x=59,
y=59,
h=8,
w=8,
dx=0,
dy=0,
maxdx=2,
maxdy=3,
acc=0.4,
boost=4,
anim=0,
running=false,
jumping=false,
falling=false,
crouching=false,
flp=false,
}
grav=1.2
friction=0.85
end
-->8
--update
function _update()
spid.x+=spid.dx
spid.y+=spid.dy
spid_update()
spid_animation()
end
-->8
--draw
function _draw()
cls()
spr(spid.sp,spid.x,spid.y,1,1,spid.flp)
map(0,0)
end
-->8
--collisions
function obj_collision(obj,aim,flag)
--obj = table and needs x,y,w,h
local x=obj.x local y=obj.y
local w=obj.w local h=obj.h
local x1=0 local y1=0
local x2=0 local y2=0
if aim=="left" then
x1=x-1 y1=y
x2=x y2=y+h-1
elseif aim=="right" then
x1=x+w y1=y
x2=x+w+1 y2=y+h-1
elseif aim=="up" then
x1=x+1 y1=y-1
x2=x+w-1 y2=y
elseif aim=="down" then
x1=x y1=y+h
x2=x+w y2=y+h
end
-- convert pixels to tiles
x/=8 y1/=8
x/=8 y2/=8
if fget(mget(x1,y1),flag)
or fget(mget(x1,y2),flag)
or fget(mget(x2,y1),flag)
or fget(mget(x2,y2),flag) then
return true
else
return false
end
end
-->8
--player
function spid_update()
spid.dy+=grav
spid.dx*=friction
end
if btn(2) then
spid.dx-=spid.acc
spid.running=true
spid.flp=true
end
if btn(1) then
spid.dx+=spid.acc
spid.running=true
spid.flp=false
end
if btnp(❎)
and spid.landed then
spid.dy-=spid.boost
spid.landed=false
end
if spid.dy>0 then
spid.falling=true
spid.landed=false
spid.jumping=false
end
if obj_collision(spid,"down",0) then
spid.landed=true
spid.falling=false
spid.dy=0
spid.y-=(spid.y+spid.h)%8
elseif spid.dy<0 then
spid.jumping=true
if obj_collision(spid,up,1) then
spid.dy=0
end
end
if spid.dx<0 then
if obj_collision(spid,"left",1) then
spid.dx=0
end
elseif spid.dx>0 then
if obj_collion(spid,"right",1) then
spid.dx=0
end
end
You have an extra end in your function on tab 4
I am assuming the end on the line after, spid.dx*=friction doesn't belong there. After correcting this pico-8 complains spid_animation() doesn't exist, which it doesn't in the code provided.
function spid_update()
spid.dy+=grav
spid.dx*=friction
end
if btn(2) then
spid.dx-=spid.acc
spid.running=true
spid.flp=true
end
May I suggest that you line up your if/end on the same column to keep them straight. This way it is much easier to look down the margin of your code and know which end's go with if statements, functions, etc.
for example, instead of:
if btn(2) then
spid.dx-=spid.acc
spid.running=true
spid.flp=true
end
use:
if btn(2) then
spid.dx-=spid.acc
spid.running=true
spid.flp=true
end
It seems like a small thing, but when you have a lot of nested code, it will make reading it much easier.
Pico-8 files may also be edited with external editors. I find this specially useful when running into issues like this (non-obvious bugs). For one you can see more of your code at once, and to they can highlight missing/extra end's.
Information on using an external editor is mentioned in the manual included with the executable: https://www.lexaloffle.com/pico-8.php?page=manual

Why do I use 'end)' instead of just end |?

draw.RoundedBox(0,0,0,100,100,Color(120,255,120))
end)
I'm watching tutorials for learning Lua, more specifically Lua for the Garry's Mod engine. During the tutorial, I noticed using just 'end' didn't work. I had to use 'end)' with a ')'.
Why do I have to place a ')' at the end of end in this code?
Some functions take other functions as parameters.
When you see a function called like this:
hello(param, function(a) print(a) end)
(Sorry, poor example. This function doesn't really do anything) The function on the inside is called internally from the source of the hello function.
The end is the end of the inside function, and the ) is the end of the parameter list for the first function.
So here we have a function hook.Add() being called:
hook.Add("HUDPaint", "DrawMyHud", function()
draw.RoundedBox(0,0,0,100,100,Color(120,255,120))
end)
and from the GMOD wiki:
hook.Add( string eventName, any identifier, function func )
--Add a hook to be called upon the given event occurring.
Although we're calling a function, what the function is doing is creating a special connection in the code called a hook. On the event "HUDPaint", the GMOD client will call the function provided.
Another way to write this function that might make the meaning of end) more clear is by making each parameter it's own line:
hook.Add(
"HUDPaint",
"DrawMyHud",
function() draw.RoundedBox(0,0,0,100,100,Color(120,255,120)) end --end of function declaration
) --end of hook.Add function call

Difference between "end" and "end)"?

A while ago I had stumbled upon script tutorials where end was used. But then, a few pages later, I've found an end) instead of just end. So I was troubled by this, what is the closing bracket meant to do?
There is no end) syntax. There is end and ), both with their own meanings. end closes a block (initiated with if, for, do, while or function) and ) closes something that started with (, an expression in parentheses, parameter list etc. You have to use end where a block was started, and use ) where something was started with (.
Since the only way a block can appear in an expression is via a function, both those parts of syntax can appear together, if a function is a part of a complex expression or an argument list. However, it's nothing special really, something like end} or end] can appear the same way.
local func = function() print("hello") end
string.dump(func)
This is the same as:
string.dump(function() print("hello") end)
end is a part of the function syntax (function expression), and ) is a part of the ( syntax (function call here).
The first line in the first piece of code can be also written like this:
local func = (function() print("hello") end)
Here, ) just closes the first parenthesis, and the expression is identical to the original one.
I assume you're talking about ROBLOX's modded version of Lua, if so then
end) would end :connect, for example.
workspace.part.Touched:connect(function(part)
--stuff
end)
If not then refer to llidanS4's answer.

Need help on ROBLOX script (Lua)

I`m making a script for my UFO in ROBLOX where whenever the UFO passes overhead it plays an audio. I made a script that goes as follows
while true do
if script.Parent.Parent.Velocity.Magnitude>10 then
if local h = hit.Parent:FindFirstChild("Humanoid")
then script.parent:play()
wait(5)
else
wait()
end
wait()
end
Any corrections would be a real help!
Thanks!
Everything aside, at the root there are a lot of syntax errors as well as the error of implementation, all in all the code block you've given us won't do what you wanted it to.
However, here's a basic idea of what the solution is:
local newThread = coroutine.create(function()
while true do
for i, v in game.Players:GetPlayers()
local playerListener = workspace[v.Name]["Head"]
local ufoListener = workspace.Ufo:FindFirstChild('Listener')
local magnitude = (playerListener.Position - ufoListener.Position).magnitude
if (magnitude > 10) then
script.Parent:play()
else
wait(0.5)
end
end
end
end)
coroutine.resume(newThread)
Essentially, here's the rundown: We're using coroutines so this while loop doesn't yield this thread for all eternity. There are some more complex avenues using bindable events and maybe some server-client handshake where, when fired from the LocalPlayer, it calls an event in the server- but I digress. This should be perfect for your needs without confusing you too much.

Resources