Add screen fade-in and card deal-in animations

Cards slide in one after another when a game starts and can't be picked
until they have landed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
SansanandClaude Opus 5.5 committed 2026-10-01 21:36:54 +02:00
1 parent 83ff9511ec
commit 3794a9e2e9
4 files changed
+1751 -1159

No files matched your search

+21 -5
View File
@@ -15,6 +15,8 @@ ROUNDNESS :: 0.16
SEGMENTS :: 16
FLIP_SPEED :: 2.6 // flips per second
DEAL_SPEED :: 3.5 // how fast a dealt card settles
DEAL_STAGGER :: 0.12 // delay between consecutive cards, in deal_t units
PULSE_DURATION :: 0.35 // seconds
HOVER_LIFT :: 4
@@ -28,6 +30,7 @@ Card :: struct {
matched: bool,
flip_t: f32, // 0 = back showing, 1 = face showing
pulse_t: f32, // counts down after a match
deal_t: f32, // > 0 while being dealt onto the table (0 = resting)
face_art: raylib.RenderTexture2D,
}
@@ -214,6 +217,14 @@ update :: proc(card: ^Card, dt: f32) {
if card.pulse_t > 0 {
card.pulse_t = max(card.pulse_t - dt, 0)
}
if card.deal_t > 0 {
card.deal_t = max(card.deal_t - dt * DEAL_SPEED, 0)
}
}
// Starts the deal-in animation; later cards in the deal arrive later
start_deal :: proc(card: ^Card, order: int) {
card.deal_t = 1 + f32(order) * DEAL_STAGGER
}
start_pulse :: proc(card: ^Card) {
@@ -241,7 +252,12 @@ draw :: proc(card: ^Card, theme: themes.Theme, clickable: bool, focused := false
hovered := mouse_over || (clickable && focused)
if hovered { lift += HOVER_LIFT }
scale: f32 = 1
// Dealing: slide up from below and grow in
dealt := smoothstep(1 - clamp(card.deal_t, 0, 1))
if dealt == 0 { return }
deal_offset := (1 - dealt) * 60
scale: f32 = 0.85 + 0.15 * dealt
if card.pulse_t > 0 {
progress := 1 - card.pulse_t / PULSE_DURATION
scale += 0.09 * math.sin(progress * math.PI)
@@ -249,20 +265,20 @@ draw :: proc(card: ^Card, theme: themes.Theme, clickable: bool, focused := false
width := card.rect.width * scale
height := card.rect.height * scale
center := raylib.Vector2{card.rect.x + card.rect.width / 2, card.rect.y + card.rect.height / 2 - lift}
center := raylib.Vector2{card.rect.x + card.rect.width / 2, card.rect.y + card.rect.height / 2 - lift + deal_offset}
// Shadow stays on the table and spreads as the card lifts
shadow := raylib.Rectangle{
center.x - width * squash / 2 + 2,
card.rect.y + card.rect.height * (1 - scale) / 2 + 4 + lift * 0.15,
card.rect.y + card.rect.height * (1 - scale) / 2 + 4 + lift * 0.15 + deal_offset,
max(width * squash, 2),
height,
}
raylib.DrawRectangleRounded(shadow, ROUNDNESS, SEGMENTS, raylib.Fade(themes.BLACK, 0.12 - lift * 0.004))
raylib.DrawRectangleRounded(shadow, ROUNDNESS, SEGMENTS, raylib.Fade(themes.BLACK, (0.12 - lift * 0.004) * dealt))
// Darken the card while it is edge-on, to fake lighting
shade := u8(255 - (1 - squash) * 70)
tint := raylib.Color{shade, shade, shade, 255}
tint := raylib.Color{shade, shade, shade, u8(255 * dealt)}
if hovered && !showing_face {
tint = raylib.ColorBrightness(tint, 0.08)
}