Log In  

Cart #feyazidigi-0 | 2022-05-27 | Code ▽ | Embed ▽ | No License


I followed a tutorial on collision and cant figure out what's going wrong. its also making another player sprite when I go to the top left of the screen. I'm pretty new to coding and just want to find a not too complicated collision system. any help would be appreciated, thanks.

wall=0

function is_tile(tile_type,x,y)
    tile=mget(x,y)
    has_flag=fget(tile,tile_type)
    return has_flag
end

function can_move(x,y)
    return not is_tile(wall,x,y)
end
P#112357 2022-05-27 03:31 ( Edited 2022-05-27 03:35)

2

It seems that you have these map checks but your not calling them at all.
From what I see your just calling player_move() which moves the player without any of the logic you want.

What I would do is something like:

function player_move()

 can_move = fget(p.x/8, p.y/8)~=1

 if btn(⬅️) and can_move then
  p.x-=1.5
  p.sprite = 1
  p.flipx = true
  p.flipy = false
 end

 if btn(➡️) and can_move then
  p.x+=1.5
  p.sprite = 1
  p.flipx = false
  p.flipy = false
 end

 if btn(⬆️) and can_move then
  p.y-=1.5
  p.sprite = 1
  p.flipx = true
  p.flipy = false
 end

 if btn(⬇️) and can_move then
  p.y+=1.5
  p.sprite = 1
  p.flipx = false
  p.flipy = true
 end

end

(Though if you wanted to take it a step further or at least what I would do would maybe be:)

function check_coll(p, ox, oy)
 return fget((p.x+ox)/8,(p.y+oy)/8)~=1
end

function player_move()
 p.flipx, p.flipy, p.sprite = false, false, 1

 if btn(⬅️) and check_coll(p, -1, 0) then
  p.x-=1.5
  p.flipx = true
 end

 if btn(➡️) and check_coll(p, 9, 0) then
  p.x+=1.5
 end

 if btn(⬆️) and check_coll(p, 0, -1) then
  p.y-=1.5
  p.flipx = true
 end

 if btn(⬇️) and check_coll(p, 0, 9) then
  p.y+=1.5
  p.flipy = true
 end

end

I think looking at other's code is a good idea but make sure when you do you get a firm understanding of it and know how it could fit in to your project. I know that's not a easy thing to do at least for me but ya.
Hope I helped, make sure you know what your code is doing and not having a nebulous outlook on it and the API.
(that second sprite seems to you drawing it twice, once with a *8 offset I suspect.)

P#112359 2022-05-27 04:01 ( Edited 2022-05-27 04:02)

Cart #yesugrube-0 | 2022-05-27 | Code ▽ | Embed ▽ | No License

hey @SmellyFishstiks, thanks for commenting . Can't figure out how to implement your code. I tried each one of them and fiddled around a bit with each but I can't get them to work. am I missing a step?

P#112396 2022-05-27 21:37 ( Edited 2022-05-27 21:37)
1

@SmellyFishstiks Your code is missing the call to mget() to fetch the relevant map tile. Also the method you're suggesting is too simple. The top code example will get the car stuck in the first wall it hits, and both code examples will check just a corner of the car.

@scrimpy Your function can_move is being replaced with a true/false value by the first line of the player_move code. That would make sense if the true/false value were more accurate, but it not only is wrong due to the above message to SmellyFishstiks but also would result in the car being allowed to go most of the way through the top of each wall before being stopped.

Also as I mentioned to SmellyFishstiks, you'll need to move the car out of the wall after it hits.

Here's a version that fixes both issues, and also makes it not too difficult to enter your minimum width passageways

function player_move()

 local oldx,oldy = p.x,p.y -- record where the player started

 if btn(⬅️) then
  p.x-=1.5
  p.sprite = 1
  p.flipx = true
  p.flipy = false
 end

 if btn(➡️) then
  p.x+=1.5
  p.sprite = 1
  p.flipx = false
  p.flipy = false
 end

-- this splits the movement so that
-- the car will slide around corners rather
-- then getting stuck
 if not can_move(p.x,p.y) then
   p.x,p.y = oldx,oldy
 end

 oldx,oldy = p.x,p.y -- record where the player started

 if btn(⬆️) then
  p.y-=1.5
  p.sprite = 2
  p.flipx = false
  p.flipy = false
 end

 if btn(⬇️) then
  p.y+=1.5
  p.sprite = 2
  p.flipx = false
  p.flipy = true
 end

 if not can_move(p.x,p.y) then
   p.x,p.y = oldx,oldy
 end

