Need help with an error

I am getting this error:

error: [string “–tween.lua…”]:472 :attempt to perform arithmetic on local ‘d’ (a nil value)

I didn’t use d as a variable in my code. Can someone explain what this means?

And here is my code:

function setup()

    
    supportedOrientations(CurrentOrientation)
    
    
    boy = vec2(300,70)
    eb = vec2(0,70) --enemy bug
    
    lcx1 = 150 -- Large Crate 1 x
    lcy1 = 170 -- Large Crate 1 y
    lcx2 = 370 -- Large Crate 2 x
    lcy2 = 370 -- Large Crate 2 y
     dx2 = 5   -- Mine Spiked deltax

 
    msx = 400  -- Mine Spiked x
    msy = 530  -- Mine Spiked y
    
    parameter.watch("delta_x")
end

function draw()
   
    background()
    
    sprite("SpaceCute:Background",374,374)
    
    sprite("Cargo Bot:Title Large Crate 1",lcx1,lcy1)
    
    sprite("Cargo Bot:Title Large Crate 2",lcx2,lcy2)

    sprite("Planet Cute:Enemy Bug",eb.x,eb.y)  
    
    sprite("Tyrian Remastered:Mine Spiked Huge",msx,msy)
    
    sprite("Platformer Art:Cloud 3",600,600)
    
    sprite("Planet Cute:Character Cat Girl",600,650)
    
    sprite("Planet Cute:Character Boy",boy.x,boy.y)
    
    msx = msx + dx2
    if msx >= WIDTH - 50 then dx2 = -dx2 end 
    if msx <= 50 then dx2 = -dx2 end
    if math.abs(eb.x-boy.x)<=65 and math.abs(eb.y-boy.y)<=10 then
    tween.stopAll()
    else tween(4.0, eb, {WIDTH-50,70},tween.easing.linear,tween.loop.forever) end
    
    
    
    
    if eb.x-65<=boy.x and boy.x<=eb.x+65 and eb.y-10<=boy.y and boy.y<=eb.y+10 then
        
        
        
    background()
    font("Futura-Medium")
    fontSize(40)
    textWrapWidth(150)
    text("GAME OVER", 350,450)
 
    w,h = textSize("RESTART")
   
    fill(120,0,40)
    strokeWidth(2)
    rectMode(CENTER)
    rect(350,250,w+15,h-50)
    fontSize(30)
    fill(255)
    text("RESTART",350,250)
    end

    stroke(37, 202, 38, 255)
    strokeWidth(10)
    line(0,10,WIDTH,10)
    
end
    
function touched(touch)
        
         delta_x = touch.deltaX
        
        
    
        if delta_x < 0 then boy.x = boy.x - 10 end
        if delta_x > 0 then boy.x = boy.x + 10 end
    
        if touch.deltaY > 6 and boy.y == 70 and math.abs(eb.x-boy.x)>65 then
        sound(SOUND_JUMP, 32003) 
        
         
      
        t1 =  tween(0.35, boy, {y=300}, tween.easing.expoOut)
        t2 =  tween(0.35, boy, {y=70}, tween.easing.expoInOut)
        
        tween.sequence(t1,t2) 
        end
        
        if eb.x-65<=boy.x and boy.x<=eb.x+65 and eb.y-10<=boy.y and boy.y<=eb.y+10 then
        
           if touch.x<=450 and touch.x>=250 and touch.y<=300 and touch.y>200 then
         tween.resetAll() else tween.stopAll() end
        end
        
              
        
  
end

It means that you’ve passed something to a tween function that it didn’t expect. d is just the internal name for whatever it was. Look carefully through your code to see if you either pass a nil or forget to pass something to a tween function.

Thanks but I have ran over the code many times, still I can’t see the mistake.

Assuming the tween library is the same as one I found on the web, then d internally will be duration. I also played with your game and it’s a bit intermittent to get it to crash… Addint loads of print statements it seems to die in the draw loop…

I think you might be hitting a bug in tween, rather than something you’ve written.

One thing I noticed is that you’re constantly calling tween routines in draw. You should create a tween once, let it do it’s thing, and when it’s done call it again. If you need to stop a tween that’s running, call tween.stop . It looks like you need to review what you’re trying to do with the Tweens.
The error you’re getting is probably because of tween calls on Tweens that aren’t running anymore.

