I don't understand "Attempting to index a nil value"

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
ponger3d
Prole
Posts: 6
Joined: Mon Jun 16, 2014 8:00 pm

I don't understand "Attempting to index a nil value"

Post by ponger3d »

I am making a simple ASCII game and I am now trying to implement wall detection. I have looked at multiple online forums and wikis attempting to make sense of what they are explaining, but I am just not quite comprehending it. Perhaps I am not on the same thinking pattern? What I am attempting to do is pass the stage outline, a 2D array of 1s and 0s to my player function and then checking the players position against the 2D array to see if the next tile will be a 0 or 1. The program runs, however, when I go to move I get this error:

Image

What I am actually attempting to do is below (Where I get "outline" from my stage.lua and pass it to my player.lua in the main.lua file)

stage.lua (EDIT: I added more of my stage.lua)

Code: Select all

stage = {}

function stage.load()

	--Unit Declaration 
	stage.w = 20
	stage.h = 20
	stage.unit_w = 10 
	stage.unit_h = 16
	stage.offset_x = 40
	stage.offset_y = 40

	--Stage Outline
	stage.outline = {
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
	}
end

function stage.get_outline()
	return stage.outline
end
main.lua

Code: Select all

player.get_outline(stage.get_outline())
player.lua

Code: Select all

function player.get_outline( outline )
	outline = outline  --Outline should be a 2D array
end

function player.keypressed( key )
	--Checks
	if key == "up" then
		if outline[player.y - 16 - 72][player.x] == 0 then --72 is the starting location of the player and 16 is the size of each tile (y-values)
			player.y = player.y - 16					   --58 is the starting location and 10 is the tile size (x-values)
		end
	end

	if key == "down" then
		if outline[player.y + 16 - 72][player.x] == 0 then
			player.y = player.y + 16
		end
	end

	if key == "left" then
		if outline[player.y][player.x - 10 - 58] == 0 then
			player.x = player.x - 10
		end
	end

	if key == "right" then
		if outline[player.y][player.x + 10 - 58] == 0 then
			player.x = player.x + 10
		end
	end
end
Below I have also attache the .love file. I feel like this should be right but am not quite sure what is messing up. Ive been messing up alot but I with yalls help and the wikis help ive been able to get a lot done. Thanks again for the help!
Attachments
dummy_game.love
(2.06 KiB) Downloaded 73 times
Last edited by ponger3d on Tue Jun 17, 2014 2:17 am, edited 2 times in total.
User avatar
Jasoco
Inner party member
Posts: 3726
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: I don't understand "Attempting to index a nil value"

Post by Jasoco »

Your outline variable isn't attached to your player or stage. You need to make it part of the player or stage object.

Look into using self.

For example:

Code: Select all

player = {}

function player:init()
    self.outline = whatever
    self.x = whatever
    self.y = whatever
end

function player:get_outline()
    return self.outline
end

...
Note: The colon implies the object being passed as the first argument, which self then refers to. If you use a period (player.get_outline) you'd have to pass player as the first argument. So the colon saves time and coding.
ponger3d
Prole
Posts: 6
Joined: Mon Jun 16, 2014 8:00 pm

Re: I don't understand "Attempting to index a nil value"

Post by ponger3d »

I am trying to make sense of what you are saying but I am still confused? When I try to attach the map to the stage object I still get the same error. Also I would like to keep the player and map files separate to help with later improvements I have planned.
Joemag
Prole
Posts: 24
Joined: Sun Apr 14, 2013 5:42 pm

Re: I don't understand "Attempting to index a nil value"

Post by Joemag »

In player.get_outline the line

Code: Select all

outline = outline
doesn't do anything. The variable is still local, so it doesn't exist in player.keypressed. This causes the error.
ponger3d
Prole
Posts: 6
Joined: Mon Jun 16, 2014 8:00 pm

Re: I don't understand "Attempting to index a nil value"

Post by ponger3d »

Ok, So I understand why the error is happening now, and it makes since why it is happening, but I can not figure out how to pass the stage.outline effectively to player.lua with out getting a nil error.

Now I am trying to just pass the outline directly to my player.keypressed() as an argument, but have yet to make it work.

My updated code:

stage.lua

Code: Select all

stage = {}

function stage.load()

	--Unit Declaration 
	stage.w = 20
	stage.h = 20
	stage.unit_w = 10 
	stage.unit_h = 16
	stage.offset_x = 40
	stage.offset_y = 40

	--Stage Outline
	stage.outline = {
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
	}

end

Code: Select all

function stage.get_outline()
	return stage.outline
end
main.lua

Code: Select all

function love.keypressed( key, unicode )

	player.keypressed( key, stage.get_outline() )

end
player.lua

Code: Select all

