- moved configuration settings into config.lua file
- improved algorithm for surface collision sound fx
- implemented support for node groups of materials
- added fallback definition table for unknown nodes
- added compatibility layer for Minetest S3 engine
- bumped version number and included depends.txt
This commit is contained in:
Leslie Krause 2020-05-17 10:43:18 -04:00
parent e8f4007f5b
commit 8902e13891
6 changed files with 276 additions and 103 deletions

View File

@ -1,4 +1,4 @@
Interactive Physics Mod v1.0
Interactive Physics Mod v1.1
By Leslie E. Krause
Interactive Physics is a completely Lua-driven physics simulator for Minetest based on a
@ -15,6 +15,17 @@ For more information, please refer to the forum topic:
https://forum.minetest.net/viewtopic.php?f=9&t=22164
Compatibility
----------------------
Requires PR #9717 for Minetest 5.3-dev
Dependencies
----------------------
Default Mod (required)
https://github.com/minetest-game-mods/default
Repository
----------------------

8
compatibility.lua Normal file
View File

@ -0,0 +1,8 @@
minetest.get_node_above = function ( pos, off )
return minetest.get_node( { x = pos.x, y = pos.y + ( off or 1 ), z = pos.z } )
end
vector.origin = { x = 0, y = 0, z = 0 }
print( "RUNNING!" )

5
config.lua Normal file
View File

@ -0,0 +1,5 @@
world_gravity = 10
air_viscosity = 0.0
air_density = 0.2
default_liquid = { viscosity = 0.0, density = 0.5 }
default_solid = { friction = 0.5, elasticity = 0.0 }

2
depends.txt Normal file
View File

@ -0,0 +1,2 @@
default
config

346
init.lua
View File

