LoginLogin
Nintendo shutting down 3DS + Wii U online services, see our post

Bg collision. help please

Root / Programming Questions / [.]

Tiger2Created:
Can someone show me a small demo picture as to how to make my character have collision with bg tiles. specifically the bg tile and not the whole 16x16 box it is in. double question. how do i get my character to use gravity with the circle pad? so it starts out slowly and gets faster up to a certain speed. same deal with jumping?

The circle pad has nothing to do with background collision or gravity. It is just an input. If you want circle pad input use something like:
 STICK OUT SX#, SY#
. That gives you two floating numbers letting you know the direction the circle pad is pointed. The Y value is sign flipped from what you want so multiply it by -1. You will want to include a "dead" zone in the center you treat as no input to prevent noise. Long story short, unless this is a top down game where you move a full tile with every step, background collision is complicated. There isn't an easy fix. You need to make a physics simulation of some sort to get things working right. If you want sub tile accuracy that is even more complicated. Getting a nice arc for jumping is again physics. There is an article on time based movement on this site. Go find it and read it. It is good stuff. For proper physics you need to know how much time you are simulating. Anyway, for jumping you give your player a large velocity in the negative Y direction. The velocity says how many meters per second the player moves (you will need to map meters to pixels). So if they are moving up at 10 meters per second and a game meter is 8 pixels, then in a sixtieth of a second the player moves 1.33 pixels up. Gravity on Earth is ~9.8 meters per second squared. So when falling you fall toward Earth faster and faster gaining 9.8 meters a second additional velocity every second. In our example this adds about 0.1633 meters/second to the player's velocity toward the Earth (don't forget to account for terminal velocity). So the player starts out jumping up quickly, but gravity eventually zeros out their upward speed and they fall to the ground at a constantly increasing speed. I do have a smallish game with some Super Mario style physics. Can you try reading the code for Find the Exit http://smilebasicsource.com/page?pid=820 Key K2KYJCS I tried to keep the code readable and some of the physics are a bit bad but it should be some good example code. When you are finished feel free to post questions.

Thank you. I actually think I may already have that. But let me try. My mind is a little............let's just say I'm pretty stupid at reading codes. But I'll try.

I looked at it and, I think just about everything in there needs to be explained to me. I know about setting sprites and printing, but apparently I know a little bit less than I thought.

OPTION STRICT
'VARIABLES
VAR BRICK% = 416, DIRT% = 334, GHOST% = 1021
VAR X%, Y%, SP%, MAXX% = 25, MAXY% = 15, B%
VAR X1%, Y1%, DOOR% = 870, GAMEOVER% = 0
DIM MAZE%[0, 0]

'SETUP SCREEN. MAKE A MAZE AND PUT THE PLAYER AND AN EXIT IN THE MAZE.
MAZE% = GENERATE_MAZE(MAXX%, MAXY%)
BGSCREEN 0, MAXX%, MAXY%
FOR Y% = 0 TO MAXY% - 1
 FOR X% = 0 TO MAXX% - 1
  IF MAZE%[X%, Y%] != 0 THEN
   BGPUT 0, X%, Y%, BRICK%
  ELSE
   BGPUT 0, X%, Y%, DIRT%
  ENDIF
 NEXT X%
NEXT Y%

'FIND A SPOT FOR THE EXIT
REPEAT 
 X% = RND(MAXX%) | Y% = RAND(MAXY%)
UNTIL BGGET(0, X%, Y%, 0) != BRICK%
BGPUT 0, X%, Y%, DOOR%

'fIND A SPOT FOR THE PLAYER
REPEAT
 X% = RND(MAXX%) | Y% = RAND(MAXY%)
UNTIL BGGET(0, X%, Y%, 0) == DIRT%

SPSET GHOST% OUT SP%
SPOFS SP%, X% * 16, Y% * 16

'TELL THE PLAYER HOW TO EXIT THE GAME
GPRIO -256
GPUTCHR 96, 112, "FIND THE EXIT", 2, 2
WAIT 60
GCLS

'MAIN GAME LOOP
WHILE (GAMEOVER% == 0)
 B% = BUTTON()
 'USING X1, Y1 SO WE CAN REVERT TO OLD 
 'COORDINATES IF THE DESTINATION IS FULL
 X1% = X%, Y1% = Y%

 'CALCLUATE THE NEW COORDINATES
 IF B% AND #LEFT THEN DEC X1%
 IF B% AND #RIGHT THEN INC X1%
 IF B% AND #UP THEN DEC Y1%
 IF B% AND #DOWN THEN INC Y1%

 'CLIP TO MAP
 X1% = MAX(0, MIN(MAXX% - 1, X1%))
 Y1% = MAX(0, MIN(MAXY% - 1, Y1%))

 'MOVE IF WE HAVE A NEW POSITION
 IF X1% != X% OR Y1% != Y% THEN
  IF BGGET(0, X1%, Y1%, 0) == BRICK% THEN
   'IF A BRICK DON'T MOVE THERE, JUST BEEP
   BEEP 24
  ELSEIF BGGET(0, X1%, Y1%, 0) == DOOR% THEN
   'YOU FOUND THE DOOR, YOU WIN
   BEEP 34
   SPOFS SP%, X1% * 16, Y1% * 16
   GPUTCHR 72, 104, "YOU WIN!", 4, 4
   GAMEOVER% = 1
   WAIT 240
   GCLS
  ELSE
   'IF DIRT MOVE THERE. WAIT IS BECAUSE
   'WE MOVE FULL TILES, WANT THINGS TO
   'REMAIN CONTROLLABLE
   X% = X1% : Y% = Y1%
   SPOFS SP%, X% * 16, Y% * 16
   WAIT 4
  ENDIF
 ENDIF
 VSYNC 'MINIMUM FRAME TIME
WEND

'CLEANUP AND EXIT
SPCLR SP%
END

DEF GENERATE_MAZE(WIDTH%, HEIGHT%)
 VAR H%
 VAR W%
 VAR CELL_W%
 VAR CELL_H%
 VAR STACK_X%[0]
 VAR STACK_Y%[0]
 DIM VISIT%[4]
 VAR X%, Y%
 VAR START_X%, START_Y%
 VAR DIR%
 VAR I%, J%
 VAR UNVISITED%

 CELL_W% = CEIL((WIDTH% - 1) / 2)
 CELL_H% = CEIL((HEIGHT% - 1) / 2)
 W% = (CELL_W% * 2) + 1
 H% = (CELL_H% * 2) + 1
 DIM MAZE%[W%, H%]
 FILL MAZE%, 1

 Y% = 0
 X% = RND(CELL_W%)
 START_X% = X% * 2 + 1
 START_Y% = Y% * 2 + 1
 UNVISITED% = CELL_W% * CELL_H%
 
 MAZE%[X% * 2 + 1, Y% * 2 + 1] = 0
 DEC(UNVISITED%)

 WHILE UNVISITED% > 0
  DIR% = RND(4)
  VISIT%[0] = IS_VISITED(MAZ%, X%, Y% - 1, CELL_W%, CELL_H%)
  VISIT%[1] = IS_VISITED(MAZ%, X% - 1, Y%, CELL_W%, CELL_H%) 
  VISIT%[2] = IS_VISITED(MAZ%, X% + 1, Y%, CELL_W%, CELL_H%)
  VISIT%[3] = IS_VISITED(MAZ%, X%, Y% + 1, CELL_W%, CELL_H%)

  IF VISIT%[0] +  VISIT%[1] + VISIT%[2] + VISIT%[3] == 0 THEN
   'ALL NEIGHBORS VISITED, BACK TRACK
   IF LEN(STACK_X%) > 0 THEN
    X% = POP(STACK_X%)
    Y% = POP(STACK_Y%)
   ELSE
    BREAK
   ENDIF
  ELSE
   'PICK UNVISITED NEIGHBOR
   WHILE VISIT%[DIR%] == 0
    DIR% = (DIR% + 1) MOD 4
   WEND

   PUSH STACK_X%, X%
   PUSH STACK_Y%, Y%

   'REMOVE WALL
   IF DIR% == 0 THEN
    'NORTH
    MAZE%[X% * 2 + 1, Y% * 2] = 0
    Y% = Y% - 1
   ELSEIF DIR% == 1 THEN
    'WEST
    MAZE%[X% * 2 , Y% * 2 + 1] = 0
    X% = X% - 1
   ELSEIF DIR% == 2 THEN
    'EAST
    MAZE%[X% * 2 + 2, Y% * 2 + 1] = 0
    X% = X% + 1
   ELSE
    'SOUTH
    MAZE%[X% * 2 + 1, Y% * 2 + 2] = 0
    Y% = Y% - 1
   ENDIF
   MAZE%[X%*2 + 1, Y% * 2 + 1] = 0
   DEC(UNVISITED%)
  ENDIF%
 WEND

 RETURN MAZE%
END

DEF IS_VISITED(MAZE%, X%, Y%, WIDTH%, HEIGHT%)
 VAR Z%
 IF X% >= 0 AND X% < WIDTH AND Y% >= 0 AND Y% < HEIGHT% THEN
  RETURN MAZE%[X% * 2 + 1, Y% * 2 + 1]
 ELSE
  RETURN 0
 ENDIF
END

Let's start with something a bit simpler. The code above makes a small maze and lets the player move around it. When you hit the exit you win and the game exits. Feel free to ignore everything about the maze generation. If you type it in and give it a try, you will notice that the player moves in small jumps from one spot to another and not smoothly. You will also notice that despite the player being a ghost they can't walk through walls. The not walking through walls part is the point of interest. If you find the line after the comment MAIN GAME LOOP this is where things are calculated. First of all we save a copy of the current position. We don't want to overwrite the position until we are certain we want to move the player there. Then we read input from the buttons calculate the new position we want to go, and clip to stay in the maze. After this we use BGGET to see if the new position is the exit, a brick or a dirt path (the 0 at the end says to use tile coordinates instead of pixel coordinates). If the new location is a brick we beep and don't update the position of the player. If it is the exit we move the player there and run the game over code. If the new position is a dirt path we simply place the player there, and update the current position. So, if we wanted this to have smooth motion we would need to do basically the same thing except move the character only a little bit every frame instead of a whole tile. This is of course harder than I am making it sound. If you want gravity you have forces constantly pulling the player down, and jumps would give the player a large velocity in the upward direction. Hopefully that makes more sense and is helpful.

Thanks. This is really long, so I will have to look over it later first and see if I understand it. Until then, thanks.

OPTION STRICT
'VARIABLES
VAR BRICK% = 416, DIRT% = 334, GHOST% = 1021
VAR X%, Y%, SP%, MAXX% = 25, MAXY% = 15, B%
VAR X1%, Y1%, DOOR% = 870, GAMEOVER% = 0
DIM MAZE%[0, 0]

'SETUP SCREEN. MAKE A MAZE AND PUT THE PLAYER AND AN EXIT IN THE MAZE.
MAZE% = GENERATE_MAZE(MAXX%, MAXY%)
BGSCREEN 0, MAXX%, MAXY%
FOR Y% = 0 TO MAXY% - 1
 FOR X% = 0 TO MAXX% - 1
  IF MAZE%[X%, Y%] != 0 THEN
   BGPUT 0, X%, Y%, BRICK%
  ELSE
   BGPUT 0, X%, Y%, DIRT%
  ENDIF
 NEXT X%
NEXT Y%

'FIND A SPOT FOR THE EXIT
REPEAT 
 X% = RND(MAXX%) | Y% = RAND(MAXY%)
UNTIL BGGET(0, X%, Y%, 0) != BRICK%
BGPUT 0, X%, Y%, DOOR%

'fIND A SPOT FOR THE PLAYER
REPEAT
 X% = RND(MAXX%) | Y% = RAND(MAXY%)
UNTIL BGGET(0, X%, Y%, 0) == DIRT%

SPSET GHOST% OUT SP%
SPOFS SP%, X% * 16, Y% * 16

'TELL THE PLAYER HOW TO EXIT THE GAME
GPRIO -256
GPUTCHR 96, 112, "FIND THE EXIT", 2, 2
WAIT 60
GCLS

'MAIN GAME LOOP
WHILE (GAMEOVER% == 0)
 B% = BUTTON()
 'USING X1, Y1 SO WE CAN REVERT TO OLD 
 'COORDINATES IF THE DESTINATION IS FULL
 X1% = X%, Y1% = Y%

 'CALCLUATE THE NEW COORDINATES
 IF B% AND #LEFT THEN DEC X1%
 IF B% AND #RIGHT THEN INC X1%
 IF B% AND #UP THEN DEC Y1%
 IF B% AND #DOWN THEN INC Y1%

 'CLIP TO MAP
 X1% = MAX(0, MIN(MAXX% - 1, X1%))
 Y1% = MAX(0, MIN(MAXY% - 1, Y1%))

 'MOVE IF WE HAVE A NEW POSITION
 IF X1% != X% OR Y1% != Y% THEN
  IF BGGET(0, X1%, Y1%, 0) == BRICK% THEN
   'IF A BRICK DON'T MOVE THERE, JUST BEEP
   BEEP 24
  ELSEIF BGGET(0, X1%, Y1%, 0) == DOOR% THEN
   'YOU FOUND THE DOOR, YOU WIN
   BEEP 34
   SPOFS SP%, X1% * 16, Y1% * 16
   GPUTCHR 72, 104, "YOU WIN!", 4, 4
   GAMEOVER% = 1
   WAIT 240
   GCLS
  ELSE
   'IF DIRT MOVE THERE. WAIT IS BECAUSE
   'WE MOVE FULL TILES, WANT THINGS TO
   'REMAIN CONTROLLABLE
   X% = X1% : Y% = Y1%
   SPOFS SP%, X% * 16, Y% * 16
   WAIT 4
  ENDIF
 ENDIF
 VSYNC 'MINIMUM FRAME TIME
WEND

'CLEANUP AND EXIT
SPCLR SP%
END

DEF GENERATE_MAZE(WIDTH%, HEIGHT%)
 VAR H%
 VAR W%
 VAR CELL_W%
 VAR CELL_H%
 VAR STACK_X%[0]
 VAR STACK_Y%[0]
 DIM VISIT%[4]
 VAR X%, Y%
 VAR START_X%, START_Y%
 VAR DIR%
 VAR I%, J%
 VAR UNVISITED%

 CELL_W% = CEIL((WIDTH% - 1) / 2)
 CELL_H% = CEIL((HEIGHT% - 1) / 2)
 W% = (CELL_W% * 2) + 1
 H% = (CELL_H% * 2) + 1
 DIM MAZE%[W%, H%]
 FILL MAZE%, 1

 Y% = 0
 X% = RND(CELL_W%)
 START_X% = X% * 2 + 1
 START_Y% = Y% * 2 + 1
 UNVISITED% = CELL_W% * CELL_H%
 
 MAZE%[X% * 2 + 1, Y% * 2 + 1] = 0
 DEC(UNVISITED%)

 WHILE UNVISITED% > 0
  DIR% = RND(4)
  VISIT%[0] = IS_VISITED(MAZ%, X%, Y% - 1, CELL_W%, CELL_H%)
  VISIT%[1] = IS_VISITED(MAZ%, X% - 1, Y%, CELL_W%, CELL_H%) 
  VISIT%[2] = IS_VISITED(MAZ%, X% + 1, Y%, CELL_W%, CELL_H%)
  VISIT%[3] = IS_VISITED(MAZ%, X%, Y% + 1, CELL_W%, CELL_H%)

  IF VISIT%[0] +  VISIT%[1] + VISIT%[2] + VISIT%[3] == 0 THEN
   'ALL NEIGHBORS VISITED, BACK TRACK
   IF LEN(STACK_X%) > 0 THEN
    X% = POP(STACK_X%)
    Y% = POP(STACK_Y%)
   ELSE
    BREAK
   ENDIF
  ELSE
   'PICK UNVISITED NEIGHBOR
   WHILE VISIT%[DIR%] == 0
    DIR% = (DIR% + 1) MOD 4
   WEND

   PUSH STACK_X%, X%
   PUSH STACK_Y%, Y%

   'REMOVE WALL
   IF DIR% == 0 THEN
    'NORTH
    MAZE%[X% * 2 + 1, Y% * 2] = 0
    Y% = Y% - 1
   ELSEIF DIR% == 1 THEN
    'WEST
    MAZE%[X% * 2 , Y% * 2 + 1] = 0
    X% = X% - 1
   ELSEIF DIR% == 2 THEN
    'EAST
    MAZE%[X% * 2 + 2, Y% * 2 + 1] = 0
    X% = X% + 1
   ELSE
    'SOUTH
    MAZE%[X% * 2 + 1, Y% * 2 + 2] = 0
    Y% = Y% - 1
   ENDIF
   MAZE%[X%*2 + 1, Y% * 2 + 1] = 0
   DEC(UNVISITED%)
  ENDIF%
 WEND

 RETURN MAZE%
END

DEF IS_VISITED(MAZE%, X%, Y%, WIDTH%, HEIGHT%)
 VAR Z%
 IF X% >= 0 AND X% < WIDTH AND Y% >= 0 AND Y% < HEIGHT% THEN
  RETURN MAZE%[X% * 2 + 1, Y% * 2 + 1]
 ELSE
  RETURN 0
 ENDIF
END

Let's start with something a bit simpler. The code above makes a small maze and lets the player move around it. When you hit the exit you win and the game exits. Feel free to ignore everything about the maze generation. If you type it in and give it a try, you will notice that the player moves in small jumps from one spot to another and not smoothly. You will also notice that despite the player being a ghost they can't walk through walls. The not walking through walls part is the point of interest. If you find the line after the comment MAIN GAME LOOP this is where things are calculated. First of all we save a copy of the current position. We don't want to overwrite the position until we are certain we want to move the player there. Then we read input from the buttons calculate the new position we want to go, and clip to stay in the maze. After this we use BGGET to see if the new position is the exit, a brick or a dirt path (the 0 at the end says to use tile coordinates instead of pixel coordinates). If the new location is a brick we beep and don't update the position of the player. If it is the exit we move the player there and run the game over code. If the new position is a dirt path we simply place the player there, and update the current position. So, if we wanted this to have smooth motion we would need to do basically the same thing except move the character only a little bit every frame instead of a whole tile. This is of course harder than I am making it sound. If you want gravity you have forces constantly pulling the player down, and jumps would give the player a large velocity in the upward direction. Hopefully that makes more sense and is helpful.
Sorry it took me so long. I only get online on Fridays for the most part. Anyway, I typed all of that in, but it didn't work. There were a lot of errors. I tried to fix some, but some of them when I tried it unraveled a bunch of other things. I tried to understand what was their, but, still, it is confusing. I think what I really need is like a program that focuses on one issue only. For example, if I'm learning about bg collision, it can't be a hole game, just a sprite and a bg tile. That's how I learned to apply jump gravity. I just happened to find something that was nothing but jump gravity and nothing else.

I wonder, is it possible that someone can make a code that is nothing but a sprite that can be moved and a bg tile to collide with so I can see how it works without a bunch of other irrelevent code to get in the way?