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

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

Related

Why isn't this Roblox function/script working?

I started with Roblox a few months ago and my only semi-related prior experience is in web development, so you're dealing with a noob here.
I'm having trouble awarding my game's currency to the players of the winning team of a round. Every other aspect of my currency seems to work fine - it displays, can update, saves with datastores etc.
This in-game currency is set up in the same manner as leaderstats (but not as a leaderstats) - it's created under the player at runtime (if that's the proper way of saying it) via a script in SSS.
The function I'm having issues with doesn't seem to do anything, and I've tried about 20 different variations, some of which were radically different from this. The one below is the last one I tried before giving up to seek help here.
function goldToWinningTeam()
local winningTeam = TeamManager:GetWinningTeam()
for i, Player in pairs(Players:GetPlayers()) do
if player.TeamColor == winningTeam.TeamColor then
player.currency.Gold.Value += 100
else
player.currency.Gold.Value += 50
end
end
end
This doesn't produce any output errors or interfere with other game logic as far as I can tell.
At the moment, for testing, the function above is in my main game script (a regular script). Its proper/ideal location, upon getting it to work, is also something I'd appreciate some feedback on. I was thinking either in my TeamManager or PlayerManager module scripts, or possibly my GameCurrecy script, which is a regular script in SSS.
Below are the TeamManager function(s) called from above. I've tried using either. Both work as expected for their intended purpose of displaying a victor at round end. I figured they would also work in this use case.
function TeamManager:GetWinningTeam()
local highestScore = 0
local winningTeam = nil
for _, team in ipairs(Teams:GetTeams()) do
if TeamScores[team] > highestScore then
highestScore = TeamScores[team]
winningTeam = team
end
end
return winningTeam
end
-- Below works identically for displaying victor
function TeamManager:HasTeamWon()
for _, team in ipairs(Teams:GetTeams()) do
if TeamScores[team] >= Configurations.DESTROYS_TO_WIN then
return team
end
end
return false
end
Again, I'm very new to this and it's only a hobby, please forgive any obvious ignorances.

Attemp to call a nil value (field ‘ShowInventory’) [ESX2]

I just installed ESX 2 into my new server, im Really new at lua and i dont really know what i should do with some resources or how to start coding
I wan to work in the inventory system based on es_extended, but, it doesnt work.
I press the Inventory Key informed in the cofig file \server-data\resources\es_extended\config\default\config.lua
“Config.InventoryKey = “REPLAY_START_STOP_RECORDING_SECONDARY” – Key F2 by default”
module.InitESX = function()
module.RegisterControl(module.Groups.MOVE, module.Controls[Config.InventoryKey])
module.On('released', module.Groups.MOVE, module.Controls[Config.InventoryKey], function(lastPressed)
print("Comment before show The Inventory")
ESX.ShowInventory()
-- if Menu.IsOpen ~= nil then
-- if (not ESX.IsDead) and (not Menu.IsOpen('default', 'es_extended', 'inventory')) then
-- ESX.ShowInventory()
-- end
-- end
end)
end
I literally change a little bit the code to directly execute the ShowInventory() Function but i got this error
the original code look like this
module.InitESX = function()
module.RegisterControl(module.Groups.MOVE, module.Controls[Config.InventoryKey])
module.On('released', module.Groups.MOVE, module.Controls[Config.InventoryKey], function(lastPressed)
if Menu.IsOpen ~= nil then
if (not ESX.IsDead) and (not Menu.IsOpen('default', 'es_extended', 'inventory')) then
ESX.ShowInventory()
end
end
end)
end
but when i press the key dont do nothing and doesnt show anything in the console.

Pico-8 coroutines are occasionally dead

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

Lua not overriding # metamethod

