HGE small demo: Using linked lists

Advanced game related topics
byo
Enthusiast
Enthusiast
Posts: 635
Joined: Mon Apr 02, 2007 1:43 am
Location: Brazil

HGE small demo: Using linked lists

Post by byo »

Hi, guys.

I just made this small demo using linked lists. It does nothing special right now, it was written just to show the usage of linked lists and to add to the HGE examples.

It may be helpful to those who just started using HGE with Purebasic to set things up properly and make a first demo run. :)

You can download all the resources below (I'm not the author of any of those images):

http://rapidshare.com/files/128501932/H ... o.zip.html
[EDIT] : you must change the #PROJECT_PATH constant.

Code: Select all

IncludeFile "..\HGEWrapper_Include.pbi"

Structure hgeRect
	x1.f
	x2.f
	y1.f
	y2.f
EndStructure

Structure sprite
	x.f
	y.f
	w.l
	h.l
	speed.f
	sprite.l
	tex.l
EndStructure

Global player.sprite
player\x = 303.0
player\y = 410.0
player\w = 48
player\h = 39
player\speed = 0.2

Global NewList bullet.sprite()
Global NewList block.sprite()

Global bulletsOnScreen.l

#PROJECT_PATH = "C:\Purebasic\HGE\Projeto\"
#SCREEN_WIDTH = 640
#SCREEN_HEIGHT = 480
#MAX_BULLETS = 12

ProcedureCDLL frameFunc()  
	If hge_Input_GetKeyState(#HGEK_ESCAPE)
		ProcedureReturn #True
	EndIf
	If hge_Input_GetKeyState(#HGEK_RIGHT)
		player\x + player\speed
	
		If player\x > #SCREEN_WIDTH - player\w
			player\x = #SCREEN_WIDTH - player\w
		EndIf  	
	EndIf
	If hge_Input_GetKeyState(#HGEK_LEFT)
		player\x - player\speed
	
		If player\x < 0
			player\x = 0
		EndIf	
  	EndIf
  	If hge_Input_KeyDown(#HGEK_SPACE)
  		If bulletsOnScreen < #MAX_BULLETS
  			AddElement(bullet())
  			bullet()\x = player\x + player\w/2 - 5
  			bullet()\y = player\y - 10
  			bullet()\w = 10 : bullet()\h = 10
  			bullet()\tex = hge_Texture_Load(#PROJECT_PATH + "bullet.png")
  			bullet()\sprite = hge_Sprite(bullet()\tex, 0, 0, bullet()\w, bullet()\h)
  			hge_Sprite_SetBlendMode(bullet()\sprite, #BLEND_COLORMUL|#BLEND_ALPHAADD|#BLEND_NOZWRITE)
  			
  			bulletsOnScreen + 1
  		EndIf
  	EndIf
  	
  	ForEach bullet()
  		bullet()\y - 0.3  		
  		
  		ResetList(block())
  		While NextElement(block())
  			If (bullet()\x+bullet()\w >= block()\x And bullet()\x < block()\x+block()\w) And (bullet()\y+bullet()\h >= block()\y And bullet()\y < block()\y+block()\h)
				DeleteElement(block(), 1)
				DeleteElement(bullet(), 1)				
				
				bulletsOnScreen -1
				Break
		  	EndIf
		  	
		  	If bullet()\y < -10
  				DeleteElement(bullet(), 1)
  				bulletsOnScreen - 1
  				Break
  			EndIf
		Wend
  	Next

	ProcedureReturn #False
    
EndProcedure

ProcedureCDLL renderFunc()
  hge_Gfx_BeginScene(#Null)
  
  hge_Gfx_Clear(0)
  hge_Sprite_Render(player\sprite, player\x, player\y)
  
  ForEach block()
  	hge_Sprite_Render(block()\sprite, block()\x, block()\y)
  Next
    
  ForEach bullet()
  	hge_Sprite_Render(bullet()\sprite, bullet()\x, bullet()\y)
  Next  
  
  hge_Gfx_EndScene()
  
  ProcedureReturn #False
EndProcedure  

hge_Create(#HGE_VERSION)
hge_System_SetStateBool(#HGE_WINDOWED, #True)
hge_System_SetStateString(#hge_LOGFILE, #PROJECT_PATH + "byo_demo.log")
hge_System_SetStateFunc(#HGE_FRAMEFUNC, @frameFunc())
hge_System_SetStateFunc(#hge_RENDERFUNC, @renderFunc())
hge_System_SetStateBool(#hge_SHOWSPLASH, #False)
hge_System_SetStateString(#HGE_TITLE, "byo demo")
hge_System_SetStateBool(#HGE_USESOUND, #False)
hge_System_SetStateInt(#hge_SCREENHEIGHT, #SCREEN_HEIGHT)
hge_System_SetStateInt(#hge_SCREENWIDTH, #SCREEN_WIDTH)
hge_System_SetStateInt(#hge_SCREENBPP, 32)

If hge_System_Initiate()
	player\tex = hge_Texture_Load(#PROJECT_PATH + "shuttle.png")
	player\sprite = hge_Sprite(player\tex, 0, 0, player\w, player\h)
	hge_Sprite_SetBlendMode(player\sprite, #BLEND_COLORMUL|#BLEND_ALPHAADD|#BLEND_NOZWRITE)
	
	#blocksize = 32
	
	For y.l = 0 To 320 Step #blocksize
		For x.l = 0 To 640 Step #blocksize
			AddElement(block())
			block()\x = x
			block()\y = y
			block()\w = #blocksize
			block()\h = #blocksize
			block()\tex = hge_Texture_Load(#PROJECT_PATH + "block.png")
			block()\sprite = hge_Sprite(block()\tex, block()\x, block()\y, block()\w, block()\h)
			hge_Sprite_SetBlendMode(block()\sprite, #BLEND_COLORMUL|#BLEND_ALPHAADD|#BLEND_NOZWRITE)
		Next
	Next			
	
	hge_System_Start()
	hge_System_Shutdown()
	hge_Release()
EndIf
Proud registered Purebasic user.
Because programming should be fun.
untune
User
User
Posts: 56
Joined: Sun Jul 06, 2008 10:07 pm
Location: Bolton, UK

Post by untune »

Thanks byo, great little demo, nice and easy to understand. I suppose linked lists would be the most effective method of running through everything that needs to be rendered per loop - in this case would it be more efficient rather than having separate bullet and block lists, to have one 'sprite' list... which is then run through in one call?

Maybe there could be a VisibleSprites list for only what is on screen... and lists to check for collisions etc... what do you think?
byo
Enthusiast
Enthusiast
Posts: 635
Joined: Mon Apr 02, 2007 1:43 am
Location: Brazil

Post by byo »

Thanks, untune.
Yes, I think it's a great method of dealing with large numbers of objects on screen since linked lists are crash-proof if used with care and the ForEach command alone is very versatile.

You could easily create the code for taking care of armies and workers in a RTS game, for example having a linked list with a structure. I remember a time when arrays or pointers were the standard way of listing sprites on screen and their properties.

HGE seems good enough but I wonder if the renderFunc and frameFunc can lead to some confusion to what code goes into either functions. Maybe I should read the HGE full documentation when I have the time. :lol:
Proud registered Purebasic user.
Because programming should be fun.
untune
User
User
Posts: 56
Joined: Sun Jul 06, 2008 10:07 pm
Location: Bolton, UK

Post by untune »

Hehe yeah, the RTS idea is great, it would be easy to manage lots of units with linked lists... but then think about the AI and pathfinding... that could soon spiral out of control :D

Yeah I know what you mean about the frame and render functions... the way I've come to understand it is... use the frameFunc to calculate everything.... movement, timing, physics, everything like that... and then use the renderFunc to actually do the drawing calls. You can even hack deeper and organise your own batching of vertices for sending to the GPU... lots of possibilities!
User avatar
zxtunes.com
Enthusiast
Enthusiast
Posts: 375
Joined: Wed Apr 23, 2008 7:51 am
Location: Saint-Petersburg, Russia
Contact:

Post by zxtunes.com »

Byo dont use "hge_Texture_Load" in "frameFunc()".
Load texture and sprites before "hge_System_Start()".
And use pointers, there is no sense to load the same texture for everyone bullets, you in vain spend memory.



This most true:

Code: Select all

texture.l = hge_Texture_Load(PROJECT_PATH$ + "block.png")
	For y.l = 0 To 320 Step #blocksize
		For x.l = 0 To 640 Step #blocksize
			AddElement(block())
			block()\x = x
			block()\y = y
			block()\w = #blocksize
			block()\h = #blocksize
			block()\tex = texture
			block()\Sprite = hge_Sprite(block()\tex, block()\x, block()\y, block()\w, block()\h)
			hge_Sprite_SetBlendMode(block()\Sprite, #BLEND_COLORMUL|#BLEND_ALPHAADD|#BLEND_NOZWRITE)
		Next
	Next	
byo
Enthusiast
Enthusiast
Posts: 635
Joined: Mon Apr 02, 2007 1:43 am
Location: Brazil

Post by byo »

Thank you, zxtunes. I haven't thought about memory optimisation, as I was loading the same image over and over again. :oops:

How about this?:

Code: Select all

IncludeFile "..\HGEWrapper_Include.pbi"

Structure hgeRect
	x1.f
	x2.f
	y1.f
	y2.f
EndStructure

Structure sprite
	x.f
	y.f
	w.l
	h.l
	speed.f
	sprite.l
EndStructure

Global player.sprite
player\x = 303.0
player\y = 410.0
player\w = 48
player\h = 39
player\speed = 0.5

Global NewList bullet.sprite()
Global NewList block.sprite()

Global bulletsOnScreen.l
Global *font

Global playerTex.l, blockTex.l, bulletTex.l

#PROJECT_PATH = "C:\Purebasic\HGE\Projeto\"
#SCREEN_WIDTH = 640
#SCREEN_HEIGHT = 480
#MAX_BULLETS = 12

ProcedureCDLL frameFunc()  
	If hge_Input_GetKeyState(#HGEK_ESCAPE)
		ProcedureReturn #True
	EndIf
	If hge_Input_GetKeyState(#HGEK_RIGHT)
		player\x + player\speed
	
		If player\x > #SCREEN_WIDTH - player\w
			player\x = #SCREEN_WIDTH - player\w
		EndIf  	
	EndIf
	If hge_Input_GetKeyState(#HGEK_LEFT)
		player\x - player\speed
	
		If player\x < 0
			player\x = 0
		EndIf	
  	EndIf
  	If hge_Input_KeyDown(#HGEK_SPACE)
  		If bulletsOnScreen < #MAX_BULLETS
  			AddElement(bullet())
  			bullet()\x = player\x + player\w/2 - 5
  			bullet()\y = player\y - 10
  			bullet()\w = 10 : bullet()\h = 10
  			bullet()\speed = 0.5  			
  			bullet()\sprite = hge_Sprite(bulletTex, 0, 0, bullet()\w, bullet()\h)
  			hge_Sprite_SetBlendMode(bullet()\sprite, #BLEND_COLORMUL|#BLEND_ALPHAADD|#BLEND_NOZWRITE)
  			
  			bulletsOnScreen + 1
  		EndIf
  	EndIf
  	
  	ForEach bullet()
  		bullet()\y - bullet()\speed
  		
  		ResetList(block())
  		While NextElement(block())
  			If (bullet()\x+bullet()\w >= block()\x And bullet()\x < block()\x+block()\w) And (bullet()\y+bullet()\h >= block()\y And bullet()\y < block()\y+block()\h)
				If bullet()\sprite : hge_Sprite_Delete(bullet()\sprite) : EndIf
				If block()\sprite : hge_Sprite_Delete(block()\sprite) : EndIf
				DeleteElement(block(), 1)
				DeleteElement(bullet(), 1)				
				
				bulletsOnScreen -1
				Break
		  	EndIf
		  	
		  	If bullet()\y < -10
		  		If bullet()\sprite : hge_Sprite_Delete(bullet()\sprite) : EndIf
  				DeleteElement(bullet(), 1)
  				bulletsOnScreen - 1
  				Break
  			EndIf
		Wend
  	Next

	ProcedureReturn #False
    
EndProcedure

ProcedureCDLL renderFunc()
  hge_Gfx_BeginScene(#Null)
  
  hge_Gfx_Clear(0)
  hge_Sprite_Render(player\sprite, player\x, player\y)
  
  ForEach block()
  	hge_Sprite_Render(block()\sprite, block()\x, block()\y)
  Next
    
  ForEach bullet()
  	hge_Sprite_Render(bullet()\sprite, bullet()\x, bullet()\y)
  Next
  
  hge_Gfx_EndScene()
  
  ProcedureReturn #False
EndProcedure  

hge_Create(#HGE_VERSION)
hge_System_SetStateBool(#HGE_WINDOWED, #True)
hge_System_SetStateString(#hge_LOGFILE, #PROJECT_PATH + "byo_demo.log")
hge_System_SetStateFunc(#HGE_FRAMEFUNC, @frameFunc())
hge_System_SetStateFunc(#hge_RENDERFUNC, @renderFunc())
hge_System_SetStateBool(#hge_SHOWSPLASH, #False)
hge_System_SetStateString(#HGE_TITLE, "byo demo")
hge_System_SetStateBool(#HGE_USESOUND, #False)
hge_System_SetStateInt(#hge_SCREENWIDTH, #SCREEN_WIDTH)
hge_System_SetStateInt(#hge_SCREENHEIGHT, #SCREEN_HEIGHT)
hge_System_SetStateInt(#hge_SCREENBPP, 32)

If hge_System_Initiate()
	blockTex = hge_Texture_Load(#PROJECT_PATH + "block.png")
	bulletTex = hge_Texture_Load(#PROJECT_PATH + "bullet.png")
	playerTex = hge_Texture_Load(#PROJECT_PATH + "shuttle.png")
	
	player\sprite = hge_Sprite(playerTex, 0, 0, player\w, player\h)
	hge_Sprite_SetBlendMode(player\sprite, #BLEND_COLORMUL|#BLEND_ALPHAADD|#BLEND_NOZWRITE)
	
	#blocksize = 32	
	
	For y.l = 0 To 320 Step #blocksize
		For x.l = 0 To 640 Step #blocksize
			AddElement(block())
			block()\x = x
			block()\y = y
			block()\w = #blocksize
			block()\h = #blocksize
			block()\sprite = hge_Sprite(blockTex, block()\x, block()\y, block()\w, block()\h)
			hge_Sprite_SetBlendMode(block()\sprite, #BLEND_COLORMUL|#BLEND_ALPHAADD|#BLEND_NOZWRITE)			
		Next
	Next			
	
	hge_System_Start()
	hge_System_Shutdown()
	hge_Release()
EndIf
Proud registered Purebasic user.
Because programming should be fun.
Post Reply