.@inancyuce Here is a simple example of what I was trying to explain above about creating a tween, letting it do it’s thing, and creating it again if needed.

EDIT: changed tween.easing.linear to tween.easing.cubicOut and cubicIn.


supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)

function setup()
    val=2
    done=true
    cb={x=60,y=50}
end

function setupTween()
    t1=tween(.5,cb,{y=600},tween.easing.cubicOut)
    t2=tween(.5,cb,{y=100},tween.easing.cubicIn,tweenDone)
    tween.sequence(t1,t2)   
end

function draw()
    background(40, 40, 50)
    fill(255)
    if done then
        text("Tap screen to jump",WIDTH/2,700)
    end
    if cb.x<50 or cb.x>WIDTH-50 then    -- keep sprite on the screen
        val=- val
    end
    cb.x=cb.x+val    -- move sprite 
    sprite("Planet Cute:Character Boy",cb.x,cb.y)    -- draw sprite
end

function tweenDone()
    done=true   -- tween is done, allow next tween
end

function touched(t)
    if t.state==BEGAN and done then    -- if tween is done, allow another
        done=false
        setupTween()    -- start the next tween
    end
end

Thank you guys. I reviewed my code as you told and I discovered that when I erase the tween.loop part I didn’t get the same error so space monkey is probably right about the bug. There’s something wrong with tween.loop. Anyway, I changed my code as the following and achieved what I was trying for.

Next thing I need to do is make the crates solid. It would be nice if you gave me a hint about how to do it in an easy way. I guess I will need to implement physics bodies into my code, right?

function setup()

    
    supportedOrientations(CurrentOrientation)
    
      sm = vec2(50,530) -- spiked mine
      dx = 5 -- delta x of spiked mine 
     boy = vec2(300,70) -- boy
    lcx1 = 150 -- Large Crate 1 x
    lcy1 = 170 -- Large Crate 1 y
    lcx2 = 370 -- Large Crate 2 x
    lcy2 = 370 -- Large Crate 2 y
     ebx = 0   -- enemy bug x
     eby = 70  -- enemy bug y
 
   delta_x = 0
   delta_y = 0

end


function draw()
   
    background()
    
    sprite("SpaceCute:Background",374,374)
    
    sprite("Cargo Bot:Title Large Crate 1",lcx1,lcy1)
    
    sprite("Cargo Bot:Title Large Crate 2",lcx2,lcy2)

    sprite("Planet Cute:Enemy Bug",ebx,eby)  
    
    sprite("Tyrian Remastered:Mine Spiked Huge",sm.x,sm.y)
    
    sprite("Platformer Art:Cloud 3",600,600)
    
    sprite("Planet Cute:Character Cat Girl",600,650)
    
    sprite("Planet Cute:Character Boy",boy.x,boy.y)
    
    stroke(37, 202, 38, 255)
    strokeWidth(10)
    line(0,10,WIDTH,10)
    
    sm.x = sm.x + dx
    if sm.x >= WIDTH - 50 then dx = -dx end
    if sm.x <= 50 then dx = -dx end
    
    if math.abs(ebx-boy.x)<=65 and math.abs(eby-boy.y)<=10 then
        
    background()
    font("Futura-Medium")
    fontSize(40)
    textWrapWidth(150)
    text("GAME OVER", 350,450)
 
    w,h = textSize("RESTART")
   
    fill(120,0,40)
    strokeWidth(2)
    rectMode(CENTER)
    rect(350,250,w+15,h-50)
    fontSize(30)
    fill(255)
    text("RESTART",350,250)
    
    else ebx = ebx + 4
         if ebx >= WIDTH - 50 then ebx = 0 end
    end
    
end
    

function touched(touch)
    
        delta_x = touch.deltaX
        delta_y = touch.deltaY
        
        if delta_x < 0 then boy.x = boy.x - 10 end
        if delta_x > 0 then boy.x = boy.x + 10 end
    
        if touch.deltaY > 6 and boy.y == 70 and math.abs(ebx-boy.x)>65 then
        sound(SOUND_JUMP, 32003) 
        
        t1 =  tween(0.35, boy, {y=300}, tween.easing.expoOut)
        t2 =  tween(0.35, boy, {y=70}, tween.easing.expoInOut)
        
        tween.sequence(t1,t2) 
       
        end
    
         if math.abs(ebx-boy.x)<=65 and math.abs(eby-boy.y)<=10 then 
         
         ebx = ebx
         boy.x = ebx
         boy.y = eby
            
             if touch.x<=450 and touch.x>=250 and touch.y<=300 and touch.y>200 then
             ebx = 0  boy.x = 300 
             end
         
         end
        
