Bg collision. help please (Page 1) ● SmileBASIC Source Forums

Register

• #2 ✎ 104 seggiepants 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. Posted
• #5 ✎ 104 seggiepants ``` 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. Posted
``` 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.