Trigonometry and tank control movement

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
sero
Posts: 59
Joined: Mar 06, 2018 13:26
Location: USA

Trigonometry and tank control movement

Post by sero »

This demonstration shows both numpad movement and tank movement. Slope, pythagorean formula, cos, sin, and atan2 are used. Holding the right mouse button will enable tank controls relative to the mouse position. Use arrows or wasd to move. Shift increases movement speed and control decreases it. Escape or q will exit.

I made this to learn a bit about trigonometry and am hoping to share this so that someone else might find interest in trig. The FreeBasic manual was very helpful to me. Code criticism is welcome.

edit -
- frame rate controller that accounts for skipped frames
- custom line & arc color fading functions
- fast cos, sin, & atan2 functions
- screen scaling

Image

Code: Select all

' ... top down tank controls ...
'
' this demonstration shows player movement relative to the
' mouse position.
'
' _right_mouse_button_ to enable tank movement
'
' _wasd_ or _arrows_ move player
' _shift_ fast speed
' _control_ slow speed
' _escape_ or _q_ to exit

#define rgb_r( c )            ( culng( c ) shr 16 and 255 )
#define rgb_g( c )            ( culng( c ) shr  8 and 255 )
#define rgb_b( c )            ( culng( c )        and 255 )

#define c_black               rgb(   0,   0,   0 )
#define c_fuchsia             rgb( 255,   0, 255 )
#define c_player              rgb( 159,  63,  63 )
#define c_tile                rgb(   7,   7,   7 )
#define c_path_dark           rgb(  15,  15,   7 )
#define c_path_light          rgb( 127,  63,  31 )
#define c_strafe_border       rgb(  63,   0,   0 )

#define negative_pi          -3.141593
#define negative_pi_half     -1.570796
#define radian                0.01745329
#define cos_45_over_pi        0.2250791
#define fast_atan2_const      0.2808722
#define four_over_pi_squared  0.4052847
#define cos_45                0.7071068
'#define sin_45                0.7071068
#define four_over_pi          1.273239
#define pi_half               1.570796
#define pi                    3.141593
#define tau                   6.283185

#define pathway_dist          37
#define pathway_dist_diag     ( pathway_dist * cos_45 )

#define fb_windowed           &h00 ' screencontrol flags
#define fb_fullscreen         &h01
#define fb_GDI               "GDI"
#define fb_DirectX           "DirectX"
#define source_w              640
#define source_h              360

#define sixteen_bit_max       65536

#include "fbgfx.bi"

type t_image_old_header field = 1
  bpp as ushort
  w   as ushort
  h   as ushort
end type

type t_image field = 1
  union
    old      as t_image_old_header
    old_type as ulong
  end union
  bpp as long
  w   as ulong
  h   as ulong
  p   as ulong
  r( 1 to 12 ) as ubyte
end type

type t_display
  sw  as long ' source width
  sh  as long ' source height
  sp  as t_image ptr
  m   as long ' resolution multiplier
  ss  as integer ' scale step
  sf   as integer ' screen flag
  dr( 0 to 1 ) as integer
  rl( 1 to 6, 0 to 1 ) as integer
  w   as long
  h   as long
  dp  as long
  bpp as long
  p   as long
  r   as long
  dn  as string
end type

type t_player
  tv  as single ' temporary
  tvd as single
  x   as single ' screen coordinates
  y   as single
  v   as single ' movement speed
  vd  as single ' movement speed for diagonal
  ms  as single ' maximum tank strafe circle angle change speed
end type

type t_mouse
  tx as long ' temporary
  ty as long
  tb as long
  x  as long ' screen coordinates
  y  as long
  b  as long ' button state
  r  as long ' getmouse() result
end type

type t_player_to_mouse
  tx as single ' temporary
  ty as single
  tz as single
  ta as single
  dx as single ' deltas
  dy as single
  z  as single ' distance
  a  as single ' angle of player to mouse in radians
end type

type t_frame_rate_control
  kmj_fps_l as long ' fps limit         # keyboard mouse joystick = kmj
  kmj_fr    as double ' frame resolution
  kmj_ft_p  as double ' frame timer previous
  kmj_ct_d  as double ' cycle timer difference
  kmj_ct_p  as double 'cycle timer previous
  kmj_ct    as double ' cycle timer
  kmj_fps   as long ' frame counter sum
  kmj_fc    as long ' frame counter
  gfx_fps_l as long ' fps limit
  gfx_fr    as double ' frame resolution
  gfx_ft_p  as double ' frame timer previous
  gfx_ct_d  as double ' cycle timer difference
  gfx_ct_p  as double 'cycle timer previous
  gfx_ct    as double ' cycle timer
  gfx_fps   as long ' frame counter sum
  gfx_fc    as long ' frame counter
  st_d      as long ' sleep time difference
  st_p      as long ' sleep time previous
  st        as long ' sleep time
  fs        as ubyte ' frames skipped
  render    as boolean
end type

dim shared d   as t_display
dim shared p   as t_player
dim shared m   as t_mouse
dim shared pm  as t_player_to_mouse
dim shared frc as t_frame_rate_control

declare sub init_display( _
  byval _m as byte = -1, _
  byval _f as long = -1, _
  byval _dn as string = "" )
declare sub destroy_display()
declare sub clear_buffer_display()
declare sub scale_step_display()
declare sub flip_display()

declare sub init_frame_rate_control( _
  byval _gfx_l as long, _
  byval _kmj_l as long )

declare sub init_player( _
  byval _x  as single, _
  byval _y  as single, _
  byval _v  as single, _
  byval _ms as single )

declare sub init_mouse()
declare sub init_player_to_mouse()

declare function set_timer alias "timeBeginPeriod" ( _
  as ulong = 1 ) _
  as long
declare function release_timer alias "timeEndPeriod" ( _
  as ulong = 1 ) _
  as long

declare sub start_frame_rate_control()
declare sub regulate_frame_rate_control()
declare sub release_frame_rate_control()
declare sub simulate_lag()

declare sub update_mouse()
declare sub calc_player_to_mouse()
declare sub move_player()

declare sub draw_player_movement_pathways()
declare sub draw_player_movement_pathways_fade()
declare sub draw_player_strafe_delta_border()
declare sub draw_tiles()
declare sub draw_player()

declare sub draw_line( _
  byval _x1 as long, _
  byval _y1 as long, _
  byval _x2 as long, _
  byval _y2 as long, _
  byval _c  as long )

declare sub draw_circle( _
  byval _x as long, _
  byval _y as long, _
  byval _r as long, _
  byval _c as long )

declare sub draw_line_fade( _
  byval _x1 as long, _
  byval _y1 as long, _
  byval _x2 as long, _
  byval _y2 as long, _
  byval _c1 as long, _
  byval _c2 as long )

declare sub draw_arc_fade( _
  byval _x  as long, _
  byval _y  as long, _
  byval _r  as long, _
  byval _a1 as single, _
  byval _a2 as single, _
  byval _c1 as long, _
  byval _c2 as long )