end

You could write some collision detection and make your character stand on the box if the jump collides on its way down. Then have the collision detection set the players y to the top of the box.

Thanks for the hint. I tried this but it didn’t work although it didn’t give an error.


function collide(contact)
    
    lc1edge = physics.body(EDGE, vec2(97,170), vec2(203,170))
    boyedge = physics.body(DYNAMIC, vec2(boy.x-50,boy.y-85), vec2(boy.x+50,boy.y-85))
    if lc1edge:testOverlap(boyedge) then boy.y = 170 end

end     

Any more suggestions?

Instead of trying to do collisions, just keep track of the top edge of the crates. When the characters x,y position is in the correct area, then set the characters position.

@dave1707 yeah thats what I was trying to say :slight_smile: When i said collision I was not referring to physics bodies. wrtie your own function to check if the bottom of your character sprite is on the top of the crate and set coords accordingly

I am going to use an if statement as the following but in which function will I put it? And how will I assure that this is true only when the boy is falling down?

function()

if boy.x <= 200 and boy.x >= 100 and boy.y == 220  
        then boy.y = 220 end

end

Place it in the draw function, or create a function and put the call in draw. Add a function to compare the current boy.y with the previous boy.y values. If the current boy.y is less that the previous boy.y, the boy is falling. You also have a lot of changes to make to your code. The tween y value is always 300 and 70. If the boy jumps from a crate, those values need to be adjusted for the crate height. Also, you’re constantly creating Tweens in you touch function. You need to create a tween once, let it finish or stop it, before creating the tween again. See the example code I showed you above on how to create a tween, let it run, and create it again.

Ok, I will do that. finally can you show me an example of how to create an arbitrary function for an arbitrary purpose? Is my syntax correct above?

Here’s some examples


-- add this line to setup
    prevY=0

-- add this if statement at the end of the draw function

    if falling() then  -- boy is falling
        if boy.x>lcx1-50 and boy.x<lcx1+50 and boy.y<lcy1+120 then
            tween.stopAll()  -- stop the tween
            boy.y=lcy1+100  -- set boy y value
            prevY=0  -- zero prevY
        end
    end

end  -- last end of draw

-- add this function anywhere

function falling()  -- check if boy is falling
    if boy.y<prevY then
        prevY=boy.y
        return true
    else
        prevY=boy.y
        return false
    end    
end

I have modified my code according to your instructions Dave, I am grateful for all your help but the crate is still not solid. Where am I doing wrong?



supportedOrientations(LANDSCAPE_ANY)
    
function setup()

      sm = vec2(50,530) -- spiked mine
      dx = 5 -- delta x of spiked mine 
     boy = vec2(300,70) -- boy
     lc1 = vec2(150,170) -- Large Crate 1 
     lc2 = vec2(370,370) -- Large Crate 2
    
     ebx = 0   -- enemy bug x
     eby = 70  -- enemy bug y
 
     delta_x = 0 -- variable to be used for moving right or left
     delta_y = 0 -- variable to be used for jumping

     prevY = 0 -- used in falling function
     done = true -- used in tweenDone function
   
end

function tweenDone()   
    done = true
end 

function setupTween()
    
     t1 =  tween(0.35, boy, {y = boy.y + 230}, tween.easing.cubicOut)
     t2 =  tween(0.35, boy, {y = boy.y}, tween.easing.cubicIn, tweenDone)
     tween.sequence(t1,t2) 

end
    

function falling() -- check if boy is falling
    
    if boy.y < prevY then
       prevY = boy.y
       return true
    else prevY = boy.y
       return false
    end

end    


