From b56edd2dad19231e197627c237fe0bcf4d451c5c Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 20 Dec 2015 19:51:19 +1100 Subject: [PATCH] Add basic for old classic arms animation. --- .../2D/Screens/Menu/OptionsScreen.cs | 10 ++- ClassicalSharp/Entities/AnimatedEntity.cs | 71 ++++++++++++++++++- ClassicalSharp/Game/Game.Properties.cs | 3 + ClassicalSharp/Model/PlayerModel.cs | 6 +- 4 files changed, 84 insertions(+), 6 deletions(-) diff --git a/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs b/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs index 9c2efe8b6..c0eedfb33 100644 --- a/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/OptionsScreen.cs @@ -14,7 +14,10 @@ namespace ClassicalSharp { INetworkProcessor network = game.Network; buttons = new ButtonWidget[] { - // Column 1 + // Column 1 + Make( -140, -150, "Use simple arms", OnWidgetClick, + g => g.SimpleArmsAnim ? "yes" : "no", + (g, v) => g.SimpleArmsAnim = v == "yes"), Make( -140, -100, "Use sound", OnWidgetClick, g => g.UseSound ? "yes" : "no", @@ -71,10 +74,11 @@ namespace ClassicalSharp { (g, w) => g.SetNewScreen( new PauseScreen( g ) ) ), null, }; - buttons[1].Metadata = typeof(NameMode); - buttons[2].Metadata = typeof(FpsLimitMethod); + buttons[2].Metadata = typeof(NameMode); + buttons[3].Metadata = typeof(FpsLimitMethod); validators = new MenuInputValidator[] { + new BooleanValidator(), new BooleanValidator(), new EnumValidator(), new EnumValidator(), diff --git a/ClassicalSharp/Entities/AnimatedEntity.cs b/ClassicalSharp/Entities/AnimatedEntity.cs index 74fe0eb47..64f3f4c01 100644 --- a/ClassicalSharp/Entities/AnimatedEntity.cs +++ b/ClassicalSharp/Entities/AnimatedEntity.cs @@ -1,4 +1,5 @@ using System; +using ClassicalSharp.Model; using OpenTK; namespace ClassicalSharp { @@ -21,12 +22,14 @@ namespace ClassicalSharp { double distance = Math.Sqrt( dx * dx + dz * dz ); if( distance > 0.05 ) { - walkTimeN += (float)distance * 2 * (float)(20 * delta); + float walkDelta = (float)distance * 2 * (float)(20 * delta); + walkTimeN += walkDelta; swingN += (float)delta * 3; } else { swingN -= (float)delta * 3; } Utils.Clamp( ref swingN, 0, 1 ); + UpdateHumanState(); } const float armMax = 60 * Utils.Deg2Rad; @@ -49,6 +52,72 @@ namespace ClassicalSharp { bobYOffset = (float)(Math.Abs( Math.Cos( walkTime ) ) * swing * (2/16f)); tilt = (float)Math.Cos( walkTime ) * swing * (0.15f * Utils.Deg2Rad); + + if( Model is PlayerModel ) + CalcHumanAnim( idleXRot, idleZRot ); + } + + internal float leftXRot, leftYRot, leftZRot; + internal float rightXRot, rightYRot, rightZRot; + ArmsAnim animMode = ArmsAnim.NoPerpendicular; + int statesDone; + static Random rnd = new Random(); + + void UpdateHumanState() { + if( game.SimpleArmsAnim ) { + animMode = ArmsAnim.NoPerpendicular; + return; + } + // crosses over body, finished an arm swing + int oldState = Math.Sign( Math.Cos( walkTimeO ) ); + int newState = Math.Sign( Math.Cos( walkTimeN ) ); + if( oldState != newState ) + statesDone++; + + // should we switch animations? + if( statesDone == 5 ) { + statesDone = 0; + animMode = (ArmsAnim)rnd.Next( 0, 4 ); + } + } + + void CalcHumanAnim( float idleXRot, float idleZRot ) { + switch( animMode ) { + case ArmsAnim.NoPerpendicular: + leftXRot = armXRot; leftYRot = 0; leftZRot = armZRot; + rightXRot = -armXRot; rightYRot = 0; rightZRot = -armZRot; + return; + case ArmsAnim.LeftPerpendicular: + PerpendicularAnim( out leftXRot, out leftYRot, out leftZRot ); + rightXRot = -armXRot; rightYRot = 0; rightZRot = -armZRot; + return; + case ArmsAnim.RightPerpendicular: + leftXRot = armXRot; leftYRot = 0; leftZRot = armZRot; + PerpendicularAnim( out rightXRot, out rightYRot, out rightZRot ); + rightXRot = -rightXRot; rightZRot = -rightZRot; + return; + case ArmsAnim.BothPerpendicular: + PerpendicularAnim( out leftXRot, out leftYRot, out leftZRot ); + PerpendicularAnim( out rightXRot, out rightYRot, out rightZRot ); + rightXRot = -rightXRot; rightZRot = -rightZRot; + break; + } + } + + const float maxAngle = 90 * Utils.Deg2Rad; + void PerpendicularAnim( out float xRot, out float yRot, out float zRot ) { + xRot = 0; + yRot = 0; + yRot = (float)(Math.Cos( walkTime ) * swing * armMax * 1.5f); + float angle = (float)(1 + 0.3 * Math.Sin( walkTime ) ); + zRot = -angle * swing * maxAngle; + } + + enum ArmsAnim { + NoPerpendicular, // i.e. both parallel + LeftPerpendicular, + RightPerpendicular, + BothPerpendicular, } } } \ No newline at end of file diff --git a/ClassicalSharp/Game/Game.Properties.cs b/ClassicalSharp/Game/Game.Properties.cs index 58b438f2c..2da7b4591 100644 --- a/ClassicalSharp/Game/Game.Properties.cs +++ b/ClassicalSharp/Game/Game.Properties.cs @@ -103,6 +103,9 @@ namespace ClassicalSharp { /// Whether lines should be rendered for each axis. public bool ShowAxisLines; + /// Whether players should animate using simple swinging parallel to their bodies. + public bool SimpleArmsAnim = true; + public long Vertices; public FrustumCulling Culling; int width, height; diff --git a/ClassicalSharp/Model/PlayerModel.cs b/ClassicalSharp/Model/PlayerModel.cs index 7ddee8a47..bc46bea79 100644 --- a/ClassicalSharp/Model/PlayerModel.cs +++ b/ClassicalSharp/Model/PlayerModel.cs @@ -73,8 +73,10 @@ namespace ClassicalSharp.Model { DrawPart( model.Torso ); DrawRotate( 0, 12/16f, 0, p.legXRot, 0, 0, model.LeftLeg ); DrawRotate( 0, 12/16f, 0, -p.legXRot, 0, 0, model.RightLeg ); - DrawRotate( -6/16f, 22/16f, 0, p.armXRot, 0, p.armZRot, model.LeftArm ); - DrawRotate( 6/16f, 22/16f, 0, -p.armXRot, 0, -p.armZRot, model.RightArm ); + Rotate = RotateOrder.XZY; + DrawRotate( -6/16f, 22/16f, 0, p.leftXRot, p.leftYRot, p.leftZRot, model.LeftArm ); + DrawRotate( 6/16f, 22/16f, 0, p.rightXRot, p.rightYRot, p.rightZRot, model.RightArm ); + Rotate = RotateOrder.ZYX; graphics.UpdateDynamicIndexedVb( DrawMode.Triangles, cache.vb, cache.vertices, index, index * 6 / 4 ); graphics.AlphaTest = true;