function player.keypressed( key, outline )

	--Checks
	if key == "up" then
		if outline[player.y - 16 - 72][player.x] == 0 then --72 is the starting location of the player and 16 is the size of each tile (y-values)
			player.y = player.y - 16					   --58 is the starting location and 10 is the tile size (x-values)
		end
	end

	if key == "down" then
		if outline[player.y + 16 - 72][player.x] == 0 then
			player.y = player.y + 16
		end
	end

	if key == "left" then
		if outline[player.y][player.x - 10 - 58] == 0 then
			player.x = player.x - 10
		end
	end

	if key == "right" then
		if outline[player.y][player.x + 10 - 58] == 0 then
			player.x = player.x + 10
		end
	end
end
User avatar
MadByte
Party member
Posts: 533
Joined: Fri May 03, 2013 6:42 pm
Location: Braunschweig, Germany

Re: I don't understand "Attempting to index a nil value"

Post by MadByte »

Your problem is this :

Code: Select all

if outline[player.y - 16 - 72][player.x] == 0 then
Basically you handle the table index values wrong. They aren't proper x and y values in pixels, instead they give you the position of the "tile" inside the table. so the first tile is at position self.map[1][1], the second horizontal is at self.map[2][1] ( vertical at self.map[1][2] ) and so on.

I'am bad at explaining stuff, so I wrote you some simple code:

Code: Select all

--------------------------
-- // Rougelike Test \\ --
--------------------------

------------------------
-- // Declarations \\ --
------------------------
local level = {}
local player = {}

-----------------
-- // LEVEL \\ --
-----------------
function level:init()
  -- 0 = Nothing
  -- 1 = Wall
  -- 2 = Player

  self.canvas = love.graphics.newCanvas(love.window.getWidth(), love.window.getHeight())

  self.tileW, self.tileH = 16, 16
	self.map = {
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
		{ 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1},
		{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
	}
  -- Update the canvas
  level:updateCanvas() 
end


function level:setTile(x, y, value)
  if self.map[x][y] then self.map[x][y] = value end
end


function level:updateCanvas()
  love.graphics.setCanvas(self.canvas)
  self.canvas:clear()
  for x = 1, #self.map do
    for y = 1, #self.map[1] do
      if self.map[x][y] == 1 then -- wall
        love.graphics.setColor(255, 0, 0, 255)
        love.graphics.print(".", x * self.tileW, y * self.tileH)
      elseif self.map[x][y] == 2 then -- player
        love.graphics.setColor(0, 255, 0, 255)
        love.graphics.print("#", x * self.tileW, y * self.tileH)
      end
    end
  end
  love.graphics.setColor(255, 255, 255, 255)
  love.graphics.setCanvas()
end


function level:draw()
  love.graphics.draw(self.canvas, 0, 0)
end


------------------
-- // PLAYER \\ --
------------------
function player:init()
  self.x = 2
  self.y = 2
  level:setTile(self.x, self.y, 2)
  level:updateCanvas()
end


function player:keypressed(key)
  if key == "up" and (level.map[self.x][self.y-1] ~= 1 or nil) then
    level:setTile(self.x, self.y, 0)
    self.y = self.y - 1
    level:setTile(self.x, self.y, 2)
  elseif key == "down" and (level.map[self.x][self.y+1] ~= 1 or nil) then
    level:setTile(self.x, self.y, 0)
    self.y = self.y + 1
    level:setTile(self.x, self.y, 2)
  elseif key == "left" and (level.map[self.x-1][self.y] ~= 1 or nil) then
    level:setTile(self.x, self.y, 0)
    self.x = self.x - 1
    level:setTile(self.x, self.y, 2)
  elseif key == "right" and (level.map[self.x+1][self.y] ~= 1 or nil) then
    level:setTile(self.x, self.y, 0)
    self.x = self.x + 1
    level:setTile(self.x, self.y, 2)
  end
  -- Update the canvas 
  level:updateCanvas()
end


-----------------------
-- // MAIN LOOPS \\ ---
-----------------------
function love.load()
  level:init()
  player:init()
end


function love.draw()
  level:draw()
end


function love.keypressed(key)
  player:keypressed(key)
  if key == "escape" then love.event.quit() end
end
example.love
(here as .love)

I used a canvas for performance reasons. It ony get updated if something changes ( player movement i.e ). This is to avoid the for loops inside the love.draw.

If you have any questions, feel free to ask.

EDIT
I made a little mistake while looping through the table, I interchanged x and y :)
Here is the code with the right direction:
exampleEdit.love
ponger3d
Prole
Posts: 6
Joined: Mon Jun 16, 2014 8:00 pm

Re: I don't understand "Attempting to index a nil value"

Post by ponger3d »

Thank you so much for the help! I looked at it for a little bit and eventually it made sense! I will use this to help me expand my game! Again I can't thank you enough! the Canvas stuff is still slightly confusing but I am getting it more as I look at the wiki.
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 8 guests