Redesign of animation queue for unreal, add get_tangibles_near to drivenengine

This commit is contained in:
2023-07-24 17:19:25 -04:00
parent 4da86e6f89
commit 87aa47b96d
19 changed files with 1406 additions and 980 deletions

View File

@@ -17,56 +17,169 @@ static void tangible_getall(LuaCoreStack &LS0, LuaSlot list, const util::IdVecto
}
}
LuaDefine(tangible_animstate, "tan",
"|Get the entire animation state of the tangible."
"|Returns six values: graphic,plane,x,y,z,facing.") {
LuaArg tanobj;
LuaRet graphic, plane, x, y, z, facing;
LuaDefStack LS(L, tanobj, graphic, plane, x, y, z, facing);
World *w = World::fetch_global_pointer(L);
Tangible *tan = w->tangible_get(LS, tanobj, false);
const AnimStep &aqback = tan->anim_queue_.back();
LS.set(graphic, aqback.graphic());
LS.set(plane, aqback.plane());
LS.set(x, aqback.xyz().x);
LS.set(y, aqback.xyz().y);
LS.set(z, aqback.xyz().z);
LS.set(facing, aqback.facing());
return LS.result();
}
LuaDefine(tangible_xyz, "tan",
"|Get the current coordinates of the tangible."
"|Returns three values: x, y, z") {
"|Get the current coordinates of the tangible and the plane."
"|Returns four values: x, y, z, plane") {
LuaArg tanobj;
LuaRet x, y, z;
LuaRet x, y, z, plane;
LuaDefStack LS(L, tanobj, x, y, z);
World *w = World::fetch_global_pointer(L);
Tangible *tan = w->tangible_get(LS, tanobj, false);
const AnimStep &aqback = tan->anim_queue_.back();
LS.set(x, aqback.xyz().x);
LS.set(y, aqback.xyz().y);
LS.set(z, aqback.xyz().z);
AnimCoreState pos = tan->anim_queue_.get_final_core_state();
LS.set(x, pos.xyz.x);
LS.set(y, pos.xyz.y);
LS.set(z, pos.xyz.z);
LS.set(plane, pos.plane);
return LS.result();
}
LuaDefine(tangible_animate, "tan,configtable",
"|Add an animation step to the tangible."
"|The configtable is a table containing any of the following:"
"|action,graphic,plane,x,y,z,facing") {
LuaArg tanobj, config;
LuaDefStack LS(L, tanobj, config);
LuaKeywordParser kp(LS, config);
LuaDefine(tangible_animdebug, "tan",
"|Return a debug string showing the entire animation queue"
"|") {
LuaArg tanobj;
LuaRet result;
LuaDefStack LS(L, tanobj, result);
World *w = World::fetch_global_pointer(L);
Tangible *tan = w->tangible_get(LS, tanobj, false);
int64_t id = w->alloc_id_predictable();
AnimStep step;
step.configure(kp, tan->anim_queue_.back());
kp.final_check_throw();
if (step.action() == "") {
luaL_error(L, "animation action must be specified");
LS.set(result, tan->anim_queue_.steps_debug_string());
return LS.result();
}
LuaDefine(tangible_animstate, "tan",
"|Return the animation state variables of the tangible as a table."
"|"
"|The animation system stores 'animation state variables. "
"|There are several builtin animation state variables. The"
"|following is a list, along with some example values that"
"|might be used if the object were a pirate treasure chest."
"|"
"| xyz={1,2,3} # xyz coordinate"
"| plane='earth' # plane where the chest is located"
"| facing=0 # rotation of the chest"
"| bp='BP_piratechest' # name of an unreal blueprint"
"| model='SM_piratechest' # name of an unreal mesh"
"|"
"|There can also be user-defined animation state variables."
"|For example, for a pirate chest, you might want to add two"
"|more state variables:"
"|"
"| open=true # chest can be open or closed"
"| fullness=0.8 # how big the heap of coins is"
"|"
"|All state variables must be one of four types: number, string,"
"|boolean, or coordinate. All state variables must have simple"
"|identifiers for names."
"|"
"|Animation state variables are updated when you use"
"|tangible.animate to create an animation record. For example,"
"|suppose your character is initialized at xyz={1,1,1}. Then"
"|he walks to xyz={2,2,2}, then he walks to xyz={3,3,3}."
"|The animation queue now contains three animation steps:"
"|"
"|Animation Queue:"
"| Step 1: action:initialize xyz={1,1,1} ..."
"| Step 2: action:walkto xyz={2,2,2} ..."
"| Step 3: action:walkto xyz={3,3,3} ..."
"|"
"|Notice that the state variable xyz is stored three times, once"
"|in each animation step. All animation state variables are stored"
"|in every animation step. When you use tangible.animstate to fetch"
"|the current value of the animation state variables, you're"
"|actually fetching the state variables from the last step in"
"|the animation queue."
"|"
"|You can use this function, tangible.animstate, to view the"
"|current set of state variables. You can use tangible.animinit"
"|to reconfigure the set of user-defined state variables. You"
"|can use tangible.animate to create animation steps, which can"
"|alter any of the state variables."
"|") {
LuaArg tanobj;
LuaRet result;
LuaDefStack LS(L, tanobj, result);
World *w = World::fetch_global_pointer(L);
Tangible *tan = w->tangible_get(LS, tanobj, false);
AnimState state = tan->anim_queue_.get_final_persistent();
state.to_lua(LS, result, true);
return LS.result();
}
LuaDefine(tangible_animinit, "tan,config",
"|Reinitialize the animation queue."
"|"
"|The animation queue stores certain animation state variables."
"|See doc(tangible.animstate) for more information about animation"
"|state variables."
"|"
"|This function, tangible.animinit, is used to reconfigure the set of"
"|user-defined state variables. The config table that you pass in must"
"|be key-value pairs. Keys must be simple identifiers. Values can be"
"|numbers, strings, booleans, or coordinates."
"|"
"|After tangible.animinit, the tangible's animation state variables will"
"|consist of the user-defined variables listed in the config table,"
"|plus all the builtin animation state variables."
"|"
"|Optionally, the config table can also supply values for some or all"
"|of the builtin state variables. For example, you could supply xyz"
"|in the config table. If you do, the tangible will move to a new xyz"
"|coordinate. If not, the tangible will retain its old xyz coordinate."
"|") {
LuaArg tanobj, config;
LuaDefStack LS(L, tanobj, config);
World *w = World::fetch_global_pointer(L);
Tangible *tan = w->tangible_get(LS, tanobj, false);
AnimState state;
eng::string error = state.apply_lua(LS, config, true);
if (!error.empty()) {
luaL_error(L, "%s", error.c_str());
}
tan->anim_queue_.add(id, step);
AnimState defsource = tan->anim_queue_.get_final_persistent();
error = state.add_defaults(&defsource);
if (!error.empty()) {
luaL_error(L, "%s", error.c_str());
}
tan->anim_queue_.clear(state);
tan->update_plane_item();
return LS.result();
}
LuaDefine(tangible_animate, "tan,config",
"|Add an animation step to the tangible."
"|"
"|The animation queue stores animation steps. This function, "
"|tangible.animate, adds one new animation step to the queue."
"|"
"|It might be useful to read about 'animation state variables' before"
"|reading this explanation. See doc(tangible.animstate)."
"|"
"|An animation step is just a list of key-value pairs. Therefore,"
"|the config table must be key-value pairs. Keys must be simple"
"|identifiers. Values can be numbers, strings, booleans, or"
"|coordinates."
"|"
"|Some of the key-value pairs may match the name of an animation state"
"|variable. If so, that key-value pair permanently changes the"
"|value of that animation state variable. The new value will"
"|be retained for all future animation steps."
"|"
"|Some of the key-value pairs may NOT match the name of any animation"
"|state variable. If so, that key-value pair is part of the"
"|animation step, but nothing is propagated forward to future animation"
"|steps."
"|"
"|") {
LuaArg tanobj, config;
LuaDefStack LS(L, tanobj, config);
World *w = World::fetch_global_pointer(L);
Tangible *tan = w->tangible_get(LS, tanobj, false);
AnimState state = tan->anim_queue_.get_final_persistent();
eng::string error = state.apply_lua(LS, config, false);
if (!error.empty()) {
luaL_error(L, "%s", error.c_str());
}
tan->anim_queue_.add(state);
tan->update_plane_item();
return LS.result();
}
@@ -132,51 +245,53 @@ LuaDefine(tangible_delete, "tan",
LuaDefine(tangible_build, "config",
"|Build a new tangible object."
"|The config table must contain: class,x,y,z,plane,graphic."
"|The config table can optionally contain: facing.") {
"|"
"|The config table must contain: class,animstate."
"|" ){
LuaArg config;
LuaVar classname, classtab, mt;
LuaVar classname, classtab, mt, animstate;
LuaRet database;
LuaDefStack LS(L, config, classname, classtab, database, mt);
LuaDefStack LS(L, config, classname, classtab, database, mt, animstate);
LuaKeywordParser kp(LS, config);
// Get the class of the new tangible.
// Get the keyword arguments.
if (!kp.parse(classname, "class")) {
luaL_error(L, "You must specify a class for the tangible");
}
if (!kp.parse(animstate, "animstate")) {
luaL_error(L, "You must specify an animstate table");
}
kp.final_check_throw();
// Find the class.
eng::string err = LS.getclass(classtab, classname);
if (err != "") {
luaL_error(L, "%s", err.c_str());
}
// Parse the initial animation step.
AnimStep initstep, blank;
initstep.configure(kp, blank);
kp.final_check_throw();
if (!initstep.has_xyz()) {
luaL_error(L, "You must specify (X,Y,Z) for new tangible");
// Calculate the initial animation state.
AnimState state;
err = state.apply_lua(LS, animstate, true);
if (err != "") {
luaL_error(L, "%s", err.c_str());
}
if (!initstep.has_plane()) {
luaL_error(L, "You must specify plane for new tangible");
if (!state.contains("xyz") || !state.contains("plane")) {
luaL_error(L, "You must specify both xyz and plane in animstate");
}
if (!initstep.has_graphic()) {
luaL_error(L, "You must specify graphic for new tangible");
err = state.add_defaults(nullptr);
if (err != "") {
luaL_error(L, "%s", err.c_str());
}
// TODO: generate error if there's extra crap in the config table.
World *w = World::fetch_global_pointer(L);
int64_t new_id = w->alloc_id_predictable();
Tangible *tan = w->tangible_make(LS, database, new_id, "nowhere");
Tangible *tan = w->tangible_make(LS, database, new_id);
// Update the class of the new tangible.
LS.getmetatable(mt, database);
LS.rawset(mt, "__index", classtab);
// Update the animation queue and planemap of the new tangible.
int64_t stepid = w->alloc_id_predictable();
tan->anim_queue_.add(stepid, initstep);
tan->update_plane_item();
tan->anim_queue_.clear(state);
return LS.result();
}
@@ -259,34 +374,27 @@ LuaDefine(tangible_place, "",
}
LuaDefine(tangible_near, "tan,radius,omit_nowhere,omit_self",
"|Scan near the specified tangible."
"|If omit_nowhere is true, and the tangible is on the nowhere plane,"
"|then the scan returns empty. If omit_self is true, then the "
"|tangible passed in is omitted from the results.") {
"|Deprecated. Use tangible.find instead.") {
LuaArg ltan, lradius, lomit_nowhere, lomit_self;
LuaRet list;
LuaDefStack LS(L, ltan, lradius, lomit_nowhere, lomit_self, list);
World *w = World::fetch_global_pointer(L);
Tangible *tan = w->tangible_get(LS, ltan, false);
const AnimStep &aqback = tan->anim_queue_.back();
PlaneScan scan;
scan.set_plane(aqback.plane());
scan.set_bbox_given_center_radius(aqback.xyz(), LS.cknumber(lradius));
scan.set_radius(LS.cknumber(lradius));
scan.set_shape(PlaneScan::SPHERE);
scan.set_sorted(true);
scan.set_near(tan->id(), !LS.ckboolean(lomit_self));
scan.set_omit_nowhere(LS.ckboolean(lomit_nowhere));
util::IdVector idv = w->plane_map_.scan(scan);
util::IdVector idv;
w->get_near(scan, &idv);
tangible_getall(LS, list, idv);
return LS.result();
}
LuaDefine(tangible_scan, "plane,x,y,radius,omit_nowhere",
"|Scan the specified plane."
"|If omit_nowhere is true, and the plane is 'nowhere', then"
"|the scan returns empty.") {
"|Deprecated. Use tangible.find instead.") {
LuaArg lplane, lx, ly, lradius, lomit_nowhere;
LuaRet list;
LuaDefStack LS(L, lplane, lx, ly, lradius, lomit_nowhere, list);
@@ -294,12 +402,13 @@ LuaDefine(tangible_scan, "plane,x,y,radius,omit_nowhere",
PlaneScan scan;
scan.set_plane(LS.ckstring(lplane));
scan.set_bbox_given_center_radius(util::XYZ(LS.cknumber(lx), LS.cknumber(ly), 0), LS.cknumber(lradius));
scan.set_center_and_radius(util::XYZ(LS.cknumber(lx), LS.cknumber(ly), 0), LS.cknumber(lradius));
scan.set_shape(PlaneScan::SPHERE);
scan.set_sorted(true);
scan.set_omit_nowhere(LS.ckboolean(lomit_nowhere));
util::IdVector idv = w->plane_map_.scan(scan);
util::IdVector idv;
w->get_near(scan, &idv);
tangible_getall(LS, list, idv);
return LS.result();
}
@@ -369,21 +478,9 @@ LuaDefine(tangible_find, "config",
scan.configure(kw);
kw.final_check_throw();
// When the configure routine sees the 'near' flag, it stores the tangible
// ID, but not the center and plane, because doing so would require it to
// know about world models. We have to handle center and plane for 'near'
// separately.
World *w = World::fetch_global_pointer(L);
int64_t near = scan.near();
if (near != 0) {
Tangible *t = w->tangible_get(near);
assert(t != nullptr); // Should never happen.
const AnimStep &aqback = t->anim_queue_.back();
scan.set_plane(aqback.plane());
scan.set_center(aqback.xyz());
}
// Do the scan.
util::IdVector idv = w->plane_map_.scan(scan);
util::IdVector idv;
w->get_near(scan, &idv);
tangible_getall(LS, result, idv);
return LS.result();
}