Brick Breaker

của MusicBar, thanh tiến trình

Quả bóng phát sáng đập vỡ bức tường gạch bóng loáng tới chỗ đang phát, gạch lấp lánh theo nhạc, tới nhịp là một viên vỡ tung thành mảnh vụn.

8 lượt tải Tải file, 7.1 KB
Cách cài, mã SHA-256 và mã nguồn

Bấm Áp dụng: MusicBar tự tải về, kiểm tra mã SHA-256 rồi mặc lên taskbar; có rồi thì mặc luôn. Cần MusicBar 1.8 trở lên.

SHA-256 7a619c4e8eab7bbd58d94c61cbf13b89f60c4ccbfa8e3245290c7a971e9bc1fd

//! name: Brick Breaker
//! author: MusicBar
//! kind: progress
//! description: A glowing ball smashes a wall of glossy bricks up to the playhead, the bricks shimmer with the music, and every beat bursts a brick into flying chips.

float hash1(float n) { return frac(sin(n * 78.233 + 12.9898) * 43758.5453); }

float sdRound(float2 p, float2 b, float r) { float2 q = abs(p) - b + r; return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r; }

float sdSeg(float2 p, float2 a, float2 b)
{
    float2 pa = p - a, ba = b - a;
    return length(pa - ba * saturate(dot(pa, ba) / dot(ba, ba)));
}

// A 0..1..0 triangle wave, so the ball moves in straight lines and bounces.
float tri(float t) { return abs(frac(t) - 0.5) * 2.0; }

// Where the ball is at time t (in bar heights, relative to the wall face): it ricochets between the wall and the paddle.
float2 ballAt(float t, float u)
{
    return float2(lerp(-0.1, -1.72, tri(t * 0.85)), lerp(0.14, 0.86, tri(t * 1.31 + 0.3))) * u;
}

float3 rowColor(float r) { return r < 0.5 ? colorA.rgb : (r < 1.5 ? colorB.rgb : colorC.rgb); }

void layer(inout float3 acc, inout float cover, float3 rgb, float a)
{
    a = saturate(a);
    acc = rgb * a + acc * (1.0 - a);
    cover = a + cover * (1.0 - a);
}