end

function can_move(x,y)
 -- check all 4 corners of the car
 -- and check using a slightly smaller hitbox than 
 -- the full car so that the 1.5 pixel movement isn't 
 -- a problem
 return not (is_tile(wall,(x+1)\8,(y+1)\8) 
   or is_tile(wall,(x+7)\8,(y+1)\8)
   or is_tile(wall,(x+1)\8,(y+7)\8)
   or is_tile(wall,(x+7)\8,(y+7)\8))
end

Important: this code will only work with small movement (preferably less than 2 pixels per frame) because it doesn't have any way to move the car all the way up to a wall. Doing that requires more in-depth code.

Also, I'll go ahead and mention that the tutorial you got the initial code from was probably intended for grid-based movement. The reason you need to check all 4 corners is because you're using smooth movement between map tiles.

P#112402 2022-05-28 01:43

I forgot the mget()s ;p
the above code is how I would go about doing the same thing inplimenting the coll,
The second snippet was me suggesting sodo velocity, though you'd want to just have the real thing of course.
Pretty sure my method would not get the car stuck unless you moved over more than 8 units.. though now i see it should be -8 instead of -1. @kimiyoribaka

P#112406 2022-05-28 04:00
1

@SmellyFishstiks
The velocity one wouldn't get stuck, because it checks for a wall in the target spot and doesn't move there if so. The one without velocity does get stuck, and I know that because scrimpy implemented it and I saw it occur when testing to see if there were more problems beyond the mget issue. Here's why: it moves if the current spot doesn't have a wall then prevents all movement if the current spot does have a wall. As such, the check for a wall doesn't return true until it's too late to move back.

P#112409 2022-05-28 04:10

Cart #woneguguwo-0 | 2022-05-28 | Code ▽ | Embed ▽ | No License


@kimiyoribaka thanks that helps me out alot with getting it to work and knowing a bit how and why it works. one other thing is that the sprite for some reason is getting messed up when going left or down. I guess that might have something to do with me flipping the up an right sprite instead of making separate sprites for each position.

P#112410 2022-05-28 04:38
1

It's because of this part:

    draw_player()
    spr(p.sprite,p.x,p.y,1,1,p.flipx,p.flipy)

You have draw_player here:

function draw_player()
    spr(p.sprite,p.x,p.y)
end

which does almost but not quite the same thing as the line after the function call. As a result, your code draws the car twice, but the first time it doesn't apply the flips.

P#112411 2022-05-28 04:47 ( Edited 2022-05-28 04:47)

ah gotcha @kimiyoribaka.

P#112412 2022-05-28 04:51

@kimiyoribaka if I wanted to make items would it have similar code? You would have to use fget and mget right?

P#112438 2022-05-29 14:28
1

Yes, you can do it that way. However, since you haven't been keeping track of most of the individual objects on the map and also haven't been sticking to grid-aligned movement, it's a bit more complicated. Particularly, you need to be able to tell which tile the item was on so that you can make it disappear afterward and add any visual effects you want the item to have.

Firstly you need to add a line to the map_setup function to set another constant for the sprite flag (or "tile_type" as the tutorial apparently called it) you're going to use for item. something like item=2 would work for using the "flag 2 (0x4)" flag in the sprite editor. From there, you'll need an alternate version of the is_tile function that returns the tile when true. Personally, I would just scan the entire map on loading and make a list, but that's out of coding preference. The way that's closer to what you've been doing is to use the player position to tell which 4 tiles an item could be in and check each.

To do so, I recommend this code:

function is_tile(tile_type,x,y)
  local spr = mget(x,y)
  if fget(spr,tile_type) then
    return spr
  end
end

That checks the indicated tile for a sprite with the needed flag, then returns the sprite if so. If not, the function returns nil (which is considered false for if statement) due to not reach a return statement that tells it to return anything else. It's not as explicit as the tutorial code you used before, but it should still works in the cases you've already used it in because numbers are considered true for if statements.

