Character walking is fixed, using the new Movement Component State model.
This commit is contained in:
@@ -100,6 +100,10 @@ Look-at widgets, hotkeys, and menus are built on top of this. The menu system is
|
|||||||
- `Docs/Correct Implementation of Blocking Operations and NoPredict.md` — how to handle blocking ops
|
- `Docs/Correct Implementation of Blocking Operations and NoPredict.md` — how to handle blocking ops
|
||||||
- `Docs/Difference Transmission with Threads.md` — why concurrent diff transmission is hard
|
- `Docs/Difference Transmission with Threads.md` — why concurrent diff transmission is hard
|
||||||
|
|
||||||
|
## Blueprint Coding Conventions
|
||||||
|
|
||||||
|
- When writing UFUNCTIONs that take an `AActor*`, `UObject*`, or similar "self" parameter, add `DefaultToSelf` meta to that pin. Most functions should have this on the obvious pin so the user doesn't have to manually wire it in blueprints.
|
||||||
|
|
||||||
## Session Startup
|
## Session Startup
|
||||||
|
|
||||||
At the beginning of every session, do a directory listing of these three directories so you know what files are available:
|
At the beginning of every session, do a directory listing of these three directories so you know what files are available:
|
||||||
|
|||||||
Binary file not shown.
@@ -272,9 +272,9 @@ It is perfectly safe to call FinishedAnimation from anywhere. You can call it fr
|
|||||||
|
|
||||||
Some animations are instantaneous, such as "warpto." They take zero frames to complete. The following sequence of events occurs: the lua code pushes the "warpto" animation into the queue. The Unreal C++ code sees this and calls *AnimationQueueChanged*. This, in turn, calls *Init Action: Warpto*. That routine actually performs the warpto, and then calls *FinishedAnimation* immediately. So it's even fine to call *FinishedAnimation* directly from the routine that initiates an animation, if you want the animation to be finished as soon as it starts.
|
Some animations are instantaneous, such as "warpto." They take zero frames to complete. The following sequence of events occurs: the lua code pushes the "warpto" animation into the queue. The Unreal C++ code sees this and calls *AnimationQueueChanged*. This, in turn, calls *Init Action: Warpto*. That routine actually performs the warpto, and then calls *FinishedAnimation* immediately. So it's even fine to call *FinishedAnimation* directly from the routine that initiates an animation, if you want the animation to be finished as soon as it starts.
|
||||||
|
|
||||||
The routine FinishAnimation takes an *lxAnimationStep* as a parameter. This is so that it knows which animation step to mark as finished. TangibleStaticMesh always passes in the variable *CurrentAnimation*.
|
The routine FinishedAnimation takes an *lxAnimationStep* as a parameter. This is so that it knows which animation step to mark as finished. TangibleStaticMesh always passes in the variable *CurrentAnimation*.
|
||||||
|
|
||||||
*FinishAnimation* also takes three boolean parameters: Auto Update XYZ, Auto Update Plane, and Auto Update Facing. These require some explanation. Suppose that the lua programmer pushes an animation step that looks like this:
|
*FinishedAnimation* also takes three boolean parameters: Auto Update XYZ, Auto Update Plane, and Auto Update Facing. These require some explanation. Suppose that the lua programmer pushes an animation step that looks like this:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
tangible.animate{tan=actor, anim={action="emote", animation="dance", xyz={1,2,3}}}
|
tangible.animate{tan=actor, anim={action="emote", animation="dance", xyz={1,2,3}}}
|
||||||
@@ -284,7 +284,7 @@ Since "play an emote" isn't a travel command like "moveto" or "warpto", the lua
|
|||||||
|
|
||||||
The convention that we have adopted is that to recover from this type of mistake, it is considered acceptable to just play the emote in-place (ie, without moving the actor), then, when the emote is fully finished, the blueprint warps the player to the specified XYZ coordinate. In other words, every animation step is treated as if it has an *implicit* "warpto" at the end of it. This rule guarantees that if the lua programmer sets the xyz, facing, or plane in an animation step, the character will end up at the desired xyz, facing, and plane, no matter what the animation step is.
|
The convention that we have adopted is that to recover from this type of mistake, it is considered acceptable to just play the emote in-place (ie, without moving the actor), then, when the emote is fully finished, the blueprint warps the player to the specified XYZ coordinate. In other words, every animation step is treated as if it has an *implicit* "warpto" at the end of it. This rule guarantees that if the lua programmer sets the xyz, facing, or plane in an animation step, the character will end up at the desired xyz, facing, and plane, no matter what the animation step is.
|
||||||
|
|
||||||
That's why *FinishAnimation* has those three boolean flags: Auto Update XYZ, Auto Update Plane, Auto Update Facing. If those are all true – and they almost always should be – then *FinishAnimation* will implement the implicit "warpto" for you. I cannot think of a situation where you would want these flags to be false, but I have left the option, in case somebody wants to do something odd in a Tangible Actor.
|
That's why *FinishedAnimation* has those three boolean flags: Auto Update XYZ, Auto Update Plane, Auto Update Facing. If those are all true – and they almost always should be – then *FinishedAnimation* will implement the implicit "warpto" for you. I cannot think of a situation where you would want these flags to be false, but I have left the option, in case somebody wants to do something odd in a Tangible Actor.
|
||||||
|
|
||||||
## How Tangible Actors handle Warping Away
|
## How Tangible Actors handle Warping Away
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ ELogVerbosity::Type UlxBlueprintErrorLibrary::ConvertElxLogVerbosity(ElxLogVerbo
|
|||||||
case ElxLogVerbosity::Warning: return ELogVerbosity::Warning;
|
case ElxLogVerbosity::Warning: return ELogVerbosity::Warning;
|
||||||
case ElxLogVerbosity::Display: return ELogVerbosity::Display;
|
case ElxLogVerbosity::Display: return ELogVerbosity::Display;
|
||||||
case ElxLogVerbosity::Log: return ELogVerbosity::Log;
|
case ElxLogVerbosity::Log: return ELogVerbosity::Log;
|
||||||
|
case ElxLogVerbosity::ThrottledDisplay: return ELogVerbosity::Display;
|
||||||
|
case ElxLogVerbosity::ThrottledLog: return ELogVerbosity::Log;
|
||||||
case ElxLogVerbosity::Verbose: return ELogVerbosity::Verbose;
|
case ElxLogVerbosity::Verbose: return ELogVerbosity::Verbose;
|
||||||
case ElxLogVerbosity::VeryVerbose: return ELogVerbosity::VeryVerbose;
|
case ElxLogVerbosity::VeryVerbose: return ELogVerbosity::VeryVerbose;
|
||||||
case ElxLogVerbosity::Fatal: return ELogVerbosity::Fatal;
|
case ElxLogVerbosity::Fatal: return ELogVerbosity::Fatal;
|
||||||
|
|||||||
@@ -24,6 +24,10 @@
|
|||||||
* Unfortunately, that means the numeric values of the two enums don't match up,
|
* Unfortunately, that means the numeric values of the two enums don't match up,
|
||||||
* so we will need a conversion function.
|
* so we will need a conversion function.
|
||||||
*
|
*
|
||||||
|
* ThrottledDisplay and ThrottledLog are not present in ELogVerbosity. They
|
||||||
|
* behave like Display and Log respectively, but suppress repeated messages
|
||||||
|
* with the same format pattern, logging at most once per second.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -46,6 +50,12 @@ enum class ElxLogVerbosity : uint8 {
|
|||||||
/* Prints a message to the log file, however, it does not print to the console. */
|
/* Prints a message to the log file, however, it does not print to the console. */
|
||||||
Log,
|
Log,
|
||||||
|
|
||||||
|
/* Like Display, but suppresses repeated messages with the same format pattern (at most once per second). */
|
||||||
|
ThrottledDisplay,
|
||||||
|
|
||||||
|
/* Like Log, but suppresses repeated messages with the same format pattern (at most once per second). */
|
||||||
|
ThrottledLog,
|
||||||
|
|
||||||
/* Prints a message to a log file only if Verbose logging is enabled for the given category. This is usually used for detailed logging. */
|
/* Prints a message to a log file only if Verbose logging is enabled for the given category. This is usually used for detailed logging. */
|
||||||
Verbose,
|
Verbose,
|
||||||
|
|
||||||
|
|||||||
@@ -575,6 +575,23 @@ UK2Node_FormatLogMessage::UK2Node_FormatLogMessage(const FObjectInitializer& Obj
|
|||||||
|
|
||||||
void UK2Node_FormatMessage::FormatLogMessageInternal(UObject *Context, ElxLogVerbosity Verbosity, const FString &InPattern, TArray<FFormatArgumentData> InArgs)
|
void UK2Node_FormatMessage::FormatLogMessageInternal(UObject *Context, ElxLogVerbosity Verbosity, const FString &InPattern, TArray<FFormatArgumentData> InArgs)
|
||||||
{
|
{
|
||||||
|
// For throttled verbosity levels, suppress repeated messages with the
|
||||||
|
// same format pattern. We key on the blueprint name + format pattern,
|
||||||
|
// and allow at most one message per second per key.
|
||||||
|
//
|
||||||
|
if (Verbosity == ElxLogVerbosity::ThrottledDisplay || Verbosity == ElxLogVerbosity::ThrottledLog)
|
||||||
|
{
|
||||||
|
static TMap<FString, double> LastLogTime;
|
||||||
|
double Now = FPlatformTime::Seconds();
|
||||||
|
FString Key = Context->GetClass()->GetName() + TEXT("::") + InPattern;
|
||||||
|
double &Last = LastLogTime.FindOrAdd(Key, 0.0);
|
||||||
|
if (Now - Last < 1.0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Last = Now;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate the formatted string.
|
// Generate the formatted string.
|
||||||
//
|
//
|
||||||
FText InPatternText(FText::FromString(InPattern));
|
FText InPatternText(FText::FromString(InPattern));
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ FlxMovementComponentState UlxMovementComponentStateLibrary::SetFakeMovementCompo
|
|||||||
{
|
{
|
||||||
if (!Actor) return State;
|
if (!Actor) return State;
|
||||||
UlxTangible *Tangible = UlxTangible::GetActorTangibleOrLog(Actor);
|
UlxTangible *Tangible = UlxTangible::GetActorTangibleOrLog(Actor);
|
||||||
if (Tangible) Tangible->FakeMovementComponentState = State;
|
if (Tangible)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Display, TEXT("SetFakeMovementComponentState(%s): %s"), *Actor->GetName(), *DebugString(State));
|
||||||
|
Tangible->FakeMovementComponentState = State;
|
||||||
|
}
|
||||||
return State;
|
return State;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,6 +124,6 @@ public:
|
|||||||
// state is usually read by the animation blueprint
|
// state is usually read by the animation blueprint
|
||||||
// when the real movement component is disabled.
|
// when the real movement component is disabled.
|
||||||
//
|
//
|
||||||
UFUNCTION(BlueprintCallable, Category = "Luprex|Movement Component State", meta = (AutoCreateRefTerm = "State"))
|
UFUNCTION(BlueprintCallable, Category = "Luprex|Movement Component State", meta = (DefaultToSelf = "Actor", AutoCreateRefTerm = "State"))
|
||||||
static FlxMovementComponentState SetFakeMovementComponentState(AActor *Actor, const FlxMovementComponentState &State);
|
static FlxMovementComponentState SetFakeMovementComponentState(AActor *Actor, const FlxMovementComponentState &State);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ void UlxTangible::FinishedAnimation(AActor *target, const FlxAnimationStep &step
|
|||||||
tan->AnimTracker.FinishedAnimation(step.Hash);
|
tan->AnimTracker.FinishedAnimation(step.Hash);
|
||||||
if (AutoUpdate) tan->AutoUpdatePosition();
|
if (AutoUpdate) tan->AutoUpdatePosition();
|
||||||
FString DebugString = UlxAnimationStepLibrary::AnimationStepDebugString(step);
|
FString DebugString = UlxAnimationStepLibrary::AnimationStepDebugString(step);
|
||||||
UE_LOG(LogLuprex, Display, TEXT("Animation Finished: %s"), *DebugString);
|
// UE_LOG(LogLuprex, Display, TEXT("FinishedAnimation: %s"), *DebugString);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UlxTangible::AnimationStepIsFinished(AActor *target, const FlxAnimationStep &step)
|
bool UlxTangible::AnimationStepIsFinished(AActor *target, const FlxAnimationStep &step)
|
||||||
|
|||||||
@@ -24,10 +24,15 @@ end
|
|||||||
|
|
||||||
function engio.move(action, xyz, facing)
|
function engio.move(action, xyz, facing)
|
||||||
-- todo: sanity check the parameters.
|
-- todo: sanity check the parameters.
|
||||||
dprint("engio.move ", action, " ", xyz[1], " ", xyz[2], " ", xyz[3])
|
-- dprint("engio.move ", action, " ", xyz[1], " ", xyz[2], " ", xyz[3])
|
||||||
tangible.animate{tan=actor, anim={action=action, interactive=true, xyz=xyz, facing=facing}}
|
tangible.animate{tan=actor, anim={action=action, interactive=true, xyz=xyz, facing=facing}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function moveto(x, y)
|
||||||
|
local z = tangible.animfinal(actor).xyz[3]
|
||||||
|
tangible.animate{tan=actor, anim={action="moveto", xyz={x, y, z}, facing=math.auto}}
|
||||||
|
end
|
||||||
|
|
||||||
function cube.lookhotkeys(keys)
|
function cube.lookhotkeys(keys)
|
||||||
keys:add("Z", "Cube Hi", function () dprint("Doing Cube Hi") end)
|
keys:add("Z", "Cube Hi", function () dprint("Doing Cube Hi") end)
|
||||||
keys:add("X", "Cube Bye", function () dprint("Doing Cube Bye") end)
|
keys:add("X", "Cube Bye", function () dprint("Doing Cube Bye") end)
|
||||||
|
|||||||
Reference in New Issue
Block a user