@ -7,25 +7,23 @@
-- ./games/minetest_game/mods/physics/init.lua
--------------------------------------------------------
local S1, S1_ = Stopwatch( "physics" )
--local S1, S1_ = Stopwatch( "physics" )
local config = minetest.load_config( {
world_gravity = 10,
air_viscosity = 0.0,
air_density = 0.2,
default_liquid = { viscosity = 0.2, density = 0.5 },
default_solid = { friction = 0.5, elasticity = 0.0 },
} )
local materials = {
["default:water_source"] = { type = "liquid", viscosity = 0.5, density = 0.5 },
["default:ice"] = { type = "solid", friction = 0.0, elasticity = 0.0 },
}
local config = minetest.load_config( )
local materials = { }
local motion_sounds = {
diving = "default_water_footstep",
floating = "default_water_footstep",
bouncing = "default_place_node",
hitting_stone = "default_hard_footstep",
hitting_dirt = "default_dirt_footstep",
hitting_sand = "default_sand_footstep",
hitting_gravel = "default_gravel_footstep",
hitting_wood = "default_wood_footstep",
hitting_grass = "default_grass_footstep",
hitting_glass = "default_glass_footstep",
hitting_metal = "default_metal_foostep",
hitting_snow = "default_snow_footstep",
}
--------------------
@ -39,41 +37,107 @@ local function ramp( f, cur_v, max_v )
return max_v == 0 and f or f * min( 1, cur_v / max_v )
end
local function get_facing_axis( pos1, pos2 )
local x_abs = math.abs( pos1.x - pos2.x )
local y_abs = math.abs( pos1.y - pos2.y )
local z_abs = math.abs( pos1.z - pos2.z )
if x_abs < y_abs and z_abs < y_abs then
return "y"
elseif x_abs < z_abs and y_abs < z_abs then
return "z"
elseif z_abs < x_abs and y_abs < x_abs then
return "x"
end
return nil
end
--------------------
local function import_materials( )
local raw_materials = dofile( minetest.get_modpath( "physics" ) .. "/materials.lua" )
for k, v in pairs( raw_materials ) do
-- we need to do this with a secondary table since pairs function
-- does not support safe insertions during traversal
local group = string.match( k, "^group:([a-z0-9_]+)$" )
if group then
for name, ndef in pairs( minetest.registered_nodes ) do
if ndef.groups[ group ] and not raw_materials[ name ] then
materials[ name ] = table.copy( v )
end
end
else
materials[ k ] = v
end
end
end
--------------------
local function open_global_editor( player_name )
local get_formspec = function ( )
local formspec =
"size[8,5]" ..
"size[12,5]" ..
default.gui_bg ..
default.gui_bg_img ..
"label[4.0,0.0;Physics Properties]" ..
"box[4.0,0.6;3.8,0.1;#555555]" ..
"label[0.0,0.0;Physics Properties]" ..
"box[0.0,0.6;3.8,0.1;#555555]" ..
"box[4.0,0.6;7.8,0.1;#555555]" ..
"label[4.0,1.1;World Gravity:]" ..
"button[6.0,1.2;0.7,0.3;gravity_sub;<]" ..
"label[0.0,1.1;World Gravity:]" ..
"button[2.0,1.2;0.7,0.3;gravity_sub;<]" ..
"box[2.5,1.0;0.7,0.6;#000000]" ..
"button[3.2,1.2;0.7,0.3;gravity_add;>]" ..
string.format( "label[2.7,1.1;%d]", config.world_gravity ) ..
"label[0.0,2.1;Air Density:]" ..
"button[2.0,2.2;0.7,0.3;density_sub;<]" ..
"box[2.5,2.0;0.7,0.6;#000000]" ..
"button[3.2,2.2;0.7,0.3;density_add;>]" ..
string.format( "label[2.7,2.1;%0.1f]", config.air_density ) ..
"label[0.0,3.1;Air Viscosity:]" ..
"button[2.0,3.2;0.7,0.3;viscosity_sub;<]" ..
"box[2.5,3.0;0.7,0.6;#000000]" ..
"button[3.2,3.2;0.7,0.3;viscosity_add;>]" ..
string.format( "label[2.7,3.1;%0.1f]", config.air_viscosity ) ..
"label[4.0,1.1;Solid Friction:]" ..
"button[6.0,1.2;0.7,0.3;sol_friction_sub;<]" ..
"box[6.5,1.0;0.7,0.6;#000000]" ..
"button[7.2,1.2;0.7,0.3;gravity_add;>]" ..
string.format( "label[6.7,1.1;%d]", config.world_gravity ) ..
"button[7.2,1.2;0.7,0.3;sol_friction_add;>]" ..
string.format( "label[6.7,1.1;%0.1f]", config.default_solid.friction ) ..
"label[4.0,2.1;Air Density:]" ..
"button[6.0,2.2;0.7,0.3;density_sub;<]" ..
"label[4.0,2.1;Solid Elasticity:]" ..
"button[6.0,2.2;0.7,0.3;sol_elasticity_sub;<]" ..
"box[6.5,2.0;0.7,0.6;#000000]" ..
"button[7.2,2.2;0.7,0.3;density_add;>]" ..
string.format( "label[6.7,2.1;%0.1f]", config.air_density ) ..
"button[7.2,2.2;0.7,0.3;sol_elasticity_add;>]" ..
string.format( "label[6.7,2.1;%0.1f]", config.default_solid.elasticity ) ..
"label[4.0,3.1;Air Viscosity:]" ..
"button[6.0,3.2;0.7,0.3;viscosity_sub;<]" ..
"box[6.5,3.0;0.7,0.6;#000000]" ..
"button[7.2,3.2;0.7,0.3;viscosity_add;>]" ..
string.format( "label[6.7,3.1;%0.1f]", config.air_viscosity ) ..
"box[4.0,4.0;3.8,0.1;#555555]" ..
"button_exit[6.0,4.5;2,0.3;close;Close]"
"label[8.0,1.1;Liquid Viscosity:]" ..
"button[10.0,1.2;0.7,0.3;liq_viscosity_sub;<]" ..
"box[10.5,1.0;0.7,0.6;#000000]" ..
"button[11.2,1.2;0.7,0.3;liq_viscosity_add;>]" ..
string.format( "label[10.7,1.1;%0.1f]", config.default_liquid.viscosity ) ..
"label[8.0,2.1;Liquid Density:]" ..
"button[10.0,2.2;0.7,0.3;liq_density_sub;<]" ..
"box[10.5,2.0;0.7,0.6;#000000]" ..
"button[11.2,2.2;0.7,0.3;liq_density_add;>]" ..
string.format( "label[10.7,2.1;%0.1f]", config.default_liquid.density ) ..
"box[0.0,4.0;3.8,0.1;#555555]" ..
"box[4.0,0.6;7.8,0.1;#555555]" ..
"button_exit[10.0,4.5;2,0.3;close;Close]"
return formspec
end
local on_close = function ( meta, player, fields )
if fields.close then return end
if fields.gravity_sub then
config.world_gravity = math.max( 0.0, config.world_gravity - 1 )
elseif fields.gravity_add then
@ -86,9 +150,8 @@ local function open_global_editor( player_name )
config.air_viscosity = math.max( 0.0, config.air_viscosity - 0.1 )
elseif fields.viscosity_add then
config.air_viscosity = math.min( 1.0, config.air_viscosity + 0.1 )
else
return
end
minetest.update_form( player_name, get_formspec( ) )
end
@ -97,7 +160,7 @@ end
local function open_solid_editor( player_name, node_name )
local def = minetest.registered_items[ node_name ]
local solid = materials[ node_name ] or { friction = config.default_solid.friction, elasticity = config.default_solid.elasticity }
local props = materials[ node_name ] or { friction = config.default_solid.friction, elasticity = config.default_solid.elasticity }
local get_formspec = function ( )
local formspec =
@ -111,41 +174,42 @@ local function open_solid_editor( player_name, node_name )
"button[2.0,1.2;0.7,0.3;friction_sub;<]" ..
"box[2.5,1.0;0.7,0.6;#000000]" ..
"button[3.2,1.2;0.7,0.3;friction_add;>]" ..
string.format( "label[2.7,1.1;%0.1f]", solid.friction ) ..
string.format( "label[2.7,1.1;%0.1f]", props.friction ) ..
"label[4.0,1.1;Elasticity:]" ..
"button[6.0,1.2;0.7,0.3;elasticity_sub;<]" ..
"box[6.5,1.0;0.7,0.6;#000000]" ..
"button[7.2,1.2;0.7,0.3;elasticity_add;>]" ..
string.format( "label[6.7,1.1;%0.1f]", solid.elasticity ) ..
string.format( "label[6.7,1.1;%0.1f]", props.elasticity ) ..
"box[0.0,3.0;7.8,0.1;#555555]" ..
string.format( "image[0.1,3.2;1.0,1.0;%s]", def.tiles[ 1 ].name or def.tiles[ 1 ] ) ..
string.format( "label[1.2,3.4;%s]", def.description ) ..
"button_exit[4.0,3.5;2,0.3;reset;Reset]" ..
string.format( "label[0.0,3.4;%s]", def.description ) ..
"button[4.0,3.5;2,0.3;reset;Reset]" ..
"button_exit[6.0,3.5;2,0.3;close;Close]"
return formspec
end
local on_close = function ( meta, player, fields )
if fields.close then return end
if fields.reset then
materials[ node_name ] = nil
return
elseif fields.friction_sub then
solid.friction = math.max( 0.0, solid.friction - 0.1 )
elseif fields.friction_add then
solid.friction = math.min( 1.0, solid.friction + 0.1 )
elseif fields.elasticity_sub then
solid.elasticity = math.max( 0.0, solid.elasticity - 0.1 )
elseif fields.elasticity_add then
solid.elasticity = math.min( 1.0, solid.elasticity + 0.1 )
else
return
if fields.friction_sub then
props.friction = math.max( 0.0, props.friction - 0.1 )
elseif fields.friction_add then
props.friction = math.min( 1.0, props.friction + 0.1 )
elseif fields.elasticity_sub then
props.elasticity = math.max( 0.0, props.elasticity - 0.1 )
elseif fields.elasticity_add then
props.elasticity = math.min( 1.0, props.elasticity + 0.1 )
end
if not materials[ node_name ] then
materials[ node_name ] = props
end
end
if not materials[ node_name ] then
materials[ node_name ] = solid
end
minetest.update_form( player_name, get_formspec( ) )
end
@ -154,7 +218,7 @@ end
local function open_liquid_editor( player_name, node_name )
local def = minetest.registered_items[ node_name ]
local liquid = materials[ node_name ] or { viscosity = config.default_liquid.viscosity, density = config.default_liquid.density }
local props = materials[ node_name ] or { viscosity = config.default_liquid.viscosity, density = config.default_liquid.density }
local get_formspec = function ( )
local formspec =
@ -162,47 +226,119 @@ local function open_liquid_editor( player_name, node_name )
default.gui_bg ..
default.gui_bg_img ..
string.format( "label[0.0,0.0;Physics Properties (%s)]", materials[ node_name ] and "Override" or "Default" ) ..
"box[0.0,0.6;3.8,0.1;#555555]" ..
"box[0.0,0.6;7.8,0.1;#555555]" ..
"label[0.0,1.1;Viscosity:]" ..
"button[2.0,1.2;0.7,0.3;viscosity_sub;<]" ..
"box[2.5,1.0;0.7,0.6;#000000]" ..
"button[3.2,1.2;0.7,0.3;viscosity_add;>]" ..
string.format( "label[2.7,1.1;%0.1f]", liquid.viscosity ) ..
string.format( "label[2.7,1.1;%0.1f]", props.viscosity ) ..
"label[4.0,1.1;Density:]" ..
"button[6.0,1.2;0.7,0.3;density_sub;<]" ..
"box[6.5,1.0;0.7,0.6;#000000]" ..
"button[7.2,1.2;0.7,0.3;density_add;>]" ..
string.format( "label[6.7,1.1;%0.1f]", liquid.density ) ..
string.format( "label[6.7,1.1;%0.1f]", props.density ) ..
"box[0.0,3.0;7.8,0.1;#555555]" ..
string.format( "image[0.1,3.2;1.0,1.0;%s]", def.tiles[ 1 ].name or def.tiles[ 1 ] ) ..
string.format( "label[1.2,3.4;%s]", def.description ) ..
string.format( "label[0.0,3.4;%s]", def.description ) ..
"button_exit[4.0,3.5;2,0.3;reset;Reset]" ..
"button_exit[6.0,3.5;2,0.3;close;Close]"
return formspec
end
local on_close = function ( meta, player, fields )
if fields.close then return end
if fields.reset then
materials[ node_name ] = nil
return
elseif fields.viscosity_sub then
liquid.viscosity = math.max( 0.0, liquid.viscosity - 0.1 )
elseif fields.viscosity_add then
liquid.viscosity = math.min( 1.0, liquid.viscosity + 0.1 )
elseif fields.density_sub then
liquid.density = math.max( 0.01, liquid.density - 0.1 )
elseif fields.density_add then
liquid.density = math.min( 1.0, liquid.density + 0.1 )
else
return
if fields.viscosity_sub then
props.viscosity = math.max( 0.0, props.viscosity - 0.1 )
elseif fields.viscosity_add then
props.viscosity = math.min( 1.0, props.viscosity + 0.1 )
elseif fields.density_sub then
props.density = math.max( 0.01, props.density - 0.1 )
elseif fields.density_add then
props.density = math.min( 1.0, props.density + 0.1 )
else
return
end
end
if not materials[ node_name ] then
materials[ node_name ] = liquid
materials[ node_name ] = props
end
minetest.update_form( player_name, get_formspec( ) )
end
minetest.create_form( nil, player_name, get_formspec( ), on_close )
end
local function open_entity_editor( player_name, entity )
local props = entity.physics
local get_formspec = function ( )
local formspec =
"size[8,4]" ..
default.gui_bg ..
default.gui_bg_img ..
"label[0.0,0.0;Physics Properties]" ..
"box[0.0,0.6;7.8,0.1;#555555]" ..
"label[0.0,1.1;Friction:]" ..
"button[2.0,1.2;0.7,0.3;friction_sub;<]" ..
"box[2.5,1.0;0.7,0.6;#000000]" ..
"button[3.2,1.2;0.7,0.3;friction_add;>]" ..
string.format( "label[2.7,1.1;%0.1f]", props.friction ) ..
"label[0.0,2.1;Density:]" ..
"button[2.0,2.2;0.7,0.3;density_sub;<]" ..
"box[2.5,2.0;0.7,0.6;#000000]" ..
"button[3.2,2.2;0.7,0.3;density_add;>]" ..
string.format( "label[2.7,2.1;%0.1f]", props.density ) ..
"label[4.0,1.1;Elasticity:]" ..
"button[6.0,1.2;0.7,0.3;elasticity_sub;<]" ..
"box[6.5,1.0;0.7,0.6;#000000]" ..
"button[7.2,1.2;0.7,0.3;elasticity_add;>]" ..
string.format( "label[6.7,1.1;%0.1f]", props.elasticity ) ..
"label[4.0,2.1;Resistance:]" ..
"button[6.0,2.2;0.7,0.3;resistance_sub;<]" ..
"box[6.5,2.0;0.7,0.6;#000000]" ..
"button[7.2,2.2;0.7,0.3;resistance_add;>]" ..
string.format( "label[6.7,2.1;%0.1f]", props.resistance ) ..
"box[0.0,3.0;7.8,0.1;#555555]" ..
string.format( "label[0.0,3.4;%s (entity)]", entity.name ) ..
"button_exit[6.0,3.5;2,0.3;close;Close]"
return formspec
end
local on_close = function ( meta, player, fields )
if fields.close then return end
if fields.friction_sub then
props.friction = math.max( 0.0, props.friction - 0.1 )
elseif fields.friction_add then
props.friction = math.min( 1.0, props.friction + 0.1 )
elseif fields.density_sub then
props.density = math.max( 0.0, props.density - 0.1 )
elseif fields.density_add then
props.density = math.min( 1.0, props.density + 0.1 )
elseif fields.elasticity_sub then
props.elasticity = math.max( 0.0, props.elasticity - 0.1 )
elseif fields.elasticity_add then
props.elasticity = math.min( 1.0, props.elasticity + 0.1 )
elseif fields.resistance_sub then
props.resistance = math.max( 0.0, props.resistance - 0.1 )
elseif fields.resistance_add then
props.resistance = math.min( 1.0, props.resistance + 0.1 )
end
minetest.update_form( player_name, get_formspec( ) )
end
@ -221,8 +357,8 @@ minetest.register_tool( "physics:physics_wand", {
on_use = function ( itemstack, clicker, pointed_thing )
local player_name = clicker:get_player_name( )
if pointed_thing.type == "object" then
-- local this = pointed_thing.ref:get_luaentity( )
-- open_entity_editor( player_name, this )
local this = pointed_thing.ref:get_luaentity( )
open_entity_editor( player_name, this )
elseif pointed_thing.type == "node" then
local node_name = minetest.get_node( pointed_thing.under ).name
local def = minetest.registered_items[ node_name ]
@ -241,16 +377,17 @@ minetest.register_tool( "physics:physics_wand", {
function BasicPhysics( self )
local old_on_step = self.on_step
local unknown_ndef = { walkable = true, groups = { } }
local function play_sound( name )
minetest.sound_play( self.motion_sounds[ name ] or motion_sounds[ name ],
{ object = self.object, gain = 0.4, loop = false } )
{ object = self.object, xgain = 0.4, loop = false }, true )
end
local function handle_physics( pos, new_vel, old_vel )
local function handle_physics( pos, new_vel, old_vel, collisions )
local props = self.physics
local node_below = minetest.get_node_above( pos, self.is_swimming and 0.3 or -0.2 )
local ndef_below = minetest.registered_nodes[ node_below.name ]
local ndef_below = minetest.registered_nodes[ node_below.name ] or unknown_ndef
-- if entity is rolling or floating, then it should slow down and stop
if ndef_below.groups.liquid then
@ -304,17 +441,37 @@ function BasicPhysics( self )
end]]
-- if entity collided while rolling or floating, then it should bounce
local hit_axis
if new_vel.y == 0 and abs( old_vel.y ) > 0.2 then
play_sound( "bouncing" )
hit_axis = "y"
new_vel.y = -old_vel.y * props.elasticity
elseif new_vel.x == 0 and abs( old_vel.x ) > 0.2 then
play_sound( "bouncing" )
hit_axis = "x"
new_vel.x = -old_vel.x * props.elasticity
elseif new_vel.z == 0 and abs( old_vel.z ) > 0.2 then
play_sound( "bouncing" )
hit_axis = "z"
new_vel.z = -old_vel.z * props.elasticity
end
if hit_axis then
for idx = 1, #collisions do
local hit_info = collisions[ idx ]
if hit_info.side[ hit_axis ] ~= 0 and hit_info.impacts then
local node = minetest.get_node( hit_info.node_pos )
local ndef = minetest.registered_nodes[ node.name ] or unknown_ndef
if ndef.sounds then
local sound = "hitting_" .. string.match( ndef.sounds.footstep.name, "^default_(.-)_footstep$" )
play_sound( motion_sounds[ sound ] and sound or "hitting_stone" )
else
play_sound( "hitting_stone" )
end
end
end
end
if abs( new_vel.x ) <= 0.1 and abs( new_vel.z ) <= 0.1 then
new_vel.x = 0.0
new_vel.z = 0.0
@ -324,37 +481,22 @@ function BasicPhysics( self )
end
self.on_step = function( self, dtime, pos, rot, new_vel, old_vel, move_result )
--S1() -- handle rudimentary physics
--S1()
local is_standing = vector.equals( new_vel, vector.origin ) and move_result.is_standing
if not is_standing then
handle_physics( pos, new_vel, old_vel )
handle_physics( pos, new_vel, old_vel, move_result.collisions )
end
--S1_()
--S1_()
old_on_step( self, dtime, pos, rot, new_vel, old_vel, move_result )
end
end
--------------------
import_materials( )
-- compatibility for Minetest S3 engine
--------------------------------------------------------
-- Minetest :: MetaPhysics Mod v1.0 (physics)
--
-- See README.txt for licensing and other information.
-- Copyright (c) 2016-2019, Leslie Ellen Krause
--
-- ./games/minetest_game/mods/physics/init.lua
--------------------------------------------------------
local physics = { }
local props = {
world_gravity = 10,
air_viscosity = 0.1,
air_density = 0.5,
default_liquid = { viscosity = 0.0, density = 0.5 },
default_solid = { friction = 0.5, elasticity = 0.5 },
}
if not vector.origin and not minetest.get_node_above then
dofile( minetest.get_modpath( "physics" ) .. "/compatibility.lua" )
end

5
materials.lua Normal file
View File

@ -0,0 +1,5 @@
return {
["group:water"] = { type = "liquid", viscosity = 1.0, density = 0.5 },
["group:lava"] = { type = "liquid", viscosity = 0.7, density = 0.5 },
["default:ice"] = { type = "solid", friction = 0.0, elasticity = 0.0 },
}