declare sub pset_large( _
  byval _x as long, _
  byval _y as long, _
  byval _c as long )

declare function fast_sin( _
  byval _n as single ) _
  as single

declare function fast_cos( _
  byval _n as single ) _
  as single

declare function fast_atan2( _
  byval _y as single, _
  byval _x as single )_
  as single
'                                                                                           ____________
'__________________________________________________________________________________________/    main    \
'
'init_display( 3, fb_fullscreen, "DirectX" ) ' pass 3x scale 1920x1080, fullscreen, DirectX
init_display()
init_frame_rate_control( 24, 1000 )
init_player( ( source_w / 2 ), ( source_h / 2 ), 3, 16 )
init_mouse()
init_player_to_mouse()

start_frame_rate_control()

do
  update_mouse()
  calc_player_to_mouse()
 
  if ( frc.render = true ) then
    move_player()
    calc_player_to_mouse() ' call again to sync drawn pathways
   
    screenlock()
      clear_buffer_display()
     
      draw_tiles()
      draw_player_strafe_delta_border()
      'draw_player_movement_pathways()
      draw_player_movement_pathways_fade()
      draw_player()
      draw string d.sp, ( 9,  1 ), "keyboard/mouse fps " & frc.kmj_fps & "/" & frc.kmj_fps_l
      draw string d.sp, ( 9, 10 ), "        screen fps " & frc.gfx_fps & "/" & frc.gfx_fps_l
      draw string d.sp, ( 9, 19 ), "default sleep time " & frc.st_d
      draw string d.sp, ( 9, 28 ), "current sleep time " & frc.st
      draw string d.sp, ( 9, 37 ), "    frames skipped " & frc.fs
      draw string d.sp, ( 9, 50 ), d.w & "," & d.h & "," & d.dp & "bpp," & d.r & "hz " & d.dn
      draw string d.sp, ( ( d.sw / 2 ) - 143, d.sh - 9 ), "hold left mouse button to lag frames"
     
      flip_display()
    screenunlock()
    frc.render = false
    frc.fs = 0
   
  end if
  regulate_frame_rate_control()
  if ( m.b and 1 ) then simulate_lag()
loop until ( multikey( fb.sc_escape ) or multikey( fb.sc_q ) )

release_frame_rate_control()

destroy_display()
'                                                                                   ____________________
'__________________________________________________________________________________/    init_display    \
'
sub init_display( _
  byval _m as byte = -1, _
  byval _f as long = -1, _
  byval _dn as string = "" )
 
  dim as byte _i
 
  d.sw = source_w
  d.sh = source_h
 
  for _i = 1 to 6
    d.rl( _i, 0 ) = d.sw * _i
    d.rl( _i, 1 ) = d.sh * _i
  next _i
 
  screeninfo d.dr( 0 ), d.dr( 1 )
 
  for _i = 6 to 1 step -1
    if ( ( d.rl( _i, 0 ) < d.dr( 0 ) ) and ( d.rl( _i, 1 ) < d.dr( 1 ) ) ) then
      d.w = d.rl( _i, 0 )
      d.h = d.rl( _i, 1 )
      d.m = _i
    end if
  next _i
 
  d.rl( 1, 0 ) = d.sw
  d.rl( 1, 1 ) = d.sh
  d.m = 1
  d.w = d.rl( d.m, 0 )
  d.h = d.rl( d.m, 1 )
 
  for _i = 2 to 6
    d.rl( _i, 0 ) = d.sw * _i
    d.rl( _i, 1 ) = d.sh * _i
    if ( ( d.rl( _i, 0 ) < d.dr( 0 ) ) and ( d.rl( _i, 1 ) < d.dr( 1 ) ) ) then
      d.w = d.rl( _i, 0 )
      d.h = d.rl( _i, 1 )
      d.m = _i
    end if
  next _i
 
  if ( ( _m > 0 ) and ( _m < 7 ) ) then
    d.m = _m
    d.w = d.rl( d.m, 0 )
    d.h = d.rl( d.m, 1 )
  end if
 
  if ( _f <> -1 ) then
    d.sf = _f
  else
    d.sf = fb_windowed
  end if
 
  if ( _dn <> "" ) then
    if ( _dn = fb_GDI ) then
      d.dn = fb_GDI
    else
      if ( _dn = fb_DirectX ) then
        d.dn = fb_DirectX
      else
        d.dn = fb_GDI ' default driver if misspelled
      end if
    end if
  else
    d.dn = fb_GDI ' default driver if none given
  end if
 
  /'
  d.w = 640           d.w = 2560       available resolutions
  d.h = 360           d.h = 1440
  d.m = 1             d.m = 4
 
  d.w = 1280          d.w = 3200
  d.h = 720           d.h = 1800
  d.m = 2             d.m = 5
 
  d.w = 1920          d.w = 3840
  d.h = 1080          d.h = 2160
  d.m = 3             d.m = 6
  '/
 
  scale_step_display()
 
  screencontrol( 103, d.dn )
  screenres( d.w, d.h, 32, , d.sf )
 
  dim as integer _w, _h, _dp, _bpp, _p, _r
    screeninfo _w, _h, _dp, _bpp, _p, _r, d.dn
    d.w   = _w
    d.h   = _h
    d.dp  = _dp
    d.bpp = _bpp
    d.p   = _p
    d.r   = _r
 
  d.sp = imagecreate( d.sw, d.sh )
  if ( d.sp = 0 ) then
    end ' ######################################################################## need termination flag #
  else
    line d.sp, ( 0, 0 )-( d.w - 1, d.h - 1 ), rgb( 255, 0, 255 ), bf
  end if
end sub
'                                                                                _______________________
'_______________________________________________________________________________/    destroy_display    \
'
sub destroy_display()

  imagedestroy d.sp
  screen 0
end sub
'                                                                           ____________________________
'__________________________________________________________________________/    clear_buffer_display    \
'
sub clear_buffer_display()

  line d.sp, ( 0, 0 )-( d.w -1, d.h - 1 ), c_black, bf
end sub
'                                                                             __________________________
'____________________________________________________________________________/    scale_step_display    \
'
sub scale_step_display()

  d.ss = ( 1 / d.m ) * sixteen_bit_max
end sub
'                                                                                   ____________________
'__________________________________________________________________________________/    flip_display    \
'
sub flip_display()
  static as t_image ptr _bp
  static as ulong _scx, _scy
  static as ulong _sxs = 0
  static as ulong _sys = 0
  static as ulong ptr _ssp, _stp, _sp
 
  _bp = d.sp
 
  _ssp = cptr( ulong ptr, _bp ) + 8
  _stp = _ssp
  _sp = screenptr()
 
  if ( d.m = 1 ) then
    put( 0, 0 ), _bp, pset
  else
    if ( d.m > 1 ) then
      for _scy = 0 to ( d.h - 1 )
        _stp = _ssp + ( ( _sys shr 16 ) * d.sw )
        for _scx = 0 to ( d.w - 1 )
          *_sp = _stp[ _sxs shr 16 ]
          _sp += 1
          _sxs += d.ss
        next _scx
        _sys += d.ss
        _sxs = 0
      next _scy
      _ssp = cptr( ulong ptr, _bp ) + 8
      _sys = 0
    else
      line( 0, 0 )-( d.w - 1, d.h - 1 ), c_fuchsia, bf
    end if
  end if
