Coins not spawning in tutorial. please help (SOLVED)

ERROR:SCRIPT: level/platform.script:24: attempt to perform arithmetic on field ‘coins’ (a nil value)
stack traceback:
level/platform.script:24: in function 'create_coins’
level/platform.script:37: in function <level/platform.script:33>

the script i have in platform.script:

21 function create_coins(self, params)
22    local spacing = 56
23    local pos = go.get_position()
24    local x = pos.x - params.coins * (spacing*0.5) - 24
25    for i = 1, params.coins do
26        local coin = factory.create("#coin_factory", vmath.vector3(x + i * spacing , pos.y + 64, 1))
27        msg.post(coin, "set_parent", { parent_id = go.get_id() }) 
28        msg.post(coin, "start_animation", { delay = i/10 }) 
29        table.insert(self.coins, coin)
30    end
31 end
32
33 function on_message(self, message_id, message, sender)
34    if message_id == hash("set_speed") then
35        self.speed = message.speed
36   elseif message_id == hash("create_coins") then
37        create_coins(self, message)
38    end
39 end

It seems that your message table doesn’t contain field coins. In this case params.coins will evaluate to nil on 24 line and you can’t use it for arithmetic, as said in error message.

Exactly. And the last part of the tutorial involves a change to the controller.script where you are supposed to post the create_coins message:

msg.post(p, "create_coins", { coins = coins })

So either coins is nil there or there’s a problem when you receive the message in platform.script and pass it to the create_coins() function. My recommendation is to add:

pprint(message)

In the on_message() function in platform.script. Does the create_coins message contain a coins key-value pair? And do you pass the message along to the create_coins() function?

i seem to have followed the tutorial step by step but its still not working…can someone check and see whats wrong with my code…ill paste it here…thanks heaps

Controller.script:

go.property("speed", 6)

local grid = 460
local platform_heights = { 100, 200, 350 }
  local coins = coins
    if math.random() > 0.5 then
        f = "#platform_long_factory"
        coins = coins * 2 -- Twice the number of coins on long platforms
    end

function init(self)
    msg.post("ground/controller#script", "set_speed", { speed = self.speed })
    self.gridw = 0
    self.spawns = {} 
end

function update(self, dt)
    self.gridw = self.gridw + self.speed

    if self.gridw >= grid then
        self.gridw = 0

        -- Maybe spawn a platform at random height
        if math.random() > 0.2 then
            local h = platform_heights[math.random(#platform_heights)]
            local f = "#platform_factory"
            if math.random() > 0.5 then
                f = "#platform_long_factory"
            end

            local p = factory.create(f, vmath.vector3(1600, h, 0), nil, {}, 0.6)
             msg.post(p, "set_speed", { speed = self.speed })
    msg.post(p, "create_coins", { coins = coins })
    table.insert(self.spawns, p)
    
        end
    end
end

function on_message(self, message_id, message, sender)
    if message_id == hash("reset") then 
        -- Tell the hero to reset.
        msg.post("hero#script", "reset")
        -- Delete all platforms
        for i,p in ipairs(self.spawns) do
            go.delete(p)
        end
        self.spawns = {}
    elseif message_id == hash("delete_spawn") then 
        for i,p in ipairs(self.spawns) do
            if p == message.id then
                table.remove(self.spawns, i)
                go.delete(p)
            end
        end
    end
end

Platform.script:

function init(self)
    self.speed = 9      -- Default speed
    self.coins = {}
end

function final(self)
    for i,p in ipairs(self.coins) do
        go.delete(p)
    end
end

function update(self, dt)
    local pos = go.get_position()
    if pos.x < -500 then
        msg.post("/level/controller#script", "delete_spawn", { id = go.get_id() })
    end
    pos.x = pos.x - self.speed
    go.set_position(pos)
end

function create_coins(self, params)
    local spacing = 56
    local pos = go.get_position()
    local x = pos.x - params.coins * (spacing*0.5) - 24
    for i = 1, params.coins do
        local coin = factory.create("#coin_factory", vmath.vector3(x + i * spacing , pos.y + 64, 1))
        msg.post(coin, "set_parent", { parent_id = go.get_id() }) 
        msg.post(coin, "start_animation", { delay = i/10 }) 
        table.insert(self.coins, coin)
    end
end

function on_message(self, message_id, message, sender)
    if message_id == hash("set_speed") then
        self.speed = message.speed
    elseif message_id == hash("create_coins") then
        create_coins(self, message)
    end
end

Hmm, I believe there’s a typo in the tutorial. Could you try changing this line back:

-- controller.script
local coins = 3

Otherwise you’ll simply store a nil value into that variable, and continue to send that along.

Also, when debugging, since you know where from the message is passed, and what it should contain, you can print out the value

1 Like

Ah, yes, I remember someone else coming across the same thing… @sicher, update needed!

i managed to get 3 coins on platform, but also only 3 coins on platform_long

You have to add some code where random selection of platform type is done

            if math.random() > 0.5 then
                f = "#platform_long_factory"
                coins = coins * 2
            end

i already have that, but its still not spawning coinsx2 for platform_long

go.property("speed", 6)

local grid = 460
local platform_heights = { 100, 200, 350 }
local coins = 3
if math.random() > 0.5 then
    f = "#platform_long_factory"
    coins = coins * 2
end

No, the problem is not local coins = coins. You have added code in the wrong place, particularly the top of the file is wrongly placed:

local grid = 460
local platform_heights = { 100, 200, 350 }
  local coins = coins
    if math.random() > 0.5 then
        f = "#platform_long_factory"
        coins = coins * 2 -- Twice the number of coins on long platforms
    end

Here is what controller.lua should look like after the last step. I have added annotations for the last 3 edits; (1) (2) and (3) below:

go.property("speed", 6)

local grid = 460
local platform_heights = { 100, 200, 350 }
local coins = 3                     -- (1)  A local containing the base number of coins 

function init(self)
    msg.post("ground/controller#script", "set_speed", { speed = self.speed })
    self.gridw = 0
    self.spawns = {} 
end

function update(self, dt)
    self.gridw = self.gridw + self.speed

    if self.gridw >= grid then
        self.gridw = 0

        -- Maybe spawn a platform at random height
        if math.random() > 0.2 then
            local h = platform_heights[math.random(#platform_heights)]
            local f = "#platform_factory"
            local coins = coins                 -- (2) Make a new local var defaulting to the base number of coins defined at (1)
            if math.random() > 0.5 then
                f = "#platform_long_factory"
                coins = coins * 2                 -- (2) Twice the number of coins on long platforms
            end

            if math.random() > 0.5 then
                f = "#platform_long_factory"
            end

            local p = factory.create(f, vmath.vector3(1600, h, 0), nil, {}, 0.6)
            msg.post(p, "set_speed", { speed = self.speed })
            msg.post(p, "create_coins", { coins = coins })          -- (3) Send message to platform to create coins.
            table.insert(self.spawns, p)
        end
    end
end

function on_message(self, message_id, message, sender)
    if message_id == hash("reset") then 
        -- Tell the hero to reset.
        msg.post("hero#script", "reset")
        -- Delete all platforms
        for i,p in ipairs(self.spawns) do
            go.delete(p)
        end
        self.spawns = {}
    elseif message_id == hash("delete_spawn") then 
        for i,p in ipairs(self.spawns) do
            if p == message.id then
                table.remove(self.spawns, i)
                go.delete(p)
            end
        end
    end
end
1 Like

You can download or browse working code from our “defold-examples” github. Here’s the runner project: https://github.com/defold/defold-examples/tree/master/runner

1 Like

that fixed it…thanks for that