Basic Wandering AI

Blitz3D Forums/Blitz3D Programming/Basic Wandering AI

Had a bit of free time to do some beginner AI stuff tonight. 10 cubes wandering around trying not to get lost. Insanely simple! Feel free to expand on this if you feel the urge.


Global gameFPS = 50

Graphics3D 1024,768,32,2
SetBuffer BackBuffer()

SeedRnd MilliSecs()

Global camera = CreateCamera ()
CameraZoom camera,1.6
CameraRange camera,.1,100000
CameraClsColor camera,0,0,0
PositionEntity camera,0,140,-800

AmbientLight 150,150,150

light = CreateLight()
PositionEntity light,0,0,0

quit = False

framePeriod = 1000 / gameFPS
frameTime = MilliSecs () - framePeriod

Type cube
	Field mesh
	Field walktimer
	Field turntimer
	Field moving
	Field decision
	Field distfromhome
End Type

For i = 1 To 10
	c.cube = New cube
	c\mesh = CreateCube()
	EntityColor c\mesh,Rand(0,255),Rand(0,255),Rand(0,255)
	ScaleEntity c\mesh,10,10,10
	PositionEntity c\mesh,Rand(-300,300),10,Rand(-300,300)
Next

home = CreateSphere()
ScaleEntity home,6,6,6
PositionEntity home,0,10,0

PointEntity camera,home

Plane=CreatePlane()
EntityAlpha Plane,0.8
PlaneTexture=CreateTexture(128,128,9)
ClsColor 0,0,255
Cls
Color 255,255,255
Rect 0,0,64,64,1
Rect 64,64,64,64,1
CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(PlaneTexture)
ScaleTexture PlaneTexture,40,40
EntityTexture Plane,PlaneTexture,0,0

Repeat

	Repeat
		frameElapsed = MilliSecs () - frameTime
	Until frameElapsed

	frameTicks = frameElapsed / framePeriod

	frameTween# = Float (frameElapsed Mod framePeriod) / Float (framePeriod)

	For frameLimit = 1 To frameTicks

		If frameLimit = frameTicks Then CaptureWorld
		frameTime = frameTime + framePeriod
		
		If KeyHit(1) Then quit = True
		
		For c.cube = Each cube
		
			c\distfromhome = EntityDistance(c\mesh,home)
				
			If c\moving = False
				c\decision = Rand(1,200)
				Select True
					Case c\decision = 10
						c\walktimer = MilliSecs() + 3000
					Case c\decision = 100
						c\turntimer = MilliSecs() + 1000
				End Select
			EndIf
	
			If c\walktimer > MilliSecs() 
				c\moving = True
				MoveEntity c\mesh,0,0,2
			Else If c\turntimer > MilliSecs()
				c\moving = True
				TurnEntity c\mesh,0,2,0
			Else
				c\moving = False
			EndIf
	
			If c\distfromhome > 400
				dy#=DeltaYaw(c\mesh,home)*.04
				TurnEntity c\mesh,0,dy,0
			EndIf
			
		Next

		UpdateWorld

	Next
	
	RenderWorld frameTween
	
	Flip

Until quit = True

End


Function 'dcreateplane' not found
Line 48, Column 1

I think that's a typo? Try removing the d, and see what happens.

Whoops, sorry about that. Was a jvode line...fixed.

Boo! It was better before you fixed it - that checker plane is hurting my eyes.

Nice example though, it is more a guarding/patrol example. I would not deem this wandering AI. This type of AI is in Hinterland.

Dropped in some entity avoidance code.


Global gameFPS = 50

Graphics3D 1024,768,32,2
SetBuffer BackBuffer()

SeedRnd MilliSecs()

Global camera = CreateCamera ()
CameraZoom camera,1.6
CameraRange camera,.1,100000
CameraClsColor camera,0,0,0
PositionEntity camera,0,140,-800

AmbientLight 150,150,150

light = CreateLight()
PositionEntity light,0,0,0

quit = False

framePeriod = 1000 / gameFPS
frameTime = MilliSecs () - framePeriod

Type cube
	Field mesh
	Field walktimer
	Field turntimer
	Field moving
	Field decision
	Field distfromhome
	Field id
End Type

For i = 1 To 10
	c.cube = New cube
	c\id = i
	c\mesh = CreateCube()
	EntityColor c\mesh,Rand(0,255),Rand(0,255),Rand(0,255)
	ScaleEntity c\mesh,10,10,10
	PositionEntity c\mesh,0,10,0
	d.cube = c.cube
Next

home = CreateSphere()
ScaleEntity home,6,6,6
PositionEntity home,0,10,0

PointEntity camera,home

Plane=CreatePlane()
EntityAlpha Plane,0.8
PlaneTexture=CreateTexture(128,128,9)
ClsColor 0,0,255
Cls
Color 255,255,255
Rect 0,0,64,64,1
Rect 64,64,64,64,1
CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(PlaneTexture)
ScaleTexture PlaneTexture,40,40
EntityTexture Plane,PlaneTexture,0,0