end sub
'                                                                        _______________________________
'_______________________________________________________________________/    init_frame_rate_control    \
'
sub init_frame_rate_control( _
  byval _gfx_l as long, _
  byval _kmj_l as long )
 
  frc.kmj_fps_l = _kmj_l
  frc.gfx_fps_l = _gfx_l
  frc.kmj_fr = 1 / frc.kmj_fps_l
  frc.gfx_fr = 1 / frc.gfx_fps_l
  frc.kmj_fps = _kmj_l
  frc.gfx_fps = _gfx_l
  frc.kmj_fps = 0
  frc.gfx_fps = 0
  frc.st_d = 1000 / frc.kmj_fps_l
  frc.st_p = frc.st_d
  frc.fs = 0
  frc.render = false

  #ifdef __FB_WIN32__
    set_timer()
  #endif
end sub
'                                                                                    ___________________
'___________________________________________________________________________________/    init_player    \
'
sub init_player( _
  byval _x as single, _
  byval _y as single, _
  byval _v as single, _
  byval _ms as single )
 
  p.x = _x
  p.y = _y
  p.v = _v
  p.ms = _ms
  p.vd = cos_45 * p.v
  p.tv = p.v
  p.tvd = p.vd
end sub
'                                                                                     __________________
'____________________________________________________________________________________/    init_mouse    \
'
sub init_mouse()
 
  m.r = getmouse ( m.tx, m.ty, , m.tb )
  if ( d.m = 1 ) then
   
  else
    m.tx = m.tx / d.m
    m.ty = m.ty / d.m
  end if
end sub
'                                                                           ____________________________
'__________________________________________________________________________/    init_player_to_mouse    \
'
sub init_player_to_mouse()
 
  calc_player_to_mouse()
  if ( pm.z = 0 ) then
    ' prevent bug in backward tank movement when
    ' player coordinates equal mouse coordinates
    pm.dx = 1
    pm.dy = 0
    pm.z = 1
    pm.a = 0
  end if
end sub
'                                                                       ________________________________
'______________________________________________________________________/    start_frame_rate_control    \
'
sub start_frame_rate_control()

  frc.kmj_ct_p = timer
  frc.gfx_ct_p = frc.kmj_ct_p
end sub
'                                                                    ___________________________________
'___________________________________________________________________/    regulate_frame_rate_control    \
'
sub regulate_frame_rate_control()

  frc.kmj_fc += 1
  frc.kmj_ct = timer
 
  frc.gfx_ct_d = ((frc.kmj_ct)) - frc.gfx_ct_p
  if ( frc.gfx_ct_d > frc.gfx_fr ) then
    frc.gfx_ct_p += frc.gfx_fr
    frc.gfx_ct_d = ((frc.kmj_ct)) - frc.gfx_ct_p
    do while ( frc.gfx_ct_d > frc.gfx_fr )
      frc.gfx_ct_p += frc.gfx_fr
      frc.gfx_ct_d = ((frc.kmj_ct)) - frc.gfx_ct_p
      frc.fs += 1
    loop
    frc.gfx_fc += 1
    frc.render = true
  end if
 
  frc.kmj_ct_d = frc.kmj_ct - frc.kmj_ct_p
  if ( frc.kmj_ct_d > 1 ) then
    frc.kmj_ct_p += 1
    frc.kmj_fps = frc.kmj_fc
    frc.kmj_fc = 0
    frc.gfx_fps = frc.gfx_fc
    frc.gfx_fc = 0
  end if
 
  frc.st = frc.st_p + ( ( frc.kmj_fr - frc.kmj_ct + frc.kmj_ft_p ) * 1000 )
  frc.kmj_ft_p = frc.kmj_ct
 
  if ( frc.st < 1 ) then
    frc.st = 1
  else
    if ( frc.st > frc.st_d ) then
      frc.st = frc.st_d
    end if
  end if
 
  sleep( frc.st, 1 )
  frc.st_p = frc.st
end sub
'                                                                      __________________________________
'_____________________________________________________________________/    release_frame_rate_control    \
sub release_frame_rate_control()
  #ifdef __FB_WIN32__
    release_timer()
  #endif
end sub
'                                                                                   ____________________
'__________________________________________________________________________________/    simulate_lag    \
'
sub simulate_lag()
 
  sleep( rnd * ( 3000 * frc.gfx_fr ) )
end sub
'                                                                                   ____________________
'__________________________________________________________________________________/    update_mouse    \
'
sub update_mouse()
 
  m.r = getmouse ( m.tx, m.ty, , m.tb )
  if ( d.m = 1 ) then
   
  else
    m.tx = m.tx / d.m
    m.ty = m.ty / d.m
  end if
 
  if ( m.r = 0 ) then
    m.x = m.tx
    m.y = m.ty
    m.b = m.tb
  else
    ' mouse off screen
  end if
end sub
'                                                                           ____________________________
'__________________________________________________________________________/    calc_player_to_mouse    \
'
sub calc_player_to_mouse()
 
  pm.dx = m.x - p.x
  pm.dy = m.y - p.y
  pm.z = sqr( ( pm.dx * pm.dx ) + ( pm.dy * pm.dy ) )
  pm.a = fast_atan2( pm.dy, pm.dx )
 
  if ( pm.z <> 0 ) then
    ' fixes bug in backward tank movement when
    ' player coordinates equal mouse coordinates
    pm.tx = pm.dx
    pm.ty = pm.dy
    pm.tz = pm.z
    pm.ta = pm.a
  end if
