set display mode 1024,768,32
sync on
sync rate 60
autocam off
position camera 0,300,-500
point camera 0,0,0
 
numberoffish=60
numberofleaders=4
 
type fishtype
 
x as float
y as float
z as float
vx as float
vy as float
vz as float
newvx as float
newvy as float
newvz as float
intent as string
speed as float
 
endtype
 
dim fishproperty(numberoffish) as fishtype
 
tankx=500
tanky=200
tankz=200
 
tank=free_object()
make object box tank,tankx,tanky,tankz
color object tank,rgb(0,0,255)
ghost object on tank
 
pebbles=free_object()
make object box pebbles,tankx,tanky/10,tankz
color object pebbles,rgb(255,200,0)
position object pebbles,0,-tanky/2-object size y(pebbles)/2,0
 
glass=free_object()
make object box glass,tankx,tanky/5,tankz
ghost object on glass,2
fade object glass,50
position object glass,0,tanky/2+object size y(glass)/2,0
 
 
 
 
fishseed=free_object()
 
fish=fishseed
make object sphere 1000,10
scale object 1000,30,80,140
make object cone 1001,12
scale object 1001,30,80,120
xrotate object 1001,90
position object 1001,0,0,-25
make mesh from object 1,1001
delete object 1001
add limb 1000,1,1
delete mesh 1
make mesh from object 1,1000
delete object 1000
make object fish,1,0
delete mesh 1
color object fish,rgb(255,128,0)
fishproperty(n).x=rnd(tankx)-tankx/2
fishproperty(n).y=rnd(tanky)-tanky/2
fishproperty(n).z=rnd(tankz)-tankz/2
fishproperty(n).intent="lead"
 
for n=1 to numberoffish-1
  fish=fishseed+n
  clone object fish,fishseed
  fishproperty(n).x=rnd(tankx)-tankx/2
  fishproperty(n).y=rnd(tanky)-tanky/2
  fishproperty(n).z=rnd(tankz)-tankz/2
  if n<numberofleaders
    fishproperty(n).intent="lead"
  else
    fishproperty(n).intent="follow"
  endif
  color object fish,rgb(rnd(100)+55,rnd(200),rnd(100))
next n
 
do
 
