@@ -59,10 +59,10 @@ public class MSTSWagonViewer : TrainCarViewer
5959
6060 // Wheels are rotated by hand instead of in the shape file.
6161 float WheelRotationR ;
62- List < int > WheelPartIndexes = new List < int > ( ) ;
62+ Dictionary < int , List < int > > WheelPartIndexes = new Dictionary < int , List < int > > ( ) ; // List of wheels attached to each axle
6363
6464 // Everything else is animated through the shape file.
65- AnimatedPart RunningGear ;
65+ Dictionary < int , AnimatedPart > RunningGears ; // List of animated parts linked to every axle
6666 AnimatedPart Pantograph1 ;
6767 AnimatedPart Pantograph2 ;
6868 AnimatedPart Pantograph3 ;
@@ -313,7 +313,12 @@ from data in effect.Value
313313 if ( car . InteriorShapeFileName != null )
314314 InteriorShape = new AnimatedShape ( viewer , wagonFolderSlash + car . InteriorShapeFileName + '\0 ' + wagonFolderSlash , car . WorldPosition , ShapeFlags . Interior , 30.0f ) ;
315315
316- RunningGear = new AnimatedPart ( TrainCarShape ) ;
316+ RunningGears = new Dictionary < int , AnimatedPart > ( ) ;
317+ for ( int i = - 1 ; i < car . LocomotiveAxles . Count ; i ++ )
318+ {
319+ RunningGears [ i ] = new AnimatedPart ( TrainCarShape ) ;
320+ WheelPartIndexes [ i ] = new List < int > ( ) ;
321+ }
317322 Pantograph1 = new AnimatedPart ( TrainCarShape ) ;
318323 Pantograph2 = new AnimatedPart ( TrainCarShape ) ;
319324 Pantograph3 = new AnimatedPart ( TrainCarShape ) ;
@@ -424,6 +429,15 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
424429 var matrixName = TrainCarShape . SharedShape . MatrixNames [ matrix ] . ToUpper ( ) ;
425430 // Gate all RunningGearPartIndexes on this!
426431 var matrixAnimated = TrainCarShape . SharedShape . Animations != null && TrainCarShape . SharedShape . Animations . Count > 0 && TrainCarShape . SharedShape . Animations [ 0 ] . anim_nodes . Count > matrix && TrainCarShape . SharedShape . Animations [ 0 ] . anim_nodes [ matrix ] . controllers . Count > 0 ;
432+ int ? LinkedAxleIndex = null ;
433+ for ( int i = 0 ; i < car . LocomotiveAxles . Count ; i ++ )
434+ {
435+ if ( car . LocomotiveAxles [ i ] . AnimatedParts . Contains ( matrixName ) )
436+ {
437+ LinkedAxleIndex = i ;
438+ break ;
439+ }
440+ }
427441 if ( matrixName . StartsWith ( "WHEELS" ) && ( matrixName . Length == 7 || matrixName . Length == 8 || matrixName . Length == 9 ) )
428442 {
429443 // Standard WHEELS length would be 8 to test for WHEELS11. Came across WHEELS tag that used a period(.) between the last 2 numbers, changing max length to 9.
@@ -441,15 +455,15 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
441455 if ( matrixName . Length == 8 || matrixName . Length == 9 )
442456 Int32 . TryParse ( matrixName . Substring ( 6 , 1 ) , out id ) ;
443457 if ( matrixName . Length == 8 || matrixName . Length == 9 || ! matrixAnimated )
444- WheelPartIndexes . Add ( matrix ) ;
458+ WheelPartIndexes [ LinkedAxleIndex ?? - 1 ] . Add ( matrix ) ;
445459 else
446- RunningGear . AddMatrix ( matrix ) ;
460+ RunningGears [ LinkedAxleIndex ?? ( car . LocomotiveAxles . Count > 0 ? 0 : - 1 ) ] . AddMatrix ( matrix ) ;
447461 var pmatrix = TrainCarShape . SharedShape . GetParentMatrix ( matrix ) ;
448462 car . AddWheelSet ( m . M43 , id , pmatrix , matrixName . ToString ( ) , bogie1Axles , bogie2Axles ) ;
449463 }
450464 // Standard wheels are processed above, but wheels used as animated fans that are greater than 3m are processed here.
451465 else
452- RunningGear . AddMatrix ( matrix ) ;
466+ RunningGears [ LinkedAxleIndex ?? - 1 ] . AddMatrix ( matrix ) ;
453467 }
454468 else if ( matrixName . StartsWith ( "BOGIE" ) && matrixName . Length <= 6 ) //BOGIE1 is valid, BOGIE11 is not, it is used by some modelers to indicate this is part of bogie1
455469 {
@@ -578,7 +592,7 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
578592 else
579593 {
580594 if ( matrixAnimated && matrix != 0 )
581- RunningGear . AddMatrix ( matrix ) ;
595+ RunningGears [ LinkedAxleIndex ?? ( car . LocomotiveAxles . Count > 0 ? 0 : - 1 ) ] . AddMatrix ( matrix ) ;
582596
583597 for ( var i = 0 ; i < TrainCarShape . Hierarchy . Length ; i ++ )
584598 if ( TrainCarShape . Hierarchy [ i ] == matrix )
@@ -709,68 +723,80 @@ private void UpdateAnimation(RenderFrame frame, ElapsedTime elapsedTime)
709723 {
710724
711725 float distanceTravelledM = 0.0f ; // Distance travelled by non-driven wheels
712- float distanceTravelledDrivenM = 0.0f ; // Distance travelled by driven wheels
713726 float AnimationWheelRadiusM = MSTSWagon . WheelRadiusM ; // Radius of non driven wheels
714727 float AnimationDriveWheelRadiusM = MSTSWagon . DriverWheelRadiusM ; // Radius of driven wheels
715728
716729 if ( MSTSWagon . IsDriveable && MSTSWagon . Simulator . UseAdvancedAdhesion && ! MSTSWagon . Simulator . Settings . SimpleControlPhysics )
717730 {
731+ var loco = MSTSWagon as MSTSLocomotive ;
718732 //TODO: next code line has been modified to flip trainset physics in order to get viewing direction coincident with loco direction when using rear cab.
719733 // To achieve the same result with other means, without flipping trainset physics, the line should be changed as follows:
720734 // distanceTravelledM = MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;
721-
722- distanceTravelledM = ( ( MSTSWagon . Train != null && MSTSWagon . Train . IsPlayerDriven && ( ( MSTSLocomotive ) MSTSWagon ) . UsingRearCab ) ? - 1 : 1 ) * MSTSWagon . WheelSpeedMpS * elapsedTime . ClockSeconds ;
723- if ( Car . EngineType == Orts . Simulation . RollingStocks . TrainCar . EngineTypes . Steam )
735+ distanceTravelledM = ( ( MSTSWagon . Train != null && MSTSWagon . Train . IsPlayerDriven && loco . UsingRearCab ) ? - 1 : 1 ) * MSTSWagon . WheelSpeedMpS * elapsedTime . ClockSeconds ;
736+ if ( Car . BrakeSkid && ! loco . DriveWheelOnlyBrakes ) distanceTravelledM = 0 ;
737+ foreach ( var kvp in RunningGears )
724738 {
725- distanceTravelledDrivenM = ( ( MSTSWagon . Train != null && MSTSWagon . Train . IsPlayerDriven && ( ( MSTSLocomotive ) MSTSWagon ) . UsingRearCab ) ? - 1 : 1 ) * MSTSWagon . WheelSpeedSlipMpS * elapsedTime . ClockSeconds ;
739+ if ( ! kvp . Value . Empty ( ) )
740+ {
741+ var axle = kvp . Key >= 0 && kvp . Key < loco . LocomotiveAxles . Count ? loco . LocomotiveAxles [ kvp . Key ] : null ;
742+ if ( axle != null )
743+ //TODO: next code line has been modified to flip trainset physics in order to get viewing direction coincident with loco direction when using rear cab.
744+ kvp . Value . UpdateLoop ( ( ( MSTSWagon . Train != null && MSTSWagon . Train . IsPlayerDriven && loco . UsingRearCab ) ? - 1 : 1 ) * axle . AxleSpeedMpS * elapsedTime . ClockSeconds / MathHelper . TwoPi / axle . WheelRadiusM ) ;
745+ else if ( AnimationDriveWheelRadiusM > 0.001 )
746+ kvp . Value . UpdateLoop ( distanceTravelledM / MathHelper . TwoPi / AnimationDriveWheelRadiusM ) ;
747+ }
748+
726749 }
727- else // Other driveable rolling stocked.
750+ foreach ( var kvp in WheelPartIndexes )
728751 {
729- distanceTravelledDrivenM = ( ( MSTSWagon . Train != null && MSTSWagon . Train . IsPlayerDriven && ( ( MSTSLocomotive ) MSTSWagon ) . UsingRearCab ) ? - 1 : 1 ) * MSTSWagon . WheelSpeedMpS * elapsedTime . ClockSeconds ;
752+ var axle = kvp . Key < loco . LocomotiveAxles . Count && kvp . Key >= 0 ? loco . LocomotiveAxles [ kvp . Key ] : ( Car . EngineType == TrainCar . EngineTypes . Steam ? null : loco . LocomotiveAxles [ 0 ] ) ;
753+ Matrix wheelRotationMatrix ;
754+ if ( axle != null )
755+ {
756+ //TODO: next code line has been modified to flip trainset physics in order to get viewing direction coincident with loco direction when using rear cab.
757+ wheelRotationMatrix = Matrix . CreateRotationX ( ( ( MSTSWagon . Train != null && MSTSWagon . Train . IsPlayerDriven && loco . UsingRearCab ) ? - 1 : 1 ) * - axle . AxlePositionRad ) ;
758+ }
759+ else
760+ {
761+ var rotationalDistanceR = distanceTravelledM / AnimationWheelRadiusM ; // in radians
762+ WheelRotationR = MathHelper . WrapAngle ( WheelRotationR - rotationalDistanceR ) ;
763+ wheelRotationMatrix = Matrix . CreateRotationX ( WheelRotationR ) ;
764+ }
765+ foreach ( var iMatrix in kvp . Value )
766+ {
767+ TrainCarShape . XNAMatrices [ iMatrix ] = wheelRotationMatrix * TrainCarShape . SharedShape . Matrices [ iMatrix ] ;
768+ }
730769 }
731770 }
732771 else // set values for simple adhesion
733772 {
734773 distanceTravelledM = ( ( MSTSWagon . IsDriveable && MSTSWagon . Train != null && MSTSWagon . Train . IsPlayerDriven && ( ( MSTSLocomotive ) MSTSWagon ) . UsingRearCab ) ? - 1 : 1 ) * MSTSWagon . SpeedMpS * elapsedTime . ClockSeconds ;
735- distanceTravelledDrivenM = distanceTravelledM ;
736- }
737-
738- if ( Car . BrakeSkid ) // if car wheels are skidding because of brakes locking wheels up then stop wheels rotating.
739- {
740- // Temporary bug fix (CSantucci)
741- if ( MSTSWagon is MSTSLocomotive loco && loco . DriveWheelOnlyBrakes )
774+ if ( Car . BrakeSkid ) distanceTravelledM = 0 ;
775+ foreach ( var kvp in RunningGears )
742776 {
743- distanceTravelledDrivenM = 0.0f ;
777+ if ( ! kvp . Value . Empty ( ) && AnimationDriveWheelRadiusM > 0.001 )
778+ kvp . Value . UpdateLoop ( distanceTravelledM / MathHelper . TwoPi / AnimationDriveWheelRadiusM ) ;
744779 }
745- else
780+ // Wheel rotation (animation) - for non-drive wheels in steam locomotives and all wheels in other stock
781+ if ( WheelPartIndexes . Count > 0 )
746782 {
747- distanceTravelledM = 0.0f ;
748- distanceTravelledDrivenM = 0.0f ;
783+ var rotationalDistanceR = distanceTravelledM / AnimationWheelRadiusM ; // in radians
784+ WheelRotationR = MathHelper . WrapAngle ( WheelRotationR - rotationalDistanceR ) ;
785+ var wheelRotationMatrix = Matrix . CreateRotationX ( WheelRotationR ) ;
786+ foreach ( var kvp in WheelPartIndexes )
787+ {
788+ foreach ( var iMatrix in kvp . Value )
789+ {
790+ TrainCarShape . XNAMatrices [ iMatrix ] = wheelRotationMatrix * TrainCarShape . SharedShape . Matrices [ iMatrix ] ;
791+ }
792+ }
749793 }
750794 }
751795
752- // Running gear and drive wheel rotation (animation) in steam locomotives
753- if ( ! RunningGear . Empty ( ) && AnimationDriveWheelRadiusM > 0.001 )
754- RunningGear . UpdateLoop ( distanceTravelledDrivenM / MathHelper . TwoPi / AnimationDriveWheelRadiusM ) ;
755-
756-
757- // Wheel rotation (animation) - for non-drive wheels in steam locomotives and all wheels in other stock
758- if ( WheelPartIndexes . Count > 0 )
759- {
760- var wheelCircumferenceM = MathHelper . TwoPi * AnimationWheelRadiusM ;
761- var rotationalDistanceR = MathHelper . TwoPi * distanceTravelledM / wheelCircumferenceM ; // in radians
762- WheelRotationR = MathHelper . WrapAngle ( WheelRotationR - rotationalDistanceR ) ;
763- var wheelRotationMatrix = Matrix . CreateRotationX ( WheelRotationR ) ;
764- foreach ( var iMatrix in WheelPartIndexes )
765- {
766- TrainCarShape . XNAMatrices [ iMatrix ] = wheelRotationMatrix * TrainCarShape . SharedShape . Matrices [ iMatrix ] ;
767- }
768- }
769-
770796#if DEBUG_WHEEL_ANIMATION
771797
772798 Trace . TraceInformation ( "========================== Debug Animation in MSTSWagonViewer.cs ==========================================" ) ;
773- Trace . TraceInformation ( "Slip speed - Car ID: {0} WheelDistance: {1} SlipWheelDistance: {2} " , Car . CarID , distanceTravelledM , distanceTravelledDrivenM ) ;
799+ Trace . TraceInformation ( "Slip speed - Car ID: {0} WheelDistance: {1}" , Car . CarID , distanceTravelledM ) ;
774800 Trace . TraceInformation ( "Wag Speed - Wheelspeed: {0} Slip: {1} Train: {2}" , MSTSWagon . WheelSpeedMpS , MSTSWagon . WheelSpeedSlipMpS , MSTSWagon . SpeedMpS ) ;
775801 Trace . TraceInformation ( "Wheel Radius - DriveWheel: {0} NonDriveWheel: {1}" , AnimationDriveWheelRadiusM , AnimationWheelRadiusM ) ;
776802
0 commit comments