Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Collision detection
#1
I'm having a really hard time with this jumping game. I want to be able to jump on blocks, jump from blocks, and walk into blocks and be stopped. Also, I've noticed a glitch when you just walk off a block that you'll just keep walking on air until you jump.

Here's the code. You have to include gslib and qb.qlb. If you want to help yet don't know how to combine the two, here's the qlb and lib: http://www.venosoft.com/uploads/qbgs.zip
::EDIT::
Those who's DNS aren't updated still, here:
http://207.44.206.59/~venosoft.com/uploads/qbgs.zip

::EDIT 2::
Oh ya, the graphics files:
http://207.44.206.59/~venosoft.com/uploads/jumpgfx.zip
Code:
DECLARE FUNCTION MULTIKEY% (t%)
DEFINT A-Z
REM $DYNAMIC
'$INCLUDE: 'gslib.bi'
DECLARE SUB ABSOLUTE (address AS INTEGER)
'=================
'Graphics Routines
'=================
DECLARE SUB SpriteS (Sprite(), XX, YY, frame)
DECLARE SUB SpriteT (Sprite(), XX, YY, frame)
DECLARE SUB Box (x1, y1, x2, y2, c)
DECLARE SUB nPrint (XX%, YY%, Text$, col%)
'============
'Initializing
'============
DECLARE SUB Init ()
DECLARE SUB CreateMap ()
'==============
'Main Loop subs
'==============
DECLARE SUB Scroll ()
DECLARE SUB MainLoop ()
DECLARE SUB IngameMenu ()
DECLARE FUNCTION CheckBounds ()
'================
'Global Variables
'================
DIM SHARED buffer(31999) AS INTEGER
DIM SHARED map(32, 9), frames
DIM SHARED Jumping, LevelNum, ScrollSpeed, TimeStart#
DIM SHARED t#, t2#, CamX, CharX, CharY
DIM SHARED cY!, grav!, cYv!

'=========
'Constants
'=========
CONST FALSE = 0, TRUE = NOT FALSE
CONST LEFT = 1, RIGHT = 0, INITY = 140

'=================
'Graphic constants
'=================
CONST SKY = 2
CONST GRASS = 0
CONST GRASSB = 1
CONST ROCK = 3

'==============
'Graphic Arrays
'==============
DIM SHARED tiles(202 * 4 - 1), char(0)

'=============
'Begin Program
'=============
Init

REM $STATIC
FUNCTION CheckBounds
ppX = CamX MOD 20
IF map((CamX + CharX - ppX + 2) \ 20, CharY \ 20) = ROCK THEN CheckBounds = 0 ELSE CheckBounds = 1
IF map((CamX + CharX - ppX + 21) \ 20, CharY \ 20) = ROCK THEN CheckBounds = 0 ELSE CheckBounds = 1

IF Jumping THEN
IF map((CamX + CharX - ppX + 2) \ 20, (CharY + 20) \ 20) = ROCK THEN CheckBounds = 0 ELSE CheckBounds = 1
IF map((CamX + CharX - ppX + 21) \ 20, (CharY + 20) \ 20) = ROCK THEN CheckBounds = 0 ELSE CheckBounds = 1
END IF
nPrint 0, 0, STR$(XtileR) + STR$(Ytile), 15
END FUNCTION

REM $DYNAMIC
SUB CreateMap

FOR Y = 0 TO 7
FOR X = 0 TO UBOUND(map, 1)
  map(X, Y) = SKY
NEXT
NEXT

FOR X = 0 TO 16
  a = RND * 3
  IF a = 1 THEN map(X, 7) = ROCK
NEXT
FOR X = 0 TO UBOUND(map, 1): map(X, 8) = GRASS: NEXT
FOR X = 0 TO UBOUND(map, 1): map(X, 9) = GRASSB: NEXT

END SUB

SUB IngameMenu

END SUB

SUB Init

'===============
'Starting Values
'===============
CharY = INITY
cY! = INITY
cYv! = -4
grav! = .15
t! = TIMER
CharX = 50
Jumping = FALSE

'=======================
'Determine Graphics Size
'=======================
filenum = FREEFILE
OPEN "jmptil.put" FOR INPUT AS #filenum
REDIM tiles((LOF(filenum) - 7) \ 2 - 1)
CLOSE #filenum

filenum = FREEFILE
OPEN "jmpspt.put" FOR INPUT AS #filenum
REDIM char((LOF(filenum) - 7) \ 2 - 1)
CLOSE #filenum

'=============
'Load Graphics
'=============
DEF SEG = VARSEG(tiles(0))
BLOAD "jmptil.put", VARPTR(tiles(0))

DEF SEG = VARSEG(char(0))
BLOAD "jmpspt.put", VARPTR(char(0))


'====================
'Set Video Resolution
'====================
SCREEN 13
DEF SEG = VARSEG(buffer(0))

'==================
'Create initial map
'==================
CreateMap
MainLoop

END SUB

