@Lordofthechings : Both actually since iām not satisfied by how the navmesh and steering works!
@Smoking_mirror : That would be very nice. Take Your time and let me know when itās finished.
@sdfgeoff : A little homework xD Iāll be reading that right now!
Also Iāve made a navmesh from a pacman-like map I made.
Totally not satisfied by how the object navigates the mesh! (I think itās limited in every way)
Are ther any means of manipulating the way this works, Except from the turning and moving speed (Steering actuator)
If youāre making a game like pacman your best way forward would be to code it in a similar way.
That means using python quite a lot though. Are you comfortable with using python for most of the movement?
pros: total control of movement, doesnāt need any collision or other things, hit detection is as easy as measuring a vector.
cons: no physics, difficult to do 3d movement(up/down), no so easy to use logic bricksā¦
that is a possible ghost AI (semplified)
as usual i prefer AI with āalzaymerā (no memory)
import random
import bge
from mathutils import Vector, Matrix
"""pac-man ghost AI (iper - semplificated)
the face forward of the ghost object is +Y (green arrow)(to semplificate face_to())
the ghost obj is not a object physic (not influeced from collisions)
"""
TILE_SIZE = 2.0 # 2 meters
def face_to(own, pos): # align to position without interpolations
own.worldOrientation = (pos - own.worldPosition).to_track_quat("Y","Z")
def get_target(own):
# these are sort of -> north south owest east
FOUR_DIRECTIONS = [vec * verse for verse in [-1,1] for vec in Matrix().to_3x3()[:2]]
start = own.worldPosition
directions = []
for direction in FOUR_DIRECTIONS:
end = start + direction * TILE_SIZE * 1.5
if not own.rayCast(end, start)[0]:
directions.append(direction) # the ray has not found obstacle, so free way, add
# is assumed that at least one direction free exist (otherwise give error)
direction = random.choice(directions) # pick one random
target_position = start + (direction * TILE_SIZE)
return target_position
def main():
cont = bge.logic.getCurrentController()
own = cont.owner
if not "init" in own:
own["target_xyz"] = None
own["init"] = True
own["speed"] = 0.05
if not own["target_xyz"]:
xyz = own["target_xyz"] = get_target(own)
face_to(own, xyz)
#debug
bge.render.drawLine(own.worldPosition, own["target_xyz"], [1,0,0])
## move
speed = own["speed"]
dist = own.getDistanceTo(own["target_xyz"])
if dist > speed:
own.applyMovement((0,speed,0),1)
else:
own.worldPosition = own["target_xyz"]
own["target_xyz"] = None
try:
main()
except:
bge.logic.endGame()
raise
can be added more chances to the forward direction
and removed the ābackā direction.(as is in pacman original)
ok, now is a bit better
import random
import bge
from mathutils import Vector, Matrix
"""pac-man ghost AI (iper - semplificated)
the face forward of the ghost object is +Y (green arrow)(to semplificate face_to())
the ghost obj is not a object physic (not influeced from collisions)
added patch for "no direction founded"
"""
TILE_SIZE = 2.0 # 2 meters
def face_to(own, pos): # align to position without interpolations
own.worldOrientation = (pos - own.worldPosition).to_track_quat("Y","Z")
def get_target(own):
vx, vy = own.worldOrientation.col[:2]
local_directions = [-vx, vx, vy, vy, vy] # more forward direction
start = own.worldPosition
targets_candidate = [start+vec*TILE_SIZE for vec in local_directions]
targets_free = []
for target in targets_candidate:
if not own.rayCast(target, start)[0]:
targets_free.append(target)
if not targets_free:
return None
target = random.choice(targets_free)
# chunkifyze.. should be already , but to be more sure ...
return Vector([round(v/TILE_SIZE)*TILE_SIZE for v in target])
def main():
cont = bge.logic.getCurrentController()
own = cont.owner
if not "init" in own:
own["target_xyz"] = None
own["init"] = True
own["speed"] = 0.1
if not own["target_xyz"]:
target = own["target_xyz"] = get_target(own)
if not target:
return
face_to(own, target)
#debug
bge.render.drawLine(own.worldPosition, own["target_xyz"], [1,0,0])
## move
speed = own["speed"]
dist = own.getDistanceTo(own["target_xyz"])
if dist > speed:
own.applyMovement((0,speed,0),1)
else:
own.worldPosition = own["target_xyz"]
own["target_xyz"] = None
try:
main()
except:
bge.logic.endGame()
raise