Messed up variable with connecting block textures

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
oman
Prole
Posts: 4
Joined: Wed May 22, 2024 1:45 pm
Location: Here

Messed up variable with connecting block textures

Post by oman »

I'm making a tile-based platformer and have come into an issue.
For some reason, v and v2 both work perfectly fine, but v3 has just decided to not return true when checking its ID.
The possible IDs can only be 1 or 2 in this case, and you can see that v and v2 have no issues accessing them.

For reference, t is a table of Block Objects, state.worldW is unchangeably 32 and since the blocks are one table, adding this value basically moves the selected block down by 1 y level.

I'm curious if anyone knows why, since I can't see it being anything outside of this function, but I also have no idea what's causing it.
Lower values of state.worldW seem to work weirdly, like v3 = t[i+2] "works", but obviously it's wrong.

Code: Select all

function Block:update(t,state,dt)
	-- check adjacencies and update self.merge
	-- v (self)
	for i = 1, #t do
		local v = t[i]
		local v2 = t[i+1]
		-- FOR SOME REASON, THIS ISN'T INITIALISING IT
		local v3 = t[i+state.worldW]
		
		-- check if not edge of the world
		if i % state.worldW ~= 0
		-- check if v2 fits in the table
		and i + 1 <= #t
		-- compare v and v2
		and v.id == v2.id then
			if v.merge == 0
			or v.merge == 1
			or v.merge == 4
			or v.merge == 5
			or v.merge == 8
			or v.merge == 9
			or v.merge == 12
			or v.merge == 13 then
				v.merge = v.merge + 2
			end
			if v2.merge == 1 then
				v2.merge = v2.merge + 8
			else
				v2.merge = 8
			end
		end
		
		-- check if v3 fits in the table
		if i + state.worldW <= #t
		-- compare v and v3
		and v.id == v3.id then    -- <------ this never triggers, without this the below code works. everything above this works.
			-- check if v is unmerged
			if v.merge == 0
			or v.merge == 1
			or v.merge == 2
			or v.merge == 3
			or v.merge == 8
			or v.merge == 9
			or v.merge == 10
			or v.merge == 11 then
				v.merge = v.merge + 4
			end
			v3.merge = 1
		end
	end
end
also this is my first time on the forum lol hi
User avatar
pgimeno
Party member
Posts: 3593
Joined: Sun Oct 18, 2015 2:58 pm

Re: Messed up variable with connecting block textures

Post by pgimeno »

Hello, welcome to the forums.

Your comparison works for me. I've converted your snippet to a whole program by adding a line before and a few lines after your code, like this:

Code: Select all

local Block = {}
function Block:update(t,state,dt)
	-- check adjacencies and update self.merge
	-- v (self)
	for i = 1, #t do
		local v = t[i]
		local v2 = t[i+1]
		-- FOR SOME REASON, THIS ISN'T INITIALISING IT
		local v3 = t[i+state.worldW]
		
		-- check if not edge of the world
		if i % state.worldW ~= 0
		-- check if v2 fits in the table
		and i + 1 <= #t
		-- compare v and v2
		and v.id == v2.id then
			if v.merge == 0
			or v.merge == 1
			or v.merge == 4
			or v.merge == 5
			or v.merge == 8
			or v.merge == 9
			or v.merge == 12
			or v.merge == 13 then
				v.merge = v.merge + 2
			end
			if v2.merge == 1 then
				v2.merge = v2.merge + 8
			else
				v2.merge = 8
			end
		end
		
		-- check if v3 fits in the table
		if i + state.worldW <= #t
		-- compare v and v3
		and v.id == v3.id then    -- <------ this never triggers, without this the below code works. everything above this works.
			-- check if v is unmerged
			if v.merge == 0
			or v.merge == 1
			or v.merge == 2
			or v.merge == 3
			or v.merge == 8
			or v.merge == 9
			or v.merge == 10
			or v.merge == 11 then
				v.merge = v.merge + 4
			end
			v3.merge = 1
		end
	end
end


local A = {id=1, merge=0}
local B = {id=2, merge=0}
local t = {
  A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,
  A,B,B,B,B,B,B,A,B,A,B,B,B,B,B,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,
  A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,
}
for i = 1, #t do
  -- Make all elements of t contain copies instead of references
  t[i] = {id=t[i].id, merge=t[i].merge}
end
local state = {worldW = 32}
Block:update(t, state, 0)
for i = 1, #t do
  if t[i].merge == 1 then
    print("v3 comparison worked")
    break
  end