end sub
'                                                                                    ___________________
'___________________________________________________________________________________/    move_player    \
'
sub move_player()
 
  if ( multikey( fb.sc_lshift ) or multikey( fb.sc_rshift ) ) then
    if ( multikey( fb.sc_control ) ) then
      p.tv = p.v / 2
      p.tvd = p.vd / 2
    else
      p.tv = p.v * 2
      p.tvd = p.vd * 2
    end if
  else
    if ( multikey( fb.sc_control ) ) then
      p.tv = p.v / 2
      p.tvd = p.vd / 2
    else
      p.tv = p.v
      p.tvd = p.vd
    end if
  end if
 
  if ( frc.fs <> 0 ) then
    ' ### adjust for frame skip ####
    p.tv = p.tv * ( frc.fs + 1 )
    p.tvd = p.tvd * ( frc.fs + 1 )
  end if
 
  if ( m.b and 2 ) then
    if ( multikey( fb.sc_a ) or multikey( fb.sc_left ) ) then
      if ( multikey( fb.sc_d ) or multikey( fb.sc_right ) ) then
        if ( multikey( fb.sc_w ) or multikey( fb.sc_up ) ) then
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
           
          else
            ' ### tank forward ###
            if ( p.tv > pm.z ) then
              p.x = m.x
              p.y = m.y
            else
              p.x = p.x + ( p.tv * pm.dx / pm.z )
              p.y = p.y + ( p.tv * pm.dy / pm.z )
            end if
          end if
        else
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
            ' ### tank backward ###
            if ( pm.z <> 0 ) then
              p.x = p.x - ( p.tv * pm.dx / pm.z )
              p.y = p.y - ( p.tv * pm.dy / pm.z )
            else
              p.x = p.x - ( p.tv * pm.tx / pm.tz )
              p.y = p.y - ( p.tv * pm.ty / pm.tz )
            end if
          else
           
          end if
        end if
      else
        if ( multikey( fb.sc_w ) or multikey( fb.sc_up ) ) then
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
           
          else
            ' ### tank forward & left ###
            if ( p.tvd > pm.z ) then
              p.x = m.x
              p.y = m.y
              pm.ta += p.tv / p.ms
            else
              if ( pm.z <> 0 ) then
                if ( pm.z < p.ms ) then
                  p.x = m.x - ( pm.z * fast_cos( pm.a + ( p.tvd / p.ms ) ) ) + ( p.tvd * pm.dx / p.ms )
                  p.y = m.y - ( pm.z * fast_sin( pm.a + ( p.tvd / p.ms ) ) ) + ( p.tvd * pm.dy / p.ms )
                else
                  p.x = m.x - ( pm.z * fast_cos( pm.a + ( p.tvd / pm.z ) ) ) + ( p.tvd * pm.dx / pm.z )
                  p.y = m.y - ( pm.z * fast_sin( pm.a + ( p.tvd / pm.z ) ) ) + ( p.tvd * pm.dy / pm.z )
                end if
              else
               
              end if
            end if
          end if
        else
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
            ' ### tank backward & left ###
            if ( pm.z <> 0 ) then
              if ( pm.z < p.ms ) then
                p.x = m.x - ( pm.z * fast_cos( pm.a + ( p.tvd / p.ms ) ) ) - ( p.tvd * pm.dx / p.ms )
                p.y = m.y - ( pm.z * fast_sin( pm.a + ( p.tvd / p.ms ) ) ) - ( p.tvd * pm.dy / p.ms )
              else
                p.x = m.x - ( pm.z * fast_cos( pm.a + ( p.tvd / pm.z ) ) ) - ( p.tvd * pm.dx / pm.z )
                p.y = m.y - ( pm.z * fast_sin( pm.a + ( p.tvd / pm.z ) ) ) - ( p.tvd * pm.dy / pm.z )
              end if
            else
              pm.ta += p.tv / p.ms
              p.x = m.x - ( p.tvd * fast_cos( pm.ta ) )
              p.y = m.y - ( p.tvd * fast_sin( pm.ta ) )
            end if
          else
            ' ### tank left ###
            if ( pm.z <> 0 ) then
              if ( pm.z < p.ms ) then
                p.x = m.x - ( pm.z * fast_cos( pm.a + ( p.tv / p.ms ) ) )
                p.y = m.y - ( pm.z * fast_sin( pm.a + ( p.tv / p.ms ) ) )
              else
                p.x = m.x - ( pm.z * fast_cos( pm.a + ( p.tv / pm.z ) ) )
                p.y = m.y - ( pm.z * fast_sin( pm.a + ( p.tv / pm.z ) ) )
              end if
            else
              pm.ta += p.tv / p.ms
            end if
          end if
        end if
      end if
    else
      if ( multikey( fb.sc_d ) or multikey( fb.sc_right ) ) then
        if ( multikey( fb.sc_w ) or multikey( fb.sc_up ) ) then
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
           
          else
            ' ### tank forward & right ###
            if ( p.tvd > pm.z ) then
              p.x = m.x
              p.y = m.y
              pm.ta -= p.tv / p.ms
            else
              if ( pm.z <> 0 ) then
                if ( pm.z < p.ms ) then
                  p.x = m.x - ( pm.z * fast_cos( pm.a - ( p.tvd / p.ms ) ) ) + ( p.tvd * pm.dx / p.ms )
                  p.y = m.y - ( pm.z * fast_sin( pm.a - ( p.tvd / p.ms ) ) ) + ( p.tvd * pm.dy / p.ms )
                else
                  p.x = m.x - ( pm.z * fast_cos( pm.a - ( p.tvd / pm.z ) ) ) + ( p.tvd * pm.dx / pm.z )
                  p.y = m.y - ( pm.z * fast_sin( pm.a - ( p.tvd / pm.z ) ) ) + ( p.tvd * pm.dy / pm.z )
                end if
              else
               
              end if
            end if
          end if
        else
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
            ' ### tank backward & right ###
            if ( pm.z <> 0 ) then
              if ( pm.z < p.ms ) then
                p.x = m.x - ( pm.z * fast_cos( pm.a - ( p.tvd / p.ms ) ) ) - ( p.tvd * pm.dx / p.ms )
                p.y = m.y - ( pm.z * fast_sin( pm.a - ( p.tvd / p.ms ) ) ) - ( p.tvd * pm.dy / p.ms )
              else
                p.x = m.x - ( pm.z * fast_cos( pm.a - ( p.tvd / pm.z ) ) ) - ( p.tvd * pm.dx / pm.z )
                p.y = m.y - ( pm.z * fast_sin( pm.a - ( p.tvd / pm.z ) ) ) - ( p.tvd * pm.dy / pm.z )
              end if
            else
              pm.ta -= p.tv / p.ms
              p.x = m.x - ( p.tvd * fast_cos( pm.ta ) )
              p.y = m.y - ( p.tvd * fast_sin( pm.ta ) )
            end if
          else
            ' ### tank right ###
            if ( pm.z <> 0 ) then
              if ( pm.z < p.ms ) then
                p.x = m.x - ( pm.z * fast_cos( pm.a - ( p.tv / p.ms ) ) )
                p.y = m.y - ( pm.z * fast_sin( pm.a - ( p.tv / p.ms ) ) )
              else
                p.x = m.x - ( pm.z * fast_cos( pm.a - ( p.tv / pm.z ) ) )
                p.y = m.y - ( pm.z * fast_sin( pm.a - ( p.tv / pm.z ) ) )
              end if
            else
              pm.ta -= p.tv / p.ms
            end if
          end if
        end if
      else
        if ( multikey( fb.sc_w ) or multikey( fb.sc_up ) ) then
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
           
          else
            ' ### tank forward ###
            if ( p.tv > pm.z ) then
              p.x = m.x
              p.y = m.y
            else
              p.x = p.x + ( p.tv * pm.dx / pm.z )
              p.y = p.y + ( p.tv * pm.dy / pm.z )
            end if
          end if
        else
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
            ' ### tank backward ###
            if ( pm.z <> 0 ) then
              p.x = p.x - ( p.tv * pm.dx / pm.z )
              p.y = p.y - ( p.tv * pm.dy / pm.z )
            else
              p.x = m.x - ( p.tv * fast_cos( pm.ta ) )
              p.y = m.y - ( p.tv * fast_sin( pm.ta ) )
            end if
          else
           
          end if
        end if
      end if
    end if
  else
    if ( multikey( fb.sc_a ) or multikey( fb.sc_left ) ) then
      if ( multikey( fb.sc_d ) or multikey( fb.sc_right ) ) then
        if ( multikey( fb.sc_w ) or multikey( fb.sc_up ) ) then
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
           
          else
            ' ### move up ###
            p.y -= p.tv
          end if
        else
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
            ' ### move down ###
            p.y += p.tv
          else
           
          end if
        end if
      else
        if ( multikey( fb.sc_w ) or multikey( fb.sc_up ) ) then
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
           
          else
            ' ### move up & left ###
            p.x -= p.tvd
            p.y -= p.tvd
          end if
        else
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
            ' ### move down & left ###
            p.x -= p.tvd
            p.y += p.tvd
          else
            ' ### move left ###
            p.x -= p.tv
          end if
        end if
      end if
    else
      if ( multikey( fb.sc_d ) or multikey( fb.sc_right ) ) then
        if ( multikey( fb.sc_w ) or multikey( fb.sc_up ) ) then
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
           
          else
            ' ### move up & right ###
            p.x += p.tvd
            p.y -= p.tvd
          end if
        else
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
            ' ### move down & right ###
            p.x += p.tvd
            p.y += p.tvd
          else
            ' ### move right ###
            p.x += p.tv
          end if
        end if
      else
        if ( multikey( fb.sc_w ) or multikey( fb.sc_up ) ) then
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
           
          else
            ' ### move up ###
            p.y -= p.tv
          end if
        else
          if ( multikey( fb.sc_s ) or multikey( fb.sc_down ) ) then
            ' ### move down ###
            p.y += p.tv
          else
           
          end if
        end if
      end if
    end if
  end if
 
  ' boundary box to keep player on screen
  if ( p.x > ( d.sw - 4 ) ) then
    p.x = d.sw - 4
  else
    if ( p.x < 3 ) then
      p.x = 3
    end if
  end if
  if ( p.y > ( d.sh - 4 ) ) then
    p.y = d.sh - 4
  else
    if ( p.y < 3 ) then
      p.y = 3
    end if
  end if
