Alex Gold
Alex Gold

Reputation: 21

Lua Error "Attempt to call method '' (a nil Value)

I wanted to make a 2D-Platformer (with the Love2D-Framework) and have a main.lua-file select random maps from a states folder. To start with that, i just said that the main-main.lua should open the main.lua-file in /states/map1/. But every time I try to run it, i get this Error-Message:

Error

states/map1/main.lua:169: attempt to call method 'update' (a nil value)

Traceback

states/map1/main.lua:169: in function 'update' [C]: in function 'xpcall'

The main-main.lua-code:

function clearLoveCallbacks()
    love.draw = nil
    love.joystickpressed = nil
    love.joystickreleased = nil
    love.keypressed = nil
    love.keyreleased = nil
    --love.load = nil
    love.mousepressed = nil
    love.mousereleased = nil
    love.update = nil
end

state = {}
function loadState(name)
    state = {}
    clearLoveCallbacks()
    local path = "states/" .. name
    require(path .. "/main")
    load()
    local player
end

function load()
end

function love.load()
    loadState("map1")
end

The main.lua in the /states/map1/-file:

player = table
local AdvTiledLoader = require("AdvTiledLoader.Loader")
require("camera")

function love.load()
    love.graphics.setBackgroundColor( 198, 220, 255 )
    song1 = love.audio.newSource("sound/Brightly_Fancy.mp3", true)
    song1:setVolume(0.1)
    song1:play()

    imgPlayer = love.graphics.newImage("textures/player.png") 
    AdvTiledLoader.path = "maps/"
    map = AdvTiledLoader.load("map1.tmx") 
    map:setDrawRange(0, 0, map.width * map.tileWidth, map.height * map.tileHeight)

    camera:setBounds(0, 0, map.width * map.tileWidth - love.graphics.getWidth(), map.height * map.tileHeight - love.graphics.getHeight() )

    world =     {
                gravity = 1536,  --1536
                ground = 512,
                }

    player =    {
                x = 256,
                y = 256,
                x_vel = 0,
                y_vel = 0,
                jump_vel = -1024,
                speed = 512, --512
                flySpeed = 700,
                state = "",
                h = 32,
                w = 32,
                standing = false,
                }
    function player:jump()
        if self.standing then
            self.y_vel = self.jump_vel
            self.standing = false
        end
    end

    function player:right()
        self.x_vel = self.speed
    end

    function player:left()
        self.x_vel = -1 * (self.speed)
    end

    function player:stop()
        self.x_vel = 0
    end

    function player:collide(event)
        if event == "floor" then
            self.y_vel = 0
            self.standing = true
        end
        if event == "cieling" then
            self.y_vel = 0
        end
    end

    function player:update(dt)
        local halfX = self.w / 2
        local halfY = self.h / 2

        self.y_vel = self.y_vel + (world.gravity * dt)

        self.x_vel = math.clamp(self.x_vel, -self.speed, self.speed)
        self.y_vel = math.clamp(self.y_vel, -self.flySpeed, self.flySpeed)

        local nextY = self.y + (self.y_vel*dt)
        if self.y_vel < 0 then
            if not (self:isColliding(map, self.x - halfX, nextY - halfY))
                and not (self:isColliding(map, self.x + halfX - 1, nextY - halfY)) then
                self.y = nextY
                self.standing = false
            else
                self.y = nextY + map.tileHeight - ((nextY - halfY) % map.tileHeight)
                self:collide("cieling")
            end
        end
        if self.y_vel > 0 then
            if not (self:isColliding(map, self.x-halfX, nextY + halfY))
                and not(self:isColliding(map, self.x + halfX - 1, nextY + halfY)) then
                    self.y = nextY
                    self.standing = false
            else
                self.y = nextY - ((nextY + halfY) % map.tileHeight)
                self:collide("floor")
            end
        end

        local nextX = self.x + (self.x_vel * dt)
        if self.x_vel > 0 then
            if not(self:isColliding(map, nextX + halfX, self.y - halfY))
                and not(self:isColliding(map, nextX + halfX, self.y + halfY - 1)) then
                self.x = nextX
            else
                self.x = nextX - ((nextX + halfX) % map.tileWidth)
            end
        elseif self.x_vel < 0 then
            if not(self:isColliding(map, nextX - halfX, self.y - halfY))
                and not(self:isColliding(map, nextX - halfX, self.y + halfY - 1)) then
                self.x = nextX
            else
                self.x = nextX + map.tileWidth - ((nextX - halfX) % map.tileWidth)
            end
        end

        self.state = self:getState()
    end

    function player:isColliding(map, x, y)
        local layer = map.tl["Solid"]
        local tileX, tileY = math.floor(x / map.tileWidth), math.floor(y / map.tileHeight)
        local tile = layer.tileData(tileX, tileY)
        return not(tile == nil)
    end

    function player:getState()
        local tempState = ""
        if self.standing then
            if self.x_vel > 0 then
                tempState = "right"
            elseif self.x_vel < 0 then
                tempState = "left"
            else
                tampState = "stand"
            end
        end
        if self.y_vel > 0 then
            tempState = "fall"
        elseif self.y_vel < 0 then
            tempState = "jump"
        end
        return tempState
    end
end

function love.draw()
    camera:set()

    love.graphics.setColor( 255, 255, 255, 255 )
    love.graphics.draw( imgPlayer, player.x - player.w/2, player.y - player.h/2, 0, 1, 1, 0, 0)
    love.graphics.setColor( 255, 255, 255 )
    map:draw()

    camera:unset()
end

function love.update(dt)
    if dt > 0.05 then
        dt = 0.05
    end
    if love.keyboard.isDown("d") then
        player:right()
    end
    if love.keyboard.isDown("a") then
        player:left()
    end
    if love.keyboard.isDown("w") then --and not (hasJumped) then
        player:jump()   
    end

    player:update(dt) 

    camera:setPosition( player.x - (love.graphics.getWidth()/2), player.y - (love.graphics.getHeight()/2))
end

function love.keyreleased(key)
    if (key == "a") or (key == "d") then
        player.x_vel = 0
    end
end

I really dont know what the problem is :/

Upvotes: 2

Views: 6635

Answers (1)

Paul Kulchenko
Paul Kulchenko

Reputation: 26744

Your code is not going to work the way you think it works. You call love.load that then loads map specific file that sets its own love.load and love.update. This overwrites love.load you had before, but that change has no effect as love.load is called only once, so the map-specific initialization you have there is not executed, but map-specific love.update code is executed, but fails as it's missing the initialization part. You need to restructure your code such that you only have one love.load and love.update, but they call map-specific functions as needed. I suggest you look at examples of some love2d games to see how they are organized.

Upvotes: 1

Related Questions