function draw()
   
    background()
    
    sprite("SpaceCute:Background",374,374)
    
    sprite("Cargo Bot:Title Large Crate 1",lc1.x,lc1.y)
    
    sprite("Cargo Bot:Title Large Crate 2",lc2.x,lc2.y)

    sprite("Planet Cute:Enemy Bug",ebx,eby)  
    
    sprite("Tyrian Remastered:Mine Spiked Huge",sm.x,sm.y)
    
    sprite("Platformer Art:Cloud 3",600,600)
    
    sprite("Planet Cute:Character Cat Girl",600,650)
    
    sprite("Planet Cute:Character Boy",boy.x,boy.y)
    
    stroke(37, 202, 38, 255)
    strokeWidth(10)
    line(0,10,WIDTH,10) -- ground line
    
    sm.x = sm.x + dx -- spiked mine is constantly moving right and left
    if sm.x >= WIDTH - 50 or sm.x <= 50 then dx = -dx end
    
    if math.abs(ebx-boy.x)<=65 and math.abs(eby-boy.y)<=10 then -- the condition when boy is eaten by enemy bug
        
    background()
    font("Futura-Medium")
    fontSize(40)
    textWrapWidth(150)
    text("GAME OVER", 350,450)
 
    w,h = textSize("RESTART")
   
    fill(120,0,40)
    strokeWidth(2)
    rectMode(CENTER)
    rect(350,250,w+15,h-50)
    fontSize(30)
    fill(255)
    text("RESTART",350,250)
    
    ebx = ebx
    boy.x = ebx
    boy.y = eby
    
    else ebx = ebx + 4 -- enemy bug is constantly moving from point x=0 to right 
        if ebx >= WIDTH - 50 then ebx = 0 end
        
    end
    
    if falling() then -- trying to land the boy on the surface of large crate 1 while falling on it.(not working)
        if boy.x >= lc1.x-53 and boy.x <= lc1.x+53 and boy.y == lc1.y+120 then 
        tween.stopAll()  
        boy.y = lc1.y + 120
        prevY = 0 
        end
    end
        
end
    

function touched(touch)
    
        delta_x = touch.deltaX
        delta_y = touch.deltaY
        
        if delta_x < 0 then boy.x = boy.x - 10 end -- for moving left on left drag of touch
        if delta_x > 0 then boy.x = boy.x + 10 end -- for moving right on right drag of touch
    
        if touch.deltaY > 6 and math.abs(ebx-boy.x)>65 and done then -- for jump with up drag of touch
        sound(SOUND_JUMP, 32003) 
        done = false
        setupTween() -- calling the next tween(jump) after previous one is done
       
       end
    
        if math.abs(ebx-boy.x)<=65 and math.abs(eby-boy.y)<=10 then -- when game over screen comes
         
           if touch.x<=450 and touch.x>=250 and touch.y<=300 and touch.y>200 then -- for touching restart button
              ebx = 0  boy.x = 300 sound(SOUND_PICKUP, 607)
           end
         
        end
        
end

Change the if falling() statement to what’s below. You had >=, <=, and == . It was very unlikely that you would hit the == condition. I originally had it as >, <, and < in the above post. This will land the boy on the crate, but there is still a lot more that has to be done because the boy doesn’t do anything but move side to side after that. I’ll post more code later to help you out, but you can try making changes if you want.


    if falling() then
        if boy.x > lc1.x-53 and boy.x < lc1.x+53 and boy.y < lc1.y+120 then 
           tween.stopAll()  
           boy.y = lc1.y + 100
           prevY = 0 
        end
    end

Look over this code to see what I did. You’ll still have to fix some things for what you want. I added code for when the boy collides with the mine and when the boy reaches the girl. You’ll have to create functions for what you want to do with those conditions.


supportedOrientations(LANDSCAPE_ANY)

function setup()
    tx1=300
    tx2=70

     sm = vec2(50,530) -- spiked mine
     dx = 5 -- delta x of spiked mine 
     boy = vec2(300,70) -- boy
     lc1 = vec2(150,170) -- Large Crate 1 
     lc2 = vec2(370,370) -- Large Crate 2

     ebx = 0   -- enemy bug x
     eby = 70  -- enemy bug y

     delta_x = 0 -- variable to be used for moving right or left
     delta_y = 0 -- variable to be used for jumping

     prevY = 0 -- used in falling function
     done = true -- used in tweenDone function
     done3=true
end

function tweenDone()   
    done = true
end 

function tween3Done()
    done3=true
end

function setupTween()
     t1 =  tween(0.35, boy, {y = tx1}, tween.easing.cubicOut)
     t2 =  tween(0.35, boy, {y = tx2}, tween.easing.cubicIn, tweenDone)
     tween.sequence(t1,t2) 