end sub
'                                                                  _____________________________________
'_________________________________________________________________/    draw_player_movement_pathways    \
'
sub draw_player_movement_pathways()
  static as single _a1, _a2
  static as single _m
  static as long _b1, _b2
 
  if ( m.b and 2 ) then
    _b1 = fast_cos( pm.ta ) * ( d.w + d.h )
    _b2 = fast_sin( pm.ta ) * ( d.w + d.h )
    line d.sp, ( p.x, p.y )-( p.x - _b1, p.y - _b2 ), c_path_dark
    _b1 = fast_cos( pm.ta + pi ) * ( d.w + d.h )
    _b2 = fast_sin( pm.ta + pi ) * ( d.w + d.h )
    line d.sp, ( p.x, p.y )-( p.x - _b1, p.y - _b2 ), c_path_dark
   
    if ( pm.z <> 0 ) then
      ' only draw circle if radius is not zero
           
      _b1 = fast_cos( pm.ta ) * pathway_dist
      _b2 = fast_sin( pm.ta ) * pathway_dist
      line d.sp, ( p.x, p.y )-( p.x - _b1, p.y - _b2 ), c_path_light
      ' backward movement pathway
     
      if ( pathway_dist > pm.z ) then
        ' player movement speed is greater than the distance
        ' to the mouse coordinate
        line d.sp, ( p.x, p.y )-( m.x, m.y ), c_path_light
      else
        ' player movement speed is less than the distance
        ' to the mouse coordinate
        line d.sp, ( p.x, p.y )-( p.x + _b1, p.y + _b2 ), c_path_light
      end if
     
      circle d.sp, ( m.x, m.y ), pm.z, c_path_dark
      if ( pathway_dist > ( pi * pm.z ) ) then
        ' because player is closer to mouse coordinate than
        ' the pathway_dist, the arc pathways need to be
        ' shortened
        circle d.sp, ( m.x, m.y ), pm.z, c_path_light
      else
        _a1 = pi - pm.ta - ( pathway_dist / pm.z )
        _a2 = pi - pm.ta + ( pathway_dist / pm.z )
        if ( _a1 < 0 ) then _a1 += tau
        if ( _a2 > tau ) then _a2 -= tau
        circle d.sp, ( m.x, m.y ), pm.z, c_path_light, _a1, _a2
      end if
    else
      ' because radius is zero do not draw forward pathway
      _b1 = fast_cos( pm.ta ) * pathway_dist
      _b2 = fast_sin( pm.ta ) * pathway_dist
      line d.sp, ( p.x, p.y )-( p.x - _b1, p.y - _b2 ), c_path_light
      ' backward movement pathway
    end if
  else   
    line d.sp, ( p.x, 0 )-( p.x, d.h ), c_path_dark
    line d.sp, ( 0, p.y )-( d.w, p.y ), c_path_dark
    line d.sp, ( p.x, p.y - pathway_dist )-( p.x, p.y + pathway_dist ), c_path_light
    line d.sp, ( p.x - pathway_dist, p.y )-( p.x + pathway_dist, p.y ), c_path_light
    ' cardinal movement pathway
   
    _b1 = p.y - p.x
    _b2 = _b1 + d.w
    line d.sp, ( 0, _b1 )-( d.w, _b2 ), c_path_dark
    line d.sp, ( p.x - pathway_dist_diag, p.y - pathway_dist_diag )-( p.x + pathway_dist_diag, p.y + pathway_dist_diag ), c_path_light
    ' diagonal movement pathway
   
    _b1 = p.y + p.x
    _b2 = _b1 - d.w
    line d.sp, ( 0, _b1 )-( d.w, _b2 ), c_path_dark
    line d.sp, ( p.x - pathway_dist_diag, p.y + pathway_dist_diag )-( p.x + pathway_dist_diag, p.y - pathway_dist_diag ), c_path_light
    ' diagonal movement pathway
  end if
end sub
'                                                             __________________________________________
'____________________________________________________________/    draw_player_movement_pathways_fade    \
'
sub draw_player_movement_pathways_fade()
  static as single _a1, _a2
  static as single _m
  static as long _b1, _b2
   
  if ( m.b and 2 ) then
    _b1 = fast_cos( pm.ta ) * ( d.w + d.h )
    _b2 = fast_sin( pm.ta ) * ( d.w + d.h )
    line d.sp, ( p.x, p.y )-( p.x - _b1, p.y - _b2 ), c_path_dark
    _b1 = fast_cos( pm.ta + pi ) * ( d.w + d.h )
    _b2 = fast_sin( pm.ta + pi ) * ( d.w + d.h )
    line d.sp, ( p.x, p.y )-( p.x - _b1, p.y - _b2 ), c_path_dark
   
    if ( pm.z <> 0 ) then
      ' only draw circle if radius is not zero
     
      _b1 = fast_cos( pm.a ) * pathway_dist
      _b2 = fast_sin( pm.a ) * pathway_dist
      draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x - _b1 ), clng( p.y - _b2 ), c_path_light, c_path_dark )
      ' backward movement pathway
     
      if ( pathway_dist > pm.z ) then
        ' player movement speed is greater than the distance
        ' to the mouse coordinate
        draw_line_fade( clng( p.x ), clng( p.y ), m.x, m.y, c_path_light, c_path_dark )
      else
        ' player movement speed is less than the distance
        ' to the mouse coordinate
        draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x + _b1 ), clng( p.y + _b2 ), c_path_light, c_path_dark )
       
      end if
      circle d.sp, ( m.x, m.y ), pm.z, c_path_dark
      if ( pathway_dist > ( pi * pm.z ) ) then
        ' because player is closer to mouse coordinate than
        ' the pathway_dist, the arc pathways need to be
        ' shortened
       
        _a1 = pm.a
        _a2 = pm.a + pi
        draw_arc_fade( m.x, m.y, clng( pm.z ), ( pm.a + pi ), _a1, c_path_light, c_path_dark )
        draw_arc_fade( m.x, m.y, clng( pm.z ), ( pm.a - pi ), _a1, c_path_light, c_path_dark )
      else
        _a1 = pm.a - ( pathway_dist / pm.z ) + pi
        _a2 = pm.a + ( pathway_dist / pm.z ) + pi
        draw_arc_fade( m.x, m.y, clng( pm.z ), ( pm.a + pi ), _a1, c_path_light, c_path_dark )
        draw_arc_fade( m.x, m.y, clng( pm.z ), ( pm.a + pi ), _a2, c_path_light, c_path_dark )
      end if
    else
      ' because radius is zero do not draw forward pathway
     
      _b1 = fast_cos( pm.ta ) * pathway_dist
      _b2 = fast_sin( pm.ta ) * pathway_dist
      draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x - _b1 ), clng( p.y - _b2 ), c_path_light, c_path_dark )
      ' backward movement pathway
     
    end if
  else   
    line d.sp, ( p.x, 0 )-( p.x, d.h ), c_path_dark
    line d.sp, ( 0, p.y )-( d.w, p.y ), c_path_dark
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x ), clng( p.y - pathway_dist ), c_path_light, c_path_dark )
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x ), clng( p.y + pathway_dist ), c_path_light, c_path_dark )
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x - pathway_dist ), clng( p.y ), c_path_light, c_path_dark )
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x + pathway_dist ), clng( p.y ), c_path_light, c_path_dark )
    ' cardinal movement pathway
   
    _b1 = p.y - p.x
    _b2 = _b1 + d.w
    line d.sp, ( 0, _b1 )-( d.w, _b2 ), c_path_dark
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x - pathway_dist_diag ), clng( p.y - pathway_dist_diag ), c_path_light, c_path_dark )
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x - pathway_dist_diag ), clng( p.y - pathway_dist_diag ), c_path_light, c_path_dark )
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x + pathway_dist_diag ), clng( p.y + pathway_dist_diag ), c_path_light, c_path_dark )
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x + pathway_dist_diag ), clng( p.y + pathway_dist_diag ), c_path_light, c_path_dark )
    ' diagonal movement pathway
   
    _b1 = p.y + p.x
    _b2 = _b1 - d.w
    line d.sp, ( 0, _b1 )-( d.w, _b2 ), c_path_dark
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x + pathway_dist_diag ), clng( p.y - pathway_dist_diag ), c_path_light, c_path_dark )
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x + pathway_dist_diag ), clng( p.y - pathway_dist_diag ), c_path_light, c_path_dark )
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x - pathway_dist_diag ), clng( p.y + pathway_dist_diag ), c_path_light, c_path_dark )
    draw_line_fade( clng( p.x ), clng( p.y ), clng( p.x - pathway_dist_diag ), clng( p.y + pathway_dist_diag ), c_path_light, c_path_dark )
    ' diagonal movement pathway
   
  end if
end sub
'                                                                _______________________________________
'_______________________________________________________________/    draw_player_strafe_delta_border    \
'
sub draw_player_strafe_delta_border()
  if ( m.b and 2 ) then
    circle d.sp, ( m.x, m.y ), p.ms, c_strafe_border
    'draw_circle( m.x, m.y, clng( p.ms ), c_strafe_border )
  end if
end sub
'                                                                                     __________________
'____________________________________________________________________________________/    draw_tiles    \
'
sub draw_tiles()
  dim as long _y, _x
 
  for _y = 0 to ( d.h - 10 ) step 10
    for _x = 0 to ( d.w - 10 ) step 10
      line d.sp, ( _x + 1, _y + 1 )-( _x + 8, _y + 8 ), c_tile, bf
    next _x
  next _y
end sub
'                                                                                    ___________________
'___________________________________________________________________________________/    draw_player    \
'
sub draw_player()
 
  'line ( p.x - 3, p.y - 3 )-( p.x + 3, p.y + 3 ), c_player, bf
  'circle ( p.x, p.y ), 3, rgb( 0, 0, 0 ) , , , , f
  draw string d.sp, ( p.x - 4, p.y - 4 ), "@", rgb( 0, 0, 0 )
  draw string d.sp, ( p.x - 2, p.y - 2 ), "@", rgb( 0, 0, 0 )
  draw string d.sp, ( p.x - 4, p.y - 2 ), "@", rgb( 0, 0, 0 )
  draw string d.sp, ( p.x - 2, p.y - 4 ), "@", rgb( 0, 0, 0 )
  draw string d.sp, ( p.x - 3, p.y - 3 ), "@", c_player
end sub
'                                                                                      _________________
'_____________________________________________________________________________________/    draw_line    \
'
sub draw_line( _
  byval _x1 as long, _
  byval _y1 as long, _
  byval _x2 as long, _
  byval _y2 as long, _
  byval _c  as long )
 
  dim as long _dx, _dy
  dim as long _d, _di1, _di2
  dim as long _x, _xi1, _xi2
  dim as long _y, _yi1, _yi2
  dim as long _i, _n
 
  _dx = abs( _x2 - _x1 )
  _dy = abs( _y2 - _y1 )
 
  if ( _dx >= _dy ) then
    _n = _dx + 1
    _d = ( _dy shl 1 ) - _dx
    _di1 = _dy shl 1
    _di2 = ( _dy - _dx ) shl 1
    _xi1 = 1
    _xi2 = 1
    _yi1 = 0
    _yi2 = 1
  else
    _n = _dy + 1
    _d = ( _dx shl 1 ) - _dy
    _di1 = _dx shl 1
    _di2 = ( _dx - _dy ) shl 1
    _xi1 = 0
    _xi2 = 1
    _yi1 = 1
    _yi2 = 1
  end if
 
  if ( _x1 > _x2 ) then
    _xi1 = - _xi1
    _xi2 = - _xi2
  end if
  if ( _y1 > _y2 ) then
    _yi1 = - _yi1
    _yi2 = - _yi2
  end if
 
  _x = _x1
  _y = _y1
 
  for _i = 1 to _n
    pset d.sp, ( _x, _y ), _c
    'pset_large( _x, _y, _c )
    if _d < 0 then
      _d += _di1
      _x += _xi1
      _y += _yi1
    else
      _d += _di2
      _x += _xi2
      _y += _yi2
    end if
  next _i
