App 2.45.2: Halloween's song banner waves
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
This commit is contained in:
@@ -6,6 +6,7 @@ import android.graphics.Canvas;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PathMeasure;
|
||||
import android.graphics.RadialGradient;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
@@ -50,6 +51,8 @@ final class HalloweenView extends ClusterCanvasView {
|
||||
private final Paint image = new Paint(Paint.FILTER_BITMAP_FLAG);
|
||||
private final Paint glow = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private final Path path = new Path();
|
||||
private final Path baseline = new Path();
|
||||
private final PathMeasure measure = new PathMeasure();
|
||||
private final RectF r = new RectF();
|
||||
private final Typeface serif = Typeface.create("serif", Typeface.BOLD);
|
||||
private final Typeface face = Typeface.create("sans-serif-condensed", Typeface.BOLD);
|
||||
@@ -280,7 +283,7 @@ final class HalloweenView extends ClusterCanvasView {
|
||||
// ---------- What plays: a bat tows it across the sky on a banner ----------
|
||||
|
||||
/**
|
||||
* A bat pulls a parchment banner with the song from left to right, high in the sky, behind the
|
||||
* A bat pulls a waving parchment banner with the song from left to right, high in the sky, behind the
|
||||
* sign and the moon, again and again while something plays. Returns whether it is drawn, so
|
||||
* the view keeps animating for it.
|
||||
*/
|
||||
@@ -300,20 +303,33 @@ final class HalloweenView extends ClusterCanvasView {
|
||||
// In the strip of sky above the sign, clear of it.
|
||||
float yc = 34f * u + (float) Math.sin(t * 1.3f) * 4f * u;
|
||||
float top = yc - bh / 2f, bottom = yc + bh / 2f, right = bx + bw, notch = 12f * u;
|
||||
// The ribbon, its trailing end cut as a swallowtail.
|
||||
// The ribbon, waving in the wind: still where the bat holds it, rippling more towards its
|
||||
// tail, which is cut as a swallowtail. The text follows the waves.
|
||||
int steps = Math.max(8, Math.round(bw / (12f * u)));
|
||||
path.reset();
|
||||
path.moveTo(bx, top);
|
||||
path.lineTo(right, top);
|
||||
path.lineTo(right, bottom);
|
||||
path.lineTo(bx, bottom);
|
||||
path.lineTo(bx + notch, yc);
|
||||
for (int i = 0; i <= steps; i++) {
|
||||
float x = right - bw * i / steps;
|
||||
if (i == 0) path.moveTo(x, top + wave(x, right, bw, t, u));
|
||||
else path.lineTo(x, top + wave(x, right, bw, t, u));
|
||||
}
|
||||
path.lineTo(bx + notch, yc + wave(bx + notch, right, bw, t, u));
|
||||
for (int i = steps; i >= 0; i--) path.lineTo(right - bw * i / steps, bottom + wave(right - bw * i / steps, right, bw, t, u));
|
||||
path.close();
|
||||
fill.setColor(BONE);
|
||||
c.drawPath(path, fill);
|
||||
line.setColor(0xFF8A6A3A);
|
||||
line.setStrokeWidth(2f * u);
|
||||
c.drawPath(path, line);
|
||||
label(c, s, bx + notch + (bw - notch) / 2f, yc + 7f * u, 19f * u, INK, face, Paint.Align.CENTER);
|
||||
baseline.reset();
|
||||
for (int i = 0; i <= steps; i++) {
|
||||
float x = bx + notch + (bw - notch) * i / steps;
|
||||
if (i == 0) baseline.moveTo(x, yc + wave(x, right, bw, t, u));
|
||||
else baseline.lineTo(x, yc + wave(x, right, bw, t, u));
|
||||
}
|
||||
measure.setPath(baseline, false);
|
||||
text.setColor(INK);
|
||||
text.setTextAlign(Paint.Align.LEFT);
|
||||
c.drawTextOnPath(s, baseline, Math.max(0f, (measure.getLength() - text.measureText(s)) / 2f), 7f * u, text);
|
||||
// The tow lines, and the bat at their end.
|
||||
float batX = right + tow, batY = yc - 10f * u;
|
||||
line.setColor(BAT_EDGE);
|
||||
@@ -324,6 +340,15 @@ final class HalloweenView extends ClusterCanvasView {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* How far the banner bends at {@code x}: nothing at the bat's end ({@code right}), up to 7 units
|
||||
* at the tail, in waves that run from the bat to the tail.
|
||||
*/
|
||||
private static float wave(float x, float right, float bw, float t, float u) {
|
||||
float along = right - x;
|
||||
return 7f * u * (along / bw) * (float) Math.sin(along / (170f * u) * 2f * Math.PI - t * 5f);
|
||||
}
|
||||
|
||||
/** {@code s} cut with "…" to fit {@code room} in the text paint as set. */
|
||||
private String cut(String s, float room) {
|
||||
if (text.measureText(s) <= room) return s;
|
||||
|
||||
Reference in New Issue
Block a user