this is a very basic routine that i did a long time ago that will control an NPC's reaction to your movements so that it will always turn to face you while moving towards you. If you are directly in the line of sight of an NPC that is targeting you the NPC will shoot at you (if you move out of the way they will miss)
########################################
# Controls angular direction and inertial momentum in 3D #
# As well as governing camera & charictor A.I. actions #
# such as "homming in", "following" & "firing weapon". #
##########################################################
' Initialisation
mom.inc = 1
mom.max = 20
ang.inc = .25
ang.max = 20
rng.max = 100
radian = pi / 180
halfpi = pi / 2
' Charictor dynamics
charictors = 9
camera = 0
hero = 1
dim posx(charictors), posy(charictors), posz(charictors)
dim dirx(charictors), diry(charictors), dirz(charictors)
dim momx(charictors), momy(charictors), momz(charictors)
dim angx(charictors), angy(charictors), angz(charictors)
dim rotx(charictors), roty(charictors), rotz(charictors)
dim fire(charictors), ammo(charictors), magz(charictors)
dim looktarget(charictors), movetarget(charictors)
for c = 0 to charictors
if c<>hero then
posx(c) = int(ran(640)) - 320
posy(c) = int(ran(512)) - 256
posz(c) = int(ran(0))
rotx(c) = int(ran(15))*radian
roty(c) = int(ran(15))*radian
rotz(c) = int(ran(15))*radian
target = int(ran(charictors))
looktarget(c) = target
movetarget(c) = target
endif
next
looktarget(camera) = hero
movetarget(camera) = hero
setrgb 0, 0, 0, 90:window origin "cc":open window 640, 512
Up = 16:Right = 32:Down = 64:Left = 128
L2 = 256:R2 = 512:L1 = 1024:R1 = 2048
Trin = 4096:Circ = 8192:Cros = 16384:Sqar = 32768
' Calculation
sub navigate(c)
' Momentum
xm = momx(c)
if xm>0 then xm = xm - mom.inc
elsif xm<0 then xm = xm + mom.inc endif
if xm>mom.max then xm = mom.max
elsif xm<-mom.max then xm = -mom.max endif
momx(c) = xm
ym = momy(c)
if ym>0 then ym = ym - mom.inc
elsif ym<0 then ym = ym + mom.inc endif
if ym>mom.max then ym = mom.max
elsif ym<-mom.max then ym = -mom.max endif
momy(c) = ym
' Orientation
a = rotz(c)
if a>ang.max then a = ang.max
elsif a<-ang.max then a = -ang.max endif
a = a*radian
' Direction
angz(c) = angz(c) + a
a = angz(c)
xm = momx(c)
ym = momy(c)
if ym<>0 then
dx1 = sin(a)*ym: dy1 = cos(a)*ym
else dx1 = 0: dy1 = 0 endif
if xm<>0 then
dx2 = sin(a+halfpi)*xm: dy2 = cos(a+halfpi)*xm
else dx2 = 0: dy2 = 0 endif
dirx(c) = (dx1+dx2) / 2
diry(c) = (dy1+dy2) / 2
' Limit to screen dimensions
posx = posx(c) + dirx(c)
posy = posy(c) + diry(c)
if posx>300 posx = 300
if posx<-300 posx = -300
if posy>240 posy = 240
if posy<-240 posy = -240
posx(c) = posx
posy(c) = posy
end sub
sub homein(viewer, target)
posx = posx(viewer)
posy = posy(viewer)
trgx = posx(target)
trgy = posy(target)
vx = posx(viewer)-sin(angz(viewer))
vy = posy(viewer)-cos(angz(viewer))
cp = (posx-trgx)*(vy-trgy) - (vx-trgx)*(posy-trgy)
rotz(viewer) = -cp / 10
' Fire if target is roughly in viwers sights
if cp>-10 and cp<10 then fire(c) = 1-fire(c)
else fire(c) = 0 endif
end sub
sub follow(viewer, target)
posx = posx(viewer)
posy = posy(viewer)
trgx = posx(target)
trgy = posy(target)
adjacent = trgx-posx
opposite = trgy-posy
hypotenuse = sqrt( sqr(adjacent) + sqr(opposite))
if hypotenuse>rng.max then
posx = adjacent / hypotenuse + posx
posy = opposite / hypotenuse + posy
endif
posx(viewer) = posx
posy(viewer) = posy
end sub
label loop
setdrawbuf curbuffer: curbuffer = 1 - curbuffer
setdispbuf curbuffer: clear window
gosub readpad
for c = 0 to charictors
if c<>hero momy(c) = momy(c) - mom.inc*2
navigate(c)
posx = posx(c)
posy = posy(c)
setrgb 1, 255, 100, 100
if c=hero setrgb 1, 100, 255, 100
if c=camera setrgb 1, 100, 100, 255
fill circle posx, posy, 10
if fire(c)=0 f = 20
if fire(c)=1 f = 1000
line posx, posy to posx-sin(angz(c))*f, posy-cos(angz(c))*f
next
framerate = framerate + 1
if mod(framerate,5)=0 then
for c = 0 to charictors
if c<>hero homein(c, looktarget(c))
next
elsif mod(framerate,10)=0 then
for c = 0 to charictors
if c<>hero follow(c, movetarget(c))
next
endif
goto loop
label readpad
control = peek("port1")
if and(control, Up)>0 then momy(hero) = momy(hero) - 2
elsif and(control,Down)>0 then momy(hero) = momy(hero)+2
endif
if and(control, Right)>0 then momx(hero) = momx(hero) +2
elsif and(control,Left)>0 then momx(hero) = momx(hero)-2
endif
if and(control, Circ)>0 then
rotz(hero) = rotz(hero) - ang.inc
elsif and(control, Sqar)>0 then
rotz(hero) = rotz(hero) + ang.inc
else rotz(hero) = 0 endif
if and(control, R1)>0 then fire(hero) = 1 - fire(hero)
else fire(hero) = 0 endif
return