float4 main(float2 uv : TEXCOORD) : COLOR
{
    float u = size.y;
    float2 px = float2(uv.x * size.x, rise(uv) * size.y);
    float head = progress * size.x;
    float aa = 1.0;
    float3 acc = float3(0, 0, 0);
    float cover = 0;

    // Bricks: 3 rows in a running bond, each brick about 2.3 times as wide as it is tall.
    float bh = 0.27 * u, gap = 0.05 * u, bw = 0.62 * u, pitch = bw + gap;
    float r = clamp(floor((px.y - 0.045 * u) / (bh + gap)), 0.0, 2.0);
    float cy = 0.045 * u + r * (bh + gap) + 0.5 * bh;
    float off = frac(r * 0.5) * 2.0 * 0.5 * pitch;
    float n = floor((px.x - off) / pitch);
    float left = n * pitch + off;
    float2 lp = px - float2(left + 0.5 * bw, cy);
    float dBrick = sdRound(lp, float2(0.5 * bw, 0.5 * bh), 0.05 * u);

    // The brick the ball is working on gets chipped away from its left side and cracks; older ones are gone.
    float f = saturate((head - left) / bw);
    float jag = 0.05 * u * sin(px.y / u * 37.0 + n * 3.0) + 0.025 * u * sin(px.y / u * 91.0 + n);
    float eaten = step(px.x, left + f * bw * 0.75 + jag * step(0.01, f));
    float alive = step(head, left + bw) * (1.0 - eaten);
    float2 cp = px - float2(left + f * bw * 0.6, cy);
    float crack = min(min(sdSeg(cp, float2(0, 0), float2(0.22, 0.09) * u), sdSeg(cp, float2(0.22, 0.09) * u, float2(0.34, 0.14) * u)),
                      min(sdSeg(cp, float2(0, 0), float2(0.2, -0.1) * u), sdSeg(cp, float2(0, 0), float2(0.1, 0.13) * u)));
    float crackA = smoothstep(1.4, 0.4, crack) * step(0.01, f) * step(cp.x, f * bw * 1.4);

    // Gloss and bevel: a lit top-left rim, a dark bottom-right rim, a soft highlight band, and a shimmer with the spectrum.
    float spec = spectrum(frac(n * 0.137 + r * 0.29) * 0.8);
    float2 q = abs(lp) - float2(0.5 * bw, 0.5 * bh) + 0.05 * u;
    float2 nrm = (q.x > 0.0 || q.y > 0.0) ? normalize(max(q, 0.0)) * sign(lp) : (q.x > q.y ? float2(sign(lp.x), 0) : float2(0, sign(lp.y)));
    float rim = smoothstep(-0.06 * u, -0.01 * u, dBrick);
    float near = exp(-max(left - head, 0.0) / (3.5 * u));                                  // bricks far from the action stay quieter
    float3 base = rowColor(r) * (0.5 + 0.6 * spec) * lerp(0.7, 1.0, near);
    float3 col = base * (1.0 + rim * 0.75 * dot(nrm, float2(-0.55, 0.83)));
    col += float3(1, 1, 1) * 0.3 * smoothstep(0.0, 0.08 * u, lp.y) * (1.0 - rim) * (0.5 + 0.7 * spec);
    col += float3(1, 1, 1) * 0.45 * smoothstep(1.2, 0.0, abs(lp.y - 0.075 * u)) * step(abs(lp.x), 0.36 * u);   // a crisp gloss line
    float sweep = exp(-abs(frac((px.x - px.y * 0.6) / (7.0 * u) - time * 0.25) - 0.5) * 60.0);
    col += sweep * 0.35 * (1.0 - rim);
    col = lerp(col, rowColor(r) * 0.18, crackA);
    col += float3(1, 1, 1) * beat * 0.6 * step(left, head + 0.5 * bw) * step(head, left + bw);    // the brick at the face flashes on a beat
    float wallA = alive * lerp(0.42 + 0.3 * spec, 0.95, near);
    layer(acc, cover, rowColor(r) * 0.15, wallA * smoothstep(aa, -aa, dBrick - 1.2));
    layer(acc, cover, col, wallA * smoothstep(aa, -aa, dBrick));

    // Debris rains down behind the face: small chips falling and tumbling, fading as they fall.
    float dc = 0.28 * u;
    float di = floor(px.x / dc);
    float h1 = hash1(di), h2 = hash1(di + 31.0), h3 = hash1(di + 57.0);
    float life = frac(time * (0.6 + 0.5 * h2) + h1);
    float2 dp = float2((di + 0.5) * dc - life * 0.3 * u, (0.3 + 0.6 * h3) * u - life * life * 0.95 * u);
    float rotA = time * 5.0 * (h2 - 0.5) + h1 * 6.0;
    float2 dl = px - dp;
    dl = float2(cos(rotA) * dl.x - sin(rotA) * dl.y, sin(rotA) * dl.x + cos(rotA) * dl.y);
    float chip = smoothstep(aa, -aa, sdRound(dl, float2(0.05, 0.035) * u, 0.01 * u));
    float behind = step(px.x, head - 0.1 * u) * exp(-(head - px.x) / (2.4 * u));
    layer(acc, cover, rowColor(floor(h3 * 2.99)) * (0.8 + 0.3 * (1.0 - life)), chip * behind * (1.0 - life * life) * step(0.15, h2));

    // On a beat a brick bursts: chips fly back from the face and fall.
    for (int i = 0; i < 6; i++)
    {
        float fi = i;
        float t = (1.0 - beat) * 0.5;
        float2 v = float2(-(0.8 + 2.2 * hash1(fi + 1.0)), 0.4 + 2.2 * hash1(fi + 2.0)) * u;
        float2 p0 = float2(head, (0.15 + 0.7 * hash1(fi + 3.0)) * u);
        float2 cpos = p0 + v * t - float2(0.0, 4.5 * u) * t * t;
        float bs = 0.05 * u * (1.0 - t);
        layer(acc, cover, rowColor(floor(hash1(fi + 4.0) * 2.99)), step(0.04, beat) * smoothstep(aa, -aa, sdRound(px - cpos, float2(bs, bs * 0.7), 0.01 * u)));
    }

    // The ball with a motion trail, and the paddle that sends it back.
    float2 face = float2(head, 0.0);
    float2 ball = face + ballAt(time, u);
    float2 prev = ball;
    float trail = 0;
    for (int k = 1; k < 7; k++)
    {
        float tk = k;
        float2 bp = face + ballAt(time - tk * 0.02, u);
        float w = 0.07 * u * (1.0 - tk / 7.0);
        trail = max(trail, smoothstep(aa, -aa, sdSeg(px, prev, bp) - w) * (1.0 - tk / 7.0));
        prev = bp;
    }
    layer(acc, cover, lerp(colorC.rgb, float3(1, 1, 1), 0.25), trail * 0.6);
    float bd = length(px - ball);
    float br = 0.075 * u * (1.0 + 0.3 * beat);
    layer(acc, cover, colorC.rgb, exp(-max(bd - br, 0.0) / (0.09 * u)) * (0.55 + 0.35 * beat));
    float3 ballCol = lerp(float3(1, 1, 1), colorC.rgb, smoothstep(0.0, br, length(px - ball - float2(-0.3, 0.3) * br)) * 0.6);
    layer(acc, cover, ballCol, smoothstep(aa, -aa, bd - br));

    float py = clamp(ballAt(time - 0.08, u).y, 0.2 * u, 0.8 * u);
    float2 pp = px - float2(head - 1.84 * u, py);
    float dPad = sdRound(pp, float2(0.045, 0.2) * u, 0.045 * u);
    float pt = saturate(pp.y / (0.4 * u) + 0.5);
    float3 padCol = lerp(float3(0.55, 0.58, 0.68), float3(0.95, 0.96, 1.0), smoothstep(0.03 * u, -0.03 * u, pp.x));
    padCol = lerp(padCol, colorA.rgb, step(0.15 * u, abs(pp.y)));
    layer(acc, cover, float3(0.06, 0.06, 0.1), smoothstep(aa, -aa, dPad - 1.2));
    layer(acc, cover, padCol, smoothstep(aa, -aa, dPad));

    return paint(acc / max(cover, 0.001), cover);
}