end
This prints "v3 comparison worked", proving that at least one tile had merge=1, and that comparison is the only way for it to be set to 1.

Maybe you can provide more details as to how your algorithm works and what exactly doesn't work, and provide a runnable example demonstrating it like I did above?
User avatar
oman
Prole
Posts: 4
Joined: Wed May 22, 2024 1:45 pm
Location: Here

Re: Messed up variable with connecting block textures

Post by oman »

pgimeno wrote: Sun May 26, 2024 5:21 am Hello, welcome to the forums.

Your comparison works for me. I've converted your snippet to a whole program by adding a line before and a few lines after your code, like this:

Code: Select all

local Block = {}
function Block:update(t,state,dt)
	-- check adjacencies and update self.merge
	-- v (self)
	for i = 1, #t do
		local v = t[i]
		local v2 = t[i+1]
		-- FOR SOME REASON, THIS ISN'T INITIALISING IT
		local v3 = t[i+state.worldW]
		
		-- check if not edge of the world
		if i % state.worldW ~= 0
		-- check if v2 fits in the table
		and i + 1 <= #t
		-- compare v and v2
		and v.id == v2.id then
			if v.merge == 0
			or v.merge == 1
			or v.merge == 4
			or v.merge == 5
			or v.merge == 8
			or v.merge == 9
			or v.merge == 12
			or v.merge == 13 then
				v.merge = v.merge + 2
			end
			if v2.merge == 1 then
				v2.merge = v2.merge + 8
			else
				v2.merge = 8
			end
		end
		
		-- check if v3 fits in the table
		if i + state.worldW <= #t
		-- compare v and v3
		and v.id == v3.id then    -- <------ this never triggers, without this the below code works. everything above this works.
			-- check if v is unmerged
			if v.merge == 0
			or v.merge == 1
			or v.merge == 2
			or v.merge == 3
			or v.merge == 8
			or v.merge == 9
			or v.merge == 10
			or v.merge == 11 then
				v.merge = v.merge + 4
			end
			v3.merge = 1
		end
	end
end


local A = {id=1, merge=0}
local B = {id=2, merge=0}
local t = {
  A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,
  A,B,B,B,B,B,B,A,B,A,B,B,B,B,B,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,
  A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,
}
for i = 1, #t do
  -- Make all elements of t contain copies instead of references
  t[i] = {id=t[i].id, merge=t[i].merge}
end
local state = {worldW = 32}
Block:update(t, state, 0)
for i = 1, #t do
  if t[i].merge == 1 then
    print("v3 comparison worked")
    break
  end
end
This prints "v3 comparison worked", proving that at least one tile had merge=1, and that comparison is the only way for it to be set to 1.

Maybe you can provide more details as to how your algorithm works and what exactly doesn't work, and provide a runnable example demonstrating it like I did above?
Ahah right, sorry lol. Here's the whole thing as of rn in case you wanna nose through it a bit.
Subterrain.love
(31.06 KiB) Downloaded 33 times
There's a lot of unrelated things in it, but you can see that it's meant to show like this, but the two different block types don't connect at the top and bottom. The algorithm essentially just goes through the whole blocks table, compares the current index with the next index ( + 1), then compares the current index with the index directly below it (+ state.worldW), until one index chosen isn't part of the table. And, you can see that that method works perfectly fine for the horisontal connections (v2 handles these), but not for the vertical ones (v3 handles these). Not sure why.
Screenshot (54).png
Screenshot (54).png (65.45 KiB) Viewed 1059 times
The numbers at the top are just debug values showing you what merge value the blocks have. The values are what they're meant to be, until I add that specific line back into the if statement, then it just doesn't run any of the vertical connection code at all.
Screenshot (56).png
Screenshot (56).png (66.4 KiB) Viewed 1059 times
Hope this is a bit more helpful lol
User avatar
pgimeno
Party member
Posts: 3593
Joined: Sun Oct 18, 2015 2:58 pm

Re: Messed up variable with connecting block textures

Post by pgimeno »

Well, I've added this to main.lua right after generateTerrain, to see the map structure:

Code: Select all

  for i = 1, #self.ents[1] do
    io.stdout:write(self.ents[1][i].id)
    if i % self.worldW == 0 then io.stdout:write("\n") end
  end
The output was:

Code: Select all