end

function setupTween3()
    if done3 then
        done3=false
        t3 =  tween(0.35, boy, {y = 70}, tween.easing.cubicIn, tween3Done)
    end
end


function falling() -- check if boy is falling
    if boy.y < prevY then
       prevY = boy.y
       return true
    else prevY = boy.y
       return false
    end
end    

function draw()
    background()
    sprite("SpaceCute:Background",374,374)
    sprite("Cargo Bot:Title Large Crate 1",lc1.x,lc1.y)
    sprite("Cargo Bot:Title Large Crate 2",lc2.x,lc2.y)
    sprite("Planet Cute:Enemy Bug",ebx,eby)  
    sprite("Tyrian Remastered:Mine Spiked Huge",sm.x,sm.y)
    sprite("Platformer Art:Cloud 3",600,600)
    sprite("Planet Cute:Character Cat Girl",600,650)
    sprite("Planet Cute:Character Boy",boy.x,boy.y)
    stroke(37, 202, 38, 255)
    strokeWidth(10)
    line(0,10,WIDTH,10) -- ground line
    sm.x = sm.x + dx -- spiked mine is constantly moving right and left
    if sm.x >= WIDTH - 50 or sm.x <= 50 then
        dx = -dx 
    end
    
    -- check if boy and spiked mine collide
    if math.abs(boy.x-sm.x)<50 and math.abs(boy.y-sm.y)<50 then
        print("mine collision")    -- call your function for the collision
    end
    
    if math.abs(ebx-boy.x)<=65 and math.abs(eby-boy.y)<=10 then
        -- the condition when boy is eaten by enemy bug
        background()
        font("Futura-Medium")
        fontSize(40)
        textWrapWidth(150)
        text("GAME OVER", 350,450)
        w,h = textSize("RESTART")
        fill(120,0,40)
        strokeWidth(2)
        rectMode(CENTER)
        rect(350,250,w+15,h-50)
        fontSize(30)
        fill(255)
        text("RESTART",350,250)
    else
        ebx = ebx + 4 -- enemy bug is constantly moving from point x=0 to right 
        if ebx >= WIDTH - 50 then
            ebx = 0
        end
    end
    
    if falling() or done then
        if boy.x > lc1.x-53 and boy.x < lc1.x+53 and boy.y > lc1.y+100 and boy.y < lc1.y+120 then 
            if not done then 
                tween.stopAll() 
            end 
            done=true
            boy.y = lc1.y + 105
            tx1=500
            tx2=70
        elseif boy.x > lc2.x-53 and boy.x < lc2.x+53 and boy.y>lc2.y+100 and boy.y < lc2.y+120 then 
            if not done then 
                tween.stopAll() 
            end
            done=true
            boy.y = lc2.y + 105
            tx1=800
            tx2=70
        elseif boy.x > 530 and boy.x < 680 and boy.y>620 and boy.y < 650 then 
            if not done then 
                tween.stopAll() 
                print("girl reached")    -- add your function here
            end          
            done=true
            boy.y = 625
            tx1=625
            tx2=70
        else
            tx1=300
            tx2=70
            if boy.y>70 and done then
                setupTween3()
            end
        end
    end
end

function touched(touch)
    delta_x = touch.deltaX
    delta_y = touch.deltaY
    if delta_x < 0 then
        boy.x = boy.x - 10 
    end -- for moving left on left drag of touch
    if delta_x > 0 then 
        boy.x = boy.x + 10 
    end -- for moving right on right drag of touch

    if touch.deltaY > 6 and math.abs(ebx-boy.x)>65 and done then 
        -- for jump with up drag of touch
        sound(SOUND_JUMP, 32003) 
        setupTween() -- calling the next tween(jump) after previous one is done
        done=false
    end

    if math.abs(ebx-boy.x)<=65 and math.abs(eby-boy.y)<=10 then 
        -- when game over screen comes
        if touch.x<=450 and touch.x>=250 and touch.y<=300 and touch.y>200 then 
            -- for touching restart button
            setup()
            sound(SOUND_PICKUP, 607)
        end
    end
end

Thanks Dave. I will study these for a while to understand what’s happening why. I didn’t understand why the if statement doesn’t work with == .