endless-sky icon indicating copy to clipboard operation
endless-sky copied to clipboard

feat(enhancement): Situation based Ship Animations Refactored

Open XessWaffle opened this issue 7 months ago • 10 comments


Feature: This PR implements the feature request detailed and discussed in issue #4991

See Previous PRs for discussion:

  1. https://github.com/endless-sky/endless-sky/pull/7150
  2. https://github.com/endless-sky/endless-sky/pull/8797

Feature Details

See Wiki PR for updated details: https://github.com/endless-sky/endless-sky-wiki/pull/31

To rehash the issue, the goal is to have a ship play different animations based on the situation it is in (eg. flying, landing etc.).

This PR currently implements six different states: Flying, Fighting, Landing, Launching, Jumping, Disabled.

  • Flying: Implies that the ship is simply moving through space. This is also the default sprite i.e. if another sprite is not defined, the sprite that will be displayed is the flying sprite. For example, if a ship is defined without a landing, fighting or launching sprite, then the flying sprite will be displayed in all of those cases. Furthermore, bodies that are defined with just the "sprite" token will be loaded into the flying sprite.
  • Firing (changed from Fighting): Implies that the ship has an active enemy target i.e. the target is not disabled and it is in the system and in weapons range (thanks @Hurleveur for the weaponRange suggestion), or is targeting an asteroid. The body may or may not be firing its weapons in this state. The players ship also enters this state if their primary weapon is fired, regardless of them having a target.
  • Landing: Implies that the ship is currently descending to land on a planet or wormhole.
  • Launching: Implies that the ship is currently ascending from a planet or wormhole.
  • Jumping: Implies that the ship is currently trying to move through hyperspace (before a jump) or is moving through hyperspace (during a jump).
  • Disabled: Implies that the ship is currently disabled.

To Implement:

  • [x] Firing: Generic firing animation for a ship (uncovering hardpoints etc.) (@Zitchas)
  • [x] Special firing animations: Certain weapons on certain ships should trigger special animations (@Zitchas)
  • [x] "delay" keyword: A delay before state change (@Azure3141)
  • [x] Disabled State: Should transition the ship out of the current state (state -> disabled) and also account for being rescued (disabled -> flying) (@Azure3141).
  • [x] "random": If this keyword appears in a state, pick frames randomly while in the state (@Saugia)
  • [x] "indicate" update: Allow indicate to have a value from zero to one identifying the percentage of the animation that must complete before the specified action is allowed (@Ferociousfeind).
  • [x] Special animations update: Instead of triggering an animated sprite if the ship has the outfit, trigger the sprite if the ship is using the outfit.
  • [x] Landing and launching for fighter style ships. Launching would imply deploying fighters, and landing would imply recalling them.

Potential future PRs:

  • Hyperspacing substate: Should only occur if the ship is in the Jumping state, and the ship is travelling through hyperspace, will be implemented alongside special firing animation as a special jumping animation (e.g. play a different animation for a jump drive etc.) This is now possible as a trigger based animation.
  • Thrusting/Overheating visuals: May not be as efficient to implement as states, but may be possible to implement via shaders. (@Azure3141). Might make this a separate PR.

The PR also handles transitions between different states. For example, if transitioning from launching to flying, completing the launching animation before going into the flying animation would be something that is preferred in some cases. A couple of new animation keywords have been added:

  • "transition rewind": If a state change is requested (e.g. flying -> fighting), play the sprite animation associated with the current state (not the requested state) backwards until it reaches the first frame, then transition to the requested state.
  • "transition finish": If a state change is requested, finish the current loop of the animation and transition states. If neither keyword is used, then the transition between sprite animations is immediate.
  • "transition delay": Once a state change is requested, wait a certain number of frames, then complete the transition. Can be used to ensure that states aren't changing too rapidly. During the delay period, the transition may be cancelled as well. (@Azure3141 thanks for the suggestion!)
  • "indicate": Typically used during the Fighting or Jumping states, essentially, this keyword will make the animation non-repeatable and indicate to the ship when the last frame is reached. Upon reaching the last frame, the ship can perform the desired action (firing its weapons or jumping). For example, if "indicate" is used in "sprite-firing", then the ship will not fire until the animation is complete.
  • "indicate percentage [value]": Similar to the indicate state, except only a certain percentage of the animation has to finish before the action can be performed.
  • "random": Used when a sprite should pick random frames in a certain state. In the example below, "random" is used in the disabled state to pick frames from the flying animation randomly. (@Saugia thanks for the suggestion!)
  • "ramp [ramp in rate] [ramp out rate]": Used when an animation frame rate should ramp up or down. Ramp in rate represents the rate at which the frameRate changes when the body has just transitioned into a state, and ramp out is the rate at which the frameRate changes when the body is transitioning into another state. The ramp rates can be both negative and positive (or zero).
  • "reverse": Used to simply reverse the frame number displayed. For example, in an animation with 20 frames, if we are currently on frame 15, an animation with the reverse keyword will be on frame 5. Essentially, the animation will be played backward.

