Author Topic: Simple AI for following a target  (Read 5101 times)

0 Members and 1 Guest are viewing this topic.

Offline rain_storm

  • Here comes the Rain
  • DBF Aficionado
  • ******
  • Posts: 3088
  • Karma: 182
  • Rain never hurt nobody
    • View Profile
    • org_100h
Simple AI for following a target
« on: September 18, 2007 »
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)

Code: [Select]
########################################
# 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


Challenge Trophies Won:

Offline Clanky

  • Laser Guided Memories
  • Amiga 1200
  • ****
  • Posts: 340
  • Karma: 16
  • kiss that sound that pounds your senses
    • View Profile
Re: Simple AI for following a target
« Reply #1 on: September 19, 2007 »
I'll check this beauty out when I get home from work... looks like it's a winner!!!  :updance:
He tilts, and his eyes are focused on the ground far below.. Wind? Angels? Men..

Offline bikemadness

  • Amiga 1200
  • ****
  • Posts: 319
  • Karma: 25
  • Hard players don't go home.
    • View Profile
Re: Simple AI for following a target
« Reply #2 on: September 19, 2007 »
Great stuff. So funny making them play 'follow the leader'. Reminds me of two arcade games, Galagha and Robotron.
Have a Yahappy day.
I don't know what is wrong with the world - but I know how to fix it.

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17412
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
Re: Simple AI for following a target
« Reply #3 on: September 19, 2007 »
It all happens quite manically so I had to slow it down a little bit to see what was going on :)

It seems to work well, some bots get stuck at the top of the screen though.
Shockwave ^ Codigos
Challenge Trophies Won:

Offline Clanky

  • Laser Guided Memories
  • Amiga 1200
  • ****
  • Posts: 340
  • Karma: 16
  • kiss that sound that pounds your senses
    • View Profile
Re: Simple AI for following a target
« Reply #4 on: September 20, 2007 »
Ahh! Very nice.
That would be good for a large empty field game!  :clap:
He tilts, and his eyes are focused on the ground far below.. Wind? Angels? Men..

Offline rain_storm

  • Here comes the Rain
  • DBF Aficionado
  • ******
  • Posts: 3088
  • Karma: 182
  • Rain never hurt nobody
    • View Profile
    • org_100h
Re: Simple AI for following a target
« Reply #5 on: September 20, 2007 »
It seems to work well, some bots get stuck at the top of the screen though.
I think that happens when a bot is assigned itself as a target it simply moves in whatever direction it happens to be facing. Eventually they do manage to end up on the bottom of the screen too

Edit: I have cleaned this all up and its now easier to see how the AI works

Code: [Select]
init()
while (0 <> 1)
  bot = bot + 1
  if (bot > bots) bot = 0
  ai(bot)
  draw()
wend

sub ai(bot)
  tar = bot - 1
  if (tar < 0) tar = bots

// Look at the target bot ...
  posx = posx(bot)
  posy = posy(bot)
  tarx = posx(tar)
  tary = posy(tar)
  dirx = posx + cos(rotz(bot))
  diry = posy + sin(rotz(bot))
  crossproduct = (posx-tarx)*(diry-tary)-(dirx-tarx)*(posy-tary)
  rotz(bot) = rotz(bot) + (pi / 1800) * crossproduct

// Move towards target bot with collision ...
  adj = posx - tarx
  opp = posy - tary
  hyp = sqrt(adj^2 + opp^2)
  if (hyp > 20) then
    newx = posx + 2*cos(rotz(bot))
    newy = posy + 2*sin(rotz(bot))
    for a = 0 to bots
      if (a <> bot) then
        adj = newx - posx(a)
        opp = newy - posy(a)
        hyp = sqrt(adj^2 + opp^2)
        if (hyp < 20) then
          newx = posx
          newy = posy
        fi
      fi
    next
    posx(bot) = newx
    posy(bot) = newy
  else
    newx = posx
    newy = posy
  fi
end sub

sub draw()
  setdispbuf draw
  draw = 1 - draw
  setdrawbuf draw
  clear window
  setrgb 1, 100, 100, 255
  for a = 0 to bots
    cs = cos(rotz(a))*20 + posx(a)
    sn = sin(rotz(a))*20 + posy(a)
    fill circle posx(a), posy(a), 10
    circle posx(a), posy(a), 20
    line posx(a), posy(a) to cs, sn
  next
end sub

sub init()
  open window 640, 512
  window origin "cc"
  bots = 16
  dim posx(bots), posy(bots), rotz(bots)
  for a = 0 to bots
    rotz(a) = ran(pi) - ran(pi)
10  posx = ran(320) - ran(320)
    posy = ran(256) - ran(256)
    for b = 0 to bots
      adj = posx - posx(b)
      opp = posy - posy(b)
      hyp = sqrt(adj^2 + opp^2)
      if (hyp < 80) goto 10
    next
    posx(a) = posx
    posy(a) = posy
  next
end sub

« Last Edit: September 24, 2007 by rain_storm »

Challenge Trophies Won: