getjoystick() demo

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

getjoystick() demo

Post by sero »

Using coderJeff's previous example of getjoystick() code viewtopic.php?f=3&t=5229 as well as heavy inspiration from paul doe's fbg-mouse.bi viewtopic.php?f=7&t=28958 I've put together a new getjoystick() demonstration. All four axis and thirty two buttons are supported and represented. Axis 0 drives the screen pointer. Button 0 will drag boxes. Button 1 will add boxes. Button 2 double press to exit. Escape key to exit. getjoystick() data is on the left and class variables on the right. Code criticism is welcome.

Image

Original joystick only:

Code: Select all

type t_joystick
  public:   
    as long    id
    as integer result, button
    as single  axis_x( any ),  axis_y( any ), _ ' raw axis data
               axis_a( any )                    ' angle for axis
    as long    pointer_x,      pointer_y, _
               drag_sx,        drag_sy, _       ' start position for drag
               drag_dx,        drag_dy, _       ' delta for drag
               double_press_x, double_press_y
    as long    pointer_boundary_w, _
               pointer_boundary_h, _
               pointer_which_axis
    as single  sensitivity
    as single  deadzone
    as long    owner_drag, _
               owner_double_press
    as double  time_double_press
   
    declare constructor( _
      byval p_axis   as long = 3, _   ' set default number of axis to 4 in total
      byval p_button as long = 31 ) ' set default number of buttons to 32 in total
    declare destructor()
   
    declare sub set_pointer_position( _
      byval p_x as single = 0, _
      byval p_y as single = 0 )
    declare sub set_pointer_boundary( _
      byval p_w as long = 0, _
      byval p_h as long = 0 )
    declare sub update_pointer_position()
    declare sub get_state( _
      byval p_timer as double = timer() )
    declare sub close_state()
   
    declare function joystick() _
      as boolean
    declare function press( _
      byval p_button as long ) _
      as boolean
    declare function double_press( _
      byval p_button as long ) _
      as boolean
    declare function release( _
      byval p_button as long ) _
      as boolean
    declare function halt( _
      byval p_button as long, _
      byval p_time as double = 0.0 ) _
      as boolean
    declare function hold( _
      byval p_button as long, _
      byval p_time as double = 0.0 ) _
      as boolean
    declare function repeat( _
      byval p_button as long, _
      byval p_time as double = 0.0 ) _
      as boolean
    declare function drag( _
      byval p_button as long ) _
      as boolean
    declare function drop( _
      byval p_button as long ) _
      as boolean
   
  private:
    as integer temp_button           ' buffer for getjoystick()
    as single  temp_axis_x( any ), _
               temp_axis_y( any )
    as double  local_timer
   
    enum button_state
      none                 = 0
      press                = 1
      already_press        = 2
      release              = 3
      already_release      = 4
      double_press         = 5
      already_double_press = 6
      void                 = 7
    end enum
   
    as byte    state( any )
    as double  hold_start_time( any ), _
               repeat_start_time( any ), _
               double_press_start_time( any )
end type

constructor t_joystick( _
      byval p_axis as long = 3, _  ' set default number of axis to 4 in total
      byval p_button as long = 31 ) ' set default number of buttons to 32 in total
  dim as byte _n
 
  ' retrieve the lowest numbered joystick attached to the computer
  id = -1
  for _n = 15 to 0 step( -1 )
    result = getjoystick( _n )
    if( result = 0 ) then
      id = _n
    end if
  next _n
 
  pointer_which_axis = 0
  pointer_boundary_w = 0
  pointer_boundary_h = 0
  sensitivity        = 10
  deadzone           = 0.001
  owner_drag         = -1
  owner_double_press = -1
  time_double_press  = 0.2
 
  redim      axis_x( 0 to p_axis )
  redim      axis_y( 0 to p_axis )
  redim      axis_a( 0 to p_axis )
  redim temp_axis_x( 0 to  3 )
  redim temp_axis_y( 0 to  3 )
 
  redim                   state( 0 to p_button )
  redim         hold_start_time( 0 to p_button )
  redim       repeat_start_time( 0 to p_button )
  redim double_press_start_time( 0 to p_button )
end constructor

destructor t_joystick()
 
end destructor

sub t_joystick.set_pointer_position( _
  byval p_x as single = 0, _
  byval p_y as single = 0 )
 
  pointer_x = p_x
  pointer_y = p_y
end sub

sub t_joystick.set_pointer_boundary( _
  byval p_w as long = 0, _
  byval p_h as long = 0 )
 
  pointer_boundary_w = p_w
  pointer_boundary_h = p_h
end sub

sub t_joystick.update_pointer_position()
 
  if( axis_x( pointer_which_axis ) <> 0 ) then
    pointer_x += ( axis_x( pointer_which_axis ) * sensitivity )
    pointer_x = iif( ( pointer_x ) < ( pointer_boundary_w ), _
      ( pointer_x ), ( pointer_boundary_w ) )
    pointer_x = iif( ( pointer_x ) > ( 0 ), _
      ( pointer_x ), ( 0 ) )
  end if
  if( axis_y( pointer_which_axis ) <> 0 ) then
    pointer_y += ( axis_y( pointer_which_axis ) * sensitivity )
    pointer_y = iif( ( pointer_y ) < ( pointer_boundary_h ), _
      ( pointer_y ), ( pointer_boundary_h ) )
    pointer_y = iif( ( pointer_y ) > ( 0 ), _
      ( pointer_y ), ( 0 ) )
  end if
end sub

sub t_joystick.get_state( _
  byval p_timer as double = timer() )
 
  dim as long _i
 
  local_timer = p_timer
 
  result = getjoystick( id, button, temp_axis_x( 0 ), temp_axis_y( 0 ), _
                          temp_axis_x( 1 ), temp_axis_y( 1 ), _
                          temp_axis_x( 2 ), temp_axis_y( 2 ), _
                          temp_axis_x( 3 ), temp_axis_y( 3 ) )
  if( result = 0 ) then
    for _i = 0 to ubound( axis_a ) ' axis_x, axis_y, or axis_a all can be used here
      if( ( ( temp_axis_x( _i ) * temp_axis_x( _i ) ) + ( temp_axis_y( _i ) * temp_axis_y( _i ) ) ) > deadzone ) then
        axis_x( _i ) = temp_axis_x( _i )
        axis_y( _i ) = temp_axis_y( _i )
      else
        axis_x( _i ) = 0
        axis_y( _i ) = 0
      end if
    next _i
   
    for _i = 0 to ubound( axis_a ) ' axis_x, axis_y, or axis_a all can be used here
      'axis_a( _i ) = fast_atan2( axis_x( _i ), axis_y( _i ) )
      axis_a( _i ) = atan2( axis_x( _i ), axis_y( _i ) )
    next _i
   
    _i = ubound( state )
    do
      if( button and ( 2 ^ _i ) ) then
        if( state( _i ) = button_state.none ) then
          if ( owner_drag = -1 ) then
            owner_drag = _i
            state( _i ) = button_state.press
            hold_start_time( _i ) =local_timer
            repeat_start_time( _i ) =local_timer
            if( owner_double_press <> _i ) then
              owner_double_press = _i
              double_press_start_time( _i ) =local_timer
            else
              if( ( p_timer - double_press_start_time( _i ) ) < time_double_press ) then
                double_press_x = pointer_x
                double_press_y = pointer_y
                state( _i ) = button_state.double_press
              else
                double_press_x = pointer_x
                double_press_y = pointer_y
                double_press_start_time( _i ) =local_timer
              end if
            end if
            drag_dx = 0
            drag_dy = 0
            drag_sx = pointer_x
            drag_sy = pointer_y
          else
            if( ( _i <> owner_drag ) ) then
              ' in drag state, this button press isn't the owner of the drag, so
              ' the button state gets set to void. the only way to clear the void
              ' state is to release. ending a drag will not clear another button's
              ' voided state.
              'state( _i ) = button_state.void
              state( _i ) = button_state.press
              hold_start_time( _i ) =local_timer
              repeat_start_time( _i ) =local_timer
              if( owner_double_press <> _i ) then
                owner_double_press = _i
                double_press_start_time( _i ) =local_timer
              else
                if( ( p_timer - double_press_start_time( _i ) ) < time_double_press ) then
                  double_press_x = pointer_x
                  double_press_y = pointer_y
                  state( _i ) = button_state.double_press
                else
                  double_press_x = pointer_x
                  double_press_y = pointer_y
                  double_press_start_time( _i ) =local_timer
                end if
              end if
            end if
          end if
        else
          if( owner_drag = _i ) then
            drag_dx = pointer_x - drag_sx
            drag_dy = pointer_y - drag_sy
          end if
        end if
      else
        if( state( _i ) = button_state.already_press ) then
          state( _i ) = button_state.release
        else
          if( state( _i ) = button_state.already_release ) then
            state( _i ) = button_state.none
            if( owner_drag = _i ) then
              owner_drag = -1
            end if
          else
            if( state( _i ) = button_state.already_double_press ) then
              state( _i ) = button_state.none
              owner_drag = -1
              owner_double_press = -1
            else
              if( state( _i ) = button_state.void ) then
                state( _i ) = button_state.none
              end if
            end if
          end if
        end if
      end if
      _i -= 1
    loop until( _i = -1 )
  else
    ' result from getjoystick() is bad
  end if
end sub

sub t_joystick.close_state()
 
  dim as long _i
 
  for _i = 0 to ubound( state )
    if( state( _i ) = button_state.press ) then
      state( _i ) = button_state.already_press
    else
      if( state( _i ) = button_state.release ) then
        state( _i ) = button_state.already_release
      else
        if( state( _i ) = button_state.double_press ) then
          state( _i ) = button_state.already_double_press
        end if
      end if
    end if
  next _i
end sub

function t_joystick.joystick() _
  as boolean
 
  dim as boolean _return
 
  if( ( id < 0 ) or ( id > 15 ) ) then
    _return = false
  else
    _return = true
  end if
 
  return _return
end function

function t_joystick.press( _
  byval p_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( p_button ) = button_state.press ) then
    state( p_button ) = button_state.already_press
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_joystick.double_press( _
  byval p_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( p_button ) = button_state.double_press ) then
    state( p_button ) = button_state.already_double_press
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_joystick.release( _
  byval p_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( p_button ) = button_state.release ) then
    state( p_button ) = button_state.already_release
    _return = true
  else
    _return = false
  end if
   
  return _return
end function

function t_joystick.halt( _
  byval p_button as long, _
  byval p_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( p_button ) = button_state.press ) or _
    ( state( p_button ) = button_state.already_press ) ) then
    if( p_time <> 0 ) then
      if( ( local_timer - hold_start_time( p_button ) ) < p_time ) then
        _return = true
      else
        _return = false
      end if
    else
      _return = true
    end if
  else
    _return = false
  end if
 
  return _return
end function

function t_joystick.hold( _
  byval p_button as long, _
  byval p_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( p_button ) = button_state.press ) or _
    ( state( p_button ) = button_state.already_press ) ) then
    if( p_time <> 0 ) then
      if( ( local_timer - hold_start_time( p_button ) ) > p_time ) then
        _return = true
      else
        _return = false
      end if
    else
      _return = true
    end if
  else
    _return = false
  end if
 
  return _return
end function

