Checking fields and stuff with an array? Questions

BlitzMax Forums/BlitzMax Beginners Area/Checking fields and stuff with an array? Questions

Zacho(Posted 2011) [#1]
I am trying to make a check between player bullets and any of the 10 cpu's i created. I have successfully made 10 separate cpu images on my screen, but it only registers a hit at the invisible spot of (20,20), let me explain....



Automidhandle is set to true, and i create the types for my player/cpu and bullets
 Type spaceship
	Field x:Int,y:Int,frame:Int
	Field health:Int = 100, shield:Int
EndType 

Type bullettype
	Field x:Int
	Field y:Int = 560
	Field yv:Int = 4
	Field frame:Int
	Field sender:Int 'Who sent the bullet? 1 = player ; 0 = cpu
	Field status:Int 'Alive = 1 ; Dead = 0
EndType



I create the types for the all of the things in my game...
'
'CREATE TYPES
Global player:spaceship = New spaceship
Global cpu:spaceship = New spaceship
Global Cbullet:bullettype = New bullettype
Global Pbullet:bullettype = New bullettype

'
'CREATE THE LISTS
Global cpuList:TList = CreateList () 'List for cpu's
Global CbulletList:TList = CreateList () 'List for computer bullets
Global PbulletList:TList = CreateList () 'List for player bullets



I have a very simple main loop, only 2 functions, Draw () and UserInput (). Update () is commented out while I figure out my program

 '
'MAIN LOOP
While Not KeyHit(ESC) 
Cls


UserInput () 
Draw ()
'Update ()


Flip 
Wend



StartGame() is called before the main loop, this may be where my problem lies...

I create the player at 400,550 and 10 cpu's at an x-value of 500 and a y-value at a rand of 10-400. I assume I added them to the list correctly, because they all display on my screen


Function StartGame ()
 
	player.x = 400
	player.y = 550
	

	
For Local cpuNum:Int = 1 To 10
   Local cpu:spaceship = New spaceship
   cpu.x = 500 
   cpu.y = Rand(10,400)
  ListAddLast(cpuList,cpu)
Next

	
End Function 



UserInput () just checks input of keys hit, I don't think anything is wrong here; BOTH player (Pbullet) and cpu (Cbullet) bullet's show up on screen.

Function UserInput ()


'	
'PLAYER MOVEMENT		
	If KeyDown(LEFTKEY)
		player.x:-playerspeed
	EndIf 
	If KeyDown(RIGHTKEY)
		player.x:+playerspeed
	EndIf 

'
'FIRING 
	If KeyDown(SPACEBAR)
		Local Cbullet:bullettype = New bullettype
		Cbullet.x = Rand(0,770)
		Cbullet.y = 10
		Cbullet.frame = 0
		ListAddLast(CbulletList,Cbullet)
	EndIf
	
	
	If KeyDown(VKEY) 
		Local Pbullet:bullettype = New bullettype
		Pbullet.x = player.x + 15
		Pbullet.y = player.y + 10
		ListAddLast(PbulletList,Pbullet)
	EndIf 
	

	
EndFunction 



Draw (), this is the function I have questions about:

Function Draw ()
	
'	
'DRAW Cbullets	
	For Local Cbullet:bullettype = EachIn CbulletList
		Cbullet.y:+ Cbullet.yv
		Cbullet.frame:+1
			If Cbullet.frame > 3
				Cbullet.frame = 0
			EndIf
		DrawImage Cbulletimage:TImage,Cbullet.x,Cbullet.y,Cbullet.frame
		If Cbullet.y > 575 
			ListRemove (CbulletList,Cbullet)
		EndIf 
		If ImagesCollide(Cbulletimage,Cbullet.x,Cbullet.y,0,playerimage,player.x,player.y,0)
			player.health:-1
			ListRemove (CbulletList,Cbullet)
		EndIf 
	Next



The code above works perfectly. The y value of the bullets increases, the frames work good. If the bullet hits the boundry it is deleted. If the bullet hits the player it is deleted and the player.health decreases by one.


	
'	
'DRAW Pbullets
	For Local Pbullet:bullettype = EachIn PbulletList
		Pbullet.y:- Pbullet.yv	
	
	
		DrawImage Pbulletimage:TImage,Pbullet.x,Pbullet.y
		If Pbullet.y < 0 
			ListRemove (PbulletList,Pbullet)
		EndIf
		If ImagesCollide(Pbulletimage,Pbullet.x,Pbullet.y,0,cpuimage,cpu.x,cpu.y,0)
			cpu.health:-1 
			ListRemove (PbulletList,Pbullet)
		EndIf
	Next 
	



The player bullets DRAW, but they don't collide with any of the images of the cpu. Strangely, it DOES connect with a spot (about (20,20)) on the screen. I have a debug command that writes the cpu.health on screen and it decreases when bullets hit this spot (20,20). The bullets DO delete when hitting this spot... I have no idea why


'		
'DRAW PLAYER	
If player.health > 0
	DrawImage(playerimage:TImage,player.x,player.y)
Else
	 
EndIf 	

'	
'DRAW CPU		
For Local cpu:spaceship = EachIn cpuList
	
	If cpu.health > 0
		DrawImage cpuimage:TImage,cpu.x,cpu.y
	Else
	EndIf 
Next


And finally just drawing the player and cpu. THe player image will not be shown when player.health goes to 0, although I can still move the player. Is there a way to delete this type once health hits < 0?



If you see a problem what I did, can you suggest what I should look at? (not directlly tell me the answer; it will help me ;D ) Thanks again BMax community!!


Zacho(Posted 2011) [#2]
I think the problem lies within this piece of code:

'	
'DRAW Pbullets
	For Local Pbullet:bullettype = EachIn PbulletList
		Pbullet.y:- Pbullet.yv	
	
	
		DrawImage Pbulletimage:TImage,Pbullet.x,Pbullet.y
		If Pbullet.y < 0 
			ListRemove (PbulletList,Pbullet)
		EndIf
		If ImagesCollide(Pbulletimage,Pbullet.x,Pbullet.y,0,cpuimage,cpu.x,cpu.y,0)
			cpu.health:-1 
			ListRemove (PbulletList,Pbullet)
		EndIf
	Next 


The way I am reading this is that any instance of Pbullet that is created, if this collides with a cpu image then it will delete both. Since the cpu and Pbullet both can exist in more than one at a single instance, do you have to do something like this?

'	
'DRAW Pbullets
	For Local Pbullet:bullettype = EachIn PbulletList
	For Local cpu:spaceship = EachIn cpuList	'ADDED this
                               Pbullet.y:- Pbullet.yv	
	
	
		DrawImage Pbulletimage:TImage,Pbullet.x,Pbullet.y
		If Pbullet.y < 0 
			ListRemove (PbulletList,Pbullet)
		EndIf
		If ImagesCollide(Pbulletimage,Pbullet.x,Pbullet.y,0,cpuimage,cpu.x,cpu.y,0)
			cpu.health:-1 
			ListRemove (PbulletList,Pbullet)
		EndIf
	Next 
               Next 'ADDED this


?


Jesse(Posted 2011) [#3]
try keeping your draw and your processing separate:

for example draw:
function drawAll()
    for local cpu:spaceship eachin cpuList
         drawimage spaceshipImg,cpu.x,cpu.y,cpu.frame
    next
   for local pbullet:bullettype = eachin pbulletList
         DrawImage pbuletImage,pbullet.x,pbullet.y
   next
end function


and a function that does all of the processing that way you can keep your code a bit better organized

there is a little problem with your logic for when you remove bullet

first, if bullet y < 0 you delete the bullet but if it's deleted why are you checking for collision?

second, once the bullet is stored in Pbullet it wont be deleted until the eachin assigns the next bullet to Pbullet and that won't happen until it goes through all of the spaceships. that means that if the bullet hits the first ship and you remove it from the list it still exists in the variable Pbullet so it still going to check for collision with the other spaceships.
one way to avoid this is to exit the spaceship for loop after the bullet is deleted from the list with an exit.

Last edited 2011


Zacho(Posted 2011) [#4]
Since I am terribly inexperienced with programming can I ask as to clarify what you said?

Using the
 For Local Pbullet:bullettype = Eachin PbulletList

If ImagesCollide(Pbulletimage,Pbullet.x,Pbullet.y,0,cpuimage,cpu.x,cpu.y,0)



Specifically the part: " ...cpuimage,cpu.x,cpu.y,0" Does this signify to the compiler to check for collision of the cpu as a whole (all instances of it) or each individual cpu created. The way I am understanding what you said, you said it is checking for collisions between all images?

The exit function as well... The way I understand it (I may be wrong) but "For Local... Eachin TList" does an action for everything in this list correct? If I tell the compiler to create a bullet, and add it to the list when I hit a key. When I do this it should be added to a list correct? Should I be using ListAddFirst instead of ListAddLast? If I check for collisions in this list, if they occur I would delete them from the list and delete the bullet (I have no collision checks for bullets outside of the list)

I am trying to understand what you are saying :)


Jesse(Posted 2011) [#5]
just to clarify the" eachin lists" only goes from the top of the list to the bottom. There is no going from the bottom to the top.
what eachin does is, it start from the first object in the list and will continue grabbing objects. If the list contain bullets it will start grabbing from the top of the list one at a time and assign it to the local variable in this case the Pbullet.

on your bullet "for loop" eachin will assign the first bullet to the variable Pbullet it will perform all of the actions inside the "For loop" and when it reaches next it will go back to the "for eachin" and will assign the next bullet in the list to "Pbullet" variable until the last bullet.

that means that while inside the "for/next" loop the bullet will exist in the Pbullet variable unless you null the Pbullet.

in your previos post you created the for next loop and you include the test for when a bullet goes out of view. then, you told it to delete the bullet from the list. the bullet is removed from the list but it is still in the variable "Pbullet". so just remember that the bullet got deleted from the list because it went out of side of view but you still performed the second test to see if it collided with the spaceship. you can do that but technically there is no reason for the test because you already deleted it from the list and it can not be deleted twice. in that case there is not reason for the test.

the other problem was that you are using the bullet inside a nested for/next loop of spaceships.
lets assume the bullet hits the first ship in the for loop. the way you have it, it will collide with the ship. you will remove it from the list, afterwards it will cycle through to the next ship and because it still exists in the Pbullet bariable it will check for collision and out of bound with the new spaceship. it will continue to do that until the last ship.

what you need to do is exit the spaceship loop after either of the collisions.
this is all you need to do:
	For Local Pbullet:bullettype = EachIn PbulletList
		For Local cpu:spaceship = EachIn cpuList	'ADDED this
	         Pbullet.y:- Pbullet.yv	
		
		
			DrawImage Pbulletimage:TImage,Pbullet.x,Pbullet.y
			If Pbullet.y < 0 
				ListRemove (PbulletList,Pbullet)
				Exit ' <----------this will exit the spaceship loop 
			EndIf

			If ImagesCollide(Pbulletimage,Pbullet.x,Pbullet.y,0,cpuimage,cpu.x,cpu.y,0)
				cpu.health:-1 
				ListRemove (PbulletList,Pbullet)
				Exit ' <---------this will exit the spaceship loop
			EndIf
		Next 
	Next 'ADDED this

all you needed to do is add exit so that it will exit the inner for/next loop and continue with the next bullet.


Zacho(Posted 2011) [#6]
I understand now what you mean by:
 you created the for next loop and you include the test for when a bullet goes out of view. then, you told it to delete the bullet from the list. the bullet is removed from the list but it is still in the variable "Pbullet". 
so just remember that the bullet got deleted from the list because it went out of side of view but you still performed the second test to see if it collided with the spaceship. you can do that but technically there is no reason for the test because you already deleted it from the list and it can not be deleted twice. in that case there is not reason for the test.



When you said:
 the other problem was that you are using the bullet inside a nested for/next loop of spaceships.


and referring to:
 

'	
'DRAW Pbullets
	For Local Pbullet:bullettype = EachIn PbulletList
	For Local cpu:spaceship = EachIn cpuList	'ADDED this
                               Pbullet.y:- Pbullet.yv	
	
	
		DrawImage Pbulletimage:TImage,Pbullet.x,Pbullet.y
		If Pbullet.y < 0 
			ListRemove (PbulletList,Pbullet)
		EndIf
		If ImagesCollide(Pbulletimage,Pbullet.x,Pbullet.y,0,cpuimage,cpu.x,cpu.y,0)
			cpu.health:-1 
			ListRemove (PbulletList,Pbullet)
		EndIf
	Next 
               Next 'ADDED this


This was actually a shot in the dark by me, I don't know if it would work or not. But when you suggested to add a Exit in here I tried it out and the bullets DO now delete when they hit any of the cpu images, but the cpu.health still remains a constant. I will worry about the health later and try to understand these changes to my code.

I am thinking about re-coding this Pbullet to something like


If .... y < 0
       listremove
       exit
Elseif images collide
       listremove
       cpu.health:-2
       exit
else
       draw bullet
endif



Frankly, I do not like the look of a for...next loop within another for...next loop, it looks too complicated but it DOES work... I would rather understand and have the code longer rather than some quick fix I don't understand :P

thanks so far Jesse!!


Zacho(Posted 2011) [#7]
Is it the only way to check the bullet collision by having a For...Next (for Pbullets) and a For...Next (for cpu's) if I have more than once instance at a time?


Jesse(Posted 2011) [#8]
No. you can use repeat/until, while/wend etc. but its basically the same thing. you loop through each bullet and for each bullet you loop through each of the ships.

Last edited 2011


Zacho(Posted 2011) [#9]
? You just said you need to check for that ? "Loop through each bullet... loop through each ship"

Then I will guess it IS the way to go to put a nested loop within my bullet loop for ships?