end sub
'                                                                                    ___________________
'___________________________________________________________________________________/    draw_circle    \
'
sub draw_circle( _
  byval _x as long, _
  byval _y as long, _
  byval _r as long, _
  byval _c as long )
 
  dim as long _x1, _y1
  dim as long _x2, _y2
  dim as long _x3, _y3
  dim as long _x4, _y4
 
  dim as long _tx, _ty
  dim as long _g, _di, _ri
 
  _tx = 0
  _ty = _r
  _g = 3
  _di = 10
  _ri = 6
 
  _g -= ( _r shl 1 )
  _di -= ( _r shl 2 )
 
  _x1 = _x
  _y1 = _y + _r
  _x2 = _x
  _y2 = _y - _r
  _x3 = _x + _r
  _y3 = _y
  _x4 = _x - _r
  _y4 = _y
 
  do while ( _tx <= _ty )
    pset d.sp, ( _x1, _y1 ), _c
    pset d.sp, ( _x1, _y2 ), _c
    pset d.sp, ( _x2, _y1 ), _c
    pset d.sp, ( _x2, _y2 ), _c
    pset d.sp, ( _x3, _y3 ), _c
    pset d.sp, ( _x3, _y4 ), _c
    pset d.sp, ( _x4, _y3 ), _c
    pset d.sp, ( _x4, _y4 ), _c
    /'
    pset_large( _x1, _y1, _c )
    pset_large( _x1, _y2, _c )
    pset_large( _x2, _y1, _c )
    pset_large( _x2, _y2, _c )
    pset_large( _x3, _y3, _c )
    pset_large( _x3, _y4, _c )
    pset_large( _x4, _y3, _c )
    pset_large( _x4, _y4, _c )
    '/
    if ( _g >= 0 ) then
      _g += _di
      _di += 8
      _ty -= 1
      _y1 -= 1
      _y2 += 1
      _x3 -= 1
      _x4 += 1
    else
      _g += _ri
      _di += 4
    end if
   
    _ri += 4
    _tx += 1
    _x1 += 1
    _x2 -= 1
    _y3 += 1
    _y4 -= 1
  loop
end sub
'                                                                                 ______________________
'________________________________________________________________________________/    draw_line_fade    \
'
sub draw_line_fade( _
  byval _x1 as long, _
  byval _y1 as long, _
  byval _x2 as long, _
  byval _y2 as long, _
  byval _c1 as long, _
  byval _c2 as long )
 
  dim as single _d1 = _x2 - _x1
  dim as single _d2 = _y2 - _y1
  dim as single _m
  dim as long _r1, _g1, _b1
  dim as long _r2, _g2, _b2
  dim as single _rd, _gd, _bd
  dim as single _tr, _tg, _tb
  dim as long _i
 
  _r1 = rgb_r( _c1 )
  _g1 = rgb_g( _c1 )
  _b1 = rgb_b( _c1 )
  _r2 = rgb_r( _c2 )
  _g2 = rgb_g( _c2 )
  _b2 = rgb_b( _c2 )
 
  if ( abs( _d2 ) > abs( _d1 ) ) then
    _m = _d1 / _d2
    _rd = ( _r1 - _r2 ) / _d2
    _gd = ( _g1 - _g2 ) / _d2
    _bd = ( _b1 - _b2 ) / _d2
   
    if ( _d2 < 0 ) then
      for _i = 0 to _d2 step -1
        _tr = ( _r1 - ( _i * _rd ) )
        _tg = ( _g1 - ( _i * _gd ) )
        _tb = ( _b1 - ( _i * _bd ) )
        pset d.sp, ( ( _x1 + ( _i * _m ) ), ( _y1 + _i ) ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) )
        'pset_large( clng( ( _x1 + ( _i * _m ) ) ), clng( ( _y1 + _i ) ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) ) )
     
      next _i
    else
      for _i = 0 to _d2 step 1
        _tr = ( _r1 - ( _i * _rd ) )
        _tg = ( _g1 - ( _i * _gd ) )
        _tb = ( _b1 - ( _i * _bd ) )
        pset d.sp, ( ( _x1 + ( _i * _m ) ), ( _y1 + _i ) ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) )
        'pset_large( clng( ( _x1 + ( _i * _m ) ) ), clng( ( _y1 + _i ) ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) ) )
     
      next _i
    end if
  else
    _m = _d2 / _d1
    _rd = ( _r1 - _r2 ) / _d1
    _gd = ( _g1 - _g2 ) / _d1
    _bd = ( _b1 - _b2 ) / _d1
   
    if ( _d1 < 0 ) then
      for _i = 0 to _d1 step -1
        _tr = ( _r1 - ( _i * _rd ) )
        _tg = ( _g1 - ( _i * _gd ) )
        _tb = ( _b1 - ( _i * _bd ) )
        pset d.sp, ( ( _x1 + _i ), ( _y1 + ( _i * _m ) ) ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) )
        'pset_large( clng( ( _x1 + _i ) ), clng( ( _y1 + ( _i * _m ) ) ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) ) )
       
      next _i
    else
      for _i = 0 to _d1 step 1
        _tr = ( _r1 - ( _i * _rd ) )
        _tg = ( _g1 - ( _i * _gd ) )
        _tb = ( _b1 - ( _i * _bd ) )
        pset d.sp, ( ( _x1 + _i ), ( _y1 + ( _i * _m ) ) ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) )
        'pset_large( clng( ( _x1 + _i ) ), clng( ( _y1 + ( _i * _m ) ) ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) ) )
       
      next _i
    end if
  end if
