I have this kind of structure in my Corona code I am trying to convert but in the print line it errors with nill index value? What is the issue? The key parts are the Tile = {} andTile[counter] = {X=x, Y=y, Terrain=terrain, Cost=cost, VP=vp, Feature=feature, Owner=owner}. Then I should be able to reference that structure like;
What am I doing wrong?
function Map:draw()
print(self.Tile[1].Terrain)
end
Full class code below(Map is a class that has an array of Tiles and each tile has a property set):
Map = class()
function Map:init(FileName)
Tile = {}
local File = io.open(FileName)
local counter = 1
if File then -- nil if no file found
for Lines in File:lines() do
FileLine = Lines
local thistile = split(FileLine, ",")
local x = tonumber (thistile[1])
local y = tonumber (thistile[2])
local terrain = thistile[3]
local cost = tonumber (thistile[4])
local vp = thistile[5]
local feature = thistile[6]
local owner = thistile[7]
--local rivern = thistile[8]
--local rivere = thistile[9]
--local rivers = thistile[10]
--local riverw = thistile[11]
--local roadn = thistile[12]
--local roade = thistile[13]
--local roads = thistile[14]
--local roadw = thistile[15]
--self.Tile[x][y] = Tile()
--self.Tile[counter].Terrain = terrain
----self.Tile[counter].Image = sprite("Dropbox:desert")
--self.Tile[counter].Cost = cost
--self.Tile[counter].VP = vp
--self.Tile[counter].Feature = feature
--self.Tile[counter].Owner = owner
--self.Tile[x][y].RiverN = rivern
--self.Tile[x][y].RiverE = rivere
--self.Tile[x][y].RiverS = rivers
--self.Tile[x][y].RiverW = riverw
--self.Tile[x][y].RoadN = roadn
--self.Tile[x][y].RoadE = roade
--self.Tile[x][y].RoadN = roadn
--self.Tile[x][y].RoadW = roadw
Tile[counter] = {X=x, Y=y, Terrain=terrain, Cost=cost, VP=vp, Feature=feature, Owner=owner}
counter = counter + 1
end
io.close(file)
end
end
function Map:draw()
-- Codea does not automatically call this method
print(self.Tile[1].Terrain)
end
function Map:touched(touch)
-- Codea does not automatically call this method
end
function split(str, div)
if (div=='') then
return false
end
local pos,arr = 0,{}
-- for each divider found
for st,sp in function() return string.find(str,div,pos,true) end do
-- Attach chars left of current divider
table.insert(arr,string.sub(str,pos,st-1))
pos = sp + 1 -- Jump past current divider
end
-- Attach chars right of last divider
table.insert(arr,string.sub(str,pos))
return arr
end
thanks, fixed the code format. So why is my Map.Tile[1].Terrain variable set to nil when I populate it with this line that worked just find in Corona? I believe this is standard lua(been awhile since i created it):
@Gib I stripped out your commented code and the class information just to get a working example of your code. I replaced you data from a file with just a string. I’m only using one iteration so I set counter to 1 and didn’t bother to increment it. I printed out the Tile table for the 1 iteration and it looks like the correct info is in the table using your code. Is my example similar to what you’re trying to do.
function setup()
FileLine="123,234,terrain-1,300,vp-1,feature-1,owner-1"
Tile={}
counter=1
local thistile = split(FileLine, ",")
local x = tonumber (thistile[1])
local y = tonumber (thistile[2])
local terrain = thistile[3]
local cost = tonumber (thistile[4])
local vp = thistile[5]
local feature = thistile[6]
local owner = thistile[7]
Tile[counter] = {X=x, Y=y, Terrain=terrain, Cost=cost, VP=vp, Feature=feature, Owner=owner}
print(Tile[1].X)
print(Tile[1].Y)
print(Tile[1].Terrain)
print(Tile[1].Cost)
print(Tile[1].VP)
print(Tile[1].Feature)
print(Tile[1].Owner)
end
function split(str, div)
if (div=='') then
return false
end
local pos,arr = 0,{}
-- for each divider found
for st,sp in function() return string.find(str,div,pos,true) end do
-- Attach chars left of current divider
table.insert(arr,string.sub(str,pos,st-1))
pos = sp + 1 -- Jump past current divider
end
-- Attach chars right of last divider
table.insert(arr,string.sub(str,pos))
return arr
end
function setup()
print("Hi")
local file = "Dropbox:map1"
BattleMap = Map(file)
parameter.watch("counter")
parameter.watch("FileName")
end
function draw()
background(0,0,0)
BattleMap:draw()
end
Good idea on the single iteration. Is your setup function in your main when you tested this because its supposed to be a class and not in the main:setup function.
I’ll take out the filename pass(local file = “Dropbox:map1”) in my main:setup to eliminate a layer (dont know if that is how you point to a file?)
@Gib I took out the class code just to make it easy on me to try an see what was wrong with your code. You’ll keep it as a class for your code. From what I see so far, your code is working. Without having all your code, that makes it harder to figure out what’s not working.
I got a single iteration working. Is my file reading the issue? See where in my main:setup i set the path:filename - is that right for map1(a text file) that IS in my dropbox in the codea folder(even though codea doesnt show it)?
Then if that is right, what about my local File = io.open(FileName) in the Map:Init function?
@Gib What is the format of the file you’re reading. Does it contain multiple occurances of 7 items seperated by a comma similar to what I put in the test string I used. If I can create a file that’s similar, then I can use your code to read it and maybe see what’s happening.
ok after editing my last post, the forum format brings up the carriage return…
so after the word russian the 1,2,desert,2,1,none,german is the 2nd line
@Gib Missed my post. This is the code it should be:
Map = class()
function Map:init(FileName)
self.Tile = {} -- Change: added self.
local File = io.open(FileName)
local counter = 1
if File then -- nil if no file found
for Lines in File:lines() do
FileLine = Lines
local thistile = split(FileLine, ",")
local x = tonumber (thistile[1])
local y = tonumber (thistile[2])
local terrain = thistile[3]
local cost = tonumber (thistile[4])
local vp = thistile[5]
local feature = thistile[6]
local owner = thistile[7]
--local rivern = thistile[8]
--local rivere = thistile[9]
--local rivers = thistile[10]
--local riverw = thistile[11]
--local roadn = thistile[12]
--local roade = thistile[13]
--local roads = thistile[14]
--local roadw = thistile[15]
--self.Tile[x][y] = Tile()
--self.Tile[counter].Terrain = terrain
----self.Tile[counter].Image = sprite("Dropbox:desert")
--self.Tile[counter].Cost = cost
--self.Tile[counter].VP = vp
--self.Tile[counter].Feature = feature
--self.Tile[counter].Owner = owner
--self.Tile[x][y].RiverN = rivern
--self.Tile[x][y].RiverE = rivere
--self.Tile[x][y].RiverS = rivers
--self.Tile[x][y].RiverW = riverw
--self.Tile[x][y].RoadN = roadn
--self.Tile[x][y].RoadE = roade
--self.Tile[x][y].RoadN = roadn
--self.Tile[x][y].RoadW = roadw
self.Tile[counter] = {X=x, Y=y, Terrain=terrain, Cost=cost, VP=vp, Feature=feature, Owner=owner} -- Change: added self.
counter = counter + 1
end
io.close(file)
end
end
function Map:draw()
-- Codea does not automatically call this method
print(self.Tile[1].Terrain)
end
function Map:touched(touch)
-- Codea does not automatically call this method
end
function split(str, div)
if (div=='') then
return false
end
local pos,arr = 0,{}
-- for each divider found
for st,sp in function() return string.find(str,div,pos,true) end do
-- Attach chars left of current divider
table.insert(arr,string.sub(str,pos,st-1))
pos = sp + 1 -- Jump past current divider
end
-- Attach chars right of last divider
table.insert(arr,string.sub(str,pos))
return arr
end
Here is main and map latest version with your changes. It still fails to print the values but i get a new error: error: [string “Map = class()…”]:9: attempt to index local ‘File’ (a nil value)
--Main:
function setup()
file = "Dropbox:map1.txt"
BattleMap = Map(file)
end
function draw()
background(0,0,0)
end
--Map:
Map = class()
function Map:init(FileName)
self.Tile = {}
counter = 1
local File = io.open(FileName)
for Lines in File:lines() do
FileLine = Lines
print(FileLine)
local thistile = split(FileLine, ",")
self.Tile[counter] = {}
local x = tonumber (thistile[1])
local y = tonumber (thistile[2])
local terrain = thistile[3]
local cost = tonumber (thistile[4])
local vp = thistile[5]
local feature = thistile[6]
local owner = thistile[7]
self.Tile[counter] = {X=x, Y=y, Terrain=terrain, Cost=cost, VP=vp, Feature=feature, Owner=owner}
print(self.Tile[1].X)
print(self.Tile[1].Y)
print(self.Tile[1].Terrain)
print(self.Tile[1].Cost)
print(self.Tile[1].VP)
print(self.Tile[1].Feature)
print(self.Tile[1].Owner)
counter = counter + 1
end
io.close(File)
end
function Map:draw()
-- Codea does not automatically call this method
end
function Map:touched(touch)
-- Codea does not automatically call this method
end
function split(str, div)
if (div=='') then
return false
end
local pos,arr = 0,{}
-- for each divider found
for st,sp in function() return string.find(str,div,pos,true) end do
-- Attach chars left of current divider
table.insert(arr,string.sub(str,pos,st-1))
pos = sp + 1 -- Jump past current divider
end
-- Attach chars right of last divider
table.insert(arr,string.sub(str,pos))
return arr
end
--main:
function setup()
file = os.getenv("HOME").."/Documents/Dropbox.spritepack/map1.txt"
BattleMap = Map(file)
end
function draw()
background(0,0,0)
--BattleMap:draw()
end
Map = class()
function Map:init(file)
self.Tile = {}
counter = 1
io.input(io.open(file,"r"))
for FileLine in io.lines() do
print(i)
local thistile = split(FileLine, ",")
self.Tile[counter] = {}
local x = tonumber (thistile[1])
local y = tonumber (thistile[2])
local terrain = thistile[3]
local cost = tonumber (thistile[4])
local vp = thistile[5]
local feature = thistile[6]
local owner = thistile[7]
--local rivern = thistile[8]
--local rivere = thistile[9]
--local rivers = thistile[10]
--local riverw = thistile[11]
--local roadn = thistile[12]
--local roade = thistile[13]
--local roads = thistile[14]
--local roadw = thistile[15]
--self.Tile[x][y] = Tile()
--self.Tile[counter].Terrain = terrain
----self.Tile[counter].Image = sprite("Dropbox:desert")
--self.Tile[counter].Cost = cost
--self.Tile[counter].VP = vp
--self.Tile[counter].Feature = feature
--self.Tile[counter].Owner = owner
--self.Tile[x][y].RiverN = rivern
--self.Tile[x][y].RiverE = rivere
--self.Tile[x][y].RiverS = rivers
--self.Tile[x][y].RiverW = riverw
--self.Tile[x][y].RoadN = roadn
--self.Tile[x][y].RoadE = roade
--self.Tile[x][y].RoadN = roadn
--self.Tile[x][y].RoadW = roadw
self.Tile[counter] = {X=x, Y=y, Terrain=terrain, Cost=cost, VP=vp, Feature=feature, Owner=owner}
print("Hey im inside your map class!")
print(self.Tile[1].X)
print(self.Tile[1].Y)
print(self.Tile[1].Terrain)
print(self.Tile[1].Cost)
print(self.Tile[1].VP)
print(self.Tile[1].Feature)
print(self.Tile[1].Owner)
counter = counter + 1
end
end
function Map:draw()
-- Codea does not automatically call this method
end
function Map:touched(touch)
-- Codea does not automatically call this method
end
function split(str, div)
if (div=='') then
return false
end
local pos,arr = 0,{}
-- for each divider found
for st,sp in function() return string.find(str,div,pos,true) end do
-- Attach chars left of current divider
table.insert(arr,string.sub(str,pos,st-1))
pos = sp + 1 -- Jump past current divider
end
-- Attach chars right of last divider
table.insert(arr,string.sub(str,pos))
return arr
end
--draw horizontal lines of the grid
--for y=1,MapHeight,1 do
-- local line = display.newLine(1, y*SquareSize, SquareSize*MapWidth, y*SquareSize)
-- line:setColor( 255, 0, 0, 128)
-- line.width = 2
-- GameBoard:insert(line)
--end
--draw vertical lines of the grid
--for x=1,MapWidth,1 do
-- local line = display.newLine(x*SquareSize, 1, x*SquareSize, SquareSize*MapHeight)
-- line:setColor( 255, 0, 0, 128)
-- line.width = 2
-- GameBoard:insert(line)
--end
So how come this basic progamming method is so hard to find? Is there a complete manual on how to code in Codea or did I just miss it somewhere?
I understand Apple is way beyond Draconian/Control Freakyness when it comes to be able to browse the file system (unless you got something like iExplorer) from withing the ipad itself. I’ve been told that this prevents viruses/contributes to overall protection and security is that right?
If I may make a suggestion for the developers of Codea?.. simplify this for us(in Codea). I found no documentation on that HOME…thing, only happened to find it in all the posts(great forum thankfully). Don’t get me wrong, loving Codea but my god this was a MF to figure out. Course I am way out of practice and this is all new(ios programming) but I would think that since my spirtes are loaded just by doing sprite(Dropbox:“spritename.png”) then you should make file opening the same. Too many flamming hoops for me lol.
If you keep it in a similar format like sprites then you could do this to open and read in the contents of a file:
MyFile(Dropbox:“filename.txt”)
for lines in MyFile do
–blah
end
Do you understand what I mean by keeping it the same? Would be beautiful and elegant, and in line with the design concept of sprites.
Anyway, thanks you guys for your help! Now on to getting this to draw…
@Gib I think the problem with file io is that Codea is written to be a game/graphics language. There isn’t any true reason for file io. There is next to no file io documentation because it’s not used. Any documentation is just little bits here and there that people have shared.
@dave1707 I am not sure I understand what you mean by that since loading graphics is file io. Also a language without file io?? How could you do anything? map levels like I am doing depend on it. is Codea not for serious game development?
@Gib Cargo-Bot was said to be coded all on the iPad. So I would say it’s a serious game development language. But for some reason, file io doesn’t seem to be important. I’m not sure how they got everything on the iPad for the game, but I don’t think it was through file io.
@Gib Yes, loading sprites and stuff in file IO. But that’s handled by Codea. The file IO part is basically you, in your own code, reading or writing plain files. Codea is a legitimate game programming suite, and was designed with graphics in mind. Not things like a file manager, but games or toys.
Also, the reason it wouldn’t be Dropbox:filename.txt is because say, you didn’t want to be restricted to Codea’s files, say, you wanted to reach an entirely new area on the file system. Then Dropbox:filename.txt would be holding you back to Codea’s files.