238 lines
8.3 KiB
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,
|
|
})
|