Repeat

	Repeat
		frameElapsed = MilliSecs () - frameTime
	Until frameElapsed

	frameTicks = frameElapsed / framePeriod

	frameTween# = Float (frameElapsed Mod framePeriod) / Float (framePeriod)

	For frameLimit = 1 To frameTicks

		If frameLimit = frameTicks Then CaptureWorld
		frameTime = frameTime + framePeriod
		
		If KeyHit(1) Then quit = True
		
		For c.cube = Each cube
		
			For d.cube = Each cube
				If c\id <> d\id and c\moving = True
					avoid_entity( c\mesh, d\mesh, 2, 2 )
				EndIf
			Next
			
			c\distfromhome = EntityDistance(c\mesh,home)
				
			If c\moving = False
				c\decision = Rand(1,200)
				Select True
					Case c\decision = 10
						c\walktimer = MilliSecs() + 3000
					Case c\decision = 100
						c\turntimer = MilliSecs() + 1000
				End Select
			EndIf
	
			If c\walktimer > MilliSecs() 
				c\moving = True
				MoveEntity c\mesh,0,0,2
			Else If c\turntimer > MilliSecs()
				c\moving = True
				TurnEntity c\mesh,0,2,0
			Else
				c\moving = False
			EndIf
	
			If c\distfromhome > 400
				dy#=DeltaYaw(c\mesh,home)*.04
				TurnEntity c\mesh,0,dy,0
			EndIf
			
		Next

		UpdateWorld

	Next
	
	RenderWorld frameTween
	
	Flip

Until quit = True

End

Function avoid_entity( scr_entity, dest_entity, rate#, spd# )

	If EntityDistance(scr_entity,dest_entity) < 100 Then
		MoveEntity scr_entity,0,0,spd#
		dist1# = EntityDistance(scr_entity,dest_entity)
		MoveEntity scr_entity,0,0,-spd#
		TurnEntity scr_entity,0,rate#,0
		MoveEntity scr_entity,0,0,spd#
		dist2# = EntityDistance(scr_entity,dest_entity)
		MoveEntity scr_entity,0,0,-spd#
		TurnEntity scr_entity,0,-2*rate#,0
		MoveEntity scr_entity,0,0,spd#
		dist3# = EntityDistance(scr_entity,dest_entity)
		MoveEntity scr_entity,0,0,-spd#
		
		If dist1# > dist2# And dist1# > dist3# Then TurnEntity scr_entity,0,rate#,0
		If dist2# > dist3# And dist2# > dist1# Then TurnEntity scr_entity,0,2*rate#,0
		
		Return True
	Else
		Return False
	EndIf

End Function


mm. *claps graciously* except for the checker floor, excellent! :)

~DS~

Here it is in action: http://www.youtube.com/watch?v=vk9eqBS3H5o

Apologies for the quality. Just another one of my little projects that will probably never see the light of day. One man teams are tough!

hey it uses my avoid entity function from the archives! I knew that would come in useful someday... very nice for guard AI.

Overall, it's very neat and quite efficiently done for simplicity vs effectiveness :)

I really like it!

"Short low quality vid of a game I am coding." yet it asks If you want to watch it in high quality, lol.

It's almost exactly like the AI on Silkroad Online.
They randomly move around.
If you get close enough, they follow you.
If one is following you and they get too far away from a certain point, they ignore you and go back.

Exactly GIA, doesn't get any simpler. Just thought I'd share it for anyone that has a need for something this inane. I didn't realize there was a high quality link, thanks!

I'm still waiting for someone to spruce it up a bit! I think AI is limitless and I get a rush seeing things come to life and develop ways of doing things.

Watch 'em duke it out! Red usually wins for some odd reason. Might get a mav here and there...haven't sussed that out yet (needs some serious optimization anyway).


Global gameFPS = 50

Graphics3D 1024,768,32,2
SetBuffer BackBuffer()

SeedRnd MilliSecs()

Global camera = CreateCamera ()
CameraZoom camera,1.6
CameraRange camera,.1,100000
CameraClsColor camera,0,0,0
PositionEntity camera,0,140,-800

AmbientLight 150,150,150

light = CreateLight()
PositionEntity light,0,0,0

quit = False

framePeriod = 1000 / gameFPS
frameTime = MilliSecs () - framePeriod

redhome = CreateSphere()
ScaleEntity redhome,6,6,6
PositionEntity redhome,-400,10,0

bluehome = CreateSphere()
ScaleEntity bluehome,6,6,6
PositionEntity bluehome,400,10,0

Type cube
	Field mesh
	Field walktimer
	Field turntimer
	Field moving
	Field decision
	Field distfromhome
	Field id
	Field team
	Field level
	Field strength
	Field stamina
	Field dmg
	Field dly
	Field hp
	Field home
	Field angry
	Field timer
	Field dice
	Field damage
	Field alive
End Type

For i = 1 To 10
	c.cube = New cube
	c\id = i
	c\team = 1
	c\hp = 100
	c\dmg = 8
	c\dly = 1200
	c\stamina = 18
	c\strength = 20
	c\level = 10
	c\alive = True
	c\home = redhome
	c\mesh = CreateCube()
	EntityColor c\mesh,255,0,0
	ScaleEntity c\mesh,10,10,10
	PositionEntity c\mesh,EntityX(c\home),EntityY(c\home),EntityZ(c\home)
	d.cube = c.cube
