|
entity - the character to walk: any entity, such as a mesh, an animated model or a pivot x#, y#, z# - where to walk to; y# is the height of the ground there, so a goal on a balcony picks the balcony, not the street below run (optional) - True to run there; False to walk (default) |
|
Walks an entity to a point, finding its own way round whatever is in the way. WalkEntity is the one command a guard needs to cross a level, a shopkeeper to get to the counter, or a villager to go home round the houses. The first time, it makes the entity a NavWalker: the engine takes over moving it along the walkable map of its world, the map FindNavPath uses, and every UpdateWorld moves it a step. It turns smoothly to face its way, cuts corners a little, slows down at the end, steps round other walkers and plays the walk or run of its animation set (see WalkAnimations). There is no path to follow or free. The goal doesn't have to be exactly on the map: the walker goes to the nearest point of the map it can reach. Watch WalkState, or read the world's events after UpdateWorld (CountWorldEvents, WorldEventName and WorldEventEntity): the walker sends "arrived" when it gets there, and "cant-reach" when there is no way there and it has gone as near as it can. Walkers sent to the same place don't fight over one spot: each is given a spot of its own in rings round it, the nearest walker nearest, so a crowd called to a stage gathers in front of it. A new walker is fitted out from its looks. Its feet are the bottom of its bounds (its meshes' and its children's; a pivot's are where it is), and they go on the nearest walkable point within 4 times its radius, 1.4 m for a person. If there is none, it waits, WALK_OFF_MAP, until it is put somewhere walkable. Its size is the smallest of the world's sizes that it fits (see WalkSize), and its speeds follow from that: 1.4 m/s walking and 4 m/s running for a person (see WalkSpeed). Calling WalkEntity again gives the walker a new goal at once, which is how a patrol goes from post to post. Each step starts from wherever the walker is, so if the program, a collision or a push has moved it, it carries on from there. A hidden walker waits until it is shown again, and a freed one simply leaves. In a big world, a walker sent far beyond the cameras works out its way there as FindNavPath does, so a messenger sent 2 km across an island gets there. A walker is left out of the walkable map, whatever it is made of, so a block that walks, like the example's, never stands in a hole of its own. See also: WalkState, StopWalking, FollowEntity, WanderEntity, WalkSpeed, FindNavPath. |
; WalkEntity Example
; ------------------
Graphics3D 640,480,0,2
SetBuffer BackBuffer()
; A raised camera looking down on the courtyard
camera=CreateCamera()
PositionEntity camera,0,13,-12
RotateEntity camera,50,0,0
light=CreateLight()
RotateEntity light,45,45,0
; A 20 x 20 m courtyard, one unit to a metre: the floor's top is at y=0
floor=Block(0,-0.5,0,20,0.5,20)
EntityColor floor,60,80,55
; Walls round the edge, and two inner walls with a gap at one end
Block 0,0,-10,20,1.5,0.5
Block 0,0,10,20,1.5,0.5
Block -10,0,0,0.5,1.5,20
Block 10,0,0,0.5,1.5,20
Block -2,0,-3,16,1.5,0.5
Block 2,0,3,16,1.5,0.5
; A guard in the near corner
guard=Character(-7,-7,220,60,60)
world=GetWorld()
SeedRnd MilliSecs()
; Walk to the far corner: the guard finds its own way round the walls
goal_x#=7
goal_z#=7
run=False
WalkEntity guard,goal_x,0,goal_z
said$="none yet"
While Not KeyDown(1)
; R switches between walking and running; Space sends the guard somewhere
; new. Either way WalkEntity gives it its orders again.
If KeyHit(19) Then
run=Not run
WalkEntity guard,goal_x,0,goal_z,run
EndIf
If KeyHit(57) Then
goal_x=Rnd(-9,9)
goal_z=Rnd(-9,9)
WalkEntity guard,goal_x,0,goal_z,run
EndIf
; A ball marks the goal
DebugSphere goal_x,0.1,goal_z,0.4,12,80,160,255
; Arrow keys move the camera (turning round the world's up axis)
If KeyDown(200) Then MoveEntity camera,0,0,0.1
If KeyDown(208) Then MoveEntity camera,0,0,-0.1
If KeyDown(203) Then TurnEntity camera,0,1,0,True
If KeyDown(205) Then TurnEntity camera,0,-1,0,True
; UpdateWorld moves the guard a step along its way
UpdateWorld
; It says "arrived" when it gets there, then heads for a new goal
For i=0 To CountWorldEvents(world)-1
If WorldEventEntity(world,i)=guard Then
said=WorldEventName(world,i)
goal_x=Rnd(-9,9)
goal_z=Rnd(-9,9)
WalkEntity guard,goal_x,0,goal_z,run
EndIf
Next
RenderWorld
pace$="walking"
If run Then pace="running"
Text 0,0,"Space: new goal R: walk / run Arrow keys: move camera Esc: exit"
Text 0,20,"WalkEntity guard,"+Int(goal_x)+",0,"+Int(goal_z)+" ("+pace+")"
Text 0,40,"Last world event from the guard: "+said
Flip
Wend
End
; A stone block standing on y, centred on x,z
Function Block(x#,y#,z#,width#,height#,depth#)
b=CreateCube()
ScaleEntity b,width/2,height/2,depth/2
PositionEntity b,x,y+height/2,z
EntityColor b,125,110,90
Return b
End Function
; A character 0.6 m across and 1.8 m tall, with a visor on its face, kept out
; of the walkable map it walks on
Function Character(x#,z#,red,green,blue)
c=CreateCube()
ScaleMesh c,0.3,0.9,0.3
PositionEntity c,x,0.9,z
EntityColor c,red,green,blue
visor=CreateCube(c)
ScaleMesh visor,0.2,0.08,0.06
PositionEntity visor,0,0.6,0.32
EntityColor visor,30,30,40
Return c
End Function