Ferk wrote:I would like to animate a sprite. Can someone explain this function from LuaEntitySAO?
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
setsprite(p={x=0,y=0}, num_frames=1, framelength=0.2, select_horiz_by_yawpitch=false) — Select sprite from spritesheet with optional animation and DM-style texture selection based on yaw relative to camera
In
src/script/lua_api/l_object.cpp we have the lua function:
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
// setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2,
// select_horiz_by_yawpitch=false)
int ObjectRef::l_setsprite(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
if(co == NULL) return 0;
// Do it
v2s16 p(0,0);
if(!lua_isnil(L, 2))
p = read_v2s16(L, 2);
int num_frames = 1;
if(!lua_isnil(L, 3))
num_frames = lua_tonumber(L, 3);
float framelength = 0.2;
if(!lua_isnil(L, 4))
framelength = lua_tonumber(L, 4);
bool select_horiz_by_yawpitch = false;
if(!lua_isnil(L, 5))
select_horiz_by_yawpitch = lua_toboolean(L, 5);
co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
return 0;
}
It's just a wrapper for a C function
setSprite; this takes us to
src/content_sao.cpp :
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
void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
bool select_horiz_by_yawpitch)
{
std::string str = gob_cmd_set_sprite(
p,
num_frames,
framelength,
select_horiz_by_yawpitch
);
// create message and add to list
ActiveObjectMessage aom(getId(), true, str);
m_messages_out.push_back(aom);
}
thence to
src/genericobject.cpp :
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
std::string gob_cmd_set_sprite(
v2s16 p,
u16 num_frames,
f32 framelength,
bool select_horiz_by_yawpitch
){
std::ostringstream os(std::ios::binary);
// command
writeU8(os, GENERIC_CMD_SET_SPRITE);
// parameters
writeV2S16(os, p);
writeU16(os, num_frames);
writeF1000(os, framelength);
writeU8(os, select_horiz_by_yawpitch);
return os.str();
}
thence to
src/content_cao.cpp :
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
void GenericCAO::processMessage(const std::string &data)
// [ ... many lines omitted ... ]
else if(cmd == GENERIC_CMD_SET_SPRITE) {
v2s16 p = readV2S16(is);
int num_frames = readU16(is);
float framelength = readF1000(is);
bool select_horiz_by_yawpitch = readU8(is);
m_tx_basepos = p;
m_anim_num_frames = num_frames;
m_anim_framelength = framelength;
m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch;
updateTexturePos();
}
CAO is "Client Active Object", i.e. we've passed the setsprite command right through to the client without doing anything on the server.
These variables (
m_tx_basepos, etc.) are only ever used to manipulate
m_spritenode, which is an Irrlicht object in class
irr::scene::IBillboardSceneNode. According to the Irrlicht
documentation, this is
"A billboard scene node. / A billboard is like a 3d sprite: A 2d element, which always looks to the camera. It is usually used for explosions, fire, lensflares, particles and things like that."This sounds like just what you want! Unfortunately, there is only one per client, it is a global variable and it is created in
src/content_cso.cpp:
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
class SmokePuffCSO: public ClientSimpleObject
{
float m_age;
scene::IBillboardSceneNode *m_spritenode;
public:
SmokePuffCSO(scene::ISceneManager *smgr,
ClientEnvironment *env, v3f pos, v2f size):
m_age(0),
m_spritenode(NULL)
{
infostream<<"SmokePuffCSO: constructing"<<std::endl;
m_spritenode = smgr->addBillboardSceneNode(
NULL, v2f(1,1), pos, -1);
m_spritenode->setMaterialTexture(0,
env->getGameDef()->tsrc()->getTexture("smoke_puff.png"));
m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
//m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
// [... etc. ]
There is almost identical code in
src/content_cso.cpp, "CSO" is "Client Simple Object".
m_spritenode is referenced in a lot of places but it is only ever initialised as a smoke puff. Since there is one per client, it seems it is only ever used for the "you just killed something" animation. That must be what the lua
setsprite function does. I can guess that the basepos tells where within the texture the first frame is derived, there are some clues to this in
lua_api.txt if you look for "sprite", you'll find
spritediv and
initial_sprite_basepos mentioned in the object properties along with more familiar things like
hp_max and
collisionbox.
So if you don't like the smoke puff, you can change it with
setsprite, but I doubt you can get this sprite to be used for anything other than showing the result of a kill.
We also find the following in
lua_api.txt :
Entity damage mechanism
[…]
Client predicts damage based on damage groups. Because of this, it is able to give an immediate response when an entity is damaged or dies; the response is pre-defined somehow (e.g. by defining a sprite animation) (not implemented; TODO).
Currently a smoke puff will appear when an entity dies.
which pretty much confirms this is what
setsprite was intended for.
You might be able to use it to define mobs that are displayed as billboards, i.e. flat cardboard stand-ups like in early versions of Minetest, and if you did that, the mob's 2D appearance could be animated. But I don't see how it could work, since there is only ever one
m_spritenode in the client; and we've moved away from that, I think everyone wants their mobs to be 3-D animated now.