end sub
'                                                                                  _____________________
'_________________________________________________________________________________/    draw_arc_fade    \
'
sub draw_arc_fade( _
  byval _x  as long, _
  byval _y  as long, _
  byval _r  as long, _
  byval _a1 as single, _
  byval _a2 as single, _
  byval _c1 as long, _
  byval _c2 as long )
 
  dim as ubyte _r1, _g1, _b1, _r2, _g2, _b2
  dim as single _rd, _gd, _bd
  dim as single _rs, _gs, _bs
  dim as single _tr, _tg, _tb
  dim as single _tx, _ty
  dim as single _da, _as
  dim as single _i
  dim as long counter
 
  _r1 = rgb_r( _c1 )
  _g1 = rgb_g( _c1 )
  _b1 = rgb_b( _c1 )
  _r2 = rgb_r( _c2 )
  _g2 = rgb_g( _c2 )
  _b2 = rgb_b( _c2 )
 
  _da = _a1 - _a2
  _as = 1 / _r
 
  _rd = _r1 - _r2
  _gd = _g1 - _g2
  _bd = _b1 - _b2
 
  _rs = _rd / _da * _as
  _gs = _gd / _da * _as
  _bs = _bd / _da * _as
 
  counter = 0
  if ( _a1 < _a2 ) then
    for _i = _a1 to _a2 step _as
      '_tx = _x + ( fast_cos( _i ) * _r )
      _tx = _x + ( fast_cos( _i ) * _r )
      '_ty = _y + ( fast_sin( _i ) * _r )
      _ty = _y + ( fast_sin( _i ) * _r )
      _tr = _r1 + ( _rs * counter )
      _tg = _g1 + ( _gs * counter )
      _tb = _b1 + ( _bs * counter )
      pset d.sp, ( _tx, _ty ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) )
      'pset_large( clng( _tx ), clng( _ty ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) ) )
      counter += 1
    next _i
  else
    for _i = _a2 to _a1 step _as
     ' _tx = _x + ( fast_cos( _i ) * _r )
      _tx = _x + ( fast_cos( _i ) * _r )
      '_ty = _y + ( fast_sin( _i ) * _r )
      _ty = _y + ( fast_sin( _i ) * _r )
      _tr = _r2 + ( _rs * counter )
      _tg = _g2 + ( _gs * counter )
      _tb = _b2 + ( _bs * counter )
      pset d.sp, ( _tx, _ty ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) )
      'pset_large( clng( _tx ), clng( _ty ), rgb( cubyte( _tr ), cubyte( _tg ), cubyte( _tb ) ) )
      counter += 1
    next _i
  end if
end sub
'                                                                                     __________________
'____________________________________________________________________________________/    pset_large    \
'
sub pset_large( _
  byval _x as long, _
  byval _y as long, _
  byval _c as long )
 
  line d.sp, ( _x - 1, _y - 1 )-( _x + 1, _y + 1 ), _c, bf
end sub
'                                                                                       ________________
'______________________________________________________________________________________/    fast_sin    \
'
function fast_sin( _
  byval _n as single ) _
  as single
 
  if ( _n < negative_pi ) then
    do
      _n += tau
    loop until ( _n >= negative_pi )
  else
    if ( _n > pi ) then
      do
        _n -= tau
      loop until ( _n <= pi )
    end if
  end if
 
  if ( _n < 0 ) then
    _n = ( four_over_pi * _n ) + ( four_over_pi_squared * _n * _n )
    if ( _n < 0 ) then
      return( cos_45_over_pi * ( ( _n * -_n ) - _n ) + _n )
    else
      return( cos_45_over_pi * ( ( _n * _n ) - _n ) + _n )
    end if
  else
    _n = ( four_over_pi * _n ) - ( four_over_pi_squared * _n * _n )
    if ( _n < 0 ) then
      return( cos_45_over_pi * ( ( _n * -_n ) - _n ) + _n )
    else
      return( cos_45_over_pi * ( ( _n * _n ) - _n ) + _n )
    end if
  end if
end function
'                                                                                       ________________
'______________________________________________________________________________________/    fast_cos    \
'
function fast_cos( _
  byval _n as single ) _
  as single
 
  _n += pi_half
 
  if ( _n < negative_pi ) then
    do
      _n += tau
    loop until ( _n >= negative_pi )
  else
    if ( _n > pi ) then
      do
        _n -= tau
      loop until ( _n <= pi )
    end if
  end if
 
  if ( _n < 0 ) then
    _n = ( four_over_pi * _n ) + ( four_over_pi_squared * _n * _n )
    if ( _n < 0 ) then
      return( cos_45_over_pi * ( ( _n * -_n ) - _n ) + _n )
    else
      return( cos_45_over_pi * ( ( _n * _n ) - _n ) + _n )
    end if
  else
    _n = ( four_over_pi * _n ) - ( four_over_pi_squared * _n * _n )
    if ( _n < 0 ) then
      return( cos_45_over_pi * ( ( _n * -_n ) - _n ) + _n )
    else
      return( cos_45_over_pi * ( ( _n * _n ) - _n ) + _n )
    end if
  end if
end function

function fast_atan2( _
  byval _y as single, _
  byval _x as single )_
  as single
 
  if( _x = 0 ) then
    if( _y = 0 ) then
      return( 0 )
    else
      if( _y > 0 ) then
        return( pi_half )
      else
        return( negative_pi_half )
      end if
    end if
  end if
 
  dim as single _a
  dim as single _z = _y / _x
 
  if ( abs( _z ) < 1 ) then
    _a = _z / ( 1 + fast_atan2_const * _z * _z )
    if ( _x < 0 ) then
      if ( _y < 0 ) then
        return( _a - pi )
      else
        return( _a + pi )
      end if
    else
      return( _a )
    end if
  else
    _a = pi_half - ( _z / ( ( _z * _z ) + fast_atan2_const ) )
    if ( _y < 0 ) then
      return( _a - pi )
    else
      return( _a )
    end if
  end if
end function
Last edited by sero on Feb 12, 2021 3:11, edited 1 time in total.
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Trigonometry and tank control movement

Post by badidea »

Looks good. Without the timeBeginPeriod/timeEndPeriod it works fine on linux as well.
sero
Posts: 59
Joined: Mar 06, 2018 13:26
Location: USA

Re: Trigonometry and tank control movement

Post by sero »

badidea wrote:Without the timeBeginPeriod/timeEndPeriod it works fine on linux as well.
I'm glad to hear that. Would using an #ifdef in this case be possible to make it linux friendly? Also, is there something similar to timeBeginPeriod/timeEndPeriod on linux?
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Trigonometry and tank control movement

Post by badidea »

I don't think that timeBeginPeriod/timeEndPeriod is needed on most linux systems. Tick interval (or whatever the name is) seems to be short already.
When I run this on a laptop with Ubuntu Mate 18.04

Code: Select all

dim as double t = timer
for i as integer = 0 to 9
	sleep 1
	print str((timer - t) * 1000) & " ms"
	t = timer
next
I get:

Code: Select all

1.062943949364126 ms
1.099003362469375 ms
1.066024648025632 ms
1.093113911338151 ms
1.123116118833423 ms
1.126010785810649 ms
1.129951910115778 ms
1.123932423070073 ms
1.126919873058796 ms
1.129099284298718 ms
So the simple solution is to do:

Code: Select all

#Ifdef __FB_WIN32__
  set_timer()
#Else
#EndIf
sero
Posts: 59
Joined: Mar 06, 2018 13:26
Location: USA

Re: Trigonometry and tank control movement

Post by sero »

This is very helpful information badidea. Thank you. I'm curious about:

Code: Select all

#Ifdef __FB_WIN32__
Is there a list of __FB__ definitions? Is there documentation about it? This is preprocessor stuff right? Does the compiler define it? What are these standard definitions? I'd like to learn more about all this :)
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Trigonometry and tank control movement

Post by fxm »

See 'Intrinsic Defines' documentation page with all its links.
Post Reply