SUB MainLoop
TimeStart# = TIMER
t# = TIMER
Z = MULTIKEY(-1)
FirstTime = TRUE
walk = 0
DO
Scroll
gssprite CharX, CharY, VARSEG(buffer(0)), VARPTR(buffer(0)), VARSEG(char(walk * 202)), VARPTR(char(walk * 202))


  IF MULTIKEY(72) THEN IF NOT Jumping THEN Jumping = TRUE
  IF MULTIKEY(77) THEN IF CheckBounds THEN CharX = CharX + 2
  IF MULTIKEY(28) THEN IngameMenu
  IF MULTIKEY(1) THEN EXIT DO
WAIT &H3DA, 8
gspcopy VARSEG(buffer(0)), VARPTR(buffer(0)), &HA000, 0
REDIM buffer(31999)

IF Jumping THEN
  walk = 8
  IF CheckBounds THEN
    cY! = cY! + cYv!
    IF cY! < 80 THEN grav! = -.78
    cYv! = cYv! + grav!
    CharY = cY!
    IF CharY >= INITY THEN
      CharY = INITY
      cY! = INITY
      Jumping = FALSE
      cYv! = -4
      grav! = .15
    END IF
  ELSE
    Jumping = FALSE
  END IF
END IF
IF FirstTime THEN
CharY = INITY
CharX = 20
FirstTime = FALSE
END IF
frames = frames + 1
IF CharX >= 249 THEN
  CamX = CamX + 4
  IF MULTIKEY(77) THEN CharX = CharX - 1 ELSE CharX = CharX - 3
ELSEIF CharX >= 119 AND CharX < 199 THEN
  CamX = CamX + 2
  IF MULTIKEY(77) THEN CharX = CharX ELSE CharX = CharX - 1
ELSEIF CharX >= 199 THEN
  CamX = CamX + 3
  IF MULTIKEY(77) THEN CharX = CharX ELSE CharX = CharX - 2
ELSEIF CharX >= 0 AND char < 119 THEN
  CamX = CamX + 1
'ELSEIF CharX < 0 THEN EXIT DO
END IF
IF CharX >= 0 THEN CharX = CharX - 1
IF MULTIKEY(77) THEN
IF NOT Jumping THEN
IF kl = 4 THEN walk = walk + 1: IF walk > 7 THEN walk = 0
kl = kl + 1: IF kl > 4 THEN kl = 0
END IF
ELSE
walk = 0
kl = 0
END IF
LOOP
PRINT frames / (TIMER - TimeStart#)
Z = MULTIKEY(-2)

END SUB

FUNCTION MULTIKEY (t)

STATIC kbcontrol%(), kbmatrix%(), FirstTime, StatusFlag

IF FirstTime = 0 THEN          'Initalize
DIM kbcontrol%(128)
DIM kbmatrix%(128)
code$ = ""
code$ = code$ + "E91D00E93C00000000000000000000000000000000000000000000000000"
code$ = code$ + "00001E31C08ED8BE24000E07BF1400FCA5A58CC38EC0BF2400B85600FAAB"
code$ = code$ + "89D8ABFB1FCB1E31C08EC0BF2400BE14000E1FFCFAA5A5FB1FCBFB9C5053"
code$ = code$ + "51521E560657E460B401A8807404B400247FD0E088C3B700B0002E031E12"
code$ = code$ + "002E8E1E100086E08907E4610C82E661247FE661B020E6205F075E1F5A59"
code$ = code$ + "5B589DCF"
DEF SEG = VARSEG(kbcontrol%(0))
FOR I% = 0 TO 155                     ' Load ASM
     d% = VAL("&h" + MID$(code$, I% * 2 + 1, 2))
     POKE VARPTR(kbcontrol%(0)) + I%, d%
NEXT I%
I& = 16       ' I think this stuff connects the interrupt with kbmatrix%()
n& = VARSEG(kbmatrix%(0)): l& = n& AND 255: h& = ((n& AND &HFF00) \ 256): POKE I&, l&: POKE I& + 1, h&: I& = I& + 2
n& = VARPTR(kbmatrix%(0)): l& = n& AND 255: h& = ((n& AND &HFF00) \ 256): POKE I&, l&: POKE I& + 1, h&: I& = I& + 2
DEF SEG
FirstTime = 1
END IF

SELECT CASE t
CASE -1
  IF StatusFlag = 0 THEN
   DEF SEG = VARSEG(kbcontrol%(0))
   CALL ABSOLUTE(0)                     ' Run interrupt
   DEF SEG
   StatusFlag = 1
  END IF
CASE -2
  IF StatusFlag = 1 THEN
   DEF SEG = VARSEG(kbcontrol%(0))      ' Turn off interrupt
   CALL ABSOLUTE(3)
   DEF SEG
   StatusFlag = 0
  END IF
CASE 1 TO 128
  MULTIKEY = kbmatrix%(t)               ' Return status
CASE ELSE
  MULTIKEY = 0                          ' User Supidity Error
END SELECT

END FUNCTION

SUB nPrint (XX%, YY%, Text$, col%)
X% = XX%
Y% = YY%
  FOR I% = 0 TO LEN(Text$) - 1
    X% = X% + 8
    Offset% = 8 * ASC(MID$(Text$, I% + 1, 1)) + 14
    FOR J% = 0 TO 7
      DEF SEG = &HFFA6
      Bit% = PEEK(Offset% + J%)
      IF Bit% AND 1 THEN gspset X%, Y% + J%, VARSEG(buffer(0)), VARPTR(buffer(0)), col%
      IF Bit% AND 2 THEN gspset X% - 1, Y% + J%, VARSEG(buffer(0)), VARPTR(buffer(0)), col%
      IF Bit% AND 4 THEN gspset X% - 2, Y% + J%, VARSEG(buffer(0)), VARPTR(buffer(0)), col%
      IF Bit% AND 8 THEN gspset X% - 3, Y% + J%, VARSEG(buffer(0)), VARPTR(buffer(0)), col%
      IF Bit% AND 16 THEN gspset X% - 4, Y% + J%, VARSEG(buffer(0)), VARPTR(buffer(0)), col%
      IF Bit% AND 32 THEN gspset X% - 5, Y% + J%, VARSEG(buffer(0)), VARPTR(buffer(0)), col%
      IF Bit% AND 64 THEN gspset X% - 6, Y% + J%, VARSEG(buffer(0)), VARPTR(buffer(0)), col%
      IF Bit% AND 128 THEN gspset X% - 7, Y% + J%, VARSEG(buffer(0)), VARPTR(buffer(0)), col%
    NEXT J%
  NEXT I%

END SUB

SUB Scroll

CamXtile = INT(CamX / 20)
ppX = CamX MOD 20

FOR Y = 0 TO 9
  ziy = Y * 20
  FOR X = 0 TO 16
  xt = X + CamXtile
  IF xt > 32 THEN CamX = 0: xt = 0
    Tile = map(xt, Y)
    zix = X * 20 - ppX
    gssolidput zix, ziy, VARSEG(buffer(0)), VARPTR(buffer(0)), VARSEG(tiles(Tile * 202)), VARPTR(tiles(Tile * 202))

  NEXT X
NEXT Y

END SUB

Pleeeeeeeeeeeeeeeeeeeeeeease help me.
am an asshole. Get used to it.
Reply
#2
i think the POINT function
[Image: sig.php]
Back by popular demand!
I will byte and nibble you bit by bit until nothing remains but crumbs.
Reply
#3
Quote:i think the POINT function

Quite n00b, let teh l33t sp33k.
am an asshole. Get used to it.
Reply
#4
http://forum.qbasicnews.com/viewtopic.php?t=2800

Check here.
[Image: sig.php]
Back by popular demand!
I will byte and nibble you bit by bit until nothing remains but crumbs.
Reply
#5
I'm too lazy to try your code, so I'll just tell you how it works in Empyrean (and Microrush).

You have a single pixel that represents the 'position' of the character. I put this horizontally centred at the base of him. Then every cycle, the gravity factor is added to the ychng, so he falls automatically.

The trick is that when you go to update the character's position, you can't simply add the xchng and ychng... you need to 'trace' them. Because what if the character is falling at 4 pixels per second? You don't want them to 'miss' the floor!

And here's the key. As you trace along the line (probably just 3 or 4 pixels) from the current position to the new one, as soon as the next pixel is on top of the mask, you check if only updating xchng makes a valid move... if it does, add xchng to x and set ychng to 0. Have an ELSEIF and try the same thing for Y. The ELSEIF for that is that both xchng and ychng are set to zero.

I dunno if that made any sense, but it's very robust, and it works.
Reply
#6
Nope, it doesn't make any sense at all.
am an asshole. Get used to it.
Reply
#7
Quote:Nope, it doesn't make any sense at all.

AGREEEEEEEED!
earn.
Reply
#8
You men don't look like you want to learn... do you?

Wiz's sollution really makes sense to me. I do something slightly different and easier, though.

I each frame I "trace" the movements, like wiz said. What I do is to check where the sprite should be in the next frame (adding vx and vy). Then I check if the sprite would collide in that new position with any tiles.

Doing separate checks for vertical and horizontal collisions you can adjust the next position so if vx is 4 pixels and you eat two pixels of the tile, you should move 2 pixels and stop.
SCUMM (the band) on Myspace!
ComputerEmuzone Games Studio
underBASIC, homegrown musicians
[img]http://www.ojodepez-fanzine.net/almacen/yoghourtslover.png[/i
Reply
#9
You have to do collision checking EVERY TIME ANYTHING MOVES BY ONE PIXEL. If it moves by 2 pixels or more, chances are you have a bug.
Peace cannot be obtained without war. Why? If there is already peace, it is unnecessary for war. If there is no peace, there is already war."

Visit www.neobasic.net to see rubbish in all its finest.
Reply
#10
Quote:You have to do collision checking EVERY TIME ANYTHING MOVES BY ONE PIXEL. If it moves by 2 pixels or more, chances are you have a bug.

Not at all. In my engines, stuff don't have fixed speeds. Jill runs from 1/100 of a pixel each frame to 4 pixels each frame.
SCUMM (the band) on Myspace!
ComputerEmuzone Games Studio
underBASIC, homegrown musicians
[img]http://www.ojodepez-fanzine.net/almacen/yoghourtslover.png[/i
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)