for n=0 to numberoffish-1
  fish=fishseed+n
  if fishproperty(n).intent="lead"
    if rnd(60)=0
      `set new random direction/velocity
      fishproperty(n).newvx=rnd(40)/10.0-2
      fishproperty(n).newvy=rnd(40)/10.0-2
      fishproperty(n).newvz=rnd(40)/10.0-2
    endif
 
      fishproperty(n).vx=curvevalue(fishproperty(n).newvx,fishproperty(n).vx,10)
      fishproperty(n).vy=curvevalue(fishproperty(n).newvy,fishproperty(n).vy,10)
      fishproperty(n).vz=curvevalue(fishproperty(n).newvz,fishproperty(n).vz,10)
      fishproperty(n).speed=sqrt(fishproperty(n).vx^2+fishproperty(n).vy^2+fishproperty(n).vz^2)
      angxy=atanfull(fishproperty(n).vx,fishproperty(n).vy)
      angxz=atanfull(fishproperty(n).vx,fishproperty(n).vz)
      angyz=atanfull(fishproperty(n).vy,fishproperty(n).vz)
      oldangx#=object angle x(fish)
      oldangy#=object angle y(fish)
      oldangz#=object angle z(fish)
      point object fish,object position x(fish)+fishproperty(n).vx,object position y(fish)+fishproperty(n).vy,object position z(fish)+fishproperty(n).vz
      newangx#=object angle x(fish)
      newangy#=object angle y(fish)
      newangz#=object angle z(fish)
      rotate object fish,oldangx#,oldangy#,oldangz#
      rotate object fish,curveangle(newangx#,oldangx#,5),curveangle(newangy#,oldangy#,5),curveangle(newangz#,oldangz#,5)
 
  endif
  if fishproperty(n).intent="follow"
        closest#=1000
        for check=0 to numberoffish-1
          targetfish=fishseed+check
          if n<>check
            x#=fishproperty(check).x-fishproperty(n).x
            y#=fishproperty(check).y-fishproperty(n).y
            z#=fishproperty(check).z-fishproperty(n).z
            dist#=sqrt(x#^2+y#^2+z#^2)
            if dist#<10.0 then fishproperty(n).intent="disperse":exit
            if dist#<closest# and fishproperty(check).intent="lead"
              closest#=dist#
              leader=check
            endif
          endif
        next check
        oldangx#=object angle x(fish)
        oldangy#=object angle y(fish)
        oldangz#=object angle z(fish)
        point object fish,fishproperty(leader).x,fishproperty(leader).y,fishproperty(leader).z
        newangx#=object angle x(fish)
        newangy#=object angle y(fish)
        newangz#=object angle z(fish)
        rotate object fish,oldangx#,oldangy#,oldangz#
        rotate object fish,curveangle(newangx#,oldangx#,25),curveangle(newangy#,oldangy#,5),curveangle(newangz#,oldangz#,5)
 
        oldx#=object position x(fish)
        oldy#=object position y(fish)
        oldz#=object position z(fish)
        move object fish,fishproperty(leader).speed*0.75
        fishproperty(n).vx=object position x(fish)-oldx#
        fishproperty(n).vy=object position y(fish)-oldy#
        fishproperty(n).vz=object position z(fish)-oldz#
        fishproperty(n).speed=sqrt(fishproperty(n).vx^2+fishproperty(n).vy^2+fishproperty(n).vz^2)
        position object fish,oldx#,oldy#,oldz#
        angxy=atanfull(fishproperty(n).vx,fishproperty(n).vy)
        angxz=atanfull(fishproperty(n).vx,fishproperty(n).vz)
        angyz=atanfull(fishproperty(n).vy,fishproperty(n).vz)
  endif
  if fishproperty(n).intent="disperse"
    if fish<>fishseed
        closest#=1000
        for check=0 to numberoffish-1
          targetfish=fishseed+check
          if fish<>targetfish
            x#=object position x(targetfish)-object position x(fish)
            y#=object position y(targetfish)-object position y(fish)
            z#=object position z(targetfish)-object position z(fish)
            dist#=sqrt(x#^2+y#^2+z#^2)
            if dist#<closest# and fishproperty(check).speed>0.1
              closest#=dist#
              leader=check
            endif
          endif
        next check
        if closest#>20.0 then fishproperty(n).intent="follow"
        oldangx#=object angle x(fish)
        oldangy#=object angle y(fish)
        oldangz#=object angle z(fish)
        point object fish,fishproperty(leader).x,fishproperty(leader).y,fishproperty(leader).z
        if rnd(1)=0 then turn object right fish,180 else pitch object down fish,180
        newangx#=object angle x(fish)
        newangy#=object angle y(fish)
        newangz#=object angle z(fish)
        rotate object fish,oldangx#,oldangy#,oldangz#
        rotate object fish,curveangle(newangx#,oldangx#,25),curveangle(newangy#,oldangy#,5),curveangle(newangz#,oldangz#,5)
 
        oldx#=object position x(fish)
        oldy#=object position y(fish)
        oldz#=object position z(fish)
        move object fish,fishproperty(leader).speed
        fishproperty(n).vx=object position x(fish)-oldx#
        fishproperty(n).vy=object position y(fish)-oldy#
        fishproperty(n).vz=object position z(fish)-oldz#
        fishproperty(n).speed=sqrt(fishproperty(n).vx^2+fishproperty(n).vy^2+fishproperty(n).vz^2)
        position object fish,oldx#,oldy#,oldz#
        angxy=atanfull(fishproperty(n).vx,fishproperty(n).vy)
        angxz=atanfull(fishproperty(n).vx,fishproperty(n).vz)
        angyz=atanfull(fishproperty(n).vy,fishproperty(n).vz)
    endif
  endif
  inc fishproperty(n).x,fishproperty(n).vx
  inc fishproperty(n).y,fishproperty(n).vy
  inc fishproperty(n).z,fishproperty(n).vz
  limit=0
  if fishproperty(n).x<-tankx/2 then fishproperty(n).x=-tankx/2:limit=1
  if fishproperty(n).x>tankx/2 then fishproperty(n).x=tankx/2:limit=1
  if fishproperty(n).y<-tanky/2 then fishproperty(n).y=-tanky/2:limit=1
  if fishproperty(n).y>tanky/2 then fishproperty(n).y=tanky/2:limit=1
  if fishproperty(n).z<-tankz/2 then fishproperty(n).z=-tankz/2:limit=1
  if fishproperty(n).z>tankz/2 then fishproperty(n).z=tankz/2:limit=1
  if limit=1 and fishproperty(n).intent="disperse" then fishproperty(n).intent="follow"
  position object fish,fishproperty(n).x,fishproperty(n).y,fishproperty(n).z
next n
 
following=0
leading=0
dispersing=0
for n=0 to numberoffish-1
  if fishproperty(n).intent="lead" then inc leading
  if fishproperty(n).intent="follow" then inc following
  if fishproperty(n).intent="disperse" then inc dispersing
next n
 
 
`text 0,0,str$(screen fps())
`text 0,20,"Leading: "+str$(leading)
`text 0,40,"Following: "+str$(following)
`text 0,60,"Dispersing: "+str$(dispersing)
sync
loop
 
 
 
 
function free_object()
 
repeat
inc n
until object exist(n)=0
 
endfunction n