Next

For i = 1 To 10
	c.cube = New cube
	c\id = i
	c\team = 2
	c\hp = 100
	c\dmg = 8
	c\dly = 1200
	c\stamina = 18
	c\strength = 20
	c\level = 10
	c\alive = True
	c\home = bluehome
	c\mesh = CreateCube()
	EntityColor c\mesh,0,0,255
	ScaleEntity c\mesh,10,10,10
	PositionEntity c\mesh,EntityX(c\home),EntityY(c\home),EntityZ(c\home)
	d.cube = c.cube
Next

Plane=CreatePlane()
EntityAlpha plane,.8
EntityColor plane,50,50,50
CreateMirror()

Repeat

	Repeat
		frameElapsed = MilliSecs () - frameTime
	Until frameElapsed

	frameTicks = frameElapsed / framePeriod

	frameTween# = Float (frameElapsed Mod framePeriod) / Float (framePeriod)

	For frameLimit = 1 To frameTicks

		If frameLimit = frameTicks Then CaptureWorld
		frameTime = frameTime + framePeriod
		
		If KeyHit(1) Then quit = True
		
		If KeyDown(203) Then TurnEntity camera,0,1,0
		If KeyDown(205) Then TurnEntity camera,0,-1,0
		If KeyDown(200) Then MoveEntity camera,0,0,2
		If KeyDown(208) Then MoveEntity camera,0,0,-2
		
		For c.cube = Each cube
		
			For d.cube = Each cube
		
				If d\alive = True
					
					If d\id <> c\id And d\moving = True
						avoid_entity( d\mesh, c\mesh, 2, 2 )
					EndIf
	
					If d\team <> c\team And EntityDistance (d\mesh,c\mesh) < 500
						c\angry = True
						dy#=DeltaYaw(d\mesh,c\mesh)*.1
						TurnEntity d\mesh,0,dy,0
						
						If EntityDistance (d\mesh,c\mesh) > 300
							MoveEntity d\mesh,0,0,4
						EndIf
						
						If d\timer + d\dly < MilliSecs()
						
							d\dice = Rnd(1,5)
							d\damage = Ceil((d\strength * d\stamina * d\dmg) * d\dice * d\level / 10000)
							c\hp = c\hp - d\damage
							d\timer = MilliSecs()
							
						EndIf
						
						If d\hp <=0 Then d\alive = False
						
					Else
						d\angry = False
					EndIf
				Else
					FreeEntity d\mesh
					Delete d
				EndIf
				
			Next
			
			If c\alive = True
			
				c\distfromhome = EntityDistance(c\mesh,c\home)
					
				If c\angry = False
					
					If c\moving = False
						c\decision = Rand(1,200)
						Select True
							Case c\decision = 10
								c\walktimer = MilliSecs() + 3000
							Case c\decision = 100
								c\turntimer = MilliSecs() + 1000
						End Select
					EndIf
			
					If c\walktimer > MilliSecs() 
						c\moving = True
						MoveEntity c\mesh,0,0,2
					Else If c\turntimer > MilliSecs()
						c\moving = True
						TurnEntity c\mesh,0,2,0
					Else
						c\moving = False
					EndIf
			
					If c\distfromhome > 400
						dy#=DeltaYaw(c\mesh,c\home)*.04
						TurnEntity c\mesh,0,dy,0
					EndIf
				
				EndIf
			Else
				FreeEntity c\mesh
				Delete c
			EndIf
			
		Next

		UpdateWorld

	Next
	
	RenderWorld frameTween
	
	For c.cube = Each cube
		CameraProject(camera,EntityX(c\mesh),EntityY(c\mesh),EntityZ(c\mesh))
		
		Color 0,255,0
			
		Rect ProjectedX()-25,ProjectedY()-20,c\hp/2,4

	Next
	
	Flip

Until quit = True

End

Function avoid_entity( scr_entity, dest_entity, rate#, spd# )

	If EntityDistance(scr_entity,dest_entity) < 100 Then
		MoveEntity scr_entity,0,0,spd#
		dist1# = EntityDistance(scr_entity,dest_entity)
		MoveEntity scr_entity,0,0,-spd#
		TurnEntity scr_entity,0,rate#,0
		MoveEntity scr_entity,0,0,spd#
		dist2# = EntityDistance(scr_entity,dest_entity)
		MoveEntity scr_entity,0,0,-spd#
		TurnEntity scr_entity,0,-2*rate#,0
		MoveEntity scr_entity,0,0,spd#
		dist3# = EntityDistance(scr_entity,dest_entity)
		MoveEntity scr_entity,0,0,-spd#
		
		If dist1# > dist2# And dist1# > dist3# Then TurnEntity scr_entity,0,rate#,0
		If dist2# > dist3# And dist2# > dist1# Then TurnEntity scr_entity,0,2*rate#,0
		
		Return True
	Else
		Return False
	EndIf

End Function