Step 3¶
Animating with Image Arrays - Overview¶
In the last step, we managed to have Glod's image change based on directional key input.
Now, let's breathe more life into him.
Instead of having static images, we can have him animated. To do this we will:
-
Use an image array to house the different frames in an animation.
-
Display a single frame in
UI.Area
usingUI.Image
. -
Cycle through the image shown by going through the image array with
Step
to create a looping animation.
Without further ado, let's get to it!
Step 3.1¶
Before we can create our animation, we have to download the images that will be used.
Create a folder within "GlodImages" and name it "Character_Idle". Within the "Character_Idle" folder, create another folder named "Idle_Left" and save the images there.
- Download Glod's adorable idle animation frames here.
Step 3.2¶
Once you have the images downloaded, the next step is to have an image array to house these images.
1 2 3 4 5 6 7 8 |
|
- Remember to use
;;
comments to help segment and organize your code for better readability!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
|
>>
>>
is an alias for the shard Push
. An alias is a short form of a shard to make coding much easier. Think of it like typing "lol" instead of "laughing out loud". The Push
shard is used to add an element to the back of an array.
Step 3.3¶
Now that we have an array of images, we can take an element from this array and draw that specific image in the window. To do this:
-
Create a variable called
.idle-image-index
. This will determine the index of the image array that will be used. -
Use the
Take
shard to retrieve the image located in the specified index of the image array. -
Tell
UI.Area
to draw the image.
1 |
|
- Added to line 22, within
initialize-character
.
1 |
|
.character-image
is renamed to.idle-left-image-array
to better reflect its idling state at line 68.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
|
Step 3.4¶
We're almost there!
To have this image animated, we need to dynamically increase the value of .idle-image-index
and make it loop. To do this, we will first create a Wire that increases .idle_image_index.
1 2 3 |
|
- Use
defloop
to create a looping Wire that will add 1 to.idle-image-index
each time it is called. Added to lines 24 - 26.
Updating Variables
Whenever you make changes to a variable, remember to reassign it to the variable again at the end if you plan on using it in another segment of the code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
|
Before we can call this Wire, we have to create some variables to help us loop it properly.
If we were to try to use this Wire as it is, .idle-image-index
will increase in value indefinitely.
To prevent this from happening, we will create some variables and a conditional statement to control how .idle-image-index
increases.
1 2 |
|
.idle-image-index-max
will be used to ensure that.idle-image-index
does not exceed this value. Added to line 23.idle-animation-speed
ensures how fast our idle animation will play. Added to line 24.
1 2 3 4 5 6 7 8 |
|
-
The
When
conditional statement ensures that.idle-animation-index
will not exceed.idle-image-index-max
. This ensures that we will not try to draw an image that is beyond what the array has as it will crash the program. -
Pause
is used as thisdefloop
will eventually executeStep
. This pause will cause thedefloop
to be called at the speed indicated by.idle-animation-speed
. -
Added to lines 28 - 34.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
|
Now we just have to call this Wire in our main Wire with Step
.
Step
Step
schedules and runs another Wire on the Wire calling Step
itself.
1 |
|
Step
allows us to run a code in parallel to the main Wire. This line is added to line 62.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
|
Phew, that was a pretty long step! 😪 But it was worth it! Try running the code now. Tadah! You now have an animated idle image.
Step 3.5¶
Before we proceed to the next chapter, let's give Glod more animations.
We will be:
-
Using the same logic to give Glod his walk animation.
-
Creating the logic to ensure that he faces the correct direction when the corresponding buttons are pressed.
Create the appropriate folders and save the images accordingly:
-
Download Glod's "Walking Right" animation here.
-
Download Glod's "Walking Left" animation here.
-
Download Glod's "Idle Right" animation here.
Jumping Frame
There is no animation for jumping. Instead, it retains a single image while jumping.
2D characters feel more responsive when they transit immediately between jumping and walking/idling. This is achieved by using only a single frame.
Similar to how we created an image array for the idle animation when Glod is facing left, we will now create one for when Glod is facing right.
1 2 3 4 5 6 7 8 |
|
- Added to line 22.
Create image arrays for when Glod is walking left and for when Glod is walking right. Since the walking animation is different from the idle animation, we will be making new variables for:
-
Animation speed
-
Image index
-
Max image index
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
;; -------------- Walking Array (Facing Left) ----------------- (LoadTexture "GlodImages/Character_Walking/Walking_Left/Character1_Walking_Left_1.png") >> .walking-left-image-array ;; (1) (LoadTexture "GlodImages/Character_Walking/Walking_Left/Character1_Walking_Left_2.png") >> .walking-left-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Left/Character1_Walking_Left_3.png") >> .walking-left-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Left/Character1_Walking_Left_4.png") >> .walking-left-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Left/Character1_Walking_Left_5.png") >> .walking-left-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Left/Character1_Walking_Left_6.png") >> .walking-left-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Left/Character1_Walking_Left_7.png") >> .walking-left-image-array ;; ----------- Walking Array (Facing Right) --------------- (LoadTexture "GlodImages/Character_Walking/Walking_Right/Character1_Walking_Right_1.png") >> .walking-right-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Right/Character1_Walking_Right_2.png") >> .walking-right-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Right/Character1_Walking_Right_3.png") >> .walking-right-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Right/Character1_Walking_Right_4.png") >> .walking-right-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Right/Character1_Walking_Right_5.png") >> .walking-right-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Right/Character1_Walking_Right_6.png") >> .walking-right-image-array (LoadTexture "GlodImages/Character_Walking/Walking_Right/Character1_Walking_Right_7.png") >> .walking-right-image-array (Count .walking-left-image-array) = .walking-image-index-max 0 >= .walking-image-index 0.08 = .walking-animation-speed ;; Reduce number to increase animation speed
- Added to line 35.
.character-left
, .character-right
are updated to display an image from their respective arrays.
```{.clojure .annotate linenums="1"}
.walking-left-image-array (Take .walking-image-index) ;; (1)
.walking-right-image-array (Take .walking-image-index)
```
1. Update lines 115 - 116.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
|
Create a Wire for the walking animation and Step
it.
1 2 3 4 5 6 7 8 |
|
- Added to line 67.
1 |
|
- Added to line 104.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
|
Step 3.6¶
If you tried running the program, you might notice some problems.
Namely:
- Glod does not return to his idle animation.
- Glod's jumping animation only faces right.
Let's fix these problems.
Why don't we start with the easier one first? Let's get Glod to return to his idle animation when we are not pressing any buttons.
To do this we will:
-
Use
Inputs.KeyUp
. -
Create a variable that tracks which direction Glod is facing towards.
1 |
|
- Added to line 12 under
initialize-character
.
;; ------- Button Inputs ---------- (defshards button-inputs [] ;; (1) (Inputs.KeyDown :Key "left" :Action (-> (Msg "left") 1 > .character-state 0 > .character-direction))
(Inputs.KeyDown ;; (3) :Key "right" :Action (-> (Msg "right") 2 > .character-state 1 > .character-direction))
(Inputs.KeyDown :Key "up" :Action (-> (Msg "up") 3 > .character-state))
(Inputs.KeyUp ;; (2) :Key "left" :Action (-> 0 > .character-state))
(Inputs.KeyUp :Key "right" :Action (-> 0 > .character-state))) ```
-
Added to line 78.
-
When the left and right buttons are released,
.character-state
will revert back to 0. -
When the left and right buttons are pressed
.character-direction
will be 0 and 1 respectively.
Lastly, we will add another Match
nested within Match [0(->)]
so that Glod displays the correct image based on his direction.
```{.clojure .annotate linenums="1"}
(Match [0 (-> .character-direction
(Match [0 (-> .idle-left-image-array (Take .idle-image-index) (UI.Image :Scale (float2 0.2)))
1 (-> .idle-right-image-array (Take .idle-image-index) (UI.Image :Scale (float2 0.2)))]
:Passthrough false))
1 (-> .walking-left-image-array (Take .walking-image-index) (UI.Image :Scale (float2 0.2)))
2 (-> .walking-right-image-array (Take .walking-image-index) (UI.Image :Scale (float2 0.2)))
3 (-> .character-jumping (UI.Image :Scale (float2 0.2)))]
:Passthrough false)
```
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
|
When you run the programme, Glod will return to his idle animation whenever you stop pressing the left, right or up buttons and he should be facing the correct direction. Now we have to do the same thing for our jump animation
- Download Jumping Image here.
1 2 3 |
|
Add in a jumping right image and rename our original .character-jumping to .character-jumping-left added to line 5 - 7.
1 2 3 4 5 6 7 8 9 10 11 |
|
Then add another Match to our original Match to show the corresponding jump image depending on Glod's direction.Code added to lines 127-137.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
|
Recap¶
Try running the code now! Your adorable Glod should be fully animated and will now face the correct directions.
Congratulations on making your first animated character in Shards.
To recap, in this step, we used arrays of images to animate Glod. Next, we will break the chains that bind Glod down and give him the power to move.
See you in the next chapter! 😄