New physics

This commit is contained in:
upsilon 2020-04-02 17:17:31 +02:00
parent bd4d040c4e
commit 0dd44bb30c
No known key found for this signature in database
GPG Key ID: A80DAE1F266E1C3C
2 changed files with 71 additions and 7 deletions

View File

@ -13,10 +13,14 @@ Mods based on this API:
The settings are the following:
```
# Movement parameters
throwing.velocity_factor = 19
throwing.horizontal_acceleration_factor = -3
# Trajectory parameters
throwing.vertical_acceleration = -10
throwing.realistic_trajectory = false
throwing.frictional_coefficient = -.5
# How the initial velocity of arrows is computed: simple, strength, or momentum
throwing.velocity_mode = strength
throwing.velocity_factor = 19
# Whether to allow placing an arrow as a node
throwing.allow_arrow_placing = false
@ -28,6 +32,22 @@ throwing.bow_cooldown = 0.2
throwing.toolranks = true
```
### Trajectory parameters
By default, the trajectory of the arrow is a simple parabola. You can set the vertical acceleration (acceleration of gravity) using `throwing.vertical_acceleration`.
If you want a more realistic trajectory that uses a first-order modelling of air friction, you can set `throwing.realistic_trajectory` to true. In this mode, `throwing.frictional_coefficient` indicates the ratio between the friction force on the arrow and its velocity. It should be negative. The acceleration of the arrow is subsequently determined by dividing the force by the "mass" of the arrow, the reference mass of 1 being the mass of a simple steel arrow. Generally, the frictional coefficient should be quite small; a value of -1 will already drastically shorten the range of the arrow. The default is -0.5.
### Initial velocity computation
The mod provides three modes to compute the initial speed of an arrow: simple, strength or strengthmass.
In simple mode, the initial velocity of the arrow is always the same. The `throwing.velocity_factor` contains the value of this velocity.
In strength mode (the default), the initial velocity of the arrow only depends on the bow that is used---the more expensive the bow, the faster the arrow. The arrow strength is multiplied by the velocity factor to compute the speed of the arrow, an arrow strength of 1 is about the strength of the steel bow in `throwing_arrows`.
Finally, momentum mode is the most realistic. It computes the velocity of the arrow based on the bow strength, as in the strength mode, and on the mass of the arrow: the heavier the arrow, the slower it will be shot. It is called the momentum mode because, in this mode, the strength of a bow indicates the initial momentum of the arrow rather than its initial speed.
## API
There are two available functions in the mod API:

View File

@ -28,6 +28,22 @@ function throwing.spawn_arrow_entity(pos, arrow, player)
end
end
local function apply_realistic_acceleration(obj, mass)
if not minetest.settings:get_bool("throwing.realistic_trajectory", false) then
return
end
local vertical_acceleration = tonumber(minetest.settings:get("throwing.vertical_acceleration")) or -10
local friction_coef = tonumber(minetest.settings:get("throwing.frictional_coefficient")) or -3
local velocity = obj:get_velocity()
obj:set_acceleration({
x = friction_coef * velocity.x / mass,
y = friction_coef * velocity.y / mass + vertical_acceleration,
z = friction_coef * velocity.z / mass
})
end
local function shoot_arrow(def, toolranks_data, player, bow_index, throw_itself, new_stack)
local inventory = player:get_inventory()
local arrow_index
@ -65,14 +81,29 @@ local function shoot_arrow(def, toolranks_data, player, bow_index, throw_itself,
end
local dir = player:get_look_dir()
local velocity_factor = tonumber(minetest.settings:get("throwing.velocity_factor")) or 19
local horizontal_acceleration_factor = tonumber(minetest.settings:get("throwing.horizontal_acceleration_factor")) or -3
local vertical_acceleration = tonumber(minetest.settings:get("throwing.vertical_acceleration")) or -10
local velocity_factor = tonumber(minetest.settings:get("throwing.velocity_factor")) or 19
local velocity_mode = minetest.settings:get("throwing.velocity_mode") or "strength"
obj:set_velocity({x=dir.x*velocity_factor, y=dir.y*velocity_factor, z=dir.z*velocity_factor})
obj:set_acceleration({x=dir.x*horizontal_acceleration_factor, y=vertical_acceleration, z=dir.z*horizontal_acceleration_factor})
local velocity
if velocity_mode == "simple" then
velocity = velocity_factor
elseif velocity_mode == "momentum" then
velocity = def.strength * velocity_factor / luaentity.mass
else
velocity = def.strength * velocity_factor
end
obj:set_velocity({
x = dir.x * velocity,
y = dir.y * velocity,
z = dir.z * velocity
})
obj:set_acceleration({x = 0, y = vertical_acceleration, z = 0})
obj:set_yaw(player:get_look_horizontal()-math.pi/2)
apply_realistic_acceleration(obj, luaentity.mass)
if luaentity.on_throw_sound ~= "" then
minetest.sound_play(luaentity.on_throw_sound or "throwing_sound", {pos=playerpos, gain = 0.5})
end
@ -224,6 +255,8 @@ function throwing.arrow_step(self, dtime)
wielded_light.update_light_by_item(self.item, self.object:get_pos())
end
apply_realistic_acceleration(self.object, self.mass) -- Physics: air friction
self.last_pos = pos -- Used by the build arrow
end
@ -256,6 +289,7 @@ function throwing.register_arrow(name, def)
if not def.groups.dig_immediate then
def.groups.dig_immediate = 3
end
def.inventory_image = def.tiles[1]
def.on_place = function(itemstack, placer, pointed_thing)
if minetest.settings:get_bool("throwing.allow_arrow_placing") and pointed_thing.above then
@ -313,6 +347,7 @@ function throwing.register_arrow(name, def)
on_hit_fails = def.on_hit_fails,
on_step = throwing.arrow_step,
item = name,
mass = def.mass or 1,
})
end
@ -322,6 +357,7 @@ function throwing.register_bow(name, def)
local enable_toolranks = use_toolranks and not def.no_toolranks
def.name = name
if not def.allow_shot then
def.allow_shot = function(player, itemstack, index)
if index >= player:get_inventory():get_size("main") and not def.throw_itself then
@ -330,9 +366,15 @@ function throwing.register_bow(name, def)
return throwing.is_arrow(itemstack) or def.throw_itself
end
end
if not def.inventory_image then
def.inventory_image = def.texture
end
if not def.strength then
def.strength = 20
end
def.on_use = function(itemstack, user, pointed_thing)
-- Cooldown
local meta = itemstack:get_meta()
@ -397,9 +439,11 @@ function throwing.register_bow(name, def)
end)
return itemstack
end
if enable_toolranks then
def.original_description = def.original_description or def.description
def.description = toolranks.create_description(def.description, 0, 1)
end
minetest.register_tool(name, def)
end