Ok so I've been searching for a while and didn't get the answer. I imagine someone has this same problem but I was not able to solve this problem. I'm new to Lua, having some experience with Python but not being a programmer :S.
So I'm doing a metatable to handle complex numbers, following the tutorials here: http://www.dcc.ufrj.br/~fabiom/lua/
so I implement creation, addition, printing and equal comparison:
local mt={}
local function new(r,i)
return setmetatable({real = r or 0, im = i or 0},mt)
end
local function is_complex (v)
return getmetatable(v)==mt
end
local function add (c1,c2)
if not is_complex(c1) then
return new(c1+c2.real,c2.im)
end
if not is_complex(c2) then
return new(c1.real+c2,c1.im)
end
return new(c1.real + c2.real,c1.im + c2.im)
end
local function eq(c1,c2)
return (c1.real==c2.real) and (c1.im==c2.im)
end
local function modulus(c)
return (math.sqrt(c.real^2 + c.im^2))
end
local function tos(c)
return tostring(c.real).."+"..tostring(c.im).."i"
end
mt.new=new
mt.__add=add
mt.__tostring=tos
mt.__eq=eq
mt.__len=modulus
return mt
Then I make a small tests:
complex2=require "complex2"
print (complex2)
c1=complex2.new(3,2)
c2=complex2.new(3,4)
print (c1)
print (c2)
print(#{1,2})
print(#c2)
print(complex2.__len(c2))
print(#complex2.new(4,3))
and I get:
table: 0000000003EADBC0
3+2i
3+4i
2
0
5
0
So, What am I dong wrong? is something with calling the #, when i try to debug in the other cases the program goes to the module into the function but the # operand gets like ignored. Modulus function is working and can be called in the module... I'm sorry for such a long and I'm sure obvious question but I tried everything I could already. Thank you
May be the problem is about Lua version.
http://www.lua.org/manual/5.2/manual.html#2.4
"len": the # operation
works since Lua 5.2
and it works only with tables
So, Thank you, and you are right. I thought I had selected 5.2 but in the interpreter it was running 5.1 :S. Now i did:
complex2=require "complex2"
print (complex2)
c1=complex2.new(3,2)
c2=complex2.new(3,4)
print (c1)
print (c2)
print (c1+c2)
print(#{1,2})
print(#c2)
print(complex2.__len(c2))
print(complex2.__len(complex2.new(3,3)))
print(#complex2.new(4,3))
print(getmetatable(c2))
And i got:
table: 000000000047E1C0
3+2i
3+4i
6+6i
2
5
5
4.2426406871193
5
table: 000000000047E1C0
Everything under control ^^, at least the code was working as supposed xD

World of Warcraft Lua - If statement flow

I'm trying to create an addon for World of Warcraft. I have created a function that checks whether a buff has been added to the current player.
Button:RegisterEvent("UNIT_AURA");
local function auraGained(self, event, ...)
if (UnitAura("player", "Heating Up")) then
if (heatingUpIsActive ~= 1) then
heatingUpIsActive = heatingUpIsActive + 1
print (heatingUpIsActive)
end
end
Button:SetScript("OnEvent", auraGained);
This works great, but how do I check if UnitAura is not "Heating Up"?
Also, I would prefer if heatingUpIsActive were a boolean, but it seems to not like when I do that. What is the correct way to create a boolean in Lua?
Your function isn't checking the aura that caused the event. It's looking for "Heating Up" any time any UNIT_AURA event comes by. In fact, it looks like the UNIT_AURA event doesn't actually tell you which aura triggered it. So you can't "check if UnitAura is not "Heating Up"", because you simply don't know what aura caused the event. Perhaps it was even several auras at once.
However, the event does tell you what unit got the aura. It's the first vararg. You should probably check to make sure it's player before doing something
local unitid = ...
if unitid ~= "player" then return end
Also, you didn't explain what problems you had with booleans. You should just be able to say something like
if not heatingUpIsActive then
heatingUpIsActive = true
-- do whatever you want
end
although I never saw any declaration of the variable in your code. It's a bad idea to use globals for things like this, so you should declare
local heatingUpIsActive
before the function declaration, e.g.
local heatingUpIsActive
local function auraGained(self, event, ...)
-- ...

Resources