function t_joystick.repeat( _
  byval p_button as long, _
  byval p_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
  dim as double _time_difference
 
  if( ( state( p_button ) = button_state.press ) or _
    ( state( p_button ) = button_state.already_press ) ) then
    _time_difference = local_timer - repeat_start_time( p_button )
    if( _time_difference > p_time ) then
      repeat_start_time( p_button ) += _time_difference
      _return = true
    else
      _return = false
    end if
  else
    _return = false
  end if
 
  return _return
end function

function t_joystick.drag( _
  byval p_button as long ) _
  as boolean
 
  return( hold( p_button ) and ( owner_drag = p_button ) )
end function

function t_joystick.drop( _
  byval p_button as long ) _
  as boolean
 
  return( release( p_button ) and ( owner_drag = p_button ) )
end function


' ################################################################################ demo ####

type t_mouse
  result as long
  x as long
  y as long
  last_x as long
  last_y as long
  delta_x as long
  delta_y as long
end type

type t_box
  x as long
  y as long
  w as long
  h as long
  c as ulong
  declare sub add_box( _
    byval _x as long, _
    byval _y as long )
  declare sub draw_box( _
    byval p_n as long )
end type

declare sub draw_pointer( _
  byval p_x as single, _
  byval p_y as single, _
  byval p_r as long, _
  byval p_c as ulong, _
  byval p_b as boolean = false )

declare sub draw_joystick_stats( _
  byref p_joystick as t_joystick )

dim as long screen_w = 1280
dim as long screen_h = 720

dim as double t1, timer_post
dim as long timer_post_avg = 1

dim box( 0 to 99 ) as t_box
dim as long number_of_boxes = 2
dim as long box_n
dim as long box_drag
dim as long temp

box_drag = -1

randomize()
for temp = 0 to number_of_boxes
  box( temp ).add_box( ( ( rnd * 640 ) + 320 ), ( ( rnd * 360 ) + 180 ) )
next temp

dim as t_mouse m
dim as t_joystick j

screenres( screen_w, screen_h, 32 )

if( j.joystick() = true ) then
  dim as boolean terminate = false
 
  j.set_pointer_position( screen_w shr 1, screen_h shr 1 )
  j.set_pointer_boundary( screen_w - 1, screen_h - 1 )
  m.last_x = j.pointer_x
  m.last_y = j.pointer_y
  setmouse( j.pointer_x, j.pointer_y, 0 )
 
  do while( not terminate )
    t1 = timer()
    j.get_state()
    j.update_pointer_position()
    m.result = getmouse( m.x, m.y )
    if( m.result = 0 ) then
      m.delta_x = m.x - m.last_x
      m.delta_y = m.y - m.last_y
      if( ( m.delta_x <> 0 ) or ( m.delta_y <> 0 ) ) then
        m.last_x = m.x
        m.last_y = m.y
        j.set_pointer_position( m.x, m.y )
      else
        m.last_x = j.pointer_x
        m.last_y = j.pointer_y
        setmouse( j.pointer_x, j.pointer_y )
      end if
    end if
    
    
   
    'if( j.joystick() = false ) then terminate = true
    if( j.double_press( 2 ) ) then terminate = true
    if( multikey( 1 ) ) then terminate = true
   
    if( j.press( 0 ) ) then
      for box_n = number_of_boxes to 0 step -1
        if( ( j.pointer_x < ( box( box_n ).x + box( box_n ).w ) ) and _
            ( j.pointer_x > box( box_n ).x ) and _
            ( j.pointer_y < ( box( box_n ).y + box( box_n ).h ) ) and _
            ( j.pointer_y > box( box_n ).y ) ) then
          box_drag = box_n
          exit for
        end if
      next box_n
    else
      if( j.drop( 0 ) ) then
        box_drag = -1
      else
      end if
    end if
   
    if( j.press( 1 ) ) then
      number_of_boxes += 1
      if( number_of_boxes > 99 ) then
        number_of_boxes = 99
      else
        box( number_of_boxes ).add_box( j.pointer_x, j.pointer_y )
      end if
    end if
   
    if( j.drag( 0 ) and ( box_drag <> -1 ) ) then
      box( box_drag ).x += j.drag_dx
      box( box_drag ).y += j.drag_dy
      j.drag_sx += j.drag_dx
      j.drag_sy += j.drag_dy
    end if
   
   
    screenlock()
      cls
     
      for box_n = 0 to number_of_boxes
        box( box_n ).draw_box( box_n )
      next box_n
     
      draw_pointer( j.pointer_x, j.pointer_y, 5, rgb( 255, 255, 255 ), true )
      draw_pointer( j.pointer_x + ( j.axis_x( 1 ) * 32 ), _
                    j.pointer_y + ( j.axis_y( 1 ) * 32 ), _
                    3, rgb( 255,   0,   0 ) )
      draw_pointer( j.pointer_x + ( j.axis_x( 2 ) * 16 ), _
                    j.pointer_y + ( j.axis_y( 2 ) * 16 ), _
                    3, rgb(   0,   0, 255 ) )
      draw_pointer( j.pointer_x + ( j.axis_x( 3 ) * 8 ), _
                    j.pointer_y + ( j.axis_y( 3 ) * 8 ), _
                    3, rgb(   0, 255,   0 ) )
      draw_pointer( j.pointer_x, j.pointer_y, 3, rgb( 0, 0, 0 ) )
     
      draw_joystick_stats( j )
     
      draw string( 9, 701 ), " scene render time (ms) " & timer_post
      draw string( 9, 710 ), "scene average time (ms) " & timer_post_avg
    screenunlock()
    j.close_state()
    timer_post = ( timer() - t1 ) * 1000
    timer_post_avg = ( timer_post_avg + timer_post ) / 2
    sleep( 15 )
  loop
else
  draw string( 1, 1 ), "joystick required..."
  sleep
end if
setmouse( ,, 1 )





sub t_box.add_box( _
  byval _x as long, _
  byval _y as long )
  dim as long _temp
 
  _temp = ( rnd * 50 ) + 75
  x = _x - _temp
  w = _temp + _temp
  _temp = ( rnd * 50 ) + 75
  y = _y - _temp
  h = _temp + _temp
  c = rgb( ( ( rnd * 191 ) + 64 ), ( ( rnd * 191 ) + 64 ), ( ( rnd * 191 ) + 64 ) )
end sub

sub t_box.draw_box( _
  byval p_n as long )
 
  line( x, y )-( x + w, y + h ), c, bf
  line( x + 1, y + 1 )-( x + w - 1, y + h - 1 ), rgb( 0, 0, 0 ), b
  draw string( x + 3, y + 3 ), str( "Box " & p_n ), rgb( 0, 0, 0 )
end sub

sub draw_pointer( _
  byval p_x as single, _
  byval p_y as single, _
  byval p_r as long, _
  byval p_c as ulong, _
  byval p_b as boolean = false )
 
  if( p_b = true ) then circle( p_x, p_y ), p_r + 1, rgb( 0, 0, 0 )
  circle( p_x, p_y ), p_r, p_c,,,, f
end sub

sub draw_joystick_stats( _
  byref p_joystick as t_joystick )
  
  dim as long _i, _x, _y
  
  _x = 9
  _y = 1
  draw string( _x, _y ), "getjoystick() data:", rgb( 255, 63, 63 ):_y += 9
  with p_joystick
    for _i = 0 to 3
      _y += 9
      draw string( _x, _y ), "axis " & _i & " ( " & .axis_x( _i ) & ", " & .axis_y( _i ) & " )"
    next _i
    _y += 9
    for _i = 0 to 9
      _y += 9
      draw string( _x, _y ), "button 0" & _i & " " & cbool( .button and ( 1 shl _i ) )
    next _i
    for _i = 10 to 31
      _y += 9
      draw string( _x, _y ), "button " & _i & " " & cbool( .button and ( 1 shl _i ) )
    next _i
    
    _x = 1047
    _y = 1
    draw string( _x, _y ), "   type t_joystick variables", rgb( 255, 63, 63 ): _y += 9
    _y += 9
    draw string( _x, _y ), "                id " & .id: _y += 9
    draw string( _x, _y ), "            result " & .result: _y += 9
    draw string( _x, _y ), "            button " & .button: _y += 9
    draw string( _x, _y ), "       axis_a( 0 ) " & .axis_a( 0 ): _y += 9
    draw string( _x, _y ), "       axis_a( 1 ) " & .axis_a( 1 ): _y += 9
    draw string( _x, _y ), "       axis_a( 2 ) " & .axis_a( 2 ): _y += 9
    draw string( _x, _y ), "       axis_a( 3 ) " & .axis_a( 3 ): _y += 9
    draw string( _x, _y ), "         pointer_x " & .pointer_x: _y += 9
    draw string( _x, _y ), "         pointer_y " & .pointer_y: _y += 9
    draw string( _x, _y ), "           drag_sx " & .drag_sx: _y += 9
    draw string( _x, _y ), "           drag_sy " & .drag_sy: _y += 9
    draw string( _x, _y ), "           drag_dx " & .drag_dx: _y += 9
    draw string( _x, _y ), "           drag_dy " & .drag_dy: _y += 9
    draw string( _x, _y ), "    double_press_x " & .double_press_x: _y += 9
    draw string( _x, _y ), "    double_press_y " & .double_press_y: _y += 9
    draw string( _x, _y ), "pointer_boundary_w " & .pointer_boundary_w: _y += 9
    draw string( _x, _y ), "pointer_boundary_h " & .pointer_boundary_h: _y += 9
    draw string( _x, _y ), "pointer_which_axis " & .pointer_which_axis: _y += 9
    draw string( _x, _y ), "       sensitivity " & .sensitivity: _y += 9
    draw string( _x, _y ), "          deadzone " & .deadzone: _y += 9
    draw string( _x, _y ), "        owner_drag " & .owner_drag: _y += 9
    draw string( _x, _y ), "owner_double_press " & .owner_double_press: _y += 9
    draw string( _x, _y ), " time_double_press " & .time_double_press: _y += 9
    
    draw string( 485,  1 ), "( button 0 ) to drag boxes", rgb( 255, 127, 0 )
    draw string( 485, 10 ), "( button 1 ) to add boxes", rgb( 255, 127, 0 )
    draw string( 485, 19 ), "( button 2 ) double press to exit", rgb( 255, 127, 0 )
    draw string( 485, 28 ), "  ( escape ) to exit", rgb( 255, 127, 0 )
    
  end with
end sub
Enhanced with mouse and keyboard support:

Code: Select all

type t_fusion
  as long    j_id
  as integer j_result, _
             j_button
  as single  j_axis_x( any ), _
             j_axis_y( any ), _
             j_axis_a( any ), _
             j_sensitivity, _
             j_deadzone
  as boolean j_axis_motion( any )
 
  as integer m_result, _
             m_button
  as long    m_x, _
             m_y, _
             m_w
  as single  m_axis_x, _
             m_axis_y, _
             m_axis_a, _
             m_axis_w
 
  as single  p_x, _
             p_y, _
             p_a, _
             p_drag_sx, _
             p_drag_sy, _
             p_drag_dx, _
             p_drag_dy
  as long    p_boundary_x, _
             p_boundary_y, _
             p_boundary_w, _
             p_boundary_h, _
             p_j_which_axis, _
             owner_drag, _
             owner_double_press
 
  as double  j_time_double_press, _
             m_time_double_press, _
             k_time_double_press
 
  as boolean use_joystick_axis( any )
  as boolean use_joystick
  as boolean use_mouse
  as boolean use_keyboard
 
  as long num_j_axis
  as long num_j_buttons
  as long num_m_buttons
  as long num_k_keys
  as long m_offset
  as long k_offset
 
  as long    b( any )
  as long    k( any )
  as double  local_timer, _
             local_timer_difference, _
             hold_start_time( any ), _
             repeat_start_time( any ), _
             double_press_start_time( any )
 
  enum button_state
    none                 = 0
    press                = 1
    already_press        = 2
    release              = 3
    already_release      = 4
    double_press         = 5
    already_double_press = 6
  end enum
 
  as byte state( any )
 
  declare constructor()
  declare destructor()
  declare sub hide_mouse()
  declare sub show_mouse()
  declare sub set_pointer_position( _
    byval v_x as single, _
    byval v_y as single )
  declare sub set_pointer_boundary( _
    byval v_x as long, _
    byval v_y as long, _
    byval v_w as long, _
    byval v_h as long )
  declare sub update_pointer_position()
  declare sub get_state( _
    byval v_timer as double = timer() )
  declare sub close_state()
  declare sub correct_axis( _
    byval v_which as long = -1 )
  declare function joystick() _
    as boolean
  declare function press( _
    byval v_button as long ) _
    as boolean
  declare function double_press( _
    byval v_button as long ) _
    as boolean
  declare function release( _
    byval v_button as long ) _
    as boolean
  declare function halt( _
    byval v_button as long, _
    byval v_time as double = 0.0 ) _
    as boolean
  declare function hold( _
    byval v_button as long, _
    byval v_time as double = 0.0 ) _
    as boolean
  declare function repeat( _
    byval v_button as long, _
    byval v_time as double = 0.0 ) _
    as boolean
  declare function drag( _
    byval v_button as long ) _
    as boolean
  declare function drop( _
    byval v_button as long ) _
    as boolean
end type

constructor t_fusion()
  dim as long _n
 
  ' Cycle backwards through all possible joystick identities
  ' and assign j_id to the lowest identity and assign true
  ' to use_joystick. If there aren't joystick identities
  ' found, then j_id is assigned to -1 and use_joystick
  ' is assigned false.
  j_id = -1
  use_joystick = false
  for _n = 15 to 0 step( -1 )
    j_result = getjoystick( _n )
    if( j_result = 0 ) then
      j_id = _n
      use_joystick = true
    end if
  next _n
 
  ' Use getmouse() to find out if there is a mouse available.
  ' If there is a mouse true is assigned to use_mouse.
  ' Otherwise, use_mouse is assigned false.
  use_mouse = false
  m_result = getmouse( m_x, m_y )
  if( m_result = 0 ) then use_mouse = true
 
  ' Set use_keyboard to true by default.
  use_keyboard = true
 
  ' Default pointer position and assign which joystick axis
  ' is responsible for moving the pointer.
  p_x            = 0
  p_y            = 0
  p_a            = 0
  p_boundary_x   = 0
  p_boundary_y   = 0
  p_boundary_w   = 0
  p_boundary_h   = 0
  p_j_which_axis = 0
 
  ' These two variables hold which button is currently in
  ' drag or double press mode. Assign them -1 here.
  owner_drag         = -1
  owner_double_press = -1
 
  ' These next variables are multipliers for how much
  ' the correlating axis change the pointer position.
  j_sensitivity = 250
 
  ' This deadzone value is a squared hypotenuse length
  ' to be checked against the joystick axis deltas. This
  ' is used to prevent micro deltas that can occur even
  ' when the joystick is at rest.
  j_deadzone = 0.001
 
  ' Double press time is the time window that two presses
  ' much occur to activate double press. The value is in
  ' seconds, so a default of 0.2 = 200 milliseconds.
  j_time_double_press = 0.2
  m_time_double_press = 0.2
  k_time_double_press = 0.2
 
  ' Tell our class how many buttons and how many axis so
  ' we can redim our appropriate variables.
  num_j_axis    = 4
  num_j_buttons = 12
  num_m_buttons = 3
  num_k_keys    = 128
 
  ' Joystick,mouse and key button states are stacked in that
  ' order. Because of this, the following offset variables
  ' provide the starting array position for each.
  m_offset = num_j_buttons
  k_offset = num_j_buttons + num_m_buttons
 
  ' Create an record of mouse buttons that stores the address
  ' of each within the state() array.
  redim b( 0 to 2 )
  b( 0 ) = m_offset
  b( 1 ) = m_offset + 1
  b( 2 ) = m_offset + 2
 
  ' Create an array that takes a keyboard scancode and returns
  ' it's address in the state() array.
  redim k( 1 to 100 )
  for _n = 1 to 100
    k( _n ) = _n + k_offset
  next _n
 
  ' Subtract 1 from our buttons and axis numbers because
  ' our array numbering starts at zero.
  num_j_axis    -= 1
  num_j_buttons -= 1
  num_m_buttons -= 1
  num_k_keys    -= 1
 
  redim      j_axis_x( 0 to num_j_axis )
  redim      j_axis_y( 0 to num_j_axis )
  redim      j_axis_a( 0 to num_j_axis )
  redim j_axis_motion( 0 to num_j_axis )
  
  redim use_joystick_axis( 0 to num_j_axis )
  
  j_result = getjoystick( j_id, j_button, _
                          j_axis_x( 0 ), j_axis_y( 0 ), _
                          j_axis_x( 1 ), j_axis_y( 1 ), _
                          j_axis_x( 2 ), j_axis_y( 2 ), _
                          j_axis_x( 3 ), j_axis_y( 3 ) )
  for _n = 0 to num_j_axis
    if( j_axis_x( _n ) <> -1000 ) then
      use_joystick_axis( _n ) = true
    else
      use_joystick_axis( _n ) = false
    end if
  next _n
 
  redim         hold_start_time( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
  redim       repeat_start_time( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
  redim double_press_start_time( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
  redim                   state( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
 
  ' This variable keeps track of how much time has passed since
  ' the previous close_state(). This variable is useful for
  ' time based physics.
  local_timer_difference = 0
end constructor

destructor t_fusion()
 
end destructor

sub t_fusion.hide_mouse()
 
  setmouse( ,, 0 )
end sub

sub t_fusion.show_mouse()
 
  setmouse( ,, 1 )
end sub

sub t_fusion.set_pointer_position( _
  byval v_x as single, _
  byval v_y as single )
 
  p_x = v_x
  p_y = v_y
end sub

sub t_fusion.set_pointer_boundary( _
  byval v_x as long, _
  byval v_y as long, _
  byval v_w as long, _
  byval v_h as long )
 
  p_boundary_x = v_x
  p_boundary_y = v_y
  p_boundary_w = v_w
  p_boundary_h = v_h
end sub

sub t_fusion.update_pointer_position()
 
  if( use_mouse = true ) then
    if( m_result = 0 ) then
      p_x = m_x + ( j_axis_x( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_y = m_y + ( j_axis_y( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_x = iif( ( p_x ) < ( p_boundary_w ), _
        ( p_x ), ( p_boundary_w ) )
      p_x = iif( ( p_x ) > ( p_boundary_x ), _
        ( p_x ), ( p_boundary_x ) )
      p_y = iif( ( p_y ) < ( p_boundary_h ), _
        ( p_y ), ( p_boundary_h ) )
      p_y = iif( ( p_y ) > ( p_boundary_y ), _
        ( p_y ), ( p_boundary_y ) )
      setmouse( p_x, p_y )
      m_x = p_x
      m_y = p_y
    else
      p_x += ( j_axis_x( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_y += ( j_axis_y( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_x = iif( ( p_x ) < ( p_boundary_w ), _
        ( p_x ), ( p_boundary_w ) )
      p_x = iif( ( p_x ) > ( p_boundary_x ), _
        ( p_x ), ( p_boundary_x ) )
      p_y = iif( ( p_y ) < ( p_boundary_h ), _
        ( p_y ), ( p_boundary_h ) )
      p_y = iif( ( p_y ) > ( p_boundary_y ), _
        ( p_y ), ( p_boundary_y ) )
    end if
  else
    if( use_joystick = true ) then
      p_x += ( j_axis_x( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_y += ( j_axis_y( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_x = iif( ( p_x ) < ( p_boundary_w ), _
        ( p_x ), ( p_boundary_w ) )
      p_x = iif( ( p_x ) > ( p_boundary_x ), _
        ( p_x ), ( p_boundary_x ) )
      p_y = iif( ( p_y ) < ( p_boundary_h ), _
        ( p_y ), ( p_boundary_h ) )
      p_y = iif( ( p_y ) > ( p_boundary_y ), _
        ( p_y ), ( p_boundary_y ) )
    end if
  end if
end sub

sub t_fusion.get_state( _
  byval v_timer as double = timer() )
 
  dim as long _i
 
  local_timer_difference += ( v_timer - local_timer )
  local_timer = v_timer
 
  if( use_joystick = true ) then
    dim as single temp_axis_x( 0 to 3 ), _
                  temp_axis_y( 0 to 3 )
   
    j_result = getjoystick( j_id, j_button, _
                            temp_axis_x( 0 ), temp_axis_y( 0 ), _
                            temp_axis_x( 1 ), temp_axis_y( 1 ), _
                            temp_axis_x( 2 ), temp_axis_y( 2 ), _
                            temp_axis_x( 3 ), temp_axis_y( 3 ) )
    if( j_result = 0 ) then
      _i = num_j_axis
      do
        if( use_joystick_axis( _i ) = true ) then
          if( j_deadzone < ( ( temp_axis_x( _i ) * temp_axis_x( _i ) ) + ( temp_axis_y( _i ) * temp_axis_y( _i ) ) ) ) then
            j_axis_motion( _i ) = true
            j_axis_x( _i ) = temp_axis_x( _i )
            j_axis_y( _i ) = temp_axis_y( _i )
            'j_axis_a( _i ) = fast_atan2( j_axis_y( _i ), j_axis_x( _i ) ) ' ###############################
            j_axis_a( _i ) = atan2( j_axis_y( _i ), j_axis_x( _i ) ) ' #####################################
          else
            j_axis_motion( _i ) = false
            j_axis_x( _i ) = 0
            j_axis_y( _i ) = 0
          end if
        else
          ' not using this joystick axis
        end if
        _i -= 1
      loop until( _i = -1 )
     
      _i = num_j_buttons
      do
        if( j_button and ( 2 ^ _i ) ) then
          if( state( _i ) = button_state.none ) then
            if( owner_drag = -1 ) then
              owner_drag = _i
              state( _i ) = button_state.press
              hold_start_time( _i ) = local_timer
              repeat_start_time( _i ) = local_timer
              if( owner_double_press <> _i ) then
                owner_double_press = _i
                double_press_start_time( _i ) = local_timer
              else
                if( ( local_timer - double_press_start_time( _i ) ) < j_time_double_press ) then
                  state( _i ) = button_state.double_press
                else
                  double_press_start_time( _i ) = local_timer
                end if
              end if
              p_drag_dx = 0
              p_drag_dy = 0
              p_drag_sx = p_x
              p_drag_sy = p_y
            else
              if( ( _i <> owner_drag ) ) then
                state( _i ) = button_state.press
                hold_start_time( _i ) = local_timer
                repeat_start_time( _i ) = local_timer
                if( owner_double_press <> _i ) then
                  owner_double_press = _i
                  double_press_start_time( _i ) = local_timer
                else
                  if( ( local_timer - double_press_start_time( _i ) ) < j_time_double_press ) then
                    state( _i ) = button_state.double_press
                  else
                    double_press_start_time( _i ) = local_timer
                  end if
                end if
              end if
            end if
          else
            if( owner_drag = _i ) then
              p_drag_dx = p_x - p_drag_sx
              p_drag_dy = p_y - p_drag_sy
            end if
          end if
        else
          if( state( _i ) = button_state.already_press ) then
            state( _i ) = button_state.release
          else
            if( state( _i ) = button_state.already_release ) then
              state( _i ) = button_state.none
              if( owner_drag = _i ) then
                owner_drag = -1
              end if
            else
              if( state( _i ) = button_state.already_double_press ) then
                state( _i ) = button_state.release
              end if
            end if
          end if
        end if
        _i -= 1
      loop until( _i = -1 )
    else
      ' j_result is bad
    end if
  end if
  if( use_mouse = true ) then
    dim as long temp_x, _
                temp_y, _
                temp_w, _
                temp_b
   
    m_result = getmouse( temp_x, temp_y, temp_w, temp_b )
    if( m_result = 0 ) then
      m_axis_x = temp_x - m_x
      m_axis_y = temp_y - m_y
      m_axis_w = temp_w - m_w
      m_x = temp_x
      m_y = temp_y
      'm_w = temp_w
      'm_axis_a = fast_atan2( m_axis_y, m_axis_x )
      m_axis_a = atan2( m_axis_y, m_axis_x )
      m_button = temp_b
     
      _i = m_offset + num_m_buttons
      do
        if( m_button and ( 2 ^ ( _i - m_offset ) ) ) then
          if( state( _i ) = button_state.none ) then
            if( owner_drag = -1 ) then
              owner_drag = _i
              state( _i ) = button_state.press
              hold_start_time( _i ) = local_timer
              repeat_start_time( _i ) = local_timer
              if( owner_double_press <> _i ) then
                owner_double_press = _i
                double_press_start_time( _i ) = local_timer
              else
                if( ( local_timer - double_press_start_time( _i ) ) < m_time_double_press ) then
                  state( _i ) = button_state.double_press
                else
                  double_press_start_time( _i ) = local_timer
                end if
              end if
              p_drag_dx = 0
              p_drag_dy = 0
              p_drag_sx = p_x
              p_drag_sy = p_y
            else
              if( ( _i <> owner_drag ) ) then
                state( _i ) = button_state.press
                hold_start_time( _i ) = local_timer
                repeat_start_time( _i ) = local_timer
                if( owner_double_press <> _i ) then
                  owner_double_press = _i
                  double_press_start_time( _i ) = local_timer
                else
                  if( ( local_timer - double_press_start_time( _i ) ) < m_time_double_press ) then
                    state( _i ) = button_state.double_press
                  else
                    double_press_start_time( _i ) = local_timer
                  end if
                end if
              end if
            end if
          else
            if( owner_drag = _i ) then
              p_drag_dx = p_x - p_drag_sx
              p_drag_dy = p_y - p_drag_sy
            end if
          end if
        else
          if( state( _i ) = button_state.already_press ) then
            state( _i ) = button_state.release
          else
            if( state( _i ) = button_state.already_release ) then
              state( _i ) = button_state.none
              if( owner_drag = _i ) then
                owner_drag = -1
              end if
            else
              if( state( _i ) = button_state.already_double_press ) then
                state( _i ) = button_state.release
              end if
            end if
          end if
        end if
        _i -= 1
      loop until( _i = num_j_buttons )
    else
      ' m_result is bad
      m_axis_x = 0
      m_axis_y = 0
      m_axis_w = 0
    end if
  end if
  if( use_keyboard = true ) then
    _i = k_offset + num_k_keys
    do
      if( multikey( _i - k_offset ) ) then
        if( state( _i ) = button_state.none ) then
          state( _i ) = button_state.press
          hold_start_time( _i ) = local_timer
          repeat_start_time( _i ) = local_timer
          if( owner_double_press <> _i ) then
            owner_double_press = _i
            double_press_start_time( _i ) = local_timer
          else
            if( ( local_timer - double_press_start_time( _i ) ) < k_time_double_press ) then
              state( _i ) = button_state.double_press
            else
              double_press_start_time( _i ) = local_timer
            end if
          end if
        end if
      else
        if( state( _i ) = button_state.already_press ) then
          state( _i ) = button_state.release
        else
          if( state( _i ) = button_state.already_release ) then
            state( _i ) = none
          else
            if( state( _i ) = button_state.already_double_press ) then
              owner_double_press = -1
              state( _i ) = button_state.release
            end if
          end if
        end if
      end if
      _i -= 1
    loop until( _i = ( m_offset + num_m_buttons ) )
  end if
end sub

sub t_fusion.close_state()
 
  dim as long _i
 
  local_timer_difference = 0
 
  for _i = 0 to ubound( state )
    if( state( _i ) = button_state.press ) then
      state( _i ) = button_state.already_press
    else
      if( state( _i ) = button_state.release ) then
        state( _i ) = button_state.already_release
      else
        if( state( _i ) = button_state.double_press ) then
          state( _i ) = button_state.already_double_press
        end if
      end if
    end if
  next _i
end sub

sub t_fusion.correct_axis( _
  byval v_which as long = -1 )
  
  dim as single _distance
  
  if( v_which = -1 ) then
    dim as long _i
    for _i = 0 to num_j_axis
      if( j_axis_x( _i ) <> -1000 ) then
        _distance = ( j_axis_x( _i ) * j_axis_x( _i ) ) + ( j_axis_y( _i ) * j_axis_y( _i ) )
        if( _distance > 1 ) then
          j_axis_x( _i ) = cos( j_axis_a( _i ) )
          j_axis_y( _i ) = sin( j_axis_a( _i ) )
        end if
      end if
    next _i
  else
    if( j_axis_x( v_which ) <> -1000 ) then
      _distance = ( j_axis_x( v_which ) * j_axis_x( v_which ) ) + ( j_axis_y( v_which ) * j_axis_y( v_which ) )
      if( _distance > 1 ) then
        j_axis_x( v_which ) = cos( j_axis_a( v_which ) )
        j_axis_y( v_which ) = sin( j_axis_a( v_which ) )
      end if
    end if
  end if
end sub

function t_fusion.joystick() _
  as boolean
 
  dim as boolean _return
 
  if( ( j_id < 0 ) or ( j_id > 15 ) ) then
    _return = false
  else
    _return = true
  end if
 
  return _return
end function

function t_fusion.press( _
  byval v_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( v_button ) = button_state.press ) then
    state( v_button ) = button_state.already_press
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.double_press( _
  byval v_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( v_button ) = button_state.double_press ) then
    state( v_button ) = button_state.already_double_press
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.release( _
  byval v_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( v_button ) = button_state.release ) then
    state( v_button ) = button_state.already_release
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.halt( _
  byval v_button as long, _
  byval v_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( v_button ) = button_state.press ) or _
    ( state( v_button ) = button_state.already_press ) ) then
    if( v_time <> 0 ) then
      if( ( local_timer - hold_start_time( v_button ) ) < v_time ) then
        _return = true
      else
        _return = false
      end if
    else
      _return = true
    end if
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.hold( _
  byval v_button as long, _
  byval v_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( v_button ) = button_state.press ) or _
      ( state( v_button ) = button_state.double_press ) or _
      ( state( v_button ) = button_state.already_press ) or _
      ( state( v_button ) = button_state.already_double_press ) ) then
    if( v_time <> 0 ) then
      if( ( local_timer - hold_start_time( v_button ) ) > v_time ) then
        _return = true
      else
        _return = false
      end if
    else
      _return = true
    end if
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.repeat( _
  byval v_button as long, _
  byval v_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( v_button ) = button_state.press ) or _
      ( state( v_button ) = button_state.double_press ) ) then
    _return = true
  else
    if( ( state( v_button ) = button_state.already_press ) or _
        ( state( v_button ) = button_state.already_double_press ) ) then
     dim as double _time_difference
     
      _time_difference = local_timer - repeat_start_time( v_button )
      if( _time_difference > v_time ) then
        repeat_start_time( v_button ) += _time_difference
        _return = true
      else
        _return = false
      end if
    else
      _return = false
    end if
  end if
 
  return _return
end function

function t_fusion.drag( _
  byval v_button as long ) _
  as boolean
 
  return( hold( v_button ) and ( owner_drag = v_button ) )
end function

function t_fusion.drop( _
  byval v_button as long ) _
  as boolean
 
  return( release( v_button ) and ( owner_drag = v_button ) )
end function

' ########################################################################################################

type t_box
  x as long
  y as long
  w as long
  h as long
  c as ulong
  declare sub add_box( _
    byval v_x as long, _
    byval v_y as long )
  declare sub draw_box( _
    byval v_n as long )
end type

declare sub draw_pointer( _
  byval v_x as single, _
  byval v_y as single, _
  byval v_r as long, _
  byval v_c as ulong, _
  byval v_b as boolean = false )

declare sub draw_joystick_stats( _
  byref v_fusion as t_fusion )

dim as t_fusion fusion
'fusion.use_mouse = false

dim as long screen_w = 1280
dim as long screen_h = 720

dim as double t1, timer_post
dim as long timer_post_avg = 1

dim box( 0 to 99 ) as t_box
dim as long number_of_boxes = 2
dim as long box_n
dim as long box_drag
dim as long temp

box_drag = -1

randomize()
for temp = 0 to number_of_boxes
  box( temp ).add_box( ( ( rnd * ( screen_w shr 1 ) ) + ( screen_w shr 2 ) ), ( ( rnd * ( screen_h shr 1 ) ) + ( screen_h shr 2 ) ) )
next temp

screenres( screen_w, screen_h, 32 )
fusion.hide_mouse()

if( fusion.use_joystick = true ) then
  dim as boolean terminate = false
 
  fusion.set_pointer_position( screen_w shr 1, screen_h shr 1 )
  fusion.set_pointer_boundary( 0, 0, screen_w - 1, screen_h - 1 )
 
  do while( not terminate )
    t1 = timer()
    fusion.get_state()
    fusion.correct_axis()
    fusion.update_pointer_position()
   
    'if( fusion.double_press( 0 + fusion.m_offset ) ) then terminate = true
    if( fusion.double_press( 2 ) ) then terminate = true
    if( fusion.press( 1 + fusion.k_offset ) ) then terminate = true ' escape key
   
    if( ( fusion.press( 0 ) or fusion.double_press( 0 ) ) or ( fusion.press( fusion.m_offset ) or fusion.double_press( fusion.m_offset ) ) ) then
      for box_n = number_of_boxes to 0 step -1
        if( ( fusion.p_x < ( box( box_n ).x + box( box_n ).w ) ) and _
            ( fusion.p_x > box( box_n ).x ) and _
            ( fusion.p_y < ( box( box_n ).y + box( box_n ).h ) ) and _
            ( fusion.p_y > box( box_n ).y ) ) then
          box_drag = box_n
          exit for
        end if
      next box_n
    else
      if( ( fusion.drop( 0 ) ) or ( fusion.drop( fusion.m_offset ) ) ) then
        box_drag = -1
      else
      end if
    end if
   
    if( ( fusion.press( 1 ) ) or ( fusion.press( fusion.m_offset + 1 ) ) ) then
      number_of_boxes += 1
      if( number_of_boxes > 99 ) then
        number_of_boxes = 99
      else
        box( number_of_boxes ).add_box( fusion.p_x, fusion.p_y )
      end if
    end if
   
    if( ( fusion.drag( 0 ) ) or ( fusion.drag( fusion.m_offset ) ) ) then
      if( box_drag <> -1 ) then
        box( box_drag ).x += fusion.p_drag_dx
        box( box_drag ).y += fusion.p_drag_dy
        fusion.p_drag_sx += fusion.p_drag_dx
        fusion.p_drag_sy += fusion.p_drag_dy
      end if
    end if
   
   
    screenlock()
      cls
     
      for box_n = 0 to number_of_boxes
        box( box_n ).draw_box( box_n )
      next box_n
     
      draw_pointer( fusion.p_x, fusion.p_y, 5, rgb( 255, 255, 255 ), true )
      draw_pointer( fusion.p_x + ( fusion.j_axis_x( 1 ) * 24 ), _
                    fusion.p_y + ( fusion.j_axis_y( 1 ) * 24 ), _
                    3, rgb( 255,   0,   0 ) )
      draw_pointer( fusion.p_x + ( fusion.j_axis_x( 2 ) * 16 ), _
                    fusion.p_y + ( fusion.j_axis_y( 2 ) * 16 ), _
                    3, rgb(   0,   0, 255 ) )
      draw_pointer( fusion.p_x + ( fusion.j_axis_x( 3 ) * 8 ), _
                    fusion.p_y + ( fusion.j_axis_y( 3 ) * 8 ), _
                    3, rgb(   0, 255,   0 ) )
      draw_pointer( fusion.p_x, fusion.p_y, 3, rgb( 0, 0, 0 ) )
     
      draw_joystick_stats( fusion )
     
      draw string( 9, 701 ), " scene render time (ms) " & timer_post
      draw string( 9, 710 ), "scene average time (ms) " & timer_post_avg
    screenunlock()
    fusion.close_state()
    timer_post = ( timer() - t1 ) * 1000
    timer_post_avg = ( timer_post_avg + timer_post ) / 2
    sleep( 15 )
  loop
else
  draw string( 1, 1 ), "joystick required..."
  sleep
end if
fusion.show_mouse()





sub t_box.add_box( _
  byval _x as long, _
  byval _y as long )
  dim as long _temp
 
  _temp = ( rnd * 50 ) + 75
  x = _x - _temp
  w = _temp + _temp
  _temp = ( rnd * 50 ) + 75
  y = _y - _temp
  h = _temp + _temp
  c = rgb( ( ( rnd * 191 ) + 64 ), ( ( rnd * 191 ) + 64 ), ( ( rnd * 191 ) + 64 ) )
end sub

sub t_box.draw_box( _
  byval p_n as long )
 
  line( x, y )-( x + w, y + h ), c, bf
  line( x + 1, y + 1 )-( x + w - 1, y + h - 1 ), rgb( 0, 0, 0 ), b
  draw string( x + 3, y + 3 ), str( "Box " & p_n ), rgb( 0, 0, 0 )
end sub

sub draw_pointer( _
  byval p_x as single, _
  byval p_y as single, _
  byval p_r as long, _
  byval p_c as ulong, _
  byval p_b as boolean = false )
 
  if( p_b = true ) then circle( p_x, p_y ), p_r + 1, rgb( 0, 0, 0 )
  circle( p_x, p_y ), p_r, p_c,,,, f
end sub

sub draw_joystick_stats( _
  byref v_fusion as t_fusion )
 
  dim as long _i, _x, _y
 
  _x = 9
  _y = 1
  draw string( _x, _y ), "getjoystick() data:", rgb( 255, 63, 63 ):_y += 9
  with v_fusion
    for _i = 0 to 3
      _y += 9
      draw string( _x, _y ), "axis " & _i & " ( " & .j_axis_x( _i ) & ", " & .j_axis_y( _i ) & " )"
    next _i
    _y += 9
    for _i = 0 to 9
      _y += 9
      draw string( _x, _y ), "button 0" & _i & " " & cbool( .j_button and ( 1 shl _i ) )
    next _i
    for _i = 10 to 31
      _y += 9
      draw string( _x, _y ), "button " & _i & " " & cbool( .j_button and ( 1 shl _i ) )
    next _i
   
    _x = 1049
    _y = 1
    draw string( _x, _y ), "          joystick variables", rgb( 255, 63, 63 ): _y += 9
    _y += 9
    draw string( _x, _y ), "                  j_id " & .j_id: _y += 9
    draw string( _x, _y ), "              j_result " & .j_result: _y += 9
    draw string( _x, _y ), "              j_button " & .j_button: _y += 9
    draw string( _x, _y ), "use_joystick_axis( 0 ) " & .use_joystick_axis( 0 ): _y += 9
    draw string( _x, _y ), "use_joystick_axis( 1 ) " & .use_joystick_axis( 1 ): _y += 9
    draw string( _x, _y ), "use_joystick_axis( 2 ) " & .use_joystick_axis( 2 ): _y += 9
    draw string( _x, _y ), "use_joystick_axis( 3 ) " & .use_joystick_axis( 3 ): _y += 9
    draw string( _x, _y ), "         j_axis_a( 0 ) " & .j_axis_a( 0 ): _y += 9
    draw string( _x, _y ), "         j_axis_a( 1 ) " & .j_axis_a( 1 ): _y += 9
    draw string( _x, _y ), "         j_axis_a( 2 ) " & .j_axis_a( 2 ): _y += 9
    draw string( _x, _y ), "         j_axis_a( 3 ) " & .j_axis_a( 3 ): _y += 9
    draw string( _x, _y ), "                   p_x " & .p_x: _y += 9
    draw string( _x, _y ), "                   p_y " & .p_y: _y += 9
    draw string( _x, _y ), "             p_drag_sx " & .p_drag_sx: _y += 9
    draw string( _x, _y ), "             p_drag_sy " & .p_drag_sy: _y += 9
    draw string( _x, _y ), "             p_drag_dx " & .p_drag_dx: _y += 9
    draw string( _x, _y ), "             p_drag_dy " & .p_drag_dy: _y += 9
    draw string( _x, _y ), "          p_boundary_x " & .p_boundary_w: _y += 9
    draw string( _x, _y ), "          p_boundary_y " & .p_boundary_h: _y += 9
    draw string( _x, _y ), "          p_boundary_w " & .p_boundary_w: _y += 9
    draw string( _x, _y ), "          p_boundary_h " & .p_boundary_h: _y += 9
    draw string( _x, _y ), "        p_j_which_axis " & .p_j_which_axis: _y += 9
    draw string( _x, _y ), "         j_sensitivity " & .j_sensitivity: _y += 9
    draw string( _x, _y ), "            j_deadzone " & .j_deadzone: _y += 9
    draw string( _x, _y ), "            owner_drag " & .owner_drag: _y += 9
    draw string( _x, _y ), "    owner_double_press " & .owner_double_press: _y += 9
    draw string( _x, _y ), "   j_time_double_press " & .j_time_double_press: _y += 9
   
    draw string( 485,  1 ), "( button 0 ) to drag boxes", rgb( 255, 127, 0 )
    draw string( 485, 10 ), "( button 1 ) to add boxes", rgb( 255, 127, 0 )
    draw string( 485, 19 ), "( button 2 ) double press to exit", rgb( 255, 127, 0 )
    draw string( 485, 28 ), "  ( escape ) to exit", rgb( 255, 127, 0 )
   
  end with
end sub
Last edited by sero on Feb 12, 2021 3:25, edited 2 times in total.
sero
Posts: 59
Joined: Mar 06, 2018 13:26
Location: USA

Re: getjoystick() demo

Post by sero »

Strike down zombies in this next getjoystick() demonstration. Use thumbsticks axis 0 and axis 1 to move and aim your sword. Button 0 and 7 will activate your sword for effective zombie slaying.

A keyboard version is included separately. Use arrow keys to move and space to attack. Sword aims in the direction of player movement.

Image

Original joystick only:

Code: Select all

type t_fusion
  as long    j_id
  as integer j_result, _
             j_button
  as single  j_axis_x( any ), _
             j_axis_y( any ), _
             j_axis_a( any ), _
             j_sensitivity, _
             j_deadzone
  as boolean j_axis_motion( any )
 
  as integer m_result, _
             m_button
  as long    m_x, _
             m_y, _
             m_w
  as single  m_axis_x, _
             m_axis_y, _
             m_axis_a, _
             m_axis_w
 
  as single  p_x, _
             p_y, _
             p_a, _
             p_drag_sx, _
             p_drag_sy, _
             p_drag_dx, _
             p_drag_dy
  as long    p_boundary_x, _
             p_boundary_y, _
             p_boundary_w, _
             p_boundary_h, _
             p_j_which_axis, _
             owner_drag, _
             owner_double_press
 
  as double  j_time_double_press, _
             m_time_double_press, _
             k_time_double_press
 
  as boolean use_joystick_axis( any )
  as boolean use_joystick
  as boolean use_mouse
  as boolean use_keyboard
 
  as long num_j_axis
  as long num_j_buttons
  as long num_m_buttons
  as long num_k_keys
  as long m_offset
  as long k_offset
 
  as long    b( any )
  as long    k( any )
  as double  local_timer, _
             local_timer_difference, _
             hold_start_time( any ), _
             repeat_start_time( any ), _
             double_press_start_time( any )
 
  enum button_state
    none                 = 0
    press                = 1
    already_press        = 2
    release              = 3
    already_release      = 4
    double_press         = 5
    already_double_press = 6
  end enum
 
  as byte state( any )
 
  declare constructor()
  declare destructor()
  declare sub hide_mouse()
  declare sub show_mouse()
  declare sub set_pointer_position( _
    byval v_x as single, _
    byval v_y as single )
  declare sub set_pointer_boundary( _
    byval v_x as long, _
    byval v_y as long, _
    byval v_w as long, _
    byval v_h as long )
  declare sub update_pointer_position()
  declare sub get_state( _
    byval v_timer as double = timer() )
  declare sub close_state()
  declare sub correct_axis( _
    byval v_which as long = -1 )
  declare function joystick() _
    as boolean
  declare function press( _
    byval v_button as long ) _
    as boolean
  declare function double_press( _
    byval v_button as long ) _
    as boolean
  declare function release( _
    byval v_button as long ) _
    as boolean
  declare function halt( _
    byval v_button as long, _
    byval v_time as double = 0.0 ) _
    as boolean
  declare function hold( _
    byval v_button as long, _
    byval v_time as double = 0.0 ) _
    as boolean
  declare function repeat( _
    byval v_button as long, _
    byval v_time as double = 0.0 ) _
    as boolean
  declare function drag( _
    byval v_button as long ) _
    as boolean
  declare function drop( _
    byval v_button as long ) _
    as boolean
end type

constructor t_fusion()
  dim as long _n
 
  ' Cycle backwards through all possible joystick identities
  ' and assign j_id to the lowest identity and assign true
  ' to use_joystick. If there aren't joystick identities
  ' found, then j_id is assigned to -1 and use_joystick
  ' is assigned false.
  j_id = -1
  use_joystick = false
  for _n = 15 to 0 step( -1 )
    j_result = getjoystick( _n )
    if( j_result = 0 ) then
      j_id = _n
      use_joystick = true
    end if
  next _n
 
  ' Use getmouse() to find out if there is a mouse available.
  ' If there is a mouse true is assigned to use_mouse.
  ' Otherwise, use_mouse is assigned false.
  use_mouse = false
  m_result = getmouse( m_x, m_y )
  if( m_result = 0 ) then use_mouse = true
 
  ' Set use_keyboard to true by default.
  use_keyboard = true
 
  ' Default pointer position and assign which joystick axis
  ' is responsible for moving the pointer.
  p_x            = 0
  p_y            = 0
  p_a            = 0
  p_boundary_x   = 0
  p_boundary_y   = 0
  p_boundary_w   = 0
  p_boundary_h   = 0
  p_j_which_axis = 0
 
  ' These two variables hold which button is currently in
  ' drag or double press mode. Assign them -1 here.
  owner_drag         = -1
  owner_double_press = -1
 
  ' These next variables are multipliers for how much
  ' the correlating axis change the pointer position.
  j_sensitivity = 250
 
  ' This deadzone value is a squared hypotenuse length
  ' to be checked against the joystick axis deltas. This
  ' is used to prevent micro deltas that can occur even
  ' when the joystick is at rest.
  j_deadzone = 0.001
 
  ' Double press time is the time window that two presses
  ' much occur to activate double press. The value is in
  ' seconds, so a default of 0.2 = 200 milliseconds.
  j_time_double_press = 0.2
  m_time_double_press = 0.2
  k_time_double_press = 0.2
 
  ' Tell our class how many buttons and how many axis so
  ' we can redim our appropriate variables.
  num_j_axis    = 4
  num_j_buttons = 12
  num_m_buttons = 3
  num_k_keys    = 128
 
  ' Joystick,mouse and key button states are stacked in that
  ' order. Because of this, the following offset variables
  ' provide the starting array position for each.
  m_offset = num_j_buttons
  k_offset = num_j_buttons + num_m_buttons
 
  ' Create an record of mouse buttons that stores the address
  ' of each within the state() array.
  redim b( 0 to 2 )
  b( 0 ) = m_offset
  b( 1 ) = m_offset + 1
  b( 2 ) = m_offset + 2
 
  ' Create an array that takes a keyboard scancode and returns
  ' it's address in the state() array.
  redim k( 1 to 100 )
  for _n = 1 to 100
    k( _n ) = _n + k_offset
  next _n
 
  ' Subtract 1 from our buttons and axis numbers because
  ' our array numbering starts at zero.
  num_j_axis    -= 1
  num_j_buttons -= 1
  num_m_buttons -= 1
  num_k_keys    -= 1
 
  redim      j_axis_x( 0 to num_j_axis )
  redim      j_axis_y( 0 to num_j_axis )
  redim      j_axis_a( 0 to num_j_axis )
  redim j_axis_motion( 0 to num_j_axis )
  
  redim use_joystick_axis( 0 to num_j_axis )
  
  j_result = getjoystick( j_id, j_button, _
                          j_axis_x( 0 ), j_axis_y( 0 ), _
                          j_axis_x( 1 ), j_axis_y( 1 ), _
                          j_axis_x( 2 ), j_axis_y( 2 ), _
                          j_axis_x( 3 ), j_axis_y( 3 ) )
  for _n = 0 to num_j_axis
    if( j_axis_x( _n ) <> -1000 ) then
      use_joystick_axis( _n ) = true
    else
      use_joystick_axis( _n ) = false
    end if
  next _n
 
  redim         hold_start_time( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
  redim       repeat_start_time( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
  redim double_press_start_time( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
  redim                   state( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
 
  ' This variable keeps track of how much time has passed since
  ' the previous close_state(). This variable is useful for
  ' time based physics.
  local_timer_difference = 0
end constructor

destructor t_fusion()
 
end destructor

sub t_fusion.hide_mouse()
 
  setmouse( ,, 0 )
end sub

sub t_fusion.show_mouse()
 
  setmouse( ,, 1 )
end sub

sub t_fusion.set_pointer_position( _
  byval v_x as single, _
  byval v_y as single )
 
  p_x = v_x
  p_y = v_y
end sub

sub t_fusion.set_pointer_boundary( _
  byval v_x as long, _
  byval v_y as long, _
  byval v_w as long, _
  byval v_h as long )
 
  p_boundary_x = v_x
  p_boundary_y = v_y
  p_boundary_w = v_w
  p_boundary_h = v_h
end sub

sub t_fusion.update_pointer_position()
 
  if( use_mouse = true ) then
    if( m_result = 0 ) then
      p_x = m_x + ( j_axis_x( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_y = m_y + ( j_axis_y( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_x = iif( ( p_x ) < ( p_boundary_w ), _
        ( p_x ), ( p_boundary_w ) )
      p_x = iif( ( p_x ) > ( p_boundary_x ), _
        ( p_x ), ( p_boundary_x ) )
      p_y = iif( ( p_y ) < ( p_boundary_h ), _
        ( p_y ), ( p_boundary_h ) )
      p_y = iif( ( p_y ) > ( p_boundary_y ), _
        ( p_y ), ( p_boundary_y ) )
      setmouse( p_x, p_y )
      m_x = p_x
      m_y = p_y
    else
      p_x += ( j_axis_x( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_y += ( j_axis_y( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_x = iif( ( p_x ) < ( p_boundary_w ), _
        ( p_x ), ( p_boundary_w ) )
      p_x = iif( ( p_x ) > ( p_boundary_x ), _
        ( p_x ), ( p_boundary_x ) )
      p_y = iif( ( p_y ) < ( p_boundary_h ), _
        ( p_y ), ( p_boundary_h ) )
      p_y = iif( ( p_y ) > ( p_boundary_y ), _
        ( p_y ), ( p_boundary_y ) )
    end if
  else
    if( use_joystick = true ) then
      p_x += ( j_axis_x( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_y += ( j_axis_y( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_x = iif( ( p_x ) < ( p_boundary_w ), _
        ( p_x ), ( p_boundary_w ) )
      p_x = iif( ( p_x ) > ( p_boundary_x ), _
        ( p_x ), ( p_boundary_x ) )
      p_y = iif( ( p_y ) < ( p_boundary_h ), _
        ( p_y ), ( p_boundary_h ) )
      p_y = iif( ( p_y ) > ( p_boundary_y ), _
        ( p_y ), ( p_boundary_y ) )
    end if
  end if
end sub

sub t_fusion.get_state( _
  byval v_timer as double = timer() )
 
  dim as long _i
 
  local_timer_difference += ( v_timer - local_timer )
  local_timer = v_timer
 
  if( use_joystick = true ) then
    dim as single temp_axis_x( 0 to 3 ), _
                  temp_axis_y( 0 to 3 )
   
    j_result = getjoystick( j_id, j_button, _
                            temp_axis_x( 0 ), temp_axis_y( 0 ), _
                            temp_axis_x( 1 ), temp_axis_y( 1 ), _
                            temp_axis_x( 2 ), temp_axis_y( 2 ), _
                            temp_axis_x( 3 ), temp_axis_y( 3 ) )
    if( j_result = 0 ) then
      _i = num_j_axis
      do
        if( use_joystick_axis( _i ) = true ) then
          if( j_deadzone < ( ( temp_axis_x( _i ) * temp_axis_x( _i ) ) + ( temp_axis_y( _i ) * temp_axis_y( _i ) ) ) ) then
            j_axis_motion( _i ) = true
            j_axis_x( _i ) = temp_axis_x( _i )
            j_axis_y( _i ) = temp_axis_y( _i )
            'j_axis_a( _i ) = fast_atan2( j_axis_y( _i ), j_axis_x( _i ) ) ' ###############################
            j_axis_a( _i ) = atan2( j_axis_y( _i ), j_axis_x( _i ) ) ' #####################################
          else
            j_axis_motion( _i ) = false
            j_axis_x( _i ) = 0
            j_axis_y( _i ) = 0
          end if
        else
          ' not using this joystick axis
        end if
        _i -= 1
      loop until( _i = -1 )
     
      _i = num_j_buttons
      do
        if( j_button and ( 2 ^ _i ) ) then
          if( state( _i ) = button_state.none ) then
            if( owner_drag = -1 ) then
              owner_drag = _i
              state( _i ) = button_state.press
              hold_start_time( _i ) = local_timer
              repeat_start_time( _i ) = local_timer
              if( owner_double_press <> _i ) then
                owner_double_press = _i
                double_press_start_time( _i ) = local_timer
              else
                if( ( local_timer - double_press_start_time( _i ) ) < j_time_double_press ) then
                  state( _i ) = button_state.double_press
                else
                  double_press_start_time( _i ) = local_timer
                end if
              end if
              p_drag_dx = 0
              p_drag_dy = 0
              p_drag_sx = p_x
              p_drag_sy = p_y
            else
              if( ( _i <> owner_drag ) ) then
                state( _i ) = button_state.press
                hold_start_time( _i ) = local_timer
                repeat_start_time( _i ) = local_timer
                if( owner_double_press <> _i ) then
                  owner_double_press = _i
                  double_press_start_time( _i ) = local_timer
                else
                  if( ( local_timer - double_press_start_time( _i ) ) < j_time_double_press ) then
                    state( _i ) = button_state.double_press
                  else
                    double_press_start_time( _i ) = local_timer
                  end if
                end if
              end if
            end if
          else
            if( owner_drag = _i ) then
              p_drag_dx = p_x - p_drag_sx
              p_drag_dy = p_y - p_drag_sy
            end if
          end if
        else
          if( state( _i ) = button_state.already_press ) then
            state( _i ) = button_state.release
          else
            if( state( _i ) = button_state.already_release ) then
              state( _i ) = button_state.none
              if( owner_drag = _i ) then
                owner_drag = -1
              end if
            else
              if( state( _i ) = button_state.already_double_press ) then
                state( _i ) = button_state.release
              end if
            end if
          end if
        end if
        _i -= 1
      loop until( _i = -1 )
    else
      ' j_result is bad
    end if
  end if
  if( use_mouse = true ) then
    dim as long temp_x, _
                temp_y, _
                temp_w, _
                temp_b
   
    m_result = getmouse( temp_x, temp_y, temp_w, temp_b )
    if( m_result = 0 ) then
      m_axis_x = temp_x - m_x
      m_axis_y = temp_y - m_y
      m_axis_w = temp_w - m_w
      m_x = temp_x
      m_y = temp_y
      'm_w = temp_w
      'm_axis_a = fast_atan2( m_axis_y, m_axis_x )
      m_axis_a = atan2( m_axis_y, m_axis_x )
      m_button = temp_b
     
      _i = m_offset + num_m_buttons
      do
        if( m_button and ( 2 ^ ( _i - m_offset ) ) ) then
          if( state( _i ) = button_state.none ) then
            if( owner_drag = -1 ) then
              owner_drag = _i
              state( _i ) = button_state.press
              hold_start_time( _i ) = local_timer
              repeat_start_time( _i ) = local_timer
              if( owner_double_press <> _i ) then
                owner_double_press = _i
                double_press_start_time( _i ) = local_timer
              else
                if( ( local_timer - double_press_start_time( _i ) ) < m_time_double_press ) then
                  state( _i ) = button_state.double_press
                else
                  double_press_start_time( _i ) = local_timer
                end if
              end if
              p_drag_dx = 0
              p_drag_dy = 0
              p_drag_sx = p_x
              p_drag_sy = p_y
            else
              if( ( _i <> owner_drag ) ) then
                state( _i ) = button_state.press
                hold_start_time( _i ) = local_timer
                repeat_start_time( _i ) = local_timer
                if( owner_double_press <> _i ) then
                  owner_double_press = _i
                  double_press_start_time( _i ) = local_timer
                else
                  if( ( local_timer - double_press_start_time( _i ) ) < m_time_double_press ) then
                    state( _i ) = button_state.double_press
                  else
                    double_press_start_time( _i ) = local_timer
                  end if
                end if
              end if
            end if
          else
            if( owner_drag = _i ) then
              p_drag_dx = p_x - p_drag_sx
              p_drag_dy = p_y - p_drag_sy
            end if
          end if
        else
          if( state( _i ) = button_state.already_press ) then
            state( _i ) = button_state.release
          else
            if( state( _i ) = button_state.already_release ) then
              state( _i ) = button_state.none
              if( owner_drag = _i ) then
                owner_drag = -1
              end if
            else
              if( state( _i ) = button_state.already_double_press ) then
                state( _i ) = button_state.release
              end if
            end if
          end if
        end if
        _i -= 1
      loop until( _i = num_j_buttons )
    else
      ' m_result is bad
      m_axis_x = 0
      m_axis_y = 0
      m_axis_w = 0
    end if
  end if
  if( use_keyboard = true ) then
    _i = k_offset + num_k_keys
    do
      if( multikey( _i - k_offset ) ) then
        if( state( _i ) = button_state.none ) then
          state( _i ) = button_state.press
          hold_start_time( _i ) = local_timer
          repeat_start_time( _i ) = local_timer
          if( owner_double_press <> _i ) then
            owner_double_press = _i
            double_press_start_time( _i ) = local_timer
          else
            if( ( local_timer - double_press_start_time( _i ) ) < k_time_double_press ) then
              state( _i ) = button_state.double_press
            else
              double_press_start_time( _i ) = local_timer
            end if
          end if
        end if
      else
        if( state( _i ) = button_state.already_press ) then
          state( _i ) = button_state.release
        else
          if( state( _i ) = button_state.already_release ) then
            state( _i ) = none
          else
            if( state( _i ) = button_state.already_double_press ) then
              owner_double_press = -1
              state( _i ) = button_state.release
            end if
          end if
        end if
      end if
      _i -= 1
    loop until( _i = ( m_offset + num_m_buttons ) )
  end if
end sub

sub t_fusion.close_state()
 
  dim as long _i
 
  local_timer_difference = 0
 
  for _i = 0 to ubound( state )
    if( state( _i ) = button_state.press ) then
      state( _i ) = button_state.already_press
    else
      if( state( _i ) = button_state.release ) then
        state( _i ) = button_state.already_release
      else
        if( state( _i ) = button_state.double_press ) then
          state( _i ) = button_state.already_double_press
        end if
      end if
    end if
  next _i
end sub

sub t_fusion.correct_axis( _
  byval v_which as long = -1 )
  
  dim as single _distance
  
  if( v_which = -1 ) then
    dim as long _i
    for _i = 0 to num_j_axis
      if( j_axis_x( _i ) <> -1000 ) then
        _distance = ( j_axis_x( _i ) * j_axis_x( _i ) ) + ( j_axis_y( _i ) * j_axis_y( _i ) )
        if( _distance > 1 ) then
          j_axis_x( _i ) = cos( j_axis_a( _i ) )
          j_axis_y( _i ) = sin( j_axis_a( _i ) )
        end if
      end if
    next _i
  else
    if( j_axis_x( v_which ) <> -1000 ) then
      _distance = ( j_axis_x( v_which ) * j_axis_x( v_which ) ) + ( j_axis_y( v_which ) * j_axis_y( v_which ) )
      if( _distance > 1 ) then
        j_axis_x( v_which ) = cos( j_axis_a( v_which ) )
        j_axis_y( v_which ) = sin( j_axis_a( v_which ) )
      end if
    end if
  end if
end sub

function t_fusion.joystick() _
  as boolean
 
  dim as boolean _return
 
  if( ( j_id < 0 ) or ( j_id > 15 ) ) then
    _return = false
  else
    _return = true
  end if
 
  return _return
end function

function t_fusion.press( _
  byval v_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( v_button ) = button_state.press ) then
    state( v_button ) = button_state.already_press
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.double_press( _
  byval v_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( v_button ) = button_state.double_press ) then
    state( v_button ) = button_state.already_double_press
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.release( _
  byval v_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( v_button ) = button_state.release ) then
    state( v_button ) = button_state.already_release
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.halt( _
  byval v_button as long, _
  byval v_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( v_button ) = button_state.press ) or _
    ( state( v_button ) = button_state.already_press ) ) then
    if( v_time <> 0 ) then
      if( ( local_timer - hold_start_time( v_button ) ) < v_time ) then
        _return = true
      else
        _return = false
      end if
    else
      _return = true
    end if
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.hold( _
  byval v_button as long, _
  byval v_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( v_button ) = button_state.press ) or _
      ( state( v_button ) = button_state.double_press ) or _
      ( state( v_button ) = button_state.already_press ) or _
      ( state( v_button ) = button_state.already_double_press ) ) then
    if( v_time <> 0 ) then
      if( ( local_timer - hold_start_time( v_button ) ) > v_time ) then
        _return = true
      else
        _return = false
      end if
    else
      _return = true
    end if
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.repeat( _
  byval v_button as long, _
  byval v_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( v_button ) = button_state.press ) or _
      ( state( v_button ) = button_state.double_press ) ) then
    _return = true
  else
    if( ( state( v_button ) = button_state.already_press ) or _
        ( state( v_button ) = button_state.already_double_press ) ) then
     dim as double _time_difference
     
      _time_difference = local_timer - repeat_start_time( v_button )
      if( _time_difference > v_time ) then
        repeat_start_time( v_button ) += _time_difference
        _return = true
      else
        _return = false
      end if
    else
      _return = false
    end if
  end if
 
  return _return
end function

function t_fusion.drag( _
  byval v_button as long ) _
  as boolean
 
  return( hold( v_button ) and ( owner_drag = v_button ) )
end function

function t_fusion.drop( _
  byval v_button as long ) _
  as boolean
 
  return( release( v_button ) and ( owner_drag = v_button ) )
end function

' ########################################################################################################

randomize()

dim as t_fusion fusion
if( fusion.use_joystick = true ) then
  dim as long screen_width, screen_height
  dim as boolean terminate = false
 
  dim as long z = 31
  dim as single player_x, player_y, player_dx, player_dy, sword_x, sword_y
  dim as long zombie_x( 0 to z), zombie_y( 0 to z ), _
              zombie_c( 0 to z ), zombie_dc( 0 to z ), zombie_tc( 0 to z ), _
              zombie_trigger_dist( 0 to z )
  dim as boolean player_alive, zombie_alive( 0 to z ), zombie_triggered( 0 to z )
  dim as long n, dist
 
  screen_width = 640
  screen_height = 360
  screenres screen_width, screen_height, 32
 
  fusion.hide_mouse()
  fusion.use_mouse = false
  fusion.j_sensitivity = 100
 
  player_alive = true
  player_x = screen_width / 2
  player_y = screen_height / 2
  sword_x = player_x + ( cos( fusion.j_axis_a( 1 ) ) * 8 )
  sword_y = player_y + ( sin( fusion.j_axis_a( 1 ) ) * 8 )
 
  for n = 0 to z
    zombie_alive( n ) = true
    zombie_triggered( n ) = false
    zombie_trigger_dist( n ) = ( rnd * 4096 ) + 1024
    do
      zombie_x( n ) = ( rnd * ( screen_width - 64 ) ) + 32
      zombie_y( n ) = ( rnd * ( screen_height - 64 ) ) + 32
      dist = ( ( player_x - zombie_x( n ) ) ^ 2 ) + ( ( player_y - zombie_y( n ) ) ^ 2 )
    loop until( dist > 4096 )
    zombie_c( n ) = rgb( 63 - ( n * 2 ), 127 - ( n * 2 ), 63 - ( n * 2 ) )
    zombie_dc( n ) = rgb( 127 - ( n * 4 ), 0, 0 )
    zombie_tc( n ) = rgb( 159 - ( n * 4 ), 0, 63 )
  next n
 
  do while( not terminate )
    fusion.get_state()
    if( fusion.press( fusion.k( 1 ) ) ) then terminate = true
    if( player_alive = true ) then
      if( fusion.j_axis_motion( 0 ) ) then
        'player_dx = fusion.j_axis_x( 0 ) * fusion.j_sensitivity * fusion.local_timer_difference
        'player_dy = fusion.j_axis_y( 0 ) * fusion.j_sensitivity * fusion.local_timer_difference
        'player_dx = fusion.j_axis_x_correct_adjust( 0 )
        'player_dy = fusion.j_axis_y_correct_adjust( 0 )
        'player_dx = fusion.j_axis_x_adjust( 0 )
        'player_dy = fusion.j_axis_y_adjust( 0 )
       
        fusion.correct_axis( 0 )
        player_dx = fusion.j_axis_x( 0 ) * fusion.j_sensitivity * fusion.local_timer_difference
        player_dy = fusion.j_axis_y( 0 ) * fusion.j_sensitivity * fusion.local_timer_difference
        player_x += player_dx
        player_y += player_dy
       
        player_x = iif( ( player_x ) < ( screen_width - 8 ), _
        ( player_x ), ( screen_width - 8 ) )
        player_x = iif( ( player_x ) > ( 1 ), _
        ( player_x ), ( 1 ) )
        player_y = iif( ( player_y ) < ( screen_height - 8 ), _
        ( player_y ), ( screen_height - 8 ) )
        player_y = iif( ( player_y ) > ( 1 ), _
        ( player_y ), ( 1 ) )
       
        sword_x = player_x + ( cos( fusion.j_axis_a( 1 ) ) * 8 )
        sword_y = player_y + ( sin( fusion.j_axis_a( 1 ) ) * 8 )
      else
        if( fusion.j_axis_motion( 1 ) ) then
          sword_x = player_x + ( cos( fusion.j_axis_a( 1 ) ) * 8 )
          sword_y = player_y + ( sin( fusion.j_axis_a( 1 ) ) * 8 )
        end if
      end if
     
      for n = 0 to z
        if( zombie_alive( n ) = true ) then
          dist = ( ( player_x - zombie_x( n ) ) ^ 2 ) + ( ( player_y - zombie_y( n ) ) ^ 2 )
          if( dist < 64 ) then
            player_alive = false
          else
            if( dist < zombie_trigger_dist( n ) ) then
              zombie_triggered( n ) = true
              if( zombie_x( n ) > player_x ) then
                zombie_x( n ) += 1 - ( rnd * 3 )
              else
                zombie_x( n ) -= 1 - ( rnd * 3 )
              end if
              if( zombie_y( n ) > player_y ) then
                zombie_y( n ) += 1 - ( rnd * 3 )
              else
                zombie_y( n ) -= 1 - ( rnd * 3 )
              end if
            else
              zombie_triggered( n ) = false
              zombie_x( n ) += 1 - ( rnd * 2 )
              zombie_y( n ) += 1 - ( rnd * 2 )
            end if
          end if
        end if
        if( fusion.hold( 7 ) or fusion.hold( 0 ) ) then
          if( ( ( sword_x - zombie_x( n ) ) ^ 2 ) + ( ( sword_y - zombie_y( n ) ) ^ 2 ) < 64 ) then
            zombie_alive( n ) = false
          end if
        end if
      next n
    end if
   
    screenlock()
      cls
      for n = 0 to z
        if( zombie_alive( n ) = true ) then
          if( zombie_triggered( n ) = true ) then
            draw string( zombie_x( n ), zombie_y( n ) ), "z", zombie_tc( n )
          else
            draw string( zombie_x( n ), zombie_y( n ) ), "z", zombie_c( n )
          end if
        else
          draw string( zombie_x( n ), zombie_y( n ) ), "%", zombie_dc( n )
        end if
      next n
      if( fusion.hold( 7 ) or fusion.hold( 0 ) ) then
        draw string( sword_x, sword_y ), "+", rgb( rnd*255, rnd*255, rnd*255 )
      else
        draw string( sword_x, sword_y ), "+", rgb( 127, 127, 127 )
      end if
      if( player_alive = true ) then
        draw string( player_x, player_y ), "@"
      else
        draw string( player_x, player_y ), "@", rgb( 127, 0, 0 )
        draw string( screen_width / 2 - 56, screen_height / 2 - 5 ), _
          "YOU ARE CORPSE", rgb( 255 * tan( rnd ), 0, 0 )
        draw string( screen_width / 2 - 36, screen_height / 2 + 3 ), _
          "TRY AGAIN", rgb( 255 * tan( rnd ), 0, 0 )
      end if
      draw string( screen_width / 2 - 76, screen_height - 9 ), _
        "press escape to end", rgb( rnd*64 + 63, 0, 0 )
    screenunlock()
   
    if( player_alive = false ) and ( fusion.press( 7 ) or fusion.hold( 0 ) ) then
      player_alive = true
      player_x = screen_width / 2
      player_y = screen_height / 2
      sword_x = player_x + ( cos( fusion.j_axis_a( 1 ) ) * 8 )
      sword_y = player_y + ( sin( fusion.j_axis_a( 1 ) ) * 8 )
     
      for n = 0 to z
        zombie_alive( n ) = true
        zombie_triggered( n ) = false
        zombie_trigger_dist( n ) = ( rnd * 4096 ) + 1024
        do
          zombie_x( n ) = ( rnd * ( screen_width - 64 ) ) + 32
          zombie_y( n ) = ( rnd * ( screen_height - 64 ) ) + 32
          dist = ( ( player_x - zombie_x( n ) ) ^ 2 ) + ( ( player_y - zombie_y( n ) ) ^ 2 )
        loop until( dist > 4096 )
        zombie_c( n ) = rgb( 63 - ( n * 2 ), 127 - ( n * 2 ), 63 - ( n * 2 ) )
        zombie_dc( n ) = rgb( 127 - ( n * 4 ), 0, 0 )
        zombie_tc( n ) = rgb( 159 - ( n * 4 ), 0, 63 )
      next n
     
    end if
   
    fusion.close_state()
    sleep 15
  loop
else
  print "joystick required..."
  sleep
end if
Modified for keyboard :

Code: Select all

type t_fusion
  as long    j_id
  as integer j_result, _
             j_button
  as single  j_axis_x( any ), _
             j_axis_y( any ), _
             j_axis_a( any ), _
             j_sensitivity, _
             j_deadzone
  as boolean j_axis_motion( any )
 
  as integer m_result, _
             m_button
  as long    m_x, _
             m_y, _
             m_w
  as single  m_axis_x, _
             m_axis_y, _
             m_axis_a, _
             m_axis_w
 
  as single  p_x, _
             p_y, _
             p_a, _
             p_drag_sx, _
             p_drag_sy, _
             p_drag_dx, _
             p_drag_dy
  as long    p_boundary_x, _
             p_boundary_y, _
             p_boundary_w, _
             p_boundary_h, _
             p_j_which_axis, _
             owner_drag, _
             owner_double_press
 
  as double  j_time_double_press, _
             m_time_double_press, _
             k_time_double_press
 
  as boolean use_joystick_axis( any )
  as boolean use_joystick
  as boolean use_mouse
  as boolean use_keyboard
 
  as long num_j_axis
  as long num_j_buttons
  as long num_m_buttons
  as long num_k_keys
  as long m_offset
  as long k_offset
 
  as long    b( any )
  as long    k( any )
  as double  local_timer, _
             local_timer_difference, _
             hold_start_time( any ), _
             repeat_start_time( any ), _
             double_press_start_time( any )
 
  enum button_state
    none                 = 0
    press                = 1
    already_press        = 2
    release              = 3
    already_release      = 4
    double_press         = 5
    already_double_press = 6
  end enum
 
  as byte state( any )
 
  declare constructor()
  declare destructor()
  declare sub hide_mouse()
  declare sub show_mouse()
  declare sub set_pointer_position( _
    byval v_x as single, _
    byval v_y as single )
  declare sub set_pointer_boundary( _
    byval v_x as long, _
    byval v_y as long, _
    byval v_w as long, _
    byval v_h as long )
  declare sub update_pointer_position()
  declare sub get_state( _
    byval v_timer as double = timer() )
  declare sub close_state()
  declare sub correct_axis( _
    byval v_which as long = -1 )
  declare function joystick() _
    as boolean
  declare function press( _
    byval v_button as long ) _
    as boolean
  declare function double_press( _
    byval v_button as long ) _
    as boolean
  declare function release( _
    byval v_button as long ) _
    as boolean
  declare function halt( _
    byval v_button as long, _
    byval v_time as double = 0.0 ) _
    as boolean
  declare function hold( _
    byval v_button as long, _
    byval v_time as double = 0.0 ) _
    as boolean
  declare function repeat( _
    byval v_button as long, _
    byval v_time as double = 0.0 ) _
    as boolean
  declare function drag( _
    byval v_button as long ) _
    as boolean
  declare function drop( _
    byval v_button as long ) _
    as boolean
end type

constructor t_fusion()
  dim as long _n
 
  ' Cycle backwards through all possible joystick identities
  ' and assign j_id to the lowest identity and assign true
  ' to use_joystick. If there aren't joystick identities
  ' found, then j_id is assigned to -1 and use_joystick
  ' is assigned false.
  j_id = -1
  use_joystick = false
  for _n = 15 to 0 step( -1 )
    j_result = getjoystick( _n )
    if( j_result = 0 ) then
      j_id = _n
      use_joystick = true
    end if
  next _n
 
  ' Use getmouse() to find out if there is a mouse available.
  ' If there is a mouse true is assigned to use_mouse.
  ' Otherwise, use_mouse is assigned false.
  use_mouse = false
  m_result = getmouse( m_x, m_y )
  if( m_result = 0 ) then use_mouse = true
 
  ' Set use_keyboard to true by default.
  use_keyboard = true
 
  ' Default pointer position and assign which joystick axis
  ' is responsible for moving the pointer.
  p_x            = 0
  p_y            = 0
  p_a            = 0
  p_boundary_x   = 0
  p_boundary_y   = 0
  p_boundary_w   = 0
  p_boundary_h   = 0
  p_j_which_axis = 0
 
  ' These two variables hold which button is currently in
  ' drag or double press mode. Assign them -1 here.
  owner_drag         = -1
  owner_double_press = -1
 
  ' These next variables are multipliers for how much
  ' the correlating axis change the pointer position.
  j_sensitivity = 250
 
  ' This deadzone value is a squared hypotenuse length
  ' to be checked against the joystick axis deltas. This
  ' is used to prevent micro deltas that can occur even
  ' when the joystick is at rest.
  j_deadzone = 0.001
 
  ' Double press time is the time window that two presses
  ' much occur to activate double press. The value is in
  ' seconds, so a default of 0.2 = 200 milliseconds.
  j_time_double_press = 0.2
  m_time_double_press = 0.2
  k_time_double_press = 0.2
 
  ' Tell our class how many buttons and how many axis so
  ' we can redim our appropriate variables.
  num_j_axis    = 4
  num_j_buttons = 12
  num_m_buttons = 3
  num_k_keys    = 128
 
  ' Joystick,mouse and key button states are stacked in that
  ' order. Because of this, the following offset variables
  ' provide the starting array position for each.
  m_offset = num_j_buttons
  k_offset = num_j_buttons + num_m_buttons
 
  ' Create an record of mouse buttons that stores the address
  ' of each within the state() array.
  redim b( 0 to 2 )
  b( 0 ) = m_offset
  b( 1 ) = m_offset + 1
  b( 2 ) = m_offset + 2
 
  ' Create an array that takes a keyboard scancode and returns
  ' it's address in the state() array.
  redim k( 1 to 100 )
  for _n = 1 to 100
    k( _n ) = _n + k_offset
  next _n
 
  ' Subtract 1 from our buttons and axis numbers because
  ' our array numbering starts at zero.
  num_j_axis    -= 1
  num_j_buttons -= 1
  num_m_buttons -= 1
  num_k_keys    -= 1
 
  redim      j_axis_x( 0 to num_j_axis )
  redim      j_axis_y( 0 to num_j_axis )
  redim      j_axis_a( 0 to num_j_axis )
  redim j_axis_motion( 0 to num_j_axis )
  
  redim use_joystick_axis( 0 to num_j_axis )
  
  j_result = getjoystick( j_id, j_button, _
                          j_axis_x( 0 ), j_axis_y( 0 ), _
                          j_axis_x( 1 ), j_axis_y( 1 ), _
                          j_axis_x( 2 ), j_axis_y( 2 ), _
                          j_axis_x( 3 ), j_axis_y( 3 ) )
  for _n = 0 to num_j_axis
    if( j_axis_x( _n ) <> -1000 ) then
      use_joystick_axis( _n ) = true
    else
      use_joystick_axis( _n ) = false
    end if
  next _n
 
  redim         hold_start_time( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
  redim       repeat_start_time( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
  redim double_press_start_time( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
  redim                   state( 0 to ( num_j_buttons + num_m_buttons + num_k_keys + 2 ) )
 
  ' This variable keeps track of how much time has passed since
  ' the previous close_state(). This variable is useful for
  ' time based physics.
  local_timer_difference = 0
end constructor

destructor t_fusion()
 
end destructor

sub t_fusion.hide_mouse()
 
  setmouse( ,, 0 )
end sub

sub t_fusion.show_mouse()
 
  setmouse( ,, 1 )
end sub

sub t_fusion.set_pointer_position( _
  byval v_x as single, _
  byval v_y as single )
 
  p_x = v_x
  p_y = v_y
end sub

sub t_fusion.set_pointer_boundary( _
  byval v_x as long, _
  byval v_y as long, _
  byval v_w as long, _
  byval v_h as long )
 
  p_boundary_x = v_x
  p_boundary_y = v_y
  p_boundary_w = v_w
  p_boundary_h = v_h
end sub

sub t_fusion.update_pointer_position()
 
  if( use_mouse = true ) then
    if( m_result = 0 ) then
      p_x = m_x + ( j_axis_x( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_y = m_y + ( j_axis_y( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_x = iif( ( p_x ) < ( p_boundary_w ), _
        ( p_x ), ( p_boundary_w ) )
      p_x = iif( ( p_x ) > ( p_boundary_x ), _
        ( p_x ), ( p_boundary_x ) )
      p_y = iif( ( p_y ) < ( p_boundary_h ), _
        ( p_y ), ( p_boundary_h ) )
      p_y = iif( ( p_y ) > ( p_boundary_y ), _
        ( p_y ), ( p_boundary_y ) )
      setmouse( p_x, p_y )
      m_x = p_x
      m_y = p_y
    else
      p_x += ( j_axis_x( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_y += ( j_axis_y( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_x = iif( ( p_x ) < ( p_boundary_w ), _
        ( p_x ), ( p_boundary_w ) )
      p_x = iif( ( p_x ) > ( p_boundary_x ), _
        ( p_x ), ( p_boundary_x ) )
      p_y = iif( ( p_y ) < ( p_boundary_h ), _
        ( p_y ), ( p_boundary_h ) )
      p_y = iif( ( p_y ) > ( p_boundary_y ), _
        ( p_y ), ( p_boundary_y ) )
    end if
  else
    if( use_joystick = true ) then
      p_x += ( j_axis_x( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_y += ( j_axis_y( p_j_which_axis ) * j_sensitivity * local_timer_difference )
      p_x = iif( ( p_x ) < ( p_boundary_w ), _
        ( p_x ), ( p_boundary_w ) )
      p_x = iif( ( p_x ) > ( p_boundary_x ), _
        ( p_x ), ( p_boundary_x ) )
      p_y = iif( ( p_y ) < ( p_boundary_h ), _
        ( p_y ), ( p_boundary_h ) )
      p_y = iif( ( p_y ) > ( p_boundary_y ), _
        ( p_y ), ( p_boundary_y ) )
    end if
  end if
end sub

sub t_fusion.get_state( _
  byval v_timer as double = timer() )
 
  dim as long _i
 
  local_timer_difference += ( v_timer - local_timer )
  local_timer = v_timer
 
  if( use_joystick = true ) then
    dim as single temp_axis_x( 0 to 3 ), _
                  temp_axis_y( 0 to 3 )
   
    j_result = getjoystick( j_id, j_button, _
                            temp_axis_x( 0 ), temp_axis_y( 0 ), _
                            temp_axis_x( 1 ), temp_axis_y( 1 ), _
                            temp_axis_x( 2 ), temp_axis_y( 2 ), _
                            temp_axis_x( 3 ), temp_axis_y( 3 ) )
    if( j_result = 0 ) then
      _i = num_j_axis
      do
        if( use_joystick_axis( _i ) = true ) then
          if( j_deadzone < ( ( temp_axis_x( _i ) * temp_axis_x( _i ) ) + ( temp_axis_y( _i ) * temp_axis_y( _i ) ) ) ) then
            j_axis_motion( _i ) = true
            j_axis_x( _i ) = temp_axis_x( _i )
            j_axis_y( _i ) = temp_axis_y( _i )
            'j_axis_a( _i ) = fast_atan2( j_axis_y( _i ), j_axis_x( _i ) ) ' ###############################
            j_axis_a( _i ) = atan2( j_axis_y( _i ), j_axis_x( _i ) ) ' #####################################
          else
            j_axis_motion( _i ) = false
            j_axis_x( _i ) = 0
            j_axis_y( _i ) = 0
          end if
        else
          ' not using this joystick axis
        end if
        _i -= 1
      loop until( _i = -1 )
     
      _i = num_j_buttons
      do
        if( j_button and ( 2 ^ _i ) ) then
          if( state( _i ) = button_state.none ) then
            if( owner_drag = -1 ) then
              owner_drag = _i
              state( _i ) = button_state.press
              hold_start_time( _i ) = local_timer
              repeat_start_time( _i ) = local_timer
              if( owner_double_press <> _i ) then
                owner_double_press = _i
                double_press_start_time( _i ) = local_timer
              else
                if( ( local_timer - double_press_start_time( _i ) ) < j_time_double_press ) then
                  state( _i ) = button_state.double_press
                else
                  double_press_start_time( _i ) = local_timer
                end if
              end if
              p_drag_dx = 0
              p_drag_dy = 0
              p_drag_sx = p_x
              p_drag_sy = p_y
            else
              if( ( _i <> owner_drag ) ) then
                state( _i ) = button_state.press
                hold_start_time( _i ) = local_timer
                repeat_start_time( _i ) = local_timer
                if( owner_double_press <> _i ) then
                  owner_double_press = _i
                  double_press_start_time( _i ) = local_timer
                else
                  if( ( local_timer - double_press_start_time( _i ) ) < j_time_double_press ) then
                    state( _i ) = button_state.double_press
                  else
                    double_press_start_time( _i ) = local_timer
                  end if
                end if
              end if
            end if
          else
            if( owner_drag = _i ) then
              p_drag_dx = p_x - p_drag_sx
              p_drag_dy = p_y - p_drag_sy
            end if
          end if
        else
          if( state( _i ) = button_state.already_press ) then
            state( _i ) = button_state.release
          else
            if( state( _i ) = button_state.already_release ) then
              state( _i ) = button_state.none
              if( owner_drag = _i ) then
                owner_drag = -1
              end if
            else
              if( state( _i ) = button_state.already_double_press ) then
                state( _i ) = button_state.release
              end if
            end if
          end if
        end if
        _i -= 1
      loop until( _i = -1 )
    else
      ' j_result is bad
    end if
  end if
  if( use_mouse = true ) then
    dim as long temp_x, _
                temp_y, _
                temp_w, _
                temp_b
   
    m_result = getmouse( temp_x, temp_y, temp_w, temp_b )
    if( m_result = 0 ) then
      m_axis_x = temp_x - m_x
      m_axis_y = temp_y - m_y
      m_axis_w = temp_w - m_w
      m_x = temp_x
      m_y = temp_y
      'm_w = temp_w
      'm_axis_a = fast_atan2( m_axis_y, m_axis_x )
      m_axis_a = atan2( m_axis_y, m_axis_x )
      m_button = temp_b
     
      _i = m_offset + num_m_buttons
      do
        if( m_button and ( 2 ^ ( _i - m_offset ) ) ) then
          if( state( _i ) = button_state.none ) then
            if( owner_drag = -1 ) then
              owner_drag = _i
              state( _i ) = button_state.press
              hold_start_time( _i ) = local_timer
              repeat_start_time( _i ) = local_timer
              if( owner_double_press <> _i ) then
                owner_double_press = _i
                double_press_start_time( _i ) = local_timer
              else
                if( ( local_timer - double_press_start_time( _i ) ) < m_time_double_press ) then
                  state( _i ) = button_state.double_press
                else
                  double_press_start_time( _i ) = local_timer
                end if
              end if
              p_drag_dx = 0
              p_drag_dy = 0
              p_drag_sx = p_x
              p_drag_sy = p_y
            else
              if( ( _i <> owner_drag ) ) then
                state( _i ) = button_state.press
                hold_start_time( _i ) = local_timer
                repeat_start_time( _i ) = local_timer
                if( owner_double_press <> _i ) then
                  owner_double_press = _i
                  double_press_start_time( _i ) = local_timer
                else
                  if( ( local_timer - double_press_start_time( _i ) ) < m_time_double_press ) then
                    state( _i ) = button_state.double_press
                  else
                    double_press_start_time( _i ) = local_timer
                  end if
                end if
              end if
            end if
          else
            if( owner_drag = _i ) then
              p_drag_dx = p_x - p_drag_sx
              p_drag_dy = p_y - p_drag_sy
            end if
          end if
        else
          if( state( _i ) = button_state.already_press ) then
            state( _i ) = button_state.release
          else
            if( state( _i ) = button_state.already_release ) then
              state( _i ) = button_state.none
              if( owner_drag = _i ) then
                owner_drag = -1
              end if
            else
              if( state( _i ) = button_state.already_double_press ) then
                state( _i ) = button_state.release
              end if
            end if
          end if
        end if
        _i -= 1
      loop until( _i = num_j_buttons )
    else
      ' m_result is bad
      m_axis_x = 0
      m_axis_y = 0
      m_axis_w = 0
    end if
  end if
  if( use_keyboard = true ) then
    _i = k_offset + num_k_keys
    do
      if( multikey( _i - k_offset ) ) then
        if( state( _i ) = button_state.none ) then
          state( _i ) = button_state.press
          hold_start_time( _i ) = local_timer
          repeat_start_time( _i ) = local_timer
          if( owner_double_press <> _i ) then
            owner_double_press = _i
            double_press_start_time( _i ) = local_timer
          else
            if( ( local_timer - double_press_start_time( _i ) ) < k_time_double_press ) then
              state( _i ) = button_state.double_press
            else
              double_press_start_time( _i ) = local_timer
            end if
          end if
        end if
      else
        if( state( _i ) = button_state.already_press ) then
          state( _i ) = button_state.release
        else
          if( state( _i ) = button_state.already_release ) then
            state( _i ) = none
          else
            if( state( _i ) = button_state.already_double_press ) then
              owner_double_press = -1
              state( _i ) = button_state.release
            end if
          end if
        end if
      end if
      _i -= 1
    loop until( _i = ( m_offset + num_m_buttons ) )
  end if
end sub

sub t_fusion.close_state()
 
  dim as long _i
 
  local_timer_difference = 0
 
  for _i = 0 to ubound( state )
    if( state( _i ) = button_state.press ) then
      state( _i ) = button_state.already_press
    else
      if( state( _i ) = button_state.release ) then
        state( _i ) = button_state.already_release
      else
        if( state( _i ) = button_state.double_press ) then
          state( _i ) = button_state.already_double_press
        end if
      end if
    end if
  next _i
end sub

sub t_fusion.correct_axis( _
  byval v_which as long = -1 )
  
  dim as single _distance
  
  if( v_which = -1 ) then
    dim as long _i
    for _i = 0 to num_j_axis
      if( j_axis_x( _i ) <> -1000 ) then
        _distance = ( j_axis_x( _i ) * j_axis_x( _i ) ) + ( j_axis_y( _i ) * j_axis_y( _i ) )
        if( _distance > 1 ) then
          j_axis_x( _i ) = cos( j_axis_a( _i ) )
          j_axis_y( _i ) = sin( j_axis_a( _i ) )
        end if
      end if
    next _i
  else
    if( j_axis_x( v_which ) <> -1000 ) then
      _distance = ( j_axis_x( v_which ) * j_axis_x( v_which ) ) + ( j_axis_y( v_which ) * j_axis_y( v_which ) )
      if( _distance > 1 ) then
        j_axis_x( v_which ) = cos( j_axis_a( v_which ) )
        j_axis_y( v_which ) = sin( j_axis_a( v_which ) )
      end if
    end if
  end if
end sub

function t_fusion.joystick() _
  as boolean
 
  dim as boolean _return
 
  if( ( j_id < 0 ) or ( j_id > 15 ) ) then
    _return = false
  else
    _return = true
  end if
 
  return _return
end function

function t_fusion.press( _
  byval v_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( v_button ) = button_state.press ) then
    state( v_button ) = button_state.already_press
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.double_press( _
  byval v_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( v_button ) = button_state.double_press ) then
    state( v_button ) = button_state.already_double_press
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.release( _
  byval v_button as long ) _
  as boolean
 
  dim as boolean _return
 
  if( state( v_button ) = button_state.release ) then
    state( v_button ) = button_state.already_release
    _return = true
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.halt( _
  byval v_button as long, _
  byval v_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( v_button ) = button_state.press ) or _
    ( state( v_button ) = button_state.already_press ) ) then
    if( v_time <> 0 ) then
      if( ( local_timer - hold_start_time( v_button ) ) < v_time ) then
        _return = true
      else
        _return = false
      end if
    else
      _return = true
    end if
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.hold( _
  byval v_button as long, _
  byval v_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( v_button ) = button_state.press ) or _
      ( state( v_button ) = button_state.double_press ) or _
      ( state( v_button ) = button_state.already_press ) or _
      ( state( v_button ) = button_state.already_double_press ) ) then
    if( v_time <> 0 ) then
      if( ( local_timer - hold_start_time( v_button ) ) > v_time ) then
        _return = true
      else
        _return = false
      end if
    else
      _return = true
    end if
  else
    _return = false
  end if
 
  return _return
end function

function t_fusion.repeat( _
  byval v_button as long, _
  byval v_time as double = 0.0 ) _
  as boolean
 
  dim as boolean _return
 
  if( ( state( v_button ) = button_state.press ) or _
      ( state( v_button ) = button_state.double_press ) ) then
    _return = true
  else
    if( ( state( v_button ) = button_state.already_press ) or _
        ( state( v_button ) = button_state.already_double_press ) ) then
     dim as double _time_difference
     
      _time_difference = local_timer - repeat_start_time( v_button )
      if( _time_difference > v_time ) then
        repeat_start_time( v_button ) += _time_difference
        _return = true
      else
        _return = false
      end if
    else
      _return = false
    end if
  end if
 
  return _return
end function

function t_fusion.drag( _
  byval v_button as long ) _
  as boolean
 
  return( hold( v_button ) and ( owner_drag = v_button ) )
end function

function t_fusion.drop( _
  byval v_button as long ) _
  as boolean
 
  return( release( v_button ) and ( owner_drag = v_button ) )
end function

' ########################################################################################################

#include "fbgfx.bi"
randomize()

dim as t_fusion fusion

dim as long screen_width, screen_height
dim as boolean terminate = false

dim as long z = 31
dim as single player_x, player_y, player_dx, player_dy, sword_x, sword_y, sword_angle
dim as long zombie_x( 0 to z), zombie_y( 0 to z ), _
            zombie_c( 0 to z ), zombie_dc( 0 to z ), zombie_tc( 0 to z ), _
            zombie_trigger_dist( 0 to z )
dim as boolean player_alive, zombie_alive( 0 to z ), zombie_triggered( 0 to z )
dim as long n, dist

screen_width = 640
screen_height = 360
screenres screen_width, screen_height, 32

fusion.hide_mouse()
fusion.use_mouse = false
fusion.j_sensitivity = 100

sword_angle = 0
player_alive = true
player_x = screen_width / 2
player_y = screen_height / 2
sword_x = player_x + ( cos( fusion.j_axis_a( 1 ) ) * 8 )
sword_y = player_y + ( sin( fusion.j_axis_a( 1 ) ) * 8 )

for n = 0 to z
  zombie_alive( n ) = true
  zombie_triggered( n ) = false
  zombie_trigger_dist( n ) = ( rnd * 4096 ) + 1024
  do
    zombie_x( n ) = ( rnd * ( screen_width - 64 ) ) + 32
    zombie_y( n ) = ( rnd * ( screen_height - 64 ) ) + 32
    dist = ( ( player_x - zombie_x( n ) ) ^ 2 ) + ( ( player_y - zombie_y( n ) ) ^ 2 )
  loop until( dist > 4096 )
  zombie_c( n ) = rgb( 63 - ( n * 2 ), 127 - ( n * 2 ), 63 - ( n * 2 ) )
  zombie_dc( n ) = rgb( 127 - ( n * 4 ), 0, 0 )
  zombie_tc( n ) = rgb( 159 - ( n * 4 ), 0, 63 )
next n

do while( not terminate )
  fusion.get_state()
 
  if( fusion.press( fusion.k( 1 ) ) ) then terminate = true
  if( player_alive = true ) then
    player_dx = 0
    player_dy = 0
   
    if( fusion.hold( fusion.k( fb.sc_up ) ) ) then
      player_dy -= 2
      sword_angle = -1.57
      if( fusion.hold( fusion.k( fb.sc_left ) ) ) then
        player_dx -= 2
        sword_angle = 3.14 - ( sword_angle / 2 )
      else
        if( fusion.hold( fusion.k( fb.sc_right ) ) ) then
          player_dx += 2
          sword_angle = 0 + ( sword_angle / 2 )
        end if
      end if
    else
      if( fusion.hold( fusion.k( fb.sc_down ) ) ) then
        player_dy += 2
        sword_angle = 1.57
        if( fusion.hold( fusion.k( fb.sc_left ) ) ) then
          player_dx -= 2
          sword_angle = 3.14 - ( sword_angle / 2 )
        else
          if( fusion.hold( fusion.k( fb.sc_right ) ) ) then
            player_dx += 2
            sword_angle = 0 + ( sword_angle / 2 )
          end if
        end if
      else
        if( fusion.hold( fusion.k( fb.sc_left ) ) ) then
          player_dx -= 2
          sword_angle = 3.14
        else
          if( fusion.hold( fusion.k( fb.sc_right ) ) ) then
            player_dx += 2
            sword_angle = 0
          end if
        end if
      end if
    end if
     
    player_x += player_dx
    player_y += player_dy
   
    player_x = iif( ( player_x ) < ( screen_width - 8 ), _
    ( player_x ), ( screen_width - 8 ) )
    player_x = iif( ( player_x ) > ( 1 ), _
    ( player_x ), ( 1 ) )
    player_y = iif( ( player_y ) < ( screen_height - 8 ), _
    ( player_y ), ( screen_height - 8 ) )
    player_y = iif( ( player_y ) > ( 1 ), _
    ( player_y ), ( 1 ) )
   
    sword_x = player_x + ( cos( sword_angle ) * 8 )
    sword_y = player_y + ( sin( sword_angle ) * 8 )
   
    for n = 0 to z
      if( zombie_alive( n ) = true ) then
        dist = ( ( player_x - zombie_x( n ) ) ^ 2 ) + ( ( player_y - zombie_y( n ) ) ^ 2 )
        if( dist < 64 ) then
          player_alive = false
        else
          if( dist < zombie_trigger_dist( n ) ) then
              zombie_triggered( n ) = true
            if( zombie_x( n ) > player_x ) then
              zombie_x( n ) += 1 - ( rnd * 3 )
            else
              zombie_x( n ) -= 1 - ( rnd * 3 )
            end if
            if( zombie_y( n ) > player_y ) then
              zombie_y( n ) += 1 - ( rnd * 3 )
            else
              zombie_y( n ) -= 1 - ( rnd * 3 )
            end if
          else
            zombie_triggered( n ) = false
            zombie_x( n ) += 1 - ( rnd * 2 )
            zombie_y( n ) += 1 - ( rnd * 2 )
          end if
        end if
      end if
      if( fusion.hold( fusion.k( fb.sc_space ) ) ) then
        if( ( ( sword_x - zombie_x( n ) ) ^ 2 ) + ( ( sword_y - zombie_y( n ) ) ^ 2 ) < 64 ) then
          zombie_alive( n ) = false
        end if
      end if
    next n
  end if
 
  screenlock()
    cls
    for n = 0 to z
      if( zombie_alive( n ) = true ) then
        if( zombie_triggered( n ) = true ) then
          draw string( zombie_x( n ), zombie_y( n ) ), "z", zombie_tc( n )
        else
          draw string( zombie_x( n ), zombie_y( n ) ), "z", zombie_c( n )
        end if
      else
        draw string( zombie_x( n ), zombie_y( n ) ), "%", zombie_dc( n )
      end if
    next n
    if( fusion.hold( fusion.k( fb.sc_space ) ) ) then
      draw string( sword_x, sword_y ), "+", rgb( rnd*255, rnd*255, rnd*255 )
    else
      draw string( sword_x, sword_y ), "+", rgb( 127, 127, 127 )
    end if
    if( player_alive = true ) then
      draw string( player_x, player_y ), "@"
    else
      draw string( player_x, player_y ), "@", rgb( 127, 0, 0 )
      draw string( screen_width / 2 - 56, screen_height / 2 - 5 ), _
        "YOU ARE CORPSE", rgb( 255 * tan( rnd ), 0, 0 )
      draw string( screen_width / 2 - 36, screen_height / 2 + 3 ), _
        "TRY AGAIN", rgb( 255 * tan( rnd ), 0, 0 )
    end if
    draw string( screen_width / 2 - 76, screen_height - 9 ), _
      "press escape to end", rgb( rnd*64 + 63, 0, 0 )
  screenunlock()
 
  if( player_alive = false ) and ( fusion.hold( fusion.k( fb.sc_space ) ) ) then
    player_alive = true
    player_x = screen_width / 2
    player_y = screen_height / 2
    sword_x = player_x + ( cos( fusion.j_axis_a( 1 ) ) * 8 )
    sword_y = player_y + ( sin( fusion.j_axis_a( 1 ) ) * 8 )
   
    for n = 0 to z
      zombie_alive( n ) = true
      zombie_triggered( n ) = false
      zombie_trigger_dist( n ) = ( rnd * 4096 ) + 1024
      do
        zombie_x( n ) = ( rnd * ( screen_width - 64 ) ) + 32
        zombie_y( n ) = ( rnd * ( screen_height - 64 ) ) + 32
        dist = ( ( player_x - zombie_x( n ) ) ^ 2 ) + ( ( player_y - zombie_y( n ) ) ^ 2 )
      loop until( dist > 4096 )
      zombie_c( n ) = rgb( 63 - ( n * 2 ), 127 - ( n * 2 ), 63 - ( n * 2 ) )
      zombie_dc( n ) = rgb( 127 - ( n * 4 ), 0, 0 )
      zombie_tc( n ) = rgb( 159 - ( n * 4 ), 0, 63 )
    next n
  end if
 
  fusion.close_state()
  sleep 15
loop
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: getjoystick() demo

Post by paul doe »

Looking really nice. Did anyone else tried this?
grindstone
Posts: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: getjoystick() demo

Post by grindstone »

Works with my gamepad, but it seems I'm not a real good sword fighter...
thrive4
Posts: 70
Joined: Jun 25, 2021 15:32

Re: getjoystick() demo

Post by thrive4 »

Hi sero,

Is it possible to expand the excellent code you shared
to include the 'guide' button on xbox controllers?

Bye the bye getjoystick() is an internal function:
https://www.freebasic-portal.de/befehls ... k-288.html
https://documentation.help/FreeBASIC/Ke ... stick.html
the documentation is a bit sketchy so some questions.

a) does it work cross platform?
b) Maybe support for the guide button (1024) will need to be implemented in FB it self?
c) it detects directx and xinput (on windows) but not dynamically or the api state is not polled in runtime?

For some inspiration:
Some sample code from autoit support for guide button:

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;					 ;;
;;  _XInput UDF for use with AutoIt Beta ;;
;;					 ;;
;;	Created by Oxin8		 ;;
;;      email: xoxinx@gmail.com		 ;;
;;	modified by caveat on 8/4/2013
;;		email: caveatsemporium@gmail.com
;;			thanks to posts at this url for finding the 'secret' function to get the xbox guide button state:
;;				http://forums.tigsource.com/index.php?topic=26792.0
;;					 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function _XInputInit()
;	Opens the dll
;	returns - a handle to open dll

Func _XInputInit()
   Local $thedll
   $thedll = DllOpen("xinput1_3.dll")
   Return $thedll
EndFunc

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function _XInputCheckState($thedll)
;	Returns true if a controller is connected
;	Else returns false

Func _XInputCheckState($thedll)
   $xinputgamepad = DllStructCreate("ULONG;word;byte;byte;short;short;short;short")
   $return = DllCall($thedll,"dword",100,"long",0,"ptr",DllStructGetPtr($xinputgamepad))
   If $return[0] == 0 Then
	  Return True
   Else
	  Return False
   EndIf
EndFunc

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function _XInputGetInput($thedll)
;	Returns an array of the current controller input
;	$thedll - dll handle returned by _XInputInit()
;	returns - an array with info (see below)
;		1-Event Count
;		2-Buttons
;		3-Left Trigger - 0 to 255
;		4-Right Trigger - 0 to 255
;		5-Left X - -32768 to 32767
;		6-Left Y - -32768 to 32767
;		7-Right X - -32768 to 32767
;		8-Right Y - -32768 to 32767

Func _XInputGetInput($thedll)
   Local $temp[9]
   $xinputgamepad = DllStructCreate("ULONG;word;byte;byte;short;short;short;short")
   If DllCall($thedll,"long",100,"long",0,"ptr",DllStructGetPtr($xinputgamepad))=0 Then Return
   For $i = 1 to 8
	  $temp[$i] = DllStructGetData($xinputgamepad,$i)
   Next
   Return $temp
EndFunc

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function _XInputButtons($buttons)
;	Returns an array indicating the pressed buttons
;	$buttons - use the second element of the array returned by _XInputGetInput
;	returns - an array of pressed buttons. 1 indicating pressed
;
;	   Array Element
;               v
;Y     32768	15
;X     16384    14
;B      8192    13
;A      4096    12
;Guide  1024	11
;RButton 512    10
;LButton 256     9
;RJoy    128     8
;LJoy     64     7
;Back     32     6
;Start    16     5
;Right     8     4
;Left      4     3
;Down      2     2
;Up        1     1

Func _XInputButtons($buttons)
   Local $pressed[16]
   For $i = 15 to 12 Step -1
	  If $buttons >= (2^$i) Then
		 $buttons = $buttons - (2^$i)
		 $pressed[($i)] = 1
	  EndIf
   Next
   For $i = 10 to 0 Step -1
	  If $buttons >= (2^$i) Then
		 $buttons = $buttons - (2^$i)
		 $pressed[($i + 1)] = 1
	  EndIf
   Next
   Return $pressed
EndFunc
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function _XInputOff($thedll)
;	Turns off the xbox controller
 
Func _XInputOff($thedll)
   DllCall($thedll,"int",103,"int",0)
EndFunc
coderJeff
Site Admin
Posts: 4317
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: getjoystick() demo

Post by coderJeff »

The documentation at https://documentation.help is 5 years out of date. I have no idea if they ever plan to update it.

Most recent documentation is at https://www.freebasic.net/wiki/DocToc
Though for the GetJoystick() topic it probably hasn't changed.
thrive4
Posts: 70
Joined: Jun 25, 2021 15:32

Re: getjoystick() demo

Post by thrive4 »

coderJeff wrote:The documentation at https://documentation.help is 5 years out of date. I have no idea if they ever plan to update it.

Most recent documentation is at https://www.freebasic.net/wiki/DocToc
Though for the GetJoystick() topic it probably hasn't changed.
Thank you for the additional info.
Regrettably neither of the pages indicate if the function is cross platform
at least not explicitly.
However after combing through the search results of:
https://github.com/freebasic/fbc/search ... tick&type=

I came across some manifests for FreeBASIC-linux-x86.lst and
FreeBASIC-linux-aarch64.lst so I assume, cautiously, that
the function also works on nix platforms.... and DOS for that matter.

Alas I can not find the code for the function in the above mentioned
github so it's hard to tell if adding the guide button (xinput) is feasible,
or for that matter desirable (considering the other platforms).

Possibly a workaround would be to utilize xinput1_3.dll as illustrated
with the code for autoit.
coderJeff
Site Admin
Posts: 4317
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: getjoystick() demo

Post by coderJeff »

thrive4 wrote:Regrettably neither of the pages indicate if the function is cross platform
The getjoystick() function as advertised is cross platform -- at least it was for dos / win / linux when I worked on it years ago. Honestly though, I haven't played with it lately. Let us know if you have troubles when you actually try it.

win32/gfx_joystick.c
linux/gfx_joystick.c
dos/gfx_joystick.c
grindstone
Posts: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: getjoystick() demo

Post by grindstone »

thrive4 wrote:...so it's hard to tell if adding the guide button (xinput) is feasible...
It's quite easy to find out. Run the example code from the documentation, maybe replace

Code: Select all

For a = 0 To 26
with

Code: Select all

For a = 0 To 32
then press the guide button and look if something happens.
thrive4
Posts: 70
Joined: Jun 25, 2021 15:32

Re: getjoystick() demo

Post by thrive4 »

coderJeff wrote:
thrive4 wrote:Regrettably neither of the pages indicate if the function is cross platform
The getjoystick() function as advertised is cross platform -- at least it was for dos / win / linux when I worked on it years ago. Honestly though, I haven't played with it lately. Let us know if you have troubles when you actually try it.

win32/gfx_joystick.c
linux/gfx_joystick.c
dos/gfx_joystick.c
Thank you for pointing me to the code used by fb
also for clarifying the platform support for the function
dully noted ;)

With regard to the possibility of implementing the xbox controllers
guide button, all though by no means a thorough assessment, I think
it will be quite a chore.

As far as I can tell it is implemented on, for win32, the joystickapi.h
https://docs.microsoft.com/en-us/window ... ystickapi/
which in term is part of the Windows Multimedia api, support for the
'guide' button is slim to none, there might be a work around (possibly with)
https://www.codeproject.com/articles/18 ... tick-input
you are of course in a much better position to determine if it is feasible
or worth the effort keeping in mind it is just one button for a specific controller.

For now I have found a work around with sdl2, should have looked at the
earlier, I will post it in a separate comment.
thrive4
Posts: 70
Joined: Jun 25, 2021 15:32

Re: getjoystick() demo

Post by thrive4 »

grindstone wrote: It's quite easy to find out. Run the example code from the documentation, maybe replace

Code: Select all

For a = 0 To 26
with

Code: Select all

For a = 0 To 32
then press the guide button and look if something happens.
Regrettably that does not work.
Thank you for the suggestion
thrive4
Posts: 70
Joined: Jun 25, 2021 15:32

Re: getjoystick() demo

Post by thrive4 »

With regard to getting the 'guide' button (on the xbox controller) to work
with fb one possible route is with sdl2 (the sample code is quick and dirty).

Prerequisite:
- An xbox controller with a guide button
- download the sdl2.dll from:
https://www.libsdl.org/download-2.0.php
and place it in the same folder as the application.
tested with SDL version 2.0.14 (stable) (32bit)

Note:
Much of the code for detecting axis or button input
is placebo the main focus is on the guide button.
Not tested with 64bit.

More info on the sdl implementation for gamepad / joysticks
can be found here:
http://wiki.libsdl.org/CategoryGameController

Another approach by calling the xinput1_3.dll can be found here:
https://forums.tigsource.com/index.php?topic=26792.0

Code: Select all

' sdl2 gamepad lib based on FreeBASIC-1.07.2-gcc-5.2
#Include "SDL2/SDL.bi"

If (Not SDL_Init(SDL_INIT_EVERYTHING) = 0) Then
	Print "SDL_init(SDL_INIT_JOYSTICK) error! " & SDL_GetError()
	end
End If

Dim As SDL_GameController Ptr controller = NULL

' Check for joysticks
If (SDL_NumJoysticks() < 1) Then Print "Warning: No joysticks connected!"
If (SDL_IsGameController(0) = SDL_TRUE) Then Print "Joystick is supported by the game controller interface!"

' Load joystick
controller = SDL_GameControllerOpen(0)
If (controller = NULL) Then
   Print "Unable to open game controller! SDL Error:" & SDL_GetError()
   end
end if

' for debug
'Print SDL_GameControllerName( controller )

' possible fix for unrecognized gamepad https://github.com/gabomdq/SDL_GameControllerDB
'SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt")

Dim As ZString Ptr map = SDL_GameControllerMapping(controller)
' for debug
'Print *map
'sleep 3000

Dim As Integer axis = 0
dim event as SDL_Event

Do
    ' axis
	'SDL_CONTROLLER_AXIS_INVALID = -1
	'print SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
	'print SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)
	'print SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX)
	'print SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY)
	'print SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT)
	'print SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
	'SDL_CONTROLLER_AXIS_MAX
    
    ' buttons
    'SDL_CONTROLLER_BUTTON_INVALID = -1
    'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_A) then
    '    print "button a"
    'end if
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_B) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_X) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_Y) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_BACK) then
	if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_GUIDE) then
        print "button guide"
    end if
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_START) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_LEFTSTICK) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_RIGHTSTICK) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_DPAD_UP) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT) then
	'if SDL_GameControllerGetButton(Controller, SDL_CONTROLLER_BUTTON_MAX) then
    cls
' note polling on sdlevent is necessary otherwise there is no ouput
loop until((SDL_PollEvent(@event) <> 0) and multikey(1))

SDL_GameControllerClose(controller)
SDL_Quit()
end
grindstone
Posts: 862
Joined: May 05, 2015 5:35
Location: Germany

Re: getjoystick() demo

Post by grindstone »

Very interesting. With this modified example code you can find out if any of the buttons is recognized at all:

Code: Select all

' sdl2 gamepad lib based on FreeBASIC-1.07.2-gcc-5.2
#Include "SDL2/SDL.bi"

If (Not SDL_Init(SDL_INIT_EVERYTHING) = 0) Then
   Print "SDL_init(SDL_INIT_JOYSTICK) error! " & SDL_GetError()
   End
End If

Dim As SDL_GameController Ptr controller = NULL

' Check for joysticks
If (SDL_NumJoysticks() < 1) Then Print "Warning: No joysticks connected!"
If (SDL_IsGameController(0) = SDL_TRUE) Then Print "Joystick is supported by the game controller interface!"

' Load joystick
controller = SDL_GameControllerOpen(0)
If (controller = NULL) Then
   Print "Unable to open game controller! SDL Error:" & SDL_GetError()
   End
End If

Dim event As SDL_Event

Do
	Dim As SDL_ControllerButtonEvent Ptr bp
	bp = @event
	? bp->button, bp->state
Loop Until((SDL_PollEvent(@event) <> 0) And MultiKey(1))
Post Reply