Class: Motel::MovementStrategies::Follow

Inherits:
Motel::MovementStrategy show all
Includes:
Rotatable
Defined in:
lib/motel/movement_strategies/follow.rb

Overview

The Follow MovementStrategy follows another location at a specified distance.

If location is at this distance, it will idle in the same location. If nearer / further away this will continously calculate the direction vector to the nearest point the specified distance away from the tracked location and move in a linear fashion to it.

To be valid, specify tracked_location_id, distance, and speed

Instance Attribute Summary collapse

Attributes included from Rotatable

#rot_theta, #rot_x, #rot_y, #rot_z, #stop_angle

Attributes inherited from Motel::MovementStrategy

#step_delay

Instance Method Summary collapse

Methods included from Rotatable

#change_due_to_rotation?, #init_rotation, #rot_to_s, #rotate, #rotation_json, #valid_rotation?

Methods inherited from Motel::MovementStrategy

#change?, json_create

Constructor Details

#initialize(args = {}) ⇒ Follow

Motel::MovementStrategies::Follow initializer

Options Hash (args):

  • :tracked_location_id,'tracked_location_id' (Integer)

    id of the location to track

  • :tracked_location,'tracked_location' (Integer)

    handle to the location to track

  • :distance,'distance' (Float)

    distance away from the tracked location to try to maintain

  • :speed,'speed' (Float)

    speed to assign to the movement strategy

  • :point_to_target, (Boolean)

    define if we should rotate to face the target

Raises:


70
71
72
73
74
75
76
77
78
79
80
# File 'lib/motel/movement_strategies/follow.rb', line 70

def initialize(args = {})
  attr_from_args args, :distance => nil, :speed => nil,
                       :tracked_location_id     => nil,
                       :point_to_target         => false,
                       :rotation_speed          => 1
  # If we have to point to the target, do so before moving
  @adjusting_bearing = @point_to_target
  @on_target = false # Asume we haven't arrived at the target at first
  init_rotation
  super(args)
end

Instance Attribute Details

#adjusting_bearingObject (readonly)

Boolean

Indicates if we have stopped to face the target


32
33
34
# File 'lib/motel/movement_strategies/follow.rb', line 32

def adjusting_bearing
  @adjusting_bearing
end

#distanceObject

Distance away from tracked location to try to maintain


50
51
52
# File 'lib/motel/movement_strategies/follow.rb', line 50

def distance
  @distance
end

#on_targetObject (readonly)

Boolean

Indicates if we are close enough to the target to stop


29
30
31
# File 'lib/motel/movement_strategies/follow.rb', line 29

def on_target
  @on_target
end

#point_to_targetObject

Define if we should rotate to face target


56
57
58
# File 'lib/motel/movement_strategies/follow.rb', line 56

def point_to_target
  @point_to_target
end

#rotation_speedObject

Optional - Rotation speed


59
60
61
# File 'lib/motel/movement_strategies/follow.rb', line 59

def rotation_speed
  @rotation_speed
end

#speedObject

Distance the location moves per second (when moving)


53
54
55
# File 'lib/motel/movement_strategies/follow.rb', line 53

def speed
  @speed
end

#tracked_locationObject

Motel::Location

location being tracked


38
39
40
# File 'lib/motel/movement_strategies/follow.rb', line 38

def tracked_location
  @tracked_location
end

#tracked_location_idObject

String

ID of location which is being tracked


35
36
37
# File 'lib/motel/movement_strategies/follow.rb', line 35

def tracked_location_id
  @tracked_location_id
end

Instance Method Details

#move(loc, elapsed_seconds) ⇒ Object

Implementation of Motel::MovementStrategy#move


98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/motel/movement_strategies/follow.rb', line 98

def move(loc, elapsed_seconds)
  unless valid? && !tracked_location.nil?
    ::RJR::Logger.warn "follow movement strategy not valid, not proceeding with move"
    return
  end

  tl = tracked_location
  unless tl.parent_id == loc.parent_id
    ::RJR::Logger.warn "follow movement strategy is set to track location with different parent than the one being moved"
    return
  end

  ::RJR::Logger.debug "moving location #{loc.id} via follow movement strategy " +
               "#{speed} #{tracked_location_id } at #{distance}"

  distance_to_cover  = loc - tl

  @on_target = distance_to_cover <= @distance

  if @point_to_target
    # Calculate orientation difference
    # TODO separate this logic into helper
    od = loc.orientation_difference(*tl.coordinates)
    if od.first.abs > (Math::PI / 32)
      # TODO right now this makes sure we can move and change rotation
      # at the same time. In the future, we should probably do some math 
      # to figure out intercept trajectories
      @adjusting_bearing = true if @on_target
      init_rotation :rot_theta =>  od[0] * @rotation_speed,
                    :rot_x     =>  od[1],
                    :rot_y     =>  od[2],
                    :rot_z     =>  od[3]
      if valid_rotation?
        rotate loc, elapsed_seconds
      end
    else
      @adjusting_bearing = false
    end
  end

  if @on_target || @adjusting_bearing
    #::RJR::Logger.warn "#{location} within #{@distance} of #{tl}"
    # TODO orbit the location or similar?

  else
    # calculate direction of tracked location
    dx = (tl.x - loc.x) / distance_to_cover
    dy = (tl.y - loc.y) / distance_to_cover
    dz = (tl.z - loc.z) / distance_to_cover

    # calculate distance and update x,y,z accordingly
    distance = speed * elapsed_seconds

    loc.x += distance * dx
    loc.y += distance * dy
    loc.z += distance * dz
  end
end

#to_json(*a) ⇒ Object

Convert movement strategy to json representation and return it


158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/motel/movement_strategies/follow.rb', line 158

def to_json(*a)
  { 'json_class' => self.class.name,
    'data'       => { :step_delay => step_delay,
                      :speed => speed,
                      :tracked_location_id => tracked_location_id,
                      :distance            => distance,
                      :point_to_target     => point_to_target,
                      :rotation_speed      => rotation_speed,
                      :on_target           => on_target,
                      :adjusting_bearing   => adjusting_bearing
                    }.merge(rotation_json)
  }.to_json(*a)
end

#to_sObject

Convert movement strategy to human readable string and return it


173
174
175
# File 'lib/motel/movement_strategies/follow.rb', line 173

def to_s
  "follow-(#{@tracked_location_id} at #{@distance})"
end

#valid?Boolean

Return boolean indicating if this movement strategy is valid

Tests the various attributes of the follow movement strategy, returning 'true' if everything is consistent, else false.

Currently tests

  • tracked location id is not nil

  • speed is a valid numeric > 0

  • distance is a valid numeric > 0


91
92
93
94
95
# File 'lib/motel/movement_strategies/follow.rb', line 91

def valid?
  !@tracked_location_id.nil? &&
  @speed.numeric? && @speed > 0 &&
  @distance.numeric? && @distance > 0
end