11111111111111111111111111111111
22222222222222222222222222222222
11111111111111111111111111111111
22222222222222222222222222222222
11111111111111111111111111111111
22222222222222222222222222222222
11111111111111111111111111111111
22222222222222222222222222222222
This means that every tile has a different tile under it, therefore their IDs will always be different, so the condition for merging them will never happen in this map, which I believe is correct.
User avatar
oman
Prole
Posts: 4
Joined: Wed May 22, 2024 1:45 pm
Location: Here

Re: Messed up variable with connecting block textures

Post by oman »

pgimeno wrote: Sun May 26, 2024 3:52 pm Well, I've added this to main.lua right after generateTerrain, to see the map structure:

Code: Select all

  for i = 1, #self.ents[1] do
    io.stdout:write(self.ents[1][i].id)
    if i % self.worldW == 0 then io.stdout:write("\n") end
  end
The output was:

Code: Select all

11111111111111111111111111111111
22222222222222222222222222222222
11111111111111111111111111111111
22222222222222222222222222222222
11111111111111111111111111111111
22222222222222222222222222222222
11111111111111111111111111111111
22222222222222222222222222222222
This means that every tile has a different tile under it, therefore their IDs will always be different, so the condition for merging them will never happen in this map, which I believe is correct.
What does this mean exactly? Sorry, I'm not the best programmer ahah. How could I change the code in order to prevent something like this? Like I said, I'm not sure at all what's actually causing this in the generateTerrain code.

What I want it to do is generate 4 rows of one kind of block (id = 1), then 4 rows of the other kind below it (id = 2). I did have some wonky code before in the connection code (v, v2, v3 code) that was just caused by an extra for loop that I thought I needed but didn't, but I removed that afaik, and the block images are getting drawn correctly, so I'm unsure what's up.
User avatar
pgimeno
Party member
Posts: 3593
Joined: Sun Oct 18, 2015 2:58 pm

Re: Messed up variable with connecting block textures

Post by pgimeno »

oman wrote: Mon May 27, 2024 5:26 pm What does this mean exactly? Sorry, I'm not the best programmer ahah. How could I change the code in order to prevent something like this? Like I said, I'm not sure at all what's actually causing this in the generateTerrain code.
OK, I've finally understood what's going on here. The problem is as follows.

Basically, whatever the coordinate it is given, generateBlock() inserts the tile in the array in ascending order (via table.insert), but that doesn't take into account the coordinates it's at.

On the other hand, the loop in Block:update() expects the positions in the table to have a correspondence to coordinates.

Yet generateTerrain() generates first a row on the top, then a row on the bottom, and then it repeats the same process a total of 4 times. Since they are inserted in the table sequentially, the table contains a row from the top, then a row from the bottom, then the process repeats.

They are drawn correctly because the drawing function uses the tile coordinates, not the position in the table.

(By the way, it looks quite odd to me that state.worldH = 4 but the world has a height of 8, but that's not related to this problem).
User avatar
oman
Prole
Posts: 4
Joined: Wed May 22, 2024 1:45 pm
Location: Here

Re: Messed up variable with connecting block textures

Post by oman »

pgimeno wrote: Mon May 27, 2024 8:13 pm
oman wrote: Mon May 27, 2024 5:26 pm What does this mean exactly? Sorry, I'm not the best programmer ahah. How could I change the code in order to prevent something like this? Like I said, I'm not sure at all what's actually causing this in the generateTerrain code.
OK, I've finally understood what's going on here. The problem is as follows.

Basically, whatever the coordinate it is given, generateBlock() inserts the tile in the array in ascending order (via table.insert), but that doesn't take into account the coordinates it's at.

On the other hand, the loop in Block:update() expects the positions in the table to have a correspondence to coordinates.

Yet generateTerrain() generates first a row on the top, then a row on the bottom, and then it repeats the same process a total of 4 times. Since they are inserted in the table sequentially, the table contains a row from the top, then a row from the bottom, then the process repeats.

They are drawn correctly because the drawing function uses the tile coordinates, not the position in the table.

(By the way, it looks quite odd to me that state.worldH = 4 but the world has a height of 8, but that's not related to this problem).
Ahhh I get it yeah, I didn't realise because yeah the coordinates are technically separate from the table, I just don't reference them because they should theoretically always overlap perfectly anyway. So all I needed to do was give the second set of blocks its own set of for loops and that fixed it, thank you so much I would've never figured this out otherwise ahah.

Also yeah, the worldH value is only used in the terrainGen() that way for testing, I'm gonna basically give a local value for each layer instead then prevent it from generating more if it exceeds the worldH value (which'll be much bigger later).

Thank you so much again <3 You are a godsend.
Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests