Collision Help...

Blitz3D Forums/Blitz3D Beginners Area/Collision Help...

StOrM3(Posted 2004) [#1]
I have been working with various types of collisions in blitz3d to try and find out the best way to tell when a player bubble collides with an item laid out in a grid format, such as 6x6 grid, each item is different, and what I want to detect is number one the location of the collision, then if the item collided with is the same number as the player already, if so, remove item from the screen, add points etc.. if not, merely change the player into that item, return player to place outside of grid he was before shooting into the items. To complicate this process, I also want to track multi-hit combos, such as if the player hits an item, and there are more than one of that item next to each other, then add the points up collectively plus a multiplyer ex. 4xpointvalue + 500 bonus for it being a 4 combo.

I know this is alot to take in, I had it semi-working but had to use meshesintersect to get it to work properly, and never did get the multi-item combo's working. When I tried to improve the method, to speed up the player and to debug it, as sometimes the player would not return to correct location fast enough, and would get stuck.

The method I was using to ensure the player was facing the correct item was to use a pivot, which depending on what direction the player was on, 1-4 it would simply place the pivot at the items location that the player was facing, then I would pointentity the player at that pivot, then shoot the player until countcollisions > 0 for the player, then try to get the number of the item the player collided with. This basically worked,

I was just wondering, in the community you guys have been so helpful, there must be a better / faster more accurate way to detect the collisions, including multi-combos, and ensuring the player gets returned to his previous place, consistantly and without failure.

Also, I had enclosed the items in a 4 walled arena, and checked for collisions between the player and the walls also, so if the player shot where there was no items, it would collide with the walls, if true then I merely returned the player to where he was before shooting.

There must be a simpler way, maybe enclose the level in blitz made cubes, and check for collisions with those, so I could use the same cubes for each level, maybe just change the texture, instead of making the models and retexturing them in milkshape etc.. Also the scale of the level arena I made is a little large, and the walls are not visible to the player, they are outside of the camera range, what I am thinking is since the view is 800x600 windowed mode, maybe making some blitz cubes, to enclose the 800x600 window around the edges.

I got the bmp fonts working perfectly, thanks to FONtext which is wonderful, and the examples etc.. are great, but one question about that also, how can I get the help files to work in visual blitz like the regular blitz help files ? I have the decls file in userlib, but the f1 quick help does nothing but bring up the blitz regular help window with no topic hi-lighted or anything.

Anyways, that is a small question, I would much rather have examples / help / ideas on my bigger collision woes.

Thanks for everything you guys rock!

Ken


eBusiness(Posted 2004) [#2]
Try explaining what game you are making, your description of what you want seems very complicated, maybe there is a smarter way round.


StOrM3(Posted 2004) [#3]
Okay, here is the game concept.. basically, you have the player, whom starts off as a bubble, that rotates around the outside edge of a grid of objects, which are different items, when you press the mouse button, it shoots itself toward the item it is lined up with, if you are not that item type, it just changes you into that item, then returns you back to the outter edge where you started, if you are that item, then it will remove that item, and any items touching that item that are the same type, adds your points up based on combos etc.. then returns you to the outter edge, and you move with the mouse, which rotates you areound the outside edge, now there are other factors such as pieces of an item you must obtain to complete each level and there is a time limit for each level, and items that add or remove time, etc..

This is the premise of the game, hope it helps, I guess when I get home, I could make some screen shots.


eBusiness(Posted 2004) [#4]
Hmmm, sounds like you don't need the Blitz collision system. When you shoot yourself in, does the movement then follow the grid, or can you do this from any angle?


StOrM3(Posted 2004) [#5]
movement follows grid.. like if you are on bottom of grid, then the X does not change only the Z coord, etc..

Like I said, I had it semi working using the meshesintersect collision command, but the solution definitely was not elegant, and I wanted to try and speed it up, and make it easier to modify, so I could have special fx, and stuff added to it, and multi-combos and stuff. What I had was a mess, but it worked, just not as good as I wanted.

hehehe, since then I have come up with several things that I thought should have worked, but for some reason or another didn't.

So I am open to suggestions.


eBusiness(Posted 2004) [#6]
Ok, get an array to hold the items, for a 6x6 you would need:
Dim grid(7,7) ;Make the value of the edge -1, that'll come in handy
give each different item a number, and use 0 for a blank space. You will probably also need someting like this:
playerlaunched ;for telling if the player have been launched
playertype ;of course
playerx
playery ;position on the grid
playerspeedx
playerspeedy ;how fast the player moves in both directions, so when the player is launched, one will be 0 and one will be 1 or -1

Some movement code:
While playerlaunched
  If grid(playerx+playerspeedx,playery+playerspeedy)=0 Then
    playerx=playerx+playerspeedx
    playery=playery+playerspeedy
  Else if grid(playerx+playerspeedx,playery+playerspeedy)=playertype Then
    ;I'll save this bit for you
  Else if grid(playerx+playerspeedx,playery+playerspeedy)=-1
    ;There was nothing in the row, so the item just passed
  Else
    ;An item of a different type
  End If
  Delay 800 ;I suppose you don't want everything to happen instantly
Wend

I hope you can use it :)


StOrM3(Posted 2004) [#7]
Okay this is sort of what I needed, but also the player rotation code, and movement, etc.. I am using a pivot right now, to make sure the player is facing the correct item depending on what side of the grid the player is on, is there a better way ?

Also, what about movement until a collision, and when to correctly reset the objects collision info, etc..


eBusiness(Posted 2004) [#8]
Shall I write the game for you?

You better stay clear of the pivot, I think you just need some heavy if statements for knowing the rotation.


StOrM3(Posted 2004) [#9]
but using rotateentity was not working properly, and setting a pivot, and using pointentity is so simple to make sure the player is rotated properly, then just do a moveentity 0,0,1 to move forward or -1 to move backwards as long as the player is rotated correctly.

No you shall not write the game for me, since I already have a beta of it done, like I said, I have it working, I just want a better way to do it..

Here is some pseudo code I came up with today, gonna finish it off, and convert it to real code tonight.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NEW PLAYER SHOOT FUNCTION
;; INCLUDES MULTI-HIT COMBO CHECKING
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function PlayerShoot(p.player)
if p\direction = 4 then
  setup pivot
  rotate player
  mycounter = 1
  repeat
   Move Player
   mycounter = mycounter + 1
  until count collisions > 0 or mycounter > 3.

  if meshesintersect(p\bubble,fruitlevel(x,z)\item)=true then
    check multi
    if multi then
      ;remove items listed in multi array
      add points from multi array
      set all items from multi array in fruitlevel to hidden=1
      clear multi array
    else
      ;remove single item collided with
      add points from that item
      set that item in fruitlevel as hidden=1
    endif
    for x = 1 to 8
      for z = 1 to 8
        if fruitlevel(x,z)\hidden = 1 then
          hideentity fruitlevel(x,z)\item
        endif
      next
    next
  endif

return player to original location.
return ;return back to main game loop.
endif

;do same for other 3 directions.
end function



StOrM3(Posted 2004) [#10]
Here Is the real code, converted to blitz code.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NEW PLAYER SHOOT FUNCTION
;; INCLUDES MULTI-HIT COMBO CHECKING
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
function PlayerShoot(p.player)

local mycounter,countx,countz,cntmulti
global centerpivot

;First store positions.
p\OldX = p\CurrX
p\OldZ = p\CurrZ

if p\direction = 4 then
  if getentitytype(centerpivot) <> 9 then
    centerpivot = createpivot()
    entitytype centerpivot,9
  endif

  positionentity centerpivot,p\CurrX * GX#,0,(p\CurrZ + 1)*GZ#
  pointentity p\bubble, centerpivot
  mycounter = 1
  repeat
   moveentity p\bubble,0,0,1
   mycounter = mycounter + 1
  until count collisions > 0 or mycounter > (p\CurrZ + 3) * GZ#
  for countx = 1 to 8
    for countz = 1 to 8
      if meshesintersect(p\bubble,fruitlevel(countx,countz)\item)=true then
        ;are we this item ?  If so, CheckMulti, and continue with function.
        if p\fruit = fruitlevel(countx,countz)\number then
          multi = CheckMulti()
        else
          ;okay we are not this item, so become it, and return to position.
          p\fruit = fruitlevel(countx,countz)\number
          p\bubble = copymesh(fruitlevel(countx,countz)\item)
          positionentity p\bubble,(p\OldX * GX#),0,(p\OldZ * GZ#)
          return
        endif
      endif
      if multi then
        ; go through multi array add up points and set those items in fruitlevel hidden.
        for cntmulti = 1 to multi
          p\points = p\points + multiarray(cntmulti)\points
          fruitlevel(multiarray(cntmulti)\x,multiarray(cntmulti)\z)\hidden = 1
        next
        ; clearing out the multi array items.
        for cntmulti = 1 to multi
          multiarray(cntmulti)\points = -1
          multiarray(cntmulti)\x = -1
          multiarray(cntmulti)\z = -1
        next
      else
        ;remove single item collided with
        fruitlevel(countx,countz)\hidden = 1
        p\points = p\points + fruitlevel(countx,countz)\points        
      endif
    next
  next
  
  for countx = 1 to 8
    for countz = 1 to 8
      if fruitlevel(x,z)\hidden = 1 then
        hideentity fruitlevel(x,z)\item
      endif
    next
  next

;return player to original location.
positionentity p\bubble,(p\OldX * GX#),0,(p\OldZ * GZ#)
;return back to main game loop.
return
endif

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Direction 1 or on TOP.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
if p\direction = 1 then
  if getentitytype(centerpivot) <> 9 then
    centerpivot = createpivot()
    entitytype centerpivot,9
  endif

  positionentity centerpivot,p\CurrX * GX#,0,(p\CurrZ - 1)*GZ#
  pointentity p\bubble, centerpivot
  mycounter = 1
  repeat
   moveentity p\bubble,0,0,1
   mycounter = mycounter + 1
  until count collisions > 0 or mycounter > (p\CurrZ - 3) * GZ#
  for countx = 1 to 8
    for countz = 1 to 8
      if meshesintersect(p\bubble,fruitlevel(countx,countz)\item)=true then
        ;are we this item ?  If so, CheckMulti, and continue with function.
        if p\fruit = fruitlevel(countx,countz)\number then
          multi = CheckMulti()
        else
          ;okay we are not this item, so become it, and return to position.
          p\fruit = fruitlevel(countx,countz)\number
          p\bubble = copymesh(fruitlevel(countx,countz)\item)
          positionentity p\bubble,(p\OldX * GX#),0,(p\OldZ * GZ#)
          return
        endif
      endif
      if multi then
        ; go through multi array add up points and set those items in fruitlevel hidden.
        for cntmulti = 1 to multi
          p\points = p\points + multiarray(cntmulti)\points
          fruitlevel(multiarray(cntmulti)\x,multiarray(cntmulti)\z)\hidden = 1
        next
        ; clearing out the multi array items.
        for cntmulti = 1 to multi
          multiarray(cntmulti)\points = -1
          multiarray(cntmulti)\x = -1
          multiarray(cntmulti)\z = -1
        next
      else
        ;remove single item collided with
        fruitlevel(countx,countz)\hidden = 1
        p\points = p\points + fruitlevel(countx,countz)\points        
      endif
    next
  next
  
  for countx = 1 to 8
    for countz = 1 to 8
      if fruitlevel(x,z)\hidden = 1 then
        hideentity fruitlevel(x,z)\item
      endif
    next
  next

;return player to original location.
positionentity p\bubble,(p\OldX * GX#),0,(p\OldZ * GZ#)
;return back to main game loop.
return
endif
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Now Direction 2 or on left side...
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
if p\direction = 2 then
  if getentitytype(centerpivot) <> 9 then
    centerpivot = createpivot()
    entitytype centerpivot,9
  endif

  positionentity centerpivot,(p\CurrX + 1) * GX#,0,p\CurrZ * GZ#
  pointentity p\bubble, centerpivot
  mycounter = 1
  repeat
   moveentity p\bubble,0,0,1
   mycounter = mycounter + 1
  until count collisions > 0 or mycounter > (p\CurrX + 3) * GX#
  for countx = 1 to 8
    for countz = 1 to 8
      if meshesintersect(p\bubble,fruitlevel(countx,countz)\item)=true then
        ;are we this item ?  If so, CheckMulti, and continue with function.
        if p\fruit = fruitlevel(countx,countz)\number then
          multi = CheckMulti()
        else
          ;okay we are not this item, so become it, and return to position.
          p\fruit = fruitlevel(countx,countz)\number
          p\bubble = copymesh(fruitlevel(countx,countz)\item)
          positionentity p\bubble,(p\OldX * GX#),0,(p\OldZ * GZ#)
          return
        endif
      endif
      if multi then
        ; go through multi array add up points and set those items in fruitlevel hidden.
        for cntmulti = 1 to multi
          p\points = p\points + multiarray(cntmulti)\points
          fruitlevel(multiarray(cntmulti)\x,multiarray(cntmulti)\z)\hidden = 1
        next
        ; clearing out the multi array items.
        for cntmulti = 1 to multi
          multiarray(cntmulti)\points = -1
          multiarray(cntmulti)\x = -1
          multiarray(cntmulti)\z = -1
        next
      else
        ;remove single item collided with
        fruitlevel(countx,countz)\hidden = 1
        p\points = p\points + fruitlevel(countx,countz)\points        
      endif
    next
  next
  
  for countx = 1 to 8
    for countz = 1 to 8
      if fruitlevel(x,z)\hidden = 1 then
        hideentity fruitlevel(x,z)\item
      endif
    next
  next

;return player to original location.
positionentity p\bubble,(p\OldX * GX#),0,(p\OldZ * GZ#)
;return back to main game loop.
return
endif

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Now Direction 3 or on right side...
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
if p\direction = 3 then
  if getentitytype(centerpivot) <> 9 then
    centerpivot = createpivot()
    entitytype centerpivot,9
  endif

  positionentity centerpivot,(p\CurrX - 1) * GX#,0,p\CurrZ * GZ#
  pointentity p\bubble, centerpivot
  mycounter = 1
  repeat
   moveentity p\bubble,0,0,1
   mycounter = mycounter + 1
  until count collisions > 0 or mycounter > (p\CurrX - 3) * GX#
  for countx = 1 to 8
    for countz = 1 to 8
      if meshesintersect(p\bubble,fruitlevel(countx,countz)\item)=true then
        ;are we this item ?  If so, CheckMulti, and continue with function.
        if p\fruit = fruitlevel(countx,countz)\number then
          multi = CheckMulti()
        else
          ;okay we are not this item, so become it, and return to position.
          p\fruit = fruitlevel(countx,countz)\number
          p\bubble = copymesh(fruitlevel(countx,countz)\item)
          positionentity p\bubble,(p\OldX * GX#),0,(p\OldZ * GZ#)
          return
        endif
      endif
      if multi then
        ; go through multi array add up points and set those items in fruitlevel hidden.
        for cntmulti = 1 to multi
          p\points = p\points + multiarray(cntmulti)\points
          fruitlevel(multiarray(cntmulti)\x,multiarray(cntmulti)\z)\hidden = 1
        next
        ; clearing out the multi array items.
        for cntmulti = 1 to multi
          multiarray(cntmulti)\points = -1
          multiarray(cntmulti)\x = -1
          multiarray(cntmulti)\z = -1
        next
      else
        ;remove single item collided with
        fruitlevel(countx,countz)\hidden = 1
        p\points = p\points + fruitlevel(countx,countz)\points        
      endif
    next
  next
  
  for countx = 1 to 8
    for countz = 1 to 8
      if fruitlevel(x,z)\hidden = 1 then
        hideentity fruitlevel(x,z)\item
      endif
    next
  next

;return player to original location.
positionentity p\bubble,(p\OldX * GX#),0,(p\OldZ * GZ#)
;return back to main game loop.
return
endif

end function

function CheckMulti()
  return 0 ;for now place holder, never return multi-hits.
end function


Here is the updated post of the code, including a placeholder function which I need to figure out how to check for multi-items the same connected to the item I hit with the player bubble.

Anyone feel free to help out with this function, if you have any ideas how to make it work. I only want to check for at most 3 or 4 items connected including the item the player hits.

There UPDATED! 5/4/2004 6:58 Central time. Tell me what ya think now, and if you have any ideas how to do multi-combos again, I am open to suggestions. All 4 Directions added.

____________________________
[PKE] In The End, [PKE]
[PKE] [PKE]
[PKE] There Kan B Only 1,[PKE]
[PKE] [PKE]
[PKE] and May It B... [PKE]
\/\/\/\/\/\/\/\/\/\/\/\/\/\/
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
[PKE] Pain Killa Entertainment [PKE]
[PKE] Pain Is Reality. (tm) [PKE]
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
/\/\/\/\/\/\/\/\/\/\/\/\/\/\
[PKE]OWNER - Ken Cornett [PKE]
[PKE] [PKE]
[PKE] AUDIO - Gene Deel [PKE]
[PKE] [PKE]
[PKE]WEB - DAVE BERNSTEIN[PKE]
\/\/\/\/\/\/\/\/\/\/\/\/\/\/
_____________________________________________
|-=Copyright (c) 2004 - All Rights Reserved.=-|
=============================================


eBusiness(Posted 2004) [#11]
I think there is a memory leak, you will apparently create a pivot every time you do this check, but I don't see you deleteing it. Just ceate it once, and reposition it as you need it. I'm looking forward to see your game.


StOrM3(Posted 2004) [#12]
Hmmm how do I check if centerpivot already exists ? something like:
if getentitytype(centerpivot) <> 9 then
  centerpivot = createpivot()
  entitytype centerpivot,9
endif

or how do I check if an entity exists ? Is there a blitz command to do it ?

I think the code above will work, so now I will integrate it into my above code sample...


StOrM3(Posted 2004) [#13]
BTW: I have a beta already up and working, after I integrate this tonight, I will try to get Beta 2 working again, and if it is, then I will post it to my website for d/l then you can snag it to check it out so far.

I have the basic gameplay working, only need to add some special fx, and special items for gameplay, the bmp fonts are in and working great, controls are a little hairy at the moment, but I can work on those over time.

BTW: Thanks for the compliment.


big10p(Posted 2004) [#14]
Hey StOrM3,

After reading your original post yesterday, I thought I'd have a go at helping you out so I wrote the following basic concept code today. It's how I understand your game concept works, from the various posts you've made here.

I hadn't seen any of your source code before today so I'm probably doing things differently to you but it contains all the stuff I remember you having trouble with: collisions, smooth control (mouse control may need tweaking), combination hits, etc.

Hope it's of some use. Feel free to ask any questions, if I can help. BTW, seems like you've got a really nice game concept there - keep up the hard work!

	Graphics3D 800,600,32
	SetBuffer BackBuffer()

	WireFrame 0
	AntiAlias 0

	SeedRnd MilliSecs()

	Global frame_count%
	Global fps%
	Global slowest_fps%
	Global fps_timeout%
	Global frame_time%
	Global slowest_frame%
	Global frame_start%
	fps_timer = CreateTimer(60)
	slowmo% = False
	wiref% = False
	
	cam = CreateCamera()
	PositionEntity cam,0,1.5,-36
	CameraZoom cam,1.5
	
	light = CreateLight()
	
	Type gridT
		Field entity
		Field ID
		Field row%, col%
	End Type
			
	Const END_ROW% = 14
	Const END_COL% = 20
	Const GRID_START_X# = Float(-END_COL)
	Const GRID_START_Y# = Float(END_ROW)
	Const KEY_MOVE_FRAMES% = 8
	Const SHOOT_SPEED# = 1.0
	
	; Grid object IDs.
	Const ID_NEW_PLAYER% = -1
	Const ID_SPACE% = 0
	Const ID_WALL% = 1
	Const ID_RED_BALL% = 2
	Const ID_GREEN_BALL% = 3
	Const ID_YELLOW_BALL% = 4
	Const ID_CYAN_BALL% = 5
	Const ID_HORZ_END% = 7
	Const ID_VERT_END% = 8
	Const ID_SET_RANDOM% = 9
	
	Const CLOCKWISE% = 1
	Const ANTICLOCKWISE% = -1

	Const TYPE_PLAYER% = 1
	Const TYPE_WALL% = 2
	Const TYPE_BALL% = 3
	
	Global move_row% = 0
	Global move_col% = 1
	Global move_dx#, move_dy#
	Global move_count%
	Global player_moving% = False

	Dim grid.gridT(END_ROW,END_COL)
	create_level()

	Global player.gridT = New gridT
	player\entity = CreateSphere()
	player\ID = ID_NEW_PLAYER
	position_player(2,10)
	EntityShininess player\entity,1
	EntityType player\entity,TYPE_PLAYER
	EntityRadius player\entity,.9,.9

	Collisions TYPE_PLAYER,TYPE_BALL,1,1
	Collisions TYPE_PLAYER,TYPE_WALL,1,1

	
	; --- Main loop ---
	
	While Not KeyHit(1)
		frame_start = MilliSecs()
	
		If KeyHit(28) Then slowmo = Not slowmo
		If KeyHit(14)
			wiref = Not wiref
			WireFrame wiref
		EndIf

		control_player()
		update_player()	
		
		UpdateWorld
		RenderWorld
		
		frame_time = MilliSecs() - frame_start	
		show_info()

		WaitTimer(fps_timer)
		Flip(1)

		If slowmo Then Delay 500
	Wend

	ClearWorld	

	End


; Initial level grid layout info.
.grid_data
Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,1
Data 1,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,1
Data 1,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1



;
; Player control handler.
;
Function control_player()

	If Not player_moving
		
		mxs = MouseXSpeed()
		MoveMouse 400,300
		
		If mxs
			frames = Abs(mxs/3)
			If frames > 10 Then frames = 10
			frames = 11 - frames
			move_player(Sgn(mxs),frames)
		Else
			If KeyHit(57) Or MouseHit(1)
				shoot_player()
			Else
				If KeyDown(203) Then move_player(-1,KEY_MOVE_FRAMES)
				If KeyDown(205) Then move_player(1,KEY_MOVE_FRAMES)
			EndIf
		EndIf
	EndIf

End Function


;
; Updates player's movement and handles collisions.
;
Function update_player()

	If player_moving
		ent = EntityCollided(player\entity,TYPE_BALL)
		If ent
			; A ball was hit...
			ball.gridT = Object.gridT(EntityName(ent))
			
			If player\ID <> ball\ID
				player_is_ball(ball\ID)
				reset_player()
				position_player(player\row,player\col)
			Else
				remove_connected(ball)
				reset_player()
				position_player(player\row,player\col)
			EndIf
		Else
			ent = EntityCollided(player\entity,TYPE_WALL)
			If ent
				; A wall was hit...
				reset_player()
				position_player(player\row,player\col)
			Else
				; Player moving clockwise/anti-clockwise...
				TranslateEntity player\entity,move_dx,move_dy,0		
				move_count = move_count - 1
				If Not move_count Then reset_player()
			EndIf
		EndIf
	EndIf
		
End Function


;
; Recusively removes all connected balls of the same type.
;
Function remove_connected(ball.gridT)

	row = ball\row
	col = ball\col
	ID = ball\ID

	HideEntity ball\entity
	ball\ID = ID_SPACE

	If grid(row,col-1)\ID = ID Then remove_connected(grid(row,col-1))
	If grid(row,col+1)\ID = ID Then remove_connected(grid(row,col+1))
	If grid(row-1,col)\ID = ID Then remove_connected(grid(row-1,col))
	If grid(row+1,col)\ID = ID Then remove_connected(grid(row+1,col))
		
End Function


;
; Turns player into a ball of type ID.
;
Function player_is_ball(ID)

	Select ID
		Case ID_RED_BALL
			EntityColor player\entity,155,0,0
		Case ID_GREEN_BALL
			EntityColor player\entity,0,155,0
		Case ID_YELLOW_BALL
			EntityColor player\entity,155,155,0
		Case ID_CYAN_BALL
			EntityColor player\entity,0,155,155
	End Select

	player\ID = ID

End Function


;
; Resets player's status ready for a new movement.
;
Function reset_player()

	player_moving = False
	
	; Flush all input accumulated while moving.
	MouseXSpeed()
	FlushMouse 
	FlushKeys

End Function


;
; Moves player around ball grid.
; dir    - 1=clockwise, -1=anti-clockwise
; frames - Number of animation frames to make the move.
;
Function move_player(dir%, frames%)
	
	mr = move_row * Sgn(dir) ; Sgn() ensures dir is either CLOCKWISE
	mc = move_col * Sgn(dir) ; or ANTICLOCKWISE.

	new_row = player\row + mr
	new_col = player\col + mc

	If dir = CLOCKWISE
		Select grid(new_row,new_col)\ID
			Case ID_HORZ_END
				move_row = mc : move_col = 0
				new_row = player\row + (move_row*2)
				new_col = player\col + (mc*2)
			Case ID_VERT_END	
				move_col = -mr : move_row = 0
				new_row = player\row + (mr*2)
				new_col = player\col + (move_col*2)
		End Select
	Else
		Select grid(new_row,new_col)\ID
			Case ID_HORZ_END
				move_row = mc : move_col = 0
				new_row = player\row + (move_row*-2)
				new_col = player\col + (mc*2)
			Case ID_VERT_END
				move_col = -mr : move_row = 0
				new_row = player\row + (mr*2)
				new_col = player\col + (move_col*-2)
		End Select
	EndIf
				
	player\row = new_row
	player\col = new_col
	
	; Calculate movement animation to get from old position to new one.
	start_x# = EntityX(player\entity)
	start_y# = EntityY(player\entity)		
	end_x# = GRID_START_X + (new_col*2)
	end_y# = GRID_START_Y - (new_row*2)
	move_dx# = (end_x - start_x) / frames
	move_dy# = (end_y - start_y) / frames
	move_count = frames
	player_moving = True

End Function

;
; Set up player to shoot forward.
;
Function shoot_player()

	If player\row = 2
		move_dx = 0 : move_dy = -SHOOT_SPEED
	ElseIf player\row = END_ROW-2
		move_dx = 0 : move_dy = SHOOT_SPEED
	ElseIf player\col = 2
		move_dx = SHOOT_SPEED : move_dy = 0
	ElseIf player\col = END_COL-2
		move_dx = -SHOOT_SPEED : move_dy = 0
	EndIf

	player_moving = True
	move_count = 9999		; Make sure we can reach a wall!

End Function


;
; Positions player onscreen at level grid row,col.
;
Function position_player(row%, col%)

	player\row = row
	player\col = col
	PositionEntity player\entity,GRID_START_X+(col*2),GRID_START_Y-(row*2),0
	ResetEntity player\entity
	
End Function


;
; Create all level objects.
;
Function create_level()

	pos_x# = GRID_START_X
	pos_y# = GRID_START_Y

	Restore grid_data

	For row = 0 To END_ROW
		For col = 0 To END_COL
			this.gridT = New gridT
			this\row = row
			this\col = col
						
			Read datum
			
			Select datum
				Case ID_WALL
					ent = CreateCube()
					ScaleMesh ent,1,1,Rnd(1,3)			; For a more interesting looking wall
					EntityColor ent,0,0,Rand(100,255)   ;
					PositionEntity ent,pos_x,pos_y,0			
					EntityType ent,TYPE_WALL
					EntityRadius ent,1,1
					NameEntity ent,Handle(this) 
					this\entity = ent
					this\ID = ID_WALL
				Case ID_SET_RANDOM
					ent = CreateSphere()
					EntityShininess ent,1
					PositionEntity ent,pos_x,pos_y,0			
					EntityType ent,TYPE_BALL
					EntityRadius ent,1,1
					NameEntity ent,Handle(this)
					this\entity = ent

					random_ball = Rand(ID_RED_BALL,ID_CYAN_BALL)
					Select random_ball
						Case ID_RED_BALL
							EntityColor ent,155,0,0
						Case ID_GREEN_BALL
							EntityColor ent,0,155,0
						Case ID_YELLOW_BALL
							EntityColor ent,155,155,0
						Case ID_CYAN_BALL
							EntityColor ent,0,155,155
					End Select
					this\ID = random_ball
				Default
					this\ID = datum
			End Select
			
			grid(row,col) = this
			pos_x = pos_x + 2.0
		Next

		pos_x = GRID_START_X
		pos_y = pos_y - 2.0
	Next

End Function


;
; Display debug info
;
Function show_info()
	
	If fps_timeout
		frame_count = frame_count + 1

		If MilliSecs() > fps_timeout Then
			fps_timeout = MilliSecs() + 1000 
			fps = frame_count 
			frame_count = 0 
		
			If fps < slowest_fps Or slowest_fps = 0 Then slowest_fps = fps
		EndIf 
		
		If frame_time > slowest_frame Then slowest_frame = frame_time
		
		Color 0,255,0
		Text 10,10," Triangles: " + TrisRendered()
		Color 255,255,0
		Text 10,25," Millisecs: " + frame_time
		Text 10,40,"   Slowest: " + slowest_frame
		Color 0,255,255
		Text 10,55,"       FPS: " + fps
		Text 10,70,"     Worst: " + slowest_fps
		Color 255,255,255
		Text 200,10,"Move mouse right or press right arrow key to move clockwise"
		Text 200,25,"Move mouse left or press left arrow key to move anti-clockwise"
		Text 200,40,"Click left mouse button or press SPACE to shoot"
	Else
		; First call initialization.
		fps_timeout = MilliSecs() + 1000 
	EndIf
	
End Function
	



eBusiness(Posted 2004) [#15]
Yeah, I guess it's easiest just to leave out asking ;)


StOrM3(Posted 2004) [#16]
OMG... Dude, you are the man.. Umm Thank You!!! I don't know how to thank you, actually. Dude can I get your real name, so that I might put you in the credits etc.. ? Yea, I'm glad you did that, cuz the code I posted I added it to the game last night, and there were some prevelant bugs, such as for some reason when you hit one item, it would clear the board, and give you all the points.. hehehe, that was one quick game. Also I left out some if checks that needed to make sure the item was actually there, before trying to use it, in another check.

Thank you greatly!


StOrM3(Posted 2004) [#17]
big10p, I want to thank you, I had a read through your code, and it looks like I will be able to use some of it, even though it will need to be heavily modified, since I have multiple levels of objects, such as they start off as spheres, you hit them, they turn into either fruit items, or (?) items, or pieces to a puzzle, which you must construct in the correct order in the timelimit in order to complete the level. But you did fill in alot of holes for me, such as a different way to do the mouse movement, and a better way to check for collisions and multiple objects connected and removing them etc..

Also after looking at your code, I am rewriting almost all of my code, restructuring for the additions to the story line and the puzzle pieces etc.. I am using your ideas for using const ID's to identify different items, but also adding different handle's to point to which ever animation or stopped state the model for that item is in, this will allow me to add particle fx, or spinning motions, very easily, and I added fields for start and stop frames for each animation, linked to each items state.

I have a good handle on how to make this all work together now, before what I had was a part of a game, similar to yours, only using my models, and the movement worked, and the taking single items away and points worked, and my timer code worked. So, now from that learning experience,

Over the next couple of days or so, I will be doing a complete rewrite, starting from some core pseudo code, and some concepts I picked up from you, and this weekend while with the wife at the flea market, on the portable I will integrate the new functions, test, modify, hopefully complete the new engine code.

Thanks for the moral support, and the coding help. I really appreciate it. Once I get into a code lockdown, I will post some of the code, and some screen shots to show you any progress made.

I am kind of puzzled at some of your code though, like why when your moving you always use *2 or +2 or -2 for everything. I'm assuming it has to do with your player offset code.

I had to rewrite alot of my code anyways since, I found out by trial and error, that the reason for my errors, was the fact that my grid, that I also am reading from data statements, somehow got turned around, so the direction numbers 1-4 were not located where they were supposed to be. I learned this from the shooting code, I had missing item checking code, so when I would shoot from a side,

visual blitz would stop me, and show me that that particular item did not exist, and when I checked the if statement, it was a different direction than where I supposedly was. So error go, this is most likely why my pivot positioning and stuff was not working perfectly 100% of the time.

But again, thanks, I really appreciate you giving me some pointers to work from.

Ken


StOrM3(Posted 2004) [#18]
I will keep you updated as code progresses, so far, I have the type created, and all the fields, and some const ID's similar to how you did it. I am using a gameitems type for everything. The items on the grid, the player, the retaining walls, everything. I have added fields to the type to allow for animation fx, and different models based on what random item is selected first time, then if player hits a (?) item it chooses random again, to place either an item, or +10seconds, or -5seconds, or 1UP, or RIP tombstone instant life lost. It is a huge type, but it contains everything I need in a neat package, which will make it much easier for collision stuff, and player movement, animation fx, all kinds of good stuff, like the puzzle items also.


big10p(Posted 2004) [#19]
Glad the code's of some use to you. I tried to just keep to the basic concepts in order to keep it easier to understand (hopefully).


I am kind of puzzled at some of your code though, like why when your moving you always use *2 or +2 or -2 for everything. I'm assuming it has to do with your player offset code.



There's a couple of reasons you see *2, +2, -2 in the movement code:
1) Each grid item takes up a 2x2 blitz unit square when displayed onscreen. So, when placing an item onscreen, we need to multiply the row,col position of that item by 2.
2) When moving the player around a corner (in move_player() func), it has to be moved by 2 rows and 2 columns to reach the new, destination position.


StOrM3(Posted 2004) [#20]
*POST UPDATED*
ahhh.. okay.. I think I've got it..

I removed the type code, if anyone needs an example of how to do randomized items, and one item turning into another upon collision, let me know, I will repost the code for the types to do it.

Below is my journal of how development is going...

GameSetup, LoadModels are now done, working on CreateGrid, ReadGrid is also complete, made a stub function printgrid to ensure it was being read in, and everything was in the correct order. Working on the randomized items and pointing to the next items in CreateGrid, then when that is done, will work on PlayerMove, finally PlayerShoot which will again modify the items on the screen, depending on what the player hits. Also have animations I am setting up.

All models are now created also, except for particles model, that will be complete this week, then I now have a complete set of models to test the engine as I develop it. I also am writing a set of various stub functions merely to test each major function out as I go, to ensure correct, and bug free development as I go along, instead of the way I did it in the past, code 2000 lines, then play debug catchup for a few days, scratching my head, and rubbing my eyes, and second guessing myself.

I personally recomend this technique to anyone working on a major project in blitz, code one function at a time, then make a stub function to either print the values out or display the items on the screen, to ensure, the items load correctly and values you set are being set correctly.

Hope this little dev journal helps someone else out, whom is coding, the way I used to. Also another tip to everyone, code and comment rather like you aren't going to look at it for a year, then have to make an update, in otherwords, comment heavily, logically, the rule of thumb is this, if you have to look at it and think for a second, you need to put a comment there. Period.