So is a framework required?
I want to use existing models - a block - and place the block in the game, and make it move around.
I see from the mobs framework api that you've got a lot of features secondary to my goal. I'd like to iterate through some extremely simplistic processes to get a workable mob, with the idea of knowing exactly what's going on.
I guess a good place to start would be to strip away everything that is peripheral to this goal from the api . I'm looking at adding features to a single mob that are a bit different and more resource intensive than something that would fit inside the normal gameplay. I'd like to try out neural network controlled mobs -
https://github.com/wixico/luann is my ANN framework.
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
mobs = {}
-- Set global for other mod checks (e.g. Better HUD uses this)
mobs.mod = "redo"
function mobs:register_mob(name, def)
minetest.register_entity(name, {
name = name,
physical = true,
collisionbox = def.collisionbox,
visual = def.visual,
visual_size = def.visual_size,
mesh = def.mesh,
walk_velocity = def.walk_velocity,
drawtype = def.drawtype,
type = def.type,
sounds = def.sounds or {},
animation = def.animation,
jump = def.jump or true,
walk_chance = def.walk_chance or 50,
floats = def.floats or 1, -- floats in water by default
stimer = 0,
timer = 0,
state = "stand",
v_start = false,
old_y = nil,
lifetimer = 600,
last_state = nil,
set_velocity = function(self, v)
local yaw = self.object:getyaw()
if self.drawtype == "side" then
yaw = yaw+(math.pi/2)
end
local x = math.sin(yaw) * -v
local z = math.cos(yaw) * v
self.object:setvelocity({x=x, y=self.object:getvelocity().y, z=z})
end,
get_velocity = function(self)
local v = self.object:getvelocity()
return (v.x^2 + v.z^2)^(0.5)
end,
set_animation = function(self, type)
if not self.animation then
return
end
if not self.animation.current then
self.animation.current = ""
end
if type == "stand" and self.animation.current ~= "stand" then
if self.animation.stand_start
and self.animation.stand_end
and self.animation.speed_normal then
self.object:set_animation({x=self.animation.stand_start,
y=self.animation.stand_end},self.animation.speed_normal, 0)
self.animation.current = "stand"
end
elseif type == "walk" and self.animation.current ~= "walk" then
if self.animation.walk_start
and self.animation.walk_end
and self.animation.speed_normal then
self.object:set_animation({x=self.animation.walk_start,y=self.animation.walk_end},
self.animation.speed_normal, 0)
self.animation.current = "walk"
end
end
end,
on_step = function(self, dtime)
local yaw = 0
if self.state == "stand" then
-- randomly turn
if math.random(1, 4) == 1 then
-- if there is a player nearby look at them
local lp = nil
local s = self.object:getpos()
if lp ~= nil then
local vec = {x=lp.x-s.x, y=lp.y-s.y, z=lp.z-s.z}
yaw = math.atan(vec.z/vec.x)+math.pi/2
if self.drawtype == "side" then
yaw = yaw+(math.pi/2)
end
if lp.x > s.x then
yaw = yaw+math.pi
end
else
yaw = self.object:getyaw()+((math.random(0,360)-180)/180*math.pi)
end
self.object:setyaw(yaw)
end
self.set_velocity(self, 0)
self.set_animation(self, "stand")
if math.random(1, 100) <= self.walk_chance then
self.set_velocity(self, self.walk_velocity)
self.state = "walk"
self.set_animation(self, "walk")
end
elseif self.state == "walk" then
if math.random(1, 100) <= 30 then
self.object:setyaw(self.object:getyaw()+((math.random(0,360)-180)/180*math.pi))
end
if self.jump and self.get_velocity(self) <= 0.5 and self.object:getvelocity().y == 0 then
local v = self.object:getvelocity()
v.y = 5
self.object:setvelocity(v)
end
self:set_animation("walk")
self.set_velocity(self, self.walk_velocity)
if math.random(1, 100) <= 30 then
self.set_velocity(self, 0)
self.state = "stand"
self:set_animation("stand")
end
on_activate = function(self, staticdata, dtime_s)
local pos = self.object:getpos()
self.object:setacceleration({x=0, y=-10, z=0})
self.state = "stand"
self.object:setvelocity({x=0, y=self.object:getvelocity().y, z=0})
self.object:setyaw(math.random(1, 360)/180*math.pi)
if staticdata then
local tmp = minetest.deserialize(staticdata)
if tmp then
if tmp.lifetimer then
self.lifetimer = tmp.lifetimer - dtime_s
end
end
end
end,
get_staticdata = function(self)
-- set mob texture and model
local textures = def.available_textures["texture_"..math.random(1,def.available_textures["total"])]
local mesh = self.mesh
local tmp = {
lifetimer = self.lifetimer,
mesh = mesh,
textures = textures,
}
self.object:set_properties(tmp)
return minetest.serialize(tmp)
end,
})
end
mobs.spawning_mobs = {}
function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height)
mobs.spawning_mobs[name] = true
minetest.register_abm({
nodenames = nodes,
neighbors = {"air"},
interval = 30,
chance = chance,
action = function(pos, node, _)
-- spawn above node
pos.y = pos.y + 1
-- are we spawning inside a node?
local nod = minetest.get_node_or_nil(pos)
if not nod or minetest.registered_nodes[nod.name].walkable == true then return end
pos.y = pos.y + 1
nod = minetest.get_node_or_nil(pos)
if not nod or minetest.registered_nodes[nod.name].walkable == true then return end
if minetest.setting_getbool("display_mob_spawn") then
minetest.chat_send_all("[mobs] Add "..name.." at "..minetest.pos_to_string(pos))
end
-- spawn mob half block higher
pos.y = pos.y - 0.5
local mob = minetest.add_entity(pos, name)
end
})
end
Here's the API, with just the trivial stuff, like walk and stand, minimal animation, no gravity or type checks. Here's what a trivial chicken would look like:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
-- trivial chicken by JRowe47
mobs:register_mob("mobs:trivial_chicken", {
-- textures and model
collisionbox = {-0.3, -0.75, -0.3, 0.3, 0.1, 0.3},
visual = "mesh",
mesh = "chicken.x",
drawtype = "front",
available_textures = {
total = 2,
texture_1 = {"mobs_chicken.png", "mobs_chicken.png", "mobs_chicken.png",
"mobs_chicken.png", "mobs_chicken.png", "mobs_chicken.png",
"mobs_chicken.png", "mobs_chicken.png", "mobs_chicken.png"},
texture_2 = {"mobs_chicken_black.png", "mobs_chicken_black.png", "mobs_chicken_black.png",
"mobs_chicken_black.png", "mobs_chicken_black.png", "mobs_chicken_black.png",
"mobs_chicken_black.png", "mobs_chicken_black.png", "mobs_chicken_black.png"},
},
-- speed and jump
walk_velocity = 1,
jump = true,
-- model animation
animation = {
speed_normal = 15,
stand_start = 0,
stand_end = 1, -- 20
walk_start = 20,
walk_end = 40,
},
})
I think this might work. I'll have to dig around some more and start experimenting.
I plan on adding things incrementally, like sensors, some rough approximation of vision, hearing, smell, and so forth, and actuators that drive movement and other interactions like attacks, chat window output, noises, and so forth.
Once I've got a creature roughed in, then I'll start adding neural networks as controllers. This should be fun. :)