The last keyword is somewhat more complicated: "trigger [path-to-animated-sprite]"

  • Essentially, it is a conditional sprite that can be played when the ship is in certain states. For example, if a ship is in the firing state, and we want it to play a different animation if a certain weapon is firing, a trigger can be setup for that situation.
  • Several different preliminary conditions have been implemented:
    • "hull": Gives the amount of hull currently on the ship.
    • "shields: Gives the amount of shields currently on the ship.
    • "outfit (installed): [outfit]": Returns the number of [outfit] installed on the ship.
    • "jump (using): [outfit]": Returns 1 if the current jump is happening with [outfit] where [outfit] can be any sort of drive. If [outfit] is not a drive, then returns 0.
    • "weapon (firing): [outfit]": Returns 1 if [outfit] is a weapon and is firing in the current frame.
  • Trigger sprites can also be individually animated with the same parameters as listed above.

UI Screenshots

See Closed PR https://github.com/endless-sky/endless-sky/pull/8797

Usage Examples

I used these parameters with a ship I modeled called the Raptor. The plugin is linked below and I have attached a save file to this PR. Note that you can animate each different state's sprite individually, and as stated before, not all states need to have a transition defined. Furthermore, the "sprite" or "sprite-flying" keywords can be used interchangeably.

	sprite "ship/raptor/flying-disabled/raptor"
		"frame rate" 5
	sprite-firing "ship/raptor/fighting/raptor"
                ramp 20 0
		trigger ship/raptor/fighting/sunbeam/raptor
                         conditions
                                   has "outfit (installed): Sunbeam"
			"frame rate" 25
			"indicate percentage" 0.5
		"frame rate" 20
		"indicate percentage" 0.75
		"transition delay" 50
		"transition rewind"
	sprite-landing "ship/raptor/landing/raptor"
		"frame rate" 10
		"no repeat"
	sprite-launching "ship/raptor/launching/raptor"
		"frame rate" 5
		"no repeat"
		"transition finish"
	sprite-jumping "ship/raptor/jumping/raptor"
                trigger "Jump Drive" "ship/raptor/jumping/jump drive/raptor" "on use"
		"frame rate" 20
		"transition rewind"
	sprite-disabled "ship/raptor/flying-disabled/raptor"
		"frame rate" 5
		"random"

Plugin: https://github.com/XessWaffle/endless-sky-animation-test

  • Helps to have the all content plugin installed as well!

Testing Done

So far, I have only tested my ship with the parameters above, and ensured that other animations (e.g the Peregrine, or the Shuttle) were unchanged and uninterrupted by my changes.

Need to test

  • [x] AI fleets that have ships with animations
  • [x] Special ships with animations
  • [x] Transitions between edge case states i.e. Firing -> Landing: Noticed a jumpy bug when rapidly switching between jumping, firing and flying
  • [x] Jumping animations
  • [x] Mining ships with animations (for firing on asteroids)
  • [x] Can the game be played normally as is without being affected (all storylines, game mechanics etc.): Played through intro missions with Star barge without any noticeable sprite related bugs.

Use ESLauncher2 to run locally!

Performance Impact

More dynamic memory is used to load in different sprites and animation parameters for a certain ship, could lead to performance impacts if animations get large, but otherwise the performance impact should be minimal.

XessWaffle avatar Jul 24 '24 06:07 XessWaffle