From there, add this to the end of the player_move function to check each possible tile that could have an item:

  -- this is done separate 4 times, because it's possible 
  -- to touch as many as 3 untouched items in a single frame.
  local item_spr = is_tile(item,p.x\8, p.y\8)
  if (item_spr) get_item(item_spr, p.x\8,p.y\8)
  item_spr = is_tile(item,p.x\8 + 7, p.y\8)
  if (item_spr) get_item(item_spr, p.x\8,p.y\8)
  item_spr = is_tile(item,p.x\8, p.y\8 + 7)
  if (item_spr) get_item(item_spr, p.x\8,p.y\8)
  item_spr = is_tile(item,p.x\8 + 7, p.y\8 + 7)
  if (item_spr) get_item(item_spr, p.x\8,p.y\8)

Lastly, you create a function that handles what happens when the player touches an item, most likely including having the item disappear from the map.

For example:

function get_item(spr,x,y)
  mset(x,y,0) -- make the map tile showing the item become empty
  -- here put something like
  -- if spr == 3 then
  -- to have the effect matching the item with that sprite
end

Note, that if you want the game to be multiplayer or want enemy cars that can also pick up items, you'll need to add a parameter to the get_item function above so that you can pass in which car hit the item. Also, the code I'm recommending is probably slightly different from the tutorial's code. I've seen several cartridges that use very similar code and they tend to assign a different "tile_type" for each item. That is an option, but it also means a harsh limit on how many types of things your game can have while not actually being any more robust or efficient.

P#112443 2022-05-29 15:12
1

Cart #mamofuyewu-0 | 2022-05-29 | Code ▽ | Embed ▽ | No License
1

I screwed up somewhere and I really don't have a clue where. I got it to not give me errors but it didn't help much. maybe i put one of them in the wrong place or something.

P#112449 2022-05-29 16:34
1

Oh, uh...I guess I wasn't very clear on how the code was to be used. I meant that the is_tile function I posted should replace the one you already had. You don't need both, since the one I posted can still be used in the same way. Also, I didn't mean to put the get_item function inside the player_move function. While checking to make sure my suggestions work, I put the get_item function in the map code tab. Other than that, the if statement I put in a comment would need its own end statement, but it looks like you already put that in. I forgot that someone new to this wouldn't necessarily know to put that. Sorry about that.

That said, none of that is the reason it doesn't work. The reason it doesn't work is cause I screwed up. Testing it again, I just realized I screwed up the code I posted as well. I tested it by just putting some items in and seeing if I could grab them but I didn't pay attention to when. If the flag is placed 1 tile up you'll be able to grab it, from underneath but not as it is now.

The reason is that this code:

  local item_spr = is_tile(item,p.x\8, p.y\8)
  if (item_spr) get_item(item_spr, p.x\8,p.y\8)
  item_spr = is_tile(item,p.x\8 + 7, p.y\8)
  if (item_spr) get_item(item_spr, p.x\8,p.y\8)
  item_spr = is_tile(item,p.x\8, p.y\8 + 7)
  if (item_spr) get_item(item_spr, p.x\8,p.y\8)
  item_spr = is_tile(item,p.x\8 + 7, p.y\8 + 7)
  if (item_spr) get_item(item_spr, p.x\8,p.y\8)

should be this

  local item_spr = is_tile(item,p.x\8, p.y\8)
  if (item_spr) get_item(item_spr, p.x\8,p.y\8)
  item_spr = is_tile(item,(p.x + 7)/8, p.y\8)
  if (item_spr) get_item(item_spr, (p.x + 7)\8,p.y\8)
  item_spr = is_tile(item,p.x\8, (p.y + 7)\8)
  if (item_spr) get_item(item_spr, p.x\8,(p.y + 7)\8)
  item_spr = is_tile(item,p.x\8 + 7, p.y\8 + 7)
  if (item_spr) get_item(item_spr, (p.x + 7)\8,(p.y + 7)\8)

You may notice that that's closer to the code for checking for wall collisions. It's because in both cases the pixel position is being converted to a map position and map positions represent 8 pixels. I would still recommend removing the older is_tile function so you don't have tokens being wasted (having two functions with the same name causes the second one to overwrite the first), and I still recommend moving the get_item function for better structure, but because of the oddities of Lua, the code should work with just the above fix to the code I posted earlier.

P#112455 2022-05-29 19:59

[Please log in to post a comment]