heli_control.lua 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. --global constants
  2. helicopter.gravity = tonumber(minetest.settings:get("movement_gravity")) or 9.8
  3. helicopter.tilting_speed = 1
  4. helicopter.tilting_max = 0.20
  5. helicopter.power_max = 15
  6. helicopter.power_min = 0.2 -- if negative, the helicopter can actively fly downwards
  7. helicopter.wanted_vert_speed = 5
  8. helicopter.vector_up = vector.new(0, 1, 0)
  9. helicopter.vector_forward = vector.new(0, 0, 1)
  10. helicopter.last_time_command = 0
  11. function helicopter.vector_length_sq(v)
  12. return v.x * v.x + v.y * v.y + v.z * v.z
  13. end
  14. if not minetest.global_exists("matrix3") then
  15. dofile(minetest.get_modpath("helicopter") .. DIR_DELIM .. "matrix.lua")
  16. end
  17. function helicopter.check_node_below(obj)
  18. local pos_below = obj:get_pos()
  19. pos_below.y = pos_below.y - 0.1
  20. local node_below = minetest.get_node(pos_below).name
  21. local nodedef = minetest.registered_nodes[node_below]
  22. local touching_ground = not nodedef or -- unknown nodes are solid
  23. nodedef.walkable or false
  24. local liquid_below = not touching_ground and nodedef.liquidtype ~= "none"
  25. return touching_ground, liquid_below
  26. end
  27. function helicopter.heli_control(self, dtime, touching_ground, liquid_below, vel_before)
  28. helicopter.last_time_command = helicopter.last_time_command + dtime
  29. if helicopter.last_time_command > 1 then helicopter.last_time_command = 1 end
  30. if self.driver_name == nil then
  31. return
  32. end
  33. local driver = minetest.get_player_by_name(self.driver_name)
  34. if not driver then
  35. -- there is no driver (eg. because driver left)
  36. self.driver_name = nil
  37. if self.sound_handle then
  38. minetest.sound_stop(self.sound_handle)
  39. self.sound_handle = nil
  40. end
  41. self.object:set_animation_frame_speed(0)
  42. -- gravity
  43. self.object:set_acceleration(vector.multiply(helicopter.vector_up, -helicopter.gravity))
  44. return
  45. end
  46. local ctrl = driver:get_player_control()
  47. if ctrl.aux1 and helicopter.last_time_command > 0.3 then
  48. helicopter.last_time_command = 0
  49. if self._by_mouse == true then
  50. self._by_mouse = false
  51. else
  52. self._by_mouse = true
  53. end
  54. end
  55. local rot = self.object:get_rotation()
  56. local vert_vel_goal = 0
  57. if not liquid_below then
  58. if ctrl.jump then
  59. vert_vel_goal = vert_vel_goal + helicopter.wanted_vert_speed
  60. end
  61. if ctrl.sneak then
  62. vert_vel_goal = vert_vel_goal - helicopter.wanted_vert_speed
  63. end
  64. else
  65. vert_vel_goal = helicopter.wanted_vert_speed
  66. end
  67. -- rotation
  68. if not touching_ground then
  69. local rotation = self.object:get_rotation()
  70. local yaw = rotation.y
  71. local tilting_goal = vector.new()
  72. if ctrl.up then
  73. tilting_goal.z = tilting_goal.z + 4
  74. end
  75. if ctrl.down then
  76. tilting_goal.z = tilting_goal.z - 4
  77. end
  78. if self._by_mouse == true then
  79. if ctrl.right then
  80. tilting_goal.x = tilting_goal.x + 4
  81. end
  82. if ctrl.left then
  83. tilting_goal.x = tilting_goal.x - 4
  84. end
  85. else
  86. if ctrl.right then
  87. yaw = yaw - 0.02
  88. tilting_goal.x = tilting_goal.x + 0.2
  89. end
  90. if ctrl.left then
  91. yaw = yaw + 0.02
  92. tilting_goal.x = tilting_goal.x - 0.2
  93. end
  94. end
  95. tilting_goal = vector.multiply(vector.normalize(tilting_goal), helicopter.tilting_max)
  96. -- tilting
  97. if helicopter.vector_length_sq(vector.subtract(tilting_goal, self.tilting)) > (dtime * helicopter.tilting_speed)^2 then
  98. self.tilting = vector.add(self.tilting,
  99. vector.multiply(vector.direction(self.tilting, tilting_goal), dtime * helicopter.tilting_speed))
  100. else
  101. self.tilting = tilting_goal
  102. end
  103. if helicopter.vector_length_sq(self.tilting) > helicopter.tilting_max^2 then
  104. self.tilting = vector.multiply(vector.normalize(self.tilting), helicopter.tilting_max)
  105. end
  106. local new_up = vector.new(self.tilting)
  107. new_up.y = 1
  108. new_up = vector.normalize(new_up) -- this is what vector_up should be after the rotation
  109. local new_right = vector.cross(new_up, helicopter.vector_forward)
  110. local new_forward = vector.cross(new_right, new_up)
  111. local rot_mat = matrix3.new(
  112. new_right.x, new_up.x, new_forward.x,
  113. new_right.y, new_up.y, new_forward.y,
  114. new_right.z, new_up.z, new_forward.z
  115. )
  116. rot = matrix3.to_pitch_yaw_roll(rot_mat)
  117. if self._by_mouse == true then
  118. rot.y = driver:get_look_horizontal()
  119. else
  120. rot.y = yaw
  121. end
  122. else
  123. rot.x = 0
  124. rot.z = 0
  125. self.tilting.x = 0
  126. self.tilting.z = 0
  127. end
  128. self.object:set_rotation(rot)
  129. -- calculate how strong the heli should accelerate towards rotated up
  130. local power = vert_vel_goal - vel_before.y + helicopter.gravity * dtime
  131. power = math.min(math.max(power, helicopter.power_min * dtime), helicopter.power_max * dtime)
  132. -- calculate energy consumption --
  133. ----------------------------------
  134. if self.energy > 0 and touching_ground == false then
  135. local position = self.object:get_pos()
  136. local altitude_consumption_variable = 0
  137. -- if gaining altitude, it consumes more power
  138. local y_pos_reference = position.y - 200 --after altitude 200 the power need will increase
  139. if y_pos_reference > 0 then altitude_consumption_variable = ((y_pos_reference/1000)^2) end
  140. local consumed_power = (power/1500) + altitude_consumption_variable
  141. self.energy = self.energy - consumed_power;
  142. local energy_indicator_angle = ((self.energy * 18) - 90) * -1
  143. if self.pointer:get_luaentity() then
  144. self.pointer:set_attach(self.object,'',{x=0,y=11.26,z=9.37},{x=0,y=0,z=energy_indicator_angle})
  145. else
  146. --in case it have lost the entity by some conflict
  147. self.pointer=minetest.add_entity({x=0,y=11.26,z=9.37},'helicopter:pointer')
  148. self.pointer:set_attach(self.object,'',{x=0,y=11.26,z=9.37},{x=0,y=0,z=energy_indicator_angle})
  149. end
  150. end
  151. if self.energy <= 0 then
  152. power = 0.2
  153. if touching_ground or liquid_below then
  154. --criar uma fucao pra isso pois ela repete na linha 268
  155. -- sound and animation
  156. if self.sound_handle then minetest.sound_stop(self.sound_handle) end
  157. self.object:set_animation_frame_speed(0)
  158. -- gravity
  159. self.object:set_acceleration(vector.multiply(helicopter.vector_up, -helicopter.gravity))
  160. end
  161. end
  162. ----------------------------
  163. -- end energy consumption --
  164. local rotated_up = matrix3.multiply(matrix3.from_pitch_yaw_roll(rot), helicopter.vector_up)
  165. local added_vel = vector.multiply(rotated_up, power)
  166. added_vel = vector.add(added_vel, vector.multiply(helicopter.vector_up, -helicopter.gravity * dtime))
  167. return vector.add(vel_before, added_vel)
  168. end