Simple AI Help

Blitz3D Forums/Blitz3D Programming/Simple AI Help

Chispon(Posted 2014) [#1]
I was a bit bored and i made a program: a Ship that flies and dodge Asteroids automatically. It uses 4 sensors to check if there's a near an Asteroid.
For example: if left sensor is activated the Ship will moves to the right. If both left and right sensors are activated it will relays on two sensors of it's sides.
The problem it's, idk what to do if all sensors are activated LOL. I hope you help me to improve it, any suggestion will be nice :)

F1: Toggle Debug
Space: Center Ship
Enter: Reset game(when game over screen)

Images(2 kb): http://www.mediafire.com/download/17zuu8bmfal64r5/img.rar

;-------------------------
;- Title: Simple AI Test -
;-------------------------
;- Author: Chispon		 -
;-------------------------
;- Created: 09/01/2014	 -
;-------------------------
;- Edited: 10/01/2014	 -
;-------------------------

AppTitle "Simple AI"
Graphics 320, 240, 32, 2
SetBuffer BackBuffer()
SeedRnd MilliSecs()

SetFont LoadFont("Courier New", 14)

;----------
;- Images -
;----------

Global gfx_ship = LoadImage("ship.bmp"): MaskImage gfx_ship, 255, 0, 255
Global gfx_life = LoadImage("life.bmp"): MaskImage gfx_life, 255, 0, 255
Global gfx_background = LoadImage("background_stars.bmp")

;---------
;- Types -
;---------

Type obj_ast
	Field x#
	Field y#
	Field r# ;radius
End Type

Type obj_exp
	Field x#
	Field y#
	Field a#
	Field l ;life
End Type

;-------------
;- Variables -
;-------------

Global debug = 1
Global speed# = 2
Global player_x# = 155
Global player_y# = 220
Global player_lives = 2
Global player_score = 0
Global player_dead  = 0
Global sensors_size = 50
Global time, old_time

Global background_y = 0

fpslock = CreateTimer(60)

While Not KeyDown(1)
	If MouseDown(1) Then CreateExplosion(MouseX(), MouseY())
	
	If KeyHit(57) Then player_x# = 155
	
	If KeyHit(59) Then debug = 1 - debug
	
	Color 255, 255, 255
	Rect 0, 0, 320, 240, 0
	
	TileImage gfx_background, 0, background_y: background_y = background_y + speed#
	
	Select player_dead
		Case 0
			If Rand(20) = 5 Then
				obj_r = Rand(10, 25)
				obj_x = Rand(0, 320 / obj_r) * obj_r
				
				SpawnObj(obj_x, -20, obj_r)
			EndIf
			
			For obj_ast.obj_ast = Each obj_ast
				If debug = 1 Then
					Color 255, 255, 0
					Rect obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2, 0
				EndIf
				
				If Distance2D(obj_ast\x#, obj_ast\y#, player_x#, player_y#) < obj_ast\r# Then
					Color 255, 0, 0
					;player_score = player_score - 5
					player_dead = 1
					CreateExplosion(player_x#, player_y#)
					old_time = MilliSecs()
				Else
					Color 180, 120, 80
				EndIf
				
				Oval obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2
				
				Color 130, 0, 20
				Oval obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2, 0
				
				
				If ( RectsOverlap(obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2, player_x# - 5 , player_y# - sensors_size, 1, sensors_size) And RectsOverlap(obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2, player_x# + 15, player_y# - sensors_size, 1, sensors_size) ) = 0 Then
					;Left Sensor
					If RectsOverlap(obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2, player_x# - 5 , player_y# - sensors_size, 1, sensors_size) Then player_x# = player_x# + speed#
					;Right Sensor
					If RectsOverlap(obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2, player_x# + 15, player_y# - sensors_size, 1, sensors_size) Then player_x# = player_x# - speed#
				Else
					If ( RectsOverlap(obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2, player_x# - 35, player_y# - sensors_size,  30, 1) And RectsOverlap(obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2, player_x# + 15, player_y# - sensors_size,  30, 1) ) = 0 Then
						;Down Left Sensor
						If RectsOverlap(obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2, player_x# - 35, player_y#,  30, 1) Then player_x# = player_x# + speed#
						;Down Right Sensor
						If RectsOverlap(obj_ast\x# - obj_ast\r#, obj_ast\y# - obj_ast\r#, obj_ast\r# * 2, obj_ast\r# * 2, player_x# + 15, player_y#,  30, 1) Then player_x# = player_x# - speed#
					Else
						If player_x# < 155 Then player_x# = player_x# + speed#
						If player_x# > 155 Then player_x# = player_x# - speed#
					EndIf
				EndIf 
					
				obj_ast\y# = obj_ast\y# + speed#
				
				If obj_ast\y# > 260 Then player_score = player_score + 10: Delete obj_ast
			Next
		Case 1
			If player_lives > 0 Then
				For obj_ast.obj_ast = Each obj_ast
					Delete obj_Ast
				Next
				
				time = MilliSecs() - old_time
				
				If time > 3000 Then
					player_dead = 0
					player_lives = player_lives - 1
					player_x# = 155
				EndIf
			Else
				player_lives = -1
				
				For obj_ast.obj_ast = Each obj_ast
					Delete obj_Ast
				Next
				
				time = MilliSecs() - old_time
				
				Color 255, 0, 0
				Text 160, 120, "GAME OVER!", 1, 1
				
				If KeyHit(28) Or time > 10000 Then
					player_dead = 0
					player_lives = 2
					player_x# = 155
					player_score = 0
				EndIf
			EndIf 
	End Select
	
	For obj_exp.obj_exp = Each obj_exp
		Color 255, 0, 0
		Rect obj_exp\x#, obj_exp\y#, 3, 3
		
		obj_exp\x# = obj_exp\x# + 1 * Cos(obj_exp\a#)
		obj_exp\y# = obj_exp\y# + 1 * Sin(obj_exp\a#)
		
		obj_exp\l = obj_exp\l - 1
		
		If obj_exp\l <= 0 Then Delete obj_exp
	Next
	
	If debug = 1 Then
		Color 0, 255, 0
		;Rect player_x# + 5,  player_y# - 80, 1, 80 ;Middle Sensor
		Rect player_x# - 5,  player_y# - sensors_size, 1, sensors_size  ;Left Sensor
		Rect player_x# + 15, player_y# - sensors_size, 1, sensors_size  ;Right Sensor
		Rect player_x# - 35, player_y#,  30, 1     ;Down Left Sensor
		Rect player_x# + 15, player_y#,  30, 1	    ;Down Right Sensor
	EndIf
	
	If player_dead = 0 Then DrawImage gfx_ship, player_x#, player_y#
	
	Color 255, 255, 255
	Text 5, 5, "Score: " + player_score
	
	If player_lives > -1 Then
		For i = 0 To player_lives
			DrawImage gfx_life, 280 + i * 10, 5
		Next
	EndIf
	
	WaitTimer(fpslock)
	
	Flip
	
	Cls
Wend

End

Function CreateExplosion(x, y)
	Local i
	
	For i = 0 To Rand(25, 50)
		obj_exp.obj_exp = New obj_exp
		obj_exp\x# = x
		obj_exp\y# = y
		obj_exp\a# = Rnd(360)
		obj_exp\l  = Rand(25, 50)
	Next
End Function

Function SpawnObj(x, y, r)
	obj_ast.obj_ast = New obj_ast
	obj_ast\x = x
	obj_ast\y = y
	obj_ast\r = r
End Function

Function Distance2D#(x1, y1, x2, y2)
	Local xd# = x2 - x1
	Local yd# = y2 - y1
	
	Return (xd# * xd# + yd# * yd#)^0.5
End Function



Stevie G(Posted 2014) [#2]
It would be more useful for your sensors to return how far away the nearest object is. Set a maximum range for each sensor.

For each sensor, start at the ships position and move it forward in the vector direction of the sensor relative to the ships orientation and do a rectsoverlap check at each stage. If a contact is made prior to the sensor reaching the maximum range then store the distance to this contact, otherwise set to -1 (no contact).

Once you have contact distances for all sensors the best direction to turn would be the one where the sensor has no contact or the contact is the furthest away. You could also use this sensor information to slow down or speed up etc...


Rroff(Posted 2014) [#3]
Cheap and dirty way to do it would be to split the 3D space near the ship into grids and change heading towards the grid with the least density of objects to avoid.


Chispon(Posted 2014) [#4]
Ok, thanks for your suggestions guys :D