voxelmodel/init.lua

238 lines
8.3 KiB
Lua

--[[
Template to Easily Make Fancy Voxelized Models
Copyright (C) 2020 Noodlemire
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
--]]
--[[
Some important notes about how to use Voxelmodel:
Using the model itself means giving nodes the "mesh" drawtype, and setting their mesh to "voxelmodel.obj"
It should be provided a texture with an aspect ratio of 3:17.
Voxelmodel textures use an even grid of squares within the texture. The default square size is 16px.
See the included voxelmodel_guide.png for more details. It shows which column corresponds to which axis,
which end of each column is positive or negative, and has color-coded borders to show how axis are aligned.
Due to the nature of how it works, disable backface_culling for all nodes and entities that use voxelmodel.
Nodes have it disabled by default, but entities need it specified in their initial_properties table.
Please provide some kind of inventory and wield image. The default wield model will be partially culled.
--]]
--If default is enabled and bookshelf overriding is enabled...
if default and minetest.settings:get_bool("voxelmodel_override_bookshelf") then
--Override the default bookshelf to look like the voxelmodel bookshelf
minetest.override_item("default:bookshelf", {
drawtype = "mesh",
mesh = "voxelmodel.obj",
tiles = {"voxelmodel_bookshelf.png"},
inventory_image = "voxelmodel_bookshelf_inv.png",
wield_image = "voxelmodel_bookshelf_inv.png",
})
else
--The voxelmodel bookshelf is designed to look like the default bookshelf,
--but with added depth so you can see the covers of the books and the inside of the shelf.
minetest.register_node("voxelmodel:bookshelf", {
description = "Voxelmodel Bookshelf",
groups = {oddly_breakable_by_hand = 1},
paramtype = "light",
paramtype2 = "facedir",
drawtype = "mesh",
mesh = "voxelmodel.obj",
tiles = {"voxelmodel_bookshelf.png"},
inventory_image = "voxelmodel_bookshelf_inv.png",
wield_image = "voxelmodel_bookshelf_inv.png",
})
end
--The cat is a very basic entity meant to demonstrate some of the possibilities of voxelmodel-based animation,
--As well as an example of how entities can use voxelmodel in general.
--Its behavior is limited to alternating between wandering and standing still in 3 second intervals
--And sometimes blinking.
minetest.register_entity("voxelmodel:cat", {
initial_properties = {
physical = true,
visual = "mesh",
mesh = "voxelmodel.obj",
textures = {"voxelmodel_cat_idle.png"},
visual_size = {x = 10, y = 10},
automatic_face_movement_dir = 90,
backface_culling = false,
static_save = false,
},
--Every cat is spawned with the following:
on_activate = function(self)
--A walk timer that counts up with dtime. When it reaches 3, the cat either starts walking, or stops walking.
self.walk_timer = 0
self.walking = false
--A frame animation timer that counts up with dtime. When it reaches 0.1, the cat switches to the next frame.
--This is necessary because animating a mesh's texture automatically doesn't seem possible.
self.frame_timer = 0
self.frame = 1
--A blink timer that counts down with dtime. The cooldown between blinks is a random number in the range [4, 7] seconds.
--When it reaches 0, the cat starts blinking. While blinking, the timer is reset to 0.4 seconds.
--When it reaches 0 again, the cat opens its eyes again, and the cooldown begins again.
self.blink_timer = math.random(4, 7)
self.blinking = false
--Enable gravity by giving the cat a downwards acceleration of -9.81
self.object:set_acceleration({x = 0, y = -9.81, z = 0})
end,
--On each globalstep...
on_step = function(self, dtime, moveresult)
--First check the blink timer.
self.blink_timer = self.blink_timer - dtime
if self.blink_timer <= 0 then
--Invert the blinking boolean.
self.blinking = not self.blinking
if self.blinking then
--If it should blink now, do so by setting its texture mod to an overlay.
self.object:set_texture_mod("^voxelmodel_cat_blink.png")
self.blink_timer = 0.4
else
--Otherwise, clear the texture mod.
self.object:set_texture_mod("")
self.blink_timer = math.random(4, 7)
end
end
--If it is currently meant to be walking...
if self.walking then
--Check its animation frame timer (as it isn't animated when idle)
self.frame_timer = self.frame_timer + dtime
if self.frame_timer >= 0.1 then
self.frame_timer = self.frame_timer - 0.1
--Increment the frame, but reset it to 1 if it goes too high
self.frame = self.frame + 1
if self.frame > 5 then
self.frame = 1
end
--Replace the base texture repeatedly to make it animate.
self.object:set_properties({textures = {"voxelmodel_cat_walk_"..self.frame..".png"}})
end
end
--Check the walk timer...
self.walk_timer = self.walk_timer + dtime
if self.walk_timer >= 3 then
self.walk_timer = self.walk_timer - 3
--Invert the walking variable.
self.walking = not self.walking
if self.walking then
--If it should start walking now...
--First, get a random decimal between 0 and 2.
local vx = math.random() * 2
--Set the z velocity to be the inverse of the x velocity, so overall velocity is always 2.
local vz = 2 - vx
--The velocities of either axis have independent 50% chances to move in the opposite direction.
--This overall has an evenly random chance to move in any possible horizontal direction.
if math.random(2) == 1 then vx = -vx end
if math.random(2) == 1 then vz = -vz end
--Get the previous velocity in order to preserve vertical velocity.
local vel = self.object:get_velocity()
--Then, change the velocity to the newfound values.
self.object:set_velocity({x = vx, y = vel.y, z = vz})
else
--Otherwise, give it the idle texture and halt its horizontal velocity.
self.object:set_properties({textures = {"voxelmodel_cat_idle.png"}})
local vel = self.object:get_velocity()
self.object:set_velocity({x = 0, y = vel.y, z = 0})
end
end
end,
--Make the cat instantly die if you dare to hit it, you monster.
on_punch = function(self)
self.object:remove()
end,
})
--This craftitem is used to spawn cats.
minetest.register_craftitem("voxelmodel:cat", {
description = "Voxelmodel Cat",
inventory_image = "voxelmodel_cat_inv.png",
wield_image = "voxelmodel_cat_inv.png",
on_place = function(itemstack, placer, pointed_thing)
pointed_thing.above.y = pointed_thing.above.y + 0.1
minetest.add_entity(pointed_thing.above, "voxelmodel:cat")
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
return itemstack
end
})
--A very basic voxelnode with a very easily "readable" texture. If you study this first, it shouldn't be too hard to picture how its texture works.
minetest.register_node("voxelmodel:table", {
description = "Voxelmodel Table",
groups = {oddly_breakable_by_hand = 1},
paramtype = "light",
sunlight_propogates = true,
drawtype = "mesh",
mesh = "voxelmodel.obj",
tiles = {"voxelmodel_table.png"},
inventory_image = "voxelmodel_table_inv.png",
wield_image = "voxelmodel_table_inv.png",
})
--An example of an animated node. The flame on the torch's tip will visibly wave around.
--There would be an option to override default torches, but I didn't feel like making wall or ceiling models.
minetest.register_node("voxelmodel:torch", {
description = "Voxelmodel Torch",
groups = {oddly_breakable_by_hand = 1},
paramtype = "light",
sunlight_propogates = true,
light_source = 12,
drawtype = "mesh",
mesh = "voxelmodel.obj",
tiles = {{name = "voxelmodel_torch.png", animation = {type = "sheet_2d", frames_w = 5, frames_h = 1, frame_length = 0.333}}},
inventory_image = "voxelmodel_torch_inv.png",
wield_image = "voxelmodel_torch_inv.png",
walkable = false,
})