This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
RatcheT2497's profile picture

Game collision stopped working?

Started by RatcheT2497, 28 May 2016 - 05:16 PM
RatcheT2497 #1
Posted 28 May 2016 - 07:16 PM
I'm currently in the process of making a platform game, and I have a problem which I don't know how to fix.

For some reason, the collision detection with the tilemap only works in a straight line. Anything not in a straight line just doesn't register, which seems fairly weird to me, because I'm using the same table for rendering as I am for collision.

Basically, the map is divided into multiple tables: The object table, the block table and the tile table.
The object and block table are tables, which have a similar structure: {x, y, char, tColor, bColor} with some additional info for each.

The tile table is a 2D table, consisting only of characters, whose drawing is hardcoded into the renderer. (For example, if the character it finds is a "#", it draws a quote, with a green background color and a lime text color, putting some "grass" on the screen.)

The collision for the player and the tile is handled using one function:

local function CheckForTile(x, y)
do -- If the map is nothing, return nil
  if playerCurrentState == playerStates.PLAYER_SMALL then
   for i = 1, #currentMap do
	for w = 1, #currentMap[i] do
	 if w == x and i == y then
	  if currentMap[i][w] ~= " " then return currentMap[i][w] else return nil end
	 end
	end
   end
  else
   for i = 1, #currentMap do
	for w = 1, #currentMap[i] do
	 if (w == x and y+1 >= i and y <= i) then
	  if currentMap[i][w] ~= " " then return currentMap[i][w] else return nil end
	 end
	end
   end
  end
end
end
This error popped up only recently, and never before. I suspect it has something to do with the fact that I added loading maps to my map editor, since the error started happening pretty much at the same time.
If there's any more information needed, just tell me. I'll gladly clarify :)/>

Oh, and thanks for any help I get :)/>
Bomb Bloke #2
Posted 29 May 2016 - 03:08 AM
No idea what you expect this line to do:

do -- If the map is nothing, return nil

It creates a block within your code, which can be useful for limiting scope, but that's not what you're doing with it here. It's certainly not performing any checks based around "the map being nothing", whatever that means.

These loops here (for when the player is "small") are redundant:

   for i = 1, #currentMap do
	for w = 1, #currentMap[i] do
	 if w == x and i == y then
	  if currentMap[i][w] ~= " " then return currentMap[i][w] else return nil end
	 end
	end
   end

Why bother iterating through if you can just do:

if currentMap[y][x] ~= " " then return currentMap[y][x] else return nil end

When the player is not small, we've got other problems:

   for i = 1, #currentMap do
	for w = 1, #currentMap[i] do
	 if (w == x and y+1 >= i and y <= i) then
	  if currentMap[i][w] ~= " " then return currentMap[i][w] else return nil end
	 end
	end
   end

"y+1 >= i and y <= i" is a convoluted way of saying "i == y". It'd also be true if "i == y + 1", but "i" will never reach that value because you return on the first match. Removing the "else return nil" should be sufficient to fix that.

If you're still having problems, post your complete code. Hard to comment on why moving in different directions might matter without seeing how the movements are performed in the first place.
RatcheT2497 #3
Posted 29 May 2016 - 10:15 AM
I just tried removing the "else return nil", but it still doesn't work properly. (Probably because I'm still returning the first match, as you said.)

The code for the main file is at uh1p8vzc
Code for the map editor is at GCxiT3WV
Surface API by CrazedProgrammer: 5YWfPd8Z (Needs to be called "Surface" with a capital S)
Small characters API (Well, only one function by oli414) yp9Yfjb7 (Needs to be called "customCharacters")
"object helper" (Table of objects available for use) fE6Z5De8 (Needs to be called "objHelper")
Background (needs to be called, all lowercase, "background") kTik00EA

I can't exactly post the test map, because it's split into multiple files… My way of saving/loading the map is quite bad, and I'll probably change it later. This way seemed the easiest to write :/

And also, the do … end parts are just for clarity when using text editors like Notepad++ or Visual Studio Code, which allow folding code. (Got that from the "Generally preferred way to organize/view code" topic in General, specifically Apemanzilla's way of writing.)

Still, thanks for the reply! :)/>/>
Edit: Damnit, forgot to include a few files. Will include as soon as I get home. Sorry :/
Edit #2: I believe that's all of the files needed to actually run the game/map editor.
Edited on 29 May 2016 - 12:35 PM
Bomb Bloke #4
Posted 29 May 2016 - 02:33 PM
With the additional context you've shown thus far, I can now see you're using CheckForTile() as a boolean within a number of conditional checks. That means there's no need to return the type of wall found - returning true's faster than re-indexing into our tables to get a value we don't specifically need.

So I guess I'd re-write the function along these lines:

local function CheckForTile(x, y)
	do -- Returns whether a tile exists at the specified co-ords.
		if playerCurrentState == playerStates.PLAYER_SMALL then
			if y < 1 or x < 1 or y > #currentMap or x > #currentMap[y] then return true end
			return currentMap[y][x] ~= " "
		else
			if y < 1 or x < 1 or y >= #currentMap or x > #currentMap[y] then return true end
			return currentMap[y][x] ~= " " or currentMap[y + 1][x] ~= " "
		end
	end
end

That'll go a bit faster, but it won't change its behaviour.

As to that, I see that every time you call CheckForTile you're also calling CheckForBlock, which uses this line when the player is large:

if v.x == x and v.y <= y and v.y >= y-1 then

This's different to the "y+1 >= i and y <= i" statement used within the CheckForTile function! That one checks for a hit when the tile position matches either y or y + 1, whereas this checks for a hit when the block position matches either y or y - 1. Beats me as to which is right, though I'll assume you've already got some idea as to the order in which the rows of blocks and tiles should go. ;)/>

The line would be a heck of a lot easier to read like this, by the way:

if v.x == x and (v.y == y or v.y == y - 1) then
Edited on 29 May 2016 - 12:36 PM
RatcheT2497 #5
Posted 29 May 2016 - 05:58 PM
Thank you very much, it worked, although with a few alterations :D/>

For some reason, the engine just refuses to work if the function doesn't return a character. Not sure why, but eh, it doesn't really matter (hopefully) :P/>

Again, thank you :)/>