diff --git a/Documentation/ScriptingAPI-Documentation.md b/Documentation/ScriptingAPI-Documentation.md index 8ba4ff8c8..0b1fa089f 100644 --- a/Documentation/ScriptingAPI-Documentation.md +++ b/Documentation/ScriptingAPI-Documentation.md @@ -523,6 +523,10 @@ Describes an orientation in 3D space. - SetLooped(bool value) - IsLooped() : bool result - IsPlaying() : bool result +- SetTimer(float value) +- GetTimer() : float result +- SetAmount(float value) +- GetAmount() : float result #### MaterialComponent - SetBaseColor(Vector value) diff --git a/Editor/AnimationWindow.cpp b/Editor/AnimationWindow.cpp index 212893a8c..2fd3ab33e 100644 --- a/Editor/AnimationWindow.cpp +++ b/Editor/AnimationWindow.cpp @@ -56,6 +56,7 @@ AnimationWindow::AnimationWindow(EditorComponent* editor) : GUI(&editor->GetGUI( else { animation->Play(); + animation->amount = 0; } } }); @@ -87,6 +88,20 @@ AnimationWindow::AnimationWindow(EditorComponent* editor) : GUI(&editor->GetGUI( timerSlider->SetTooltip("Set the animation timer by hand."); animWindow->AddWidget(timerSlider); + amountSlider = new wiSlider(0, 1, 0, 100000, "Amount: "); + amountSlider->SetSize(XMFLOAT2(250, 30)); + amountSlider->SetPos(XMFLOAT2(x, y += step)); + amountSlider->OnSlide([&](wiEventArgs args) { + AnimationComponent* animation = wiScene::GetScene().animations.GetComponent(entity); + if (animation != nullptr) + { + animation->amount = args.fValue; + } + }); + amountSlider->SetEnabled(false); + amountSlider->SetTooltip("Set the animation blending amount by hand."); + animWindow->AddWidget(amountSlider); + animWindow->Translate(XMFLOAT3(100, 50, 0)); @@ -153,6 +168,7 @@ void AnimationWindow::Update() if (animation.IsPlaying()) { playButton->SetText("Pause"); + animation.amount = wiMath::Lerp(animation.amount, 1, 0.1f); } else { @@ -163,5 +179,6 @@ void AnimationWindow::Update() timerSlider->SetRange(0, animation.GetLength()); timerSlider->SetValue(animation.timer); + amountSlider->SetValue(animation.amount); } } diff --git a/Editor/AnimationWindow.h b/Editor/AnimationWindow.h index 770f9363a..213ad33d8 100644 --- a/Editor/AnimationWindow.h +++ b/Editor/AnimationWindow.h @@ -26,6 +26,7 @@ public: wiButton* playButton; wiButton* stopButton; wiSlider* timerSlider; + wiSlider* amountSlider; void Update(); }; diff --git a/WickedEngine/ArchiveVersionHistory.txt b/WickedEngine/ArchiveVersionHistory.txt index 61d7c5566..cfef6588c 100644 --- a/WickedEngine/ArchiveVersionHistory.txt +++ b/WickedEngine/ArchiveVersionHistory.txt @@ -1,5 +1,6 @@ This file contains changelog of wiArchive versions +44: Serialized AnimationComponent::amount 43: Serialized MeshComponent::vertex_windweights 42: Serialized hair particle sprite sheet properties 41: Serialized terrain blend materials in MeshComponent diff --git a/WickedEngine/wiArchive.cpp b/WickedEngine/wiArchive.cpp index 153d8cf95..d7d6e9071 100644 --- a/WickedEngine/wiArchive.cpp +++ b/WickedEngine/wiArchive.cpp @@ -7,7 +7,7 @@ using namespace std; // this should always be only INCREMENTED and only if a new serialization is implemeted somewhere! -uint64_t __archiveVersion = 43; +uint64_t __archiveVersion = 44; // this is the version number of which below the archive is not compatible with the current version uint64_t __archiveVersionBarrier = 22; diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index cafdeb552..52c87c6a7 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -1672,7 +1672,8 @@ namespace wiScene float left = sampler.keyframe_times[keyLeft]; - TransformComponent& transform = *transforms.GetComponent(channel.target); + TransformComponent& target_transform = *transforms.GetComponent(channel.target); + TransformComponent transform = target_transform; if (sampler.mode == AnimationComponent::AnimationSampler::Mode::STEP || keyLeft == keyRight) { @@ -1741,7 +1742,25 @@ namespace wiScene } } - transform.SetDirty(); + target_transform.SetDirty(); + + const float t = animation.amount; + + const XMVECTOR aS = XMLoadFloat3(&target_transform.scale_local); + const XMVECTOR aR = XMLoadFloat4(&target_transform.rotation_local); + const XMVECTOR aT = XMLoadFloat3(&target_transform.translation_local); + + const XMVECTOR bS = XMLoadFloat3(&transform.scale_local); + const XMVECTOR bR = XMLoadFloat4(&transform.rotation_local); + const XMVECTOR bT = XMLoadFloat3(&transform.translation_local); + + const XMVECTOR S = XMVectorLerp(aS, bS, t); + const XMVECTOR R = XMQuaternionSlerp(aR, bR, t); + const XMVECTOR T = XMVectorLerp(aT, bT, t); + + XMStoreFloat3(&target_transform.scale_local, S); + XMStoreFloat4(&target_transform.rotation_local, R); + XMStoreFloat3(&target_transform.translation_local, T); } diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index ae5ea87ca..077fee6d0 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -873,7 +873,8 @@ namespace wiScene uint32_t _flags = LOOPED; float start = 0; float end = 0; - float timer = 0.0f; + float timer = 0; + float amount = 1; struct AnimationChannel { diff --git a/WickedEngine/wiScene_BindLua.cpp b/WickedEngine/wiScene_BindLua.cpp index e30932363..20bdd298a 100644 --- a/WickedEngine/wiScene_BindLua.cpp +++ b/WickedEngine/wiScene_BindLua.cpp @@ -1535,6 +1535,10 @@ Luna::FunctionType AnimationComponent_BindLua::metho lunamethod(AnimationComponent_BindLua, IsLooped), lunamethod(AnimationComponent_BindLua, IsPlaying), lunamethod(AnimationComponent_BindLua, IsEnded), + lunamethod(AnimationComponent_BindLua, SetTimer), + lunamethod(AnimationComponent_BindLua, GetTimer), + lunamethod(AnimationComponent_BindLua, SetAmount), + lunamethod(AnimationComponent_BindLua, GetAmount), { NULL, NULL } }; Luna::PropertyType AnimationComponent_BindLua::properties[] = { @@ -1598,6 +1602,44 @@ int AnimationComponent_BindLua::IsEnded(lua_State* L) wiLua::SSetBool(L, component->IsEnded()); return 1; } +int AnimationComponent_BindLua::SetTimer(lua_State* L) +{ + int argc = wiLua::SGetArgCount(L); + if (argc > 0) + { + float value = wiLua::SGetFloat(L, 1); + component->timer = value; + } + else + { + wiLua::SError(L, "SetTimer(float value) not enough arguments!"); + } + return 0; +} +int AnimationComponent_BindLua::GetTimer(lua_State* L) +{ + wiLua::SSetFloat(L, component->timer); + return 1; +} +int AnimationComponent_BindLua::SetAmount(lua_State* L) +{ + int argc = wiLua::SGetArgCount(L); + if (argc > 0) + { + float value = wiLua::SGetFloat(L, 1); + component->amount = value; + } + else + { + wiLua::SError(L, "SetAmount(float value) not enough arguments!"); + } + return 0; +} +int AnimationComponent_BindLua::GetAmount(lua_State* L) +{ + wiLua::SSetFloat(L, component->amount); + return 1; +} diff --git a/WickedEngine/wiScene_BindLua.h b/WickedEngine/wiScene_BindLua.h index 412cc016c..bdb1aba7c 100644 --- a/WickedEngine/wiScene_BindLua.h +++ b/WickedEngine/wiScene_BindLua.h @@ -193,6 +193,10 @@ namespace wiScene_BindLua int IsLooped(lua_State* L); int IsPlaying(lua_State* L); int IsEnded(lua_State* L); + int SetTimer(lua_State* L); + int GetTimer(lua_State* L); + int SetAmount(lua_State* L); + int GetAmount(lua_State* L); }; class MaterialComponent_BindLua diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index 3a1c8cc59..e2dfb5546 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -636,6 +636,11 @@ namespace wiScene archive >> end; archive >> timer; + if (archive.GetVersion() >= 44) + { + archive >> amount; + } + size_t channelCount; archive >> channelCount; channels.resize(channelCount); @@ -666,6 +671,11 @@ namespace wiScene archive << end; archive << timer; + if (archive.GetVersion() >= 44) + { + archive << amount; + } + archive << channels.size(); for (size_t i = 0; i < channels.size(); ++i) { diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 1104f6b61..5a7598c3d 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 39; // minor bug fixes, alterations, refactors, updates - const int revision = 67; + const int revision = 68; long GetVersion() diff --git a/scripts/character_controller_tps.lua b/scripts/character_controller_tps.lua index f77eb7cae..4ebf42677 100644 --- a/scripts/character_controller_tps.lua +++ b/scripts/character_controller_tps.lua @@ -40,6 +40,7 @@ Character = { JUMP = 2, }, state = STAND, + state_prev = STAND, Create = function(self,entity) self.model = entity @@ -93,33 +94,30 @@ Character = { Input = function(self) - if(self.state==self.states.STAND) then - local lookDir = Vector() - if(input.Down(KEYBOARD_BUTTON_LEFT) or input.Down(string.byte('A'))) then - lookDir = lookDir:Add( Vector(-1) ) - end - if(input.Down(KEYBOARD_BUTTON_RIGHT) or input.Down(string.byte('D'))) then - lookDir = lookDir:Add( Vector(1) ) - end + local lookDir = Vector() + if(input.Down(KEYBOARD_BUTTON_LEFT) or input.Down(string.byte('A'))) then + lookDir = lookDir:Add( Vector(-1) ) + end + if(input.Down(KEYBOARD_BUTTON_RIGHT) or input.Down(string.byte('D'))) then + lookDir = lookDir:Add( Vector(1) ) + end - if(input.Down(KEYBOARD_BUTTON_UP) or input.Down(string.byte('W'))) then - lookDir = lookDir:Add( Vector(0,0,1) ) - end - if(input.Down(KEYBOARD_BUTTON_DOWN) or input.Down(string.byte('S'))) then - lookDir = lookDir:Add( Vector(0,0,-1) ) - end + if(input.Down(KEYBOARD_BUTTON_UP) or input.Down(string.byte('W'))) then + lookDir = lookDir:Add( Vector(0,0,1) ) + end + if(input.Down(KEYBOARD_BUTTON_DOWN) or input.Down(string.byte('S'))) then + lookDir = lookDir:Add( Vector(0,0,-1) ) + end - local analog = input.GetAnalog(GAMEPAD_ANALOG_THUMBSTICK_L) - lookDir = vector.Add(lookDir, Vector(analog.GetX(), 0, analog.GetY())) + local analog = input.GetAnalog(GAMEPAD_ANALOG_THUMBSTICK_L) + lookDir = vector.Add(lookDir, Vector(analog.GetX(), 0, analog.GetY())) - if(lookDir:Length()>0) then - if(input.Down(KEYBOARD_BUTTON_LSHIFT) or input.Down(GAMEPAD_BUTTON_6)) then - self:MoveDirection(lookDir,self.moveSpeed*2) - else - self:MoveDirection(lookDir,self.moveSpeed) - end + if(lookDir:Length()>0) then + if(input.Down(KEYBOARD_BUTTON_LSHIFT) or input.Down(GAMEPAD_BUTTON_6)) then + self:MoveDirection(lookDir,self.moveSpeed*2) + else + self:MoveDirection(lookDir,self.moveSpeed) end - end if( input.Press(string.byte('J')) or input.Press(KEYBOARD_BUTTON_SPACE) or input.Press(GAMEPAD_BUTTON_2) ) then @@ -157,7 +155,7 @@ Character = { local target_transform = scene.Component_GetTransform(self.target) -- gravity: - self.force = vector.Add(self.force, Vector(0,-9.8 * 10,0)) + self.force = vector.Add(self.force, Vector(0,-9.8 * 20,0)) -- apply force: self.velocity = vector.Add(self.velocity, vector.Multiply(self.force, getDeltaTime())) @@ -165,18 +163,31 @@ Character = { -- state and animation update if(self.state == self.states.STAND) then - scene.Component_GetAnimation(self.idle_anim).Play() scene.Component_GetAnimation(self.walk_anim).Stop() - self.state = self.states.STAND + local anim = scene.Component_GetAnimation(self.idle_anim) + anim.Play() + anim.SetAmount(math.lerp(anim.GetAmount(), 1, 0.1)) + if(self.state ~= self.state_prev) then + anim.SetAmount(0) + end elseif(self.state == self.states.WALK) then scene.Component_GetAnimation(self.idle_anim).Stop() - scene.Component_GetAnimation(self.walk_anim).Play() - self.state = self.states.STAND + local anim = scene.Component_GetAnimation(self.walk_anim) + anim.Play() + anim.SetAmount(math.lerp(anim.GetAmount(), 1, 0.1)) + if(self.state ~= self.state_prev) then + anim.SetAmount(0) + end elseif(self.state == self.states.JUMP) then - scene.Component_GetAnimation(self.idle_anim).Play() scene.Component_GetAnimation(self.walk_anim).Stop() - self.state = self.states.STAND + local anim = scene.Component_GetAnimation(self.idle_anim) + anim.Play() + anim.SetAmount(math.lerp(anim.GetAmount(), 1, 0.1)) + if(self.state ~= self.state_prev) then + anim.SetAmount(0) + end end + self.state_prev = self.state -- front block shoots multiple rays in front to try to find obstruction local rotations = {0, 3.1415*0.3, -3.1415*0.3} @@ -228,7 +239,7 @@ Character = { self.velocity.SetY(0) -- don't fall below ground self.velocity = vector.Multiply(self.velocity, 0.8) -- slow down on ground else - self.velocity = vector.Multiply(self.velocity, 0.96) -- slow down in air + self.velocity = vector.Multiply(self.velocity, 0.94) -- slow down in air end end @@ -368,9 +379,11 @@ runProcess(function() while true do - player:Input() - player:Update() + + fixedupdate() + + player:Input() camera:Update() diff --git a/scripts/fighting_game.lua b/scripts/fighting_game.lua index 271886ff1..45e2d2dc0 100644 --- a/scripts/fighting_game.lua +++ b/scripts/fighting_game.lua @@ -1181,7 +1181,9 @@ local function Character(face, skin_color, shirt_color, hair_color, shoe_color) end, -- Starts a new state: StartState = function(self, dst_state) - scene.Component_GetAnimation(self.states[dst_state].anim).Play() + local anim = scene.Component_GetAnimation(self.states[dst_state].anim) + anim.Play() + anim.SetAmount(0) self.frame = 0 self.state = dst_state self.hitconfirms = {} @@ -1210,6 +1212,11 @@ local function Character(face, skin_color, shirt_color, hair_color, shoe_color) end end + -- Animation blending: + local anim = scene.Component_GetAnimation(self.states[self.state].anim) + local anim_amount = anim.GetAmount() + anim.SetAmount(math.lerp(anim_amount, 1, 0.2)) + -- Execute the currently active state: local current_state = self.states[self.state] if(current_state ~= nil) then