Card flipping in Godot
Finished code (Godot project) can be found here:
The goal is to create flippable cards. The flip animation will be achieved via animating the
rect_scale.x to a near zero value; change of texture; and animating the
rect_scale.x value back to 1.
Make 2 cards. One flippable via a button close-by; and another card that can itslef be clicked to flip.
The first scene,
res://scenes/card/card.tscn, will have a
TextureRect (named "Node2D" below, but it's actually of type
TextureRect) with an AnimationPlayer. The
Control.Rect.Size will have an
170 and a y of
Pivot Offset is set at half the
85. This will be important when we animate the
rect_scale.x. If we don't change it, the animation will happen from the left side of the card.
Next, for the
- Create a new animation called "flip".
- Adjust the duration to
- Adjust the timeline zoom to fit the new duration.
- Add a track to animate the
- Insert a key at time 0.
- Insert a key at time 0.1 and adjust the
- Insert a key at time 0.2.
- Add a call method track on the
TextureRect- but there's nothing to assign yet as we haven't written the function yet. Basically, this function will get called at time 0.1 during the animation i.e. when the card is basically invisible (we want to swap the texture based on whether the card is face up or down).
Now add a script on the root
extends TextureRectonready var ap: AnimationPlayer = $AnimationPlayervar is_face_up = falseexport var front_texture: Textureexport var back_texture: Texturefunc _ready():set_texture()func set_texture(a_texture = null):if a_texture == null:texture = front_texture if is_face_up else back_textureelse:texture = a_texture
We get a reference to the
AnimationPlayer and store it in
ap since we'll need that soon enough.
is_face_up is used to track whether or not the card is facing up.
back_texture will be the 2 different images the
TextureRect can take. A
TextureRect has a
texture property. Since we are
extends TextureRect, we have access to it and in
set_texture (which we are overriding from the parent), we flip the texture based on
is_face_up if we pass in no argument.
Next we add a way to
flip_texture (which is what will be attached to the
0.1 time on the AnimationPlayer), and a
flip function which can be used to start the animation programmatically - such that calling
flip will call
flip_texture 0.1 seconds later:
func flip_texture():is_face_up = !is_face_upset_texture()func flip():ap.play("flip")
Add a new root node e.g.
Node2D, and "Instance child scene" to instanciate a node from the
res://scenes/card/card.tscn scene, and name it
TextureRect texture is just so we can see it in the Godot editor. When executed, the
Front Texture and
Back Texture will take effect.
Next add a button somewhere and give it some text like "Flip" (feel free to increase its size). We'll need to use the
pressed() signal and attach it to a function in the
tmp scene's root node, which doesn't have a script yet, so add one for it:
extends Node2D# Attach this to the button's pressed signal:func _on_flip_button_pressed():$Club10.flip()
Pretty straight-forward; we're flipping the card when the button is pressed.
Next we'll create a new scene based on the
card.tscn one. From Godot's top menubar: Scene -> New Inherited Scene; and choose
Button node as a sibling to the
AnimationPlayer and set its size equal to the
170 and y of
245. Also, we don't want the button to be visible so set it's
CanvasItem -> Visibility -> Modulate -> alpha to
0. We don't want to tick the
off as that would make it unclickable.
That's all we need to do here; we'll attach the
pressed signal elsewhere.
At this point, you can go back to
tmp.tscn, add a
clickableCard scene instance and give it a front and back texture. Add the following to
func _ready():$Diamond10/Button.connect('pressed', self, '_on_diamond10_pressed')func _on_diamond10_pressed():$Diamond10.flip()
Note that I named the
clickableCard node instance as "Diamond10" and on
tmp scene is ready, I'm attaching that instance's
pressed signal to this script's
tmp scene should allow you to click the button to flip one card, and click the other card to flip itself.