--[[ Set every name of character who should be able to turn smooth
Examples:
smt_allChars = {"Car"}
smt_allChars = {"Hero", "Car"}
--]]
smt_allChars = {"Hero", "Hero2"}
--[[ Set the below variable to each direction the character can turn to, starting with the largest number.
You can set multiple characters with different amount of direction.
Examples:
smt_animation = {Car = {315, 270, 225, 180, 135, 90, 45, 0}}
smt_animation = {Hero = {270, 180, 90, 0}, Car = {315, 270, 225, 180, 135, 90, 45, 0}}
--]]
smt_animation = {Hero = {315, 270, 225, 180, 135, 90, 45, 0}, Hero2 = {315, 270, 225, 180, 135, 90, 45, 0}}
--[[ Names of your turning animations of the character in order of the numbers above.
Examples:
smt_turningAniNames = {Car = {"character_turn_315", "character_turn_270", "character_turn_225", "character_turn_180", "character_turn_135", "character_turn_90", "character_turn_45", "character_turn_0"}}
smt_turningAniNames = {Hero = {"turn_front", "turn_left", "turn_back", "turn_right"}, Car = {"character_turn_315", "character_turn_270", "character_turn_225", "character_turn_180", "character_turn_135", "character_turn_90", "character_turn_45", "character_turn_0"}}
--]]
smt_turningAniNames = {Hero = {"character_turn_315", "character_turn_270", "character_turn_225", "character_turn_180", "character_turn_135", "character_turn_90", "character_turn_45", "character_turn_0"}, Hero2 = {"character_turn_315", "character_turn_270", "character_turn_225", "character_turn_180", "character_turn_135", "character_turn_90", "character_turn_45", "character_turn_0"}}
-- Smooth Character Turning Script
-- (c) Simon Scheckel 2014 - Visionaire Studio Engine
-----------------------------------------------------------
-- turnClockwise() and aditional changes by Pascal Lüthi
-- Special Thanks to AFRLme
-----------------------------------------------------------
--[[
---- Main Code ----
--]]
smt_direction = {}
smt_dest = {}
smt_destobj = {}
smt_actionc = {}
smt_last_position = {}
smt_anim = {}
smt_nextdir = {}
smt_clockwise = {}
smt_turnWhileStanding = {}
smt_NoTurn = {}
-- Set the variables above for every character that has the ability to turn
for i = 1, #smt_allChars do
local char = getObject("Characters[" .. smt_allChars[i] .. "]")
smt_direction[i] = char.Direction
smt_dest[i] = char.Position
smt_destobj[i] = char.DestinationObject
smt_actionc[i] = char.ActionCharacter
smt_last_position[i] = smt_direction[i]
smt_anim[i] = 0
smt_nextdir[i] = 0
smt_clockwise[i] = false
smt_turnWhileStanding[i] = true
smt_NoTurn[i] = true
end
-- Returns the turning distance between a and b in degrees
function angleDist(a,b)
return math.min(math.min( math.abs(a + 360 - b), math.abs(a - 360 - b)), math.abs(a - b))
end
-- Returns true if the fastes turn is a clockwise turn, otherwise false will be returned
function turnClockwise(startDirection, endDirection)
if startDirection == 0 then startDirection = 360 end
if endDirection == 0 then endDirection = 360 end
if startDirection > 180 then
if endDirection > startDirection - 180 and endDirection < startDirection then
return true
else
return false
end
else
if endDirection > startDirection + 180 or endDirection < startDirection then
return true
else
return false
end
end
end
-- Returns the next frame of the turning animation
function getNextTurningFrame(actualdir, maxdir, clockwise)
local nextFrame = 1
if clockwise then
if actualdir ~= maxdir then
nextFrame = actualdir + 1
end
else
if actualdir ~= 1 then
nextFrame = actualdir - 1
else
nextFrame = maxdir
end
end
return nextFrame
end
-- Checks if the person is in the actual scene or not
function isPersonInScene(person)
if person.Active then
local scene = getObject("Characters[" .. person:getName() .. "].CharacterScene")
local playerScene = getObject("Game.GameCurrentCharacter.CharacterScene")
if scene:getName() == playerScene:getName() then
-- print(person:getName() .. " is active!")
return true
else
-- print(person:getName() .. " is not on actual scene!")
return false
end
else
-- print(person:getName() .. " is inactive!")
return false
end
end
-- Main loop event handler
function smoothTurningMainLoop()
for k = 1, #smt_allChars do -- Loop every Character set to turn
local c = getObject("Characters[" .. smt_allChars[k] .. "]")
if isPersonInScene(c) then -- is character visible?
local newstate = c.AnimState
local newdir = c.Direction
local animTable = smt_animation[c:getName()]
-- After a turning animation is finished
if smt_anim[k] ~= 0 and smt_anim[k]:getId().id == -1 then
smt_nextdir[k] = getNextTurningFrame(smt_nextdir[k], #animTable, smt_clockwise[k])
c.ActionCharacter = smt_actionc[k]
if smt_nextdir[k] == smt_last_position[k] then -- turning complete?
smt_anim[k] = 0
smt_NoTurn[k] = true
if smt_turnWhileStanding[k] == false then -- end turn in a walking progress
c.DestinationObject = smt_destobj[k] -- set the original destination object
c.Destination = smt_dest[k] -- set the original destination coordinates
end
startAnimation(getObject("Characters[" .. smt_allChars[k] .. "].CharacterCurrentOutfit.OutfitCharacterAnimations[" .. smt_turningAniNames[c:getName()][smt_nextdir[k]] .. "]"))
print("end turn with: " .. smt_turningAniNames[c:getName()][smt_nextdir[k]])
print("")
else
-- Set the next turning segment
print("play turn: " .. smt_turningAniNames[c:getName()][smt_nextdir[k]])
smt_anim[k] = startAnimation(getObject("Characters[" .. smt_allChars[k] .. "].CharacterCurrentOutfit.OutfitCharacterAnimations[" .. smt_turningAniNames[c:getName()][smt_nextdir[k]] .. "]"))
end
end
-- Does character change direction?
if smt_direction[k] ~= newdir and smt_NoTurn[k] then
--[[ Finding best frame for the turning animation based on the smt_animation variable.
bestspos is then the frame of the direction the character is facing before the turn.
--]]
local bestspos = 1
local bestdist = 360
for i = 1, #animTable do
local dist = angleDist(animTable[i], smt_direction[k])
if dist < bestdist then
bestdist = dist
bestspos = i
end
end
--[[ Finding best frame for the turning animation based on the smt_animation variable.
bestlpos is then the frame of the direction the character is facing after the turn.
--]]
local bestlpos = 1
bestdist = 360
for i = 1, #animTable do
local dist = angleDist(animTable[i], newdir)
if dist < bestdist then
bestdist = dist
bestlpos = i
end
end
-- check if the first direction of the turn is different to the last direction of the turn
local turn = false
if bestspos ~= bestlpos then
print("char name: " .. c:getName())
if newstate == eWalkAnim then -- turning while walking to a point
print("turning while walking")
smt_dest[k] = c.Destination -- backup the original destination coordinats
smt_destobj[k] = c.DestinationObject -- backup the original destination object
c.Destination = c.Position -- set character destination to it's actual position so he doesn't float away while turning
smt_turnWhileStanding[k] = false
turn = true
else -- turning while standing
print("turn while standing")
smt_turnWhileStanding[k] = true
turn = true
end
end
if turn then -- should the character turn?
smt_NoTurn[k] = false
smt_actionc[k] = c.ActionCharacter
smt_last_position[k] = bestlpos -- backup last direction of the turn to start the right walking animation
smt_nextdir[k] = bestspos -- backup the starting direction of the turn
smt_clockwise[k] = turnClockwise(smt_direction[k], newdir) -- check to turn clockwise or not
print("start the turn with: " .. smt_turningAniNames[c:getName()][bestspos])
smt_anim[k] = startAnimation(getObject("Characters[" .. smt_allChars[k] .. "].CharacterCurrentOutfit.OutfitCharacterAnimations[" .. smt_turningAniNames[c:getName()][bestspos] .. "]"))
end
end
smt_direction[k] = newdir
end
end
end
registerEventHandler("mainLoop", "smoothTurningMainLoop")
Unfortunately this only works with single frames and not with real turn-animation because the animation needs to be mirrored (if the character turns to the opposit direction). Any solution for this?