if object:is_player() then
local pos2 = object:get_pos()
if self.axis_lock == "x" then
- local velocity = 1-vector.distance(vector.new(pos.x,0,0),vector.new(pos2.x,0,0))
- print(velocity)
+ local velocity = (1-vector.distance(vector.new(pos.x,0,0),vector.new(pos2.x,0,0)))/10
local dir = vector.direction(vector.new(pos2.x,0,0),vector.new(pos.x,0,0))
- self.object:add_velocity(vector.multiply(dir,velocity))
+ --self.object:add_velocity(vector.multiply(dir,velocity))
+ self.velocity = vector.multiply(dir,velocity)
self.dir = dir
elseif self.axis_lock == "z" then
- local velocity = 1-vector.distance(vector.new(0,0,pos.z),vector.new(0,0,pos2.z))
+ local velocity = (1-vector.distance(vector.new(0,0,pos.z),vector.new(0,0,pos2.z)))/10
local dir = vector.direction(vector.new(0,0,pos2.z),vector.new(0,0,pos.z))
- self.object:add_velocity(vector.multiply(dir,velocity))
+ --self.object:add_velocity(vector.multiply(dir,velocity))
+ self.velocity = vector.multiply(dir,velocity)
self.dir = dir
end
return
self.object:set_rotation(vector.new(0,yaw,0))
end
+local function turn_snap(pos,self,dir,dir2)
+ if dir.x ~= 0 and dir2.z ~= 0 then
+ --local inertia = math.abs(self.object:get_velocity().x)
+ local inertia = math.abs(self.velocity.x)
+ --self.object:set_velocity(vector.multiply(dir2,inertia))
+
+ self.velocity = vector.multiply(dir2,inertia)
+ self.dir = dir2
+ self.axis_lock = "z"
+ self.object:set_pos(pos)
+ direction_snap(self)
+ return(true)
+ elseif dir.z ~= 0 and dir2.x ~= 0 then
+ --local inertia = math.abs(self.object:get_velocity().z)
+ --print(dump(self.velocity))
+ local inertia = math.abs(self.velocity.z)
+ --self.object:set_velocity(vector.multiply(dir2,inertia))
+
+ self.velocity = vector.multiply(dir2,inertia)
+
+ self.dir = dir2
+ self.axis_lock = "x"
+ self.object:set_pos(pos)
+ direction_snap(self)
+ return(true)
+ end
+end
+
local function rail_brain(self,pos)
if not self.dir then return end
if triggered and not pool[minetest.hash_node_position(vector.add(pos,dir))] then
local possible_dirs = create_axis(pos)
if table.getn(possible_dirs) == 0 then
+ --print("train fails")
--stop slow down become physical, something
else
for _,dir2 in pairs(possible_dirs) do
- if dir.x ~= 0 and dir2.z ~= 0 then
- local intertia = math.abs(self.object:get_velocity().x)
- self.object:set_velocity(vector.multiply(dir2,intertia))
- self.dir = dir2
- self.axis_lock = "z"
- self.object:set_pos(pos)
- direction_snap(self)
- break
- elseif dir.z ~= 0 and dir2.x ~= 0 then
- local intertia = math.abs(self.object:get_velocity().z)
- self.object:set_velocity(vector.multiply(dir2,intertia))
- self.dir = dir2
- self.axis_lock = "x"
- self.object:set_pos(pos)
- direction_snap(self)
- break
+ if turn_snap(pos,self,dir,dir2) then
+ return
end
end
end
local minecart = {}
minecart.on_step = function(self,dtime)
- local pos = vector.round(self.object:get_pos())
+ local float_pos = self.object:get_pos()
+ local pos = vector.round(float_pos)
+
+ if self.velocity then
+ local new_vel = dtime/0.01
+ print(new_vel)
+ self.object:move_to(vector.add(float_pos,vector.multiply(self.velocity,new_vel)))
+ end
+
+ --stop minecarts from derailing when going super fast
+ if self.old_pos and vector.distance(float_pos,self.old_pos) > 0.5 then
+ self.object:move_to(self.old_pos)
+ float_pos = self.object:get_pos()
+ pos = vector.round(self.old_pos)
+ end
+
if not self.axis_lock then
local possible_dirs = create_axis(pos)
for _,dir in pairs(possible_dirs) do
collision_detect(self)
rail_brain(self,pos)
end
+ self.old_pos = float_pos
end
minecart.on_rightclick = function(self,clicker)
if type(data) ~= "table" then
return
end
-
+ self.old_pos = self.object:get_pos()
+ self.velocity = vector.new(0,0,0)
end
minecart.get_staticdata = function(self)
+++ /dev/null
-local path = minetest.get_modpath("minecart")
-dofile(path.."/rail.lua")
-
-
---get if rail
-local function rail(pos)
- return(minetest.get_node_group(minetest.get_node(pos).name,"rail")>0)
-end
-
---check if on rail
-local function on_rail(self,pos)
- if not rail(pos) and not self.slope then
- self.axis = nil
- return(false)
- else
- return(true)
- end
-end
-
---set physical state
-local function physical(self,pos)
- if on_rail(self,pos) then
- self.object:set_properties({physical = false})
- self.object:setacceleration(vector.new(0,0,0))
- elseif not self.slope then
- self.object:set_properties({physical = true})
- self.object:setacceleration(vector.new(0,-9.81,0))
- end
-end
-
---get if node in minecarts direction
-local function node_ahead(self,pos)
- local vel = self.object:getvelocity()
- local dir = vector.normalize(vel)
- return(rail(vector.add(pos,dir)))
-end
-
---get current axis (prefers x)
-local function axis(pos)
- if rail(pos) then
- if rail(vector.new(pos.x-1,pos.y,pos.z)) or rail(vector.new(pos.x+1,pos.y,pos.z)) then return("x") end
- if rail(vector.new(pos.x,pos.y,pos.z-1)) or rail(vector.new(pos.x,pos.y,pos.z+1)) then return("z") end
- end
-end
-
---snap object to rail
-local function snap_rail(self,pos)
- local slopy = self.slope
- if not slopy then print("the slope is nil") else
- print("the slope is ".. slopy)
- end
- local railpos = vector.floor(vector.add(pos, 0.5))
- local vel = self.object:getvelocity()
- if self.axis == "x" and pos.x ~= railpos.x then
- self.object:moveto(vector.new(pos.x,railpos.y,railpos.z))
- self.object:setvelocity(vector.new(vel.x,0,0))
- print("snapped to x")
- return
- end
- if self.axis == "z" and pos.z ~= railpos.z then
- self.object:moveto(vector.new(railpos.x,railpos.y,pos.z))
- self.object:setvelocity(vector.new(0,0,vel.z))
- print("snapped to z")
- return
- end
-end
-
---check if entering new position
-local function newnode(self,pos)
- local pos = vector.floor(vector.add(pos,0.5))
-
- pos.y = 0
-
- local equals = false
-
-
- if self.oldpos then
- equals = vector.equals(pos,self.oldpos)
- end
-
- self.oldpos = pos
- return(not equals)
-end
-
---check if past center - used for turning
-local function pastcenter(self,pos)
-
- local center = vector.floor(vector.add(pos,0.5))
- center.y = 0
- local pos2d = vector.new(pos.x,0,pos.z)
-
- local vel = self.object:getvelocity()
- local dir = vector.normalize(vel)
- dir.y = 0
- local checker = vector.round(vector.normalize(vector.subtract(pos2d,center)))
- checker.y = 0
- local past = vector.equals(checker, dir)
- return(past)
-end
-
---check if node ahead
-local function node_forward(self,pos)
- local vel = self.object:getvelocity()
- local dir = vector.normalize(vel)
- return(rail(vector.add(pos,dir)))
-end
-
---check if node above or below
-local function check_hill(self,pos)
- local vel = self.object:getvelocity()
- local dirup = vector.normalize(vel)
-
- dirup.y = dirup.y + 1
-
- print(dump(dirup))
-
- minetest.add_particlespawner({
- amount = 5,
- time = 0,
- minpos = vector.add(pos,dirup),
- maxpos = vector.add(pos,dirup),
- minvel = vector.new(0,0,0),
- maxvel = vector.new(0,0,0),
- minacc = {x=0, y=0, z=0},
- maxacc = {x=0, y=0, z=0},
- minexptime = 5,
- maxexptime = 5,
- minsize = 1,
- maxsize = 1,
- attached = player,
- collisiondetection = true,
- vertical = false,
- texture = "treecapitator.png"
- })
-
- local dirdown = vector.new(0,-0.5,0)
-
- if rail(vector.add(pos,dirup)) then
- self.slope = "up"
- return("up")
- elseif rail(vector.add(pos,dirdown)) then
- self.slope = "down"
- return("down")
- else
- self.slope = nil
- return(nil)
- end
-end
-
-local function gravity(self,pos)
-
- if self.slope == up then
- local vel = vector.multiply(self.object:getvelocity(), 0.95)
- self.object:set_velocity(vel)
- end
- if self.slope == up then
- local vel = vector.multiply(self.object:getvelocity(), 1.05)
- self.object:set_velocity(vel)
- end
-
-end
-
---make the minecart go up and down hills
-local function navigate_hill(self)
- if self.slope then
- local vel = self.object:getvelocity()
- if self.slope == "up" then
-
- local yvel = 0
- if self.axis == "x" then
- yvel = math.abs(vel.x)*1.1
- end
- if self.axis == "z" then
- yvel = math.abs(vel.z)*1.1
- end
- self.object:setvelocity(vector.new(vel.x,yvel,vel.z))
- elseif self.slope == "down" then
-
- local yvel = 0
- if self.axis == "x" then
- yvel = math.abs(vel.x)*-1
- end
- if self.axis == "z" then
- yvel = math.abs(vel.z)*-1
- end
-
- self.object:setvelocity(vector.new(vel.x,yvel,vel.z))
- end
- end
-end
-
---swap axis and speed 90 degrees
-local function turn_check(self,pos)
- local axis = self.axis
- local vel = self.object:getvelocity()
- vel.x = math.abs(vel.x)
- vel.y = math.abs(vel.y)
- vel.z = math.abs(vel.z)
-
- if axis == "x" then
- if rail(vector.new(pos.x,pos.y,pos.z-1)) then
- print("-x")
- self.object:setvelocity(vector.new(0,0,vel.x*-1))
- self.axis = "z"
- snap_rail(self,pos)
- self.turn_timer = 0
- return
- elseif rail(vector.new(pos.x,pos.y,pos.z+1)) then
- print("+x")
- self.object:setvelocity(vector.new(0,0,vel.x))
- self.axis = "z"
- snap_rail(self,pos)
- self.turn_timer = 0
- return
- end
- end
- if axis == "z" then
- if rail(vector.new(pos.x-1,pos.y,pos.z)) then
- print("-z")
- self.object:setvelocity(vector.new(vel.z*-1,0,0))
- self.axis = "x"
- snap_rail(self,pos)
- self.turn_timer = 0
- return
- elseif rail(vector.new(pos.x+1,pos.y,pos.z)) then
- print("+z")
- self.object:setvelocity(vector.new(vel.z,0,0))
- self.axis = "x"
- snap_rail(self,pos)
- self.turn_timer = 0
- return
- end
- end
-end
---try to turn
-local function turn(self,pos)
- if pastcenter(self,pos) then
- if not node_forward(self,pos) and self.axis then
- turn_check(self,pos)
- end
- end
-end
-
---the main mechanics of the minecart
-local function minecart_brain(self,dtime)
- if self.turn_timer < 5 then
- self.turn_timer = self.turn_timer + dtime
- end
- local pos = self.object:getpos()
- pos.y = pos.y - 0.5
-
-
- if not self.axis then
- self.axis = axis(pos)
- end
-
- if newnode(self,pos) then
- snap_rail(self,pos)
- end
- --check_hill(self,pos)
- --navigate_hill(self)
-
-
- turn(self,pos)
-
- on_rail(self,pos)
- physical(self,pos)
- --print(self.axis)
-
- --check if falling and then fall at the same speed to go down
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-minetest.register_entity("minecart:minecart", {
- initial_properties = {
- physical = true, -- otherwise going uphill breaks
- collisionbox = {-0.4, -0.5, -0.4, 0.4, 0.45, 0.4},--{-0.5, -0.4, -0.5, 0.5, 0.25, 0.5},
- visual = "mesh",
- mesh = "minecart.obj",
- visual_size = {x=1, y=1},
- textures = {"minecart.png"},
- automatic_face_movement_dir = 90.0,
- automatic_face_movement_max_rotation_per_sec = 600,
- },
-
- rider = nil,
- punched = false,
- speed = 0,
- turn_timer = 0,
- incline = nil,
- turn_timer = 5,
-
- on_rightclick = function(self,clicker)
- if not clicker or not clicker:is_player() then
- return
- end
- local player_name = clicker:get_player_name()
-
- if self.rider and player_name == self.rider then
- self.rider = nil
- --carts:manage_attachment(clicker, nil)
- elseif not self.rider then
- self.rider = player_name
- clicker:set_attach(self.object, "", {x=0, y=-4.5, z=0}, {x=0, y=0, z=0})
- --player:set_eye_offset({x=0, y=-4, z=0},{x=0, y=-4, z=0})
- --carts:manage_attachment(clicker, self.object)
-
- -- player_api does not update the animation
- -- when the player is attached, reset to default animation
-
- --player_api.set_animation(clicker, "stand")
- end
- end,
-
- on_activate = function(self,staticdata, dtime_s)
- self.object:set_armor_groups({immortal=1})
- if string.sub(staticdata, 1, string.len("return")) ~= "return" then
- return
- end
- local data = minetest.deserialize(staticdata)
- if type(data) ~= "table" then
- return
- end
- self.railtype = data.railtype
- if data.old_dir then
- self.old_dir = data.old_dir
- end
- end,
-
- get_staticdata = function(self)
- return minetest.serialize({
- })
- end,
-
- on_punch = function(self,puncher, time_from_last_punch, tool_capabilities, dir, damage)
- local obj = minetest.add_item(self.object:getpos(), "minecart:minecart")
- self.object:remove()
- end,
-
- --repel from players on track "push"
- push = function(self)
- if self.turn_timer > 0.3 then
- local pos = self.object:getpos()
- local radius = 1.2
- for _,object in ipairs(minetest.get_objects_inside_radius(pos, radius)) do
- if object:is_player() and object:get_player_name() ~= self.rider then
- local player_pos = object:getpos()
- pos.y = 0
- player_pos.y = 0
-
- local currentvel = self.object:getvelocity()
- local vel = vector.subtract(pos, player_pos)
- vel = vector.normalize(vel)
- local distance = vector.distance(pos,player_pos)
- distance = (radius-distance)*20
- vel = vector.multiply(vel,distance)
- local acceleration = vector.new(vel.x-currentvel.x,0,vel.z-currentvel.z)
-
- --note : set a maximum velocity that can be added to the cart to limit extreme glitches
-
- if self.axis == "x" then
- self.object:add_velocity(vector.new(acceleration.x,0,0))
- elseif self.axis == "z" then
- self.object:add_velocity(vector.new(0,0,acceleration.z))
- else
- self.object:add_velocity(acceleration)
- end
-
- --acceleration = vector.multiply(acceleration, -0.5)
- --object:add_player_velocity(acceleration)
- end
- end
- end
- end,
-
- --slows the minecart down
- slowdown = function(self)
- if not self.moving == true then
- local vel = self.object:getvelocity()
- local deceleration = vector.multiply(vel, -0.01)
- self.object:add_velocity(deceleration)
- end
- end,
-
- --mechanics to follow rails
- ride_rail = function(self,dtime)
- minecart_brain(self,dtime)
- end,
-
- on_step = function(self,dtime)
- self.push(self)
- self.slowdown(self)
- self.ride_rail(self,dtime)
- end,
-
-})
-
-minetest.register_craftitem("minecart:minecart", {
- description = "Minecart",
- inventory_image = "minecartitem.png",
- wield_image = "minecartitem.png",
- on_place = function(itemstack, placer, pointed_thing)
- if not pointed_thing.type == "node" then
- return
- end
-
- if minetest.get_item_group(minetest.get_node(pointed_thing.under).name, "rail")>0 then
- minetest.add_entity(pointed_thing.under, "minecart:minecart")
- else
- return
- end
-
- itemstack:take_item()
-
- return itemstack
- end,
-})
-
-minetest.register_craft({
- output = "minecart:minecart",
- recipe = {
- {"main:iron", "", "main:iron"},
- {"main:iron", "main:iron", "main:iron"},
- },
-})