Smooth Character Animations

From Coder Merlin
Within these castle walls be forged Mavens of Computer Science ...
— Merlin, The Coder
Player Run

Prerequisites[edit]

Research[edit]

Background[edit]

In order to make any successful game, smooth character animations are essential to make the game look slick and feel natural. In this wiki page, we will go over how to create smooth character animations and implement it into our project.

Experiment[edit]

Getting Started[edit]

Continue from the previous project; we’ll be editing all of our files there. Enter into the GameScene directory of the project.

tariq-mahamid@codermerlin: cd ~/Experiences/ChangingScenes/Sources/ScenesShell/GameScene

Player[edit]

Create and enter a player script in order to start creating a player with animations. After creating the script, initializing images with the following names and URLs, we will switch between these images in order to animate our player.

    let playerWalkingRight1 = Image(sourceURL: URL(string: "https://i.ibb.co/xg4mkBn/Naruto-Right1.png"))
    let playerWalkingRight2 = Image(sourceURL: URL(string: "https://i.ibb.co/gz3NDNN/Naruto-Right2.png"))
    let playerWalkingCrouch1 = Image(sourceURL: URL(string: "https://i.ibb.co/hKwZLFf/Naruto-Crouch.png"))
    let playerWalkingCrouch2 = Image(sourceURL: URL(string: "https://i.ibb.co/k2sXMbL/Naruto-Crouch2.png"))
    let playerWalkingJump = Image(sourceURL: URL(string: "https://i.ibb.co/P1vMWCf/Naruto-Jump.png"))

Now that we initialized the variables that we are going to switch between in order to animate our player we must now store the current state of the player, for this we can using multiple enums

enum JumpMove {                                                                                                                                                                                                                      
    case jumping, falling, hanging, none                                                                                                                                                                                             
}                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                     
enum CrouchMove {                                                                                                                                                                                                                    
    case crouching, none                                                                                                                                                                                                             
}

We will need to store these enums into variables in order to manage the state of the player:

    var jumpMove = JumpMove.none
    var crouchMove = CrouchMove.none


Using 3 different variables and 3 different functions, we can manage the state of our animations: One variable to manage the frames per animation, one variable to manage the total frames ran, and one variable to alternate the animations.

Declare these variables at the top of your script to manage the state of the animation:

    let framesToAlternate = 3                                                                                                                                                                                                        
    var animationManager = false                                                                                                                                                                                                     
    var currentAnimationFrames = 0

As well as these functions later in the script to alternate the images depending on the state:

    override func render(canvas: Canvas) {                                                                                                                                                                                           
        if getCurrentImage().isReady {                                                                                                                                                                                               
            getCurrentImage().renderMode = .destinationRect(playerRect)                                                                                                                                                              
            canvas.render(getCurrentImage())                                                                                                                                                                                         
                                                                                                                                                                                                                                     
            checkAndChangeAnimation()                                                                                                                                                                                                
        }                                                                                                                                                                                                                            
                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                     
    }                                                                                                                                                                                                                                
                                                                                                                                                                                                                                     
    func checkAndChangeAnimation() {                                                                                                                                                                                                 
        if (currentAnimationFrames % framesToAlternate == 0) {                                                                                                                                                                       
            animationManager = !animationManager                                                                                                                                                                                     
        }                                                                                                                                                                                                                            
        currentAnimationFrames += 1                                                                                                                                                                                                  
    }                                                                                                                                                                                                                                
                                                                                                                                                                                                                                     
    func getCurrentImage() -> Image {                                                                                                                                                                                                
        if jumpMove != JumpMove.none {                                                                                                                                                                                               
            return playerJump                                                                                                                                                                                                        
        }                                                                                                                                                                                                                            
                                                                                                                                                                                                                                     
        if crouchMove != CrouchMove.none && animationManager {                                                                                                                                                                                         
            return playerCrouch1                                                                                                                                                                                                     
        }                                                                                                                                                                                                                            
        else if crouchMove != CrouchMove.none && !animationManager {                                                                                                                                                                                   
            return playerCrouch2                                                                                                                                                                                                     
        }                                                                                                                                                                                                                            
                                                                                                                                                                                                                                     
        if animationManager {                                                                                                                                                                                                        
            return playerWalkingRight1                                                                                                                                                                                               
        }                                                                                                                                                                                                                            
        return playerWalkingRight2                                                                                                                                                                                                   
    }

Exercises[edit]

ExercisesExercisesIcon.png
  • Add to the player code and allow them to jump and crouch along with changing the animations
  • Create a game over screen that includes a restart button and a back to start button when an obstacle collides with the player.
  • Keep score at the top of the screen and keep track how many obstacles the player passes.