Draw the touch ring in engine instead of a particle

This commit is contained in:
shweet committed 2026-11-13 01:02:25 -05:00
1 parent dcd3006f24
commit 4e3abaa381
11 files changed
+33 -78

No files matched your search

+2 -4
View File
@@ -174,7 +174,6 @@ The first expand area is treated as the belly: it breathes, jiggles when smacked
| `scaleCycles` | float | How many oscillations the scale effect performs. Defaults to 1. | | `scaleCycles` | float | How many oscillations the scale effect performs. Defaults to 1. |
| `scaleTime` | float, seconds | How long the scale effect lasts. Defaults to a third of a second. | | `scaleTime` | float, seconds | How long the scale effect lasts. Defaults to a third of a second. |
| `sounds` | paths | Sounds played when interacting. | | `sounds` | paths | Sounds played when interacting. |
| `particles` | strings | Particles (see `particles`) spawned when interacting. |
### sounds ### sounds
| Key | Meaning | | Key | Meaning |
@@ -186,12 +185,11 @@ The first expand area is treated as the belly: it breathes, jiggles when smacked
How items move in the background (`gfx/area.anm2`): `gravity` (applied to items' velocities per tick), `friction` (applied when items are grounded or hit walls) and `airResistance`. How items move in the background (`gfx/area.anm2`): `gravity` (applied to items' velocities per tick), `friction` (applied when items are grounded or hit walls) and `airResistance`.
### cursor ### cursor
The cursor's sounds and particles. Its look is `gfx/cursor.anm2` (see "Fixed files and names"). The cursor's sounds. Its look is `gfx/cursor.anm2` (see "Fixed files and names").
| Key | Meaning | | Key | Meaning |
|---|---| |---|---|
| `sounds` | `grab` (grabbing an item), `release` (letting go) and `throw` (letting go while dragging quickly). | | `sounds` | `grab` (grabbing an item), `release` (letting go) and `throw` (letting go while dragging quickly). |
| `particles` | `grab`: particles spawned when grabbing an item. |
### menu ### menu
The UI's sounds. The UI's sounds.
@@ -201,7 +199,7 @@ The UI's sounds.
| `sounds` | `open` and `close` (the taskbar or one of its windows), `hover` and `select` (a widget), and `cheats` (after entering a special code to activate cheats). | | `sounds` | `open` and `close` (the taskbar or one of its windows), `hover` and `select` (a widget), and `cheats` (after entering a special code to activate cheats). |
### particles ### particles
An object of particles by name, each with the `anm2` and `animation` it plays once where spawned. The `Circle` particle is also spawned where an item lands hard. An object of particles by name, each with the `anm2` and `animation` it plays once where spawned. (The ring where something is touched, grabbed or lands hard is drawn by the game, not a particle.)
# items.json # items.json
+5 -10
View File
@@ -20,8 +20,7 @@
"isHold": true, "isHold": true,
"cursorHover": "Hover", "cursorHover": "Hover",
"cursorActive": "Rub", "cursorActive": "Rub",
"sounds": ["sfx/rub.ogg"], "sounds": ["sfx/rub.ogg"]
"particles": ["Circle"]
}, },
"Smack": { "Smack": {
"icon": "smack", "icon": "smack",
@@ -30,21 +29,18 @@
"dialogueCooldown": 0.6667, "dialogueCooldown": 0.6667,
"scaleAmplitude": 1, "scaleAmplitude": 1,
"scaleCycles": 3, "scaleCycles": 3,
"sounds": "sfx/smack*.ogg", "sounds": "sfx/smack*.ogg"
"particles": ["Circle"]
}, },
"Kiss": { "Kiss": {
"icon": "kiss", "icon": "kiss",
"cursorHover": "KissHover", "cursorHover": "KissHover",
"cursorActive": "Kiss", "cursorActive": "Kiss",
"sounds": "sfx/kiss*.ogg", "sounds": "sfx/kiss*.ogg"
"particles": ["Circle"]
}, },
"Turn Around": {"icon": "turn", "sounds": ["sfx/turn.ogg"], "particles": ["Circle"]} "Turn Around": {"icon": "turn", "sounds": ["sfx/turn.ogg"]}
}, },
"cursor": { "cursor": {
"sounds": {"grab": ["sfx/grab.ogg"], "release": ["sfx/release.ogg"], "throw": "sfx/throw*.ogg"}, "sounds": {"grab": ["sfx/grab.ogg"], "release": ["sfx/release.ogg"], "throw": "sfx/throw*.ogg"}
"particles": {"grab": ["Circle"]}
}, },
"menu": { "menu": {
"sounds": { "sounds": {
@@ -56,7 +52,6 @@
} }
}, },
"particles": { "particles": {
"Circle": {"anm2": "gfx/circle.anm2", "animation": "Main"},
"Puff": {"anm2": "gfx/puff.anm2", "animation": "Main"} "Puff": {"anm2": "gfx/puff.anm2", "animation": "Main"}
}, },
"area": {"gravity": 0.95, "friction": 0.75, "airResistance": 0.975} "area": {"gravity": 0.95, "friction": 0.75, "airResistance": 0.975}
-48
View File
@@ -1,48 +0,0 @@
{
"anm2ed": 1,
"info": {},
"spritesheets": [
{
"path": "circle.png",
"regions": [
{
"name": "Main",
"size": [128, 128],
"pivot": [64, 64],
"origin": "center"
}
]
}
],
"layers": [
{"name": "Main"}
],
"defaultAnimation": "Spawn",
"animations": {
"Spawn": {
"length": 11,
"loop": false,
"root": [
{"delay": 11}
],
"layers": [
{
"layer": 0,
"frames": [
{
"region": 0,
"scale": [10, 10],
"delay": 10,
"interpolation": "linear"
},
{
"region": 0,
"tint": [255, 255, 255, 0],
"interpolation": "linear"
}
]
}
]
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

+2 -8
View File
@@ -118,7 +118,7 @@ static void interact_parse(object source, InteractArea& area, Character& charact
json_keys_check(source, json_keys_check(source,
{"type", "null", "layer", "icon", "isHold", "animation", "idleOnEnd", "cursorHover", "cursorActive", {"type", "null", "layer", "icon", "isHold", "animation", "idleOnEnd", "cursorHover", "cursorActive",
"dialoguePool", "dialogueCooldown", "digestionClick", "digestionHover", "dialoguePool", "dialogueCooldown", "digestionClick", "digestionHover",
"scaleAmplitude", "scaleCycles", "scaleTime", "sounds", "particles"}, "scaleAmplitude", "scaleCycles", "scaleTime", "sounds"},
"an interact area"); "an interact area");
area.animation = json_string(source, "animation", area.animation); area.animation = json_string(source, "animation", area.animation);
area.cursorActive = json_string(source, "cursorActive", area.cursorActive); area.cursorActive = json_string(source, "cursorActive", area.cursorActive);
@@ -137,8 +137,6 @@ static void interact_parse(object source, InteractArea& area, Character& charact
area.layer = character.anm2 ? character.anm2->layer_get(json_string(source, "layer")) : -1; area.layer = character.anm2 ? character.anm2->layer_get(json_string(source, "layer")) : -1;
if (!source["null"].error()) if (!source["null"].error())
area.null = character.anm2 ? character.anm2->null_get(json_string(source, "null")) : -1; area.null = character.anm2 ? character.anm2->null_get(json_string(source, "null")) : -1;
if (!source["particles"].error())
area.particles = json_strings(source, "particles");
if (!source["sounds"].error()) if (!source["sounds"].error())
area.sounds = audio.sounds_get(character.roots, json_strings(source, "sounds")); area.sounds = audio.sounds_get(character.roots, json_strings(source, "sounds"));
} }
@@ -259,11 +257,7 @@ static void character_parse(object root, Character& character, Renderer& rendere
float_read(area, "friction", character.area.friction); float_read(area, "friction", character.area.friction);
float_read(area, "airResistance", character.area.airResistance); float_read(area, "airResistance", character.area.airResistance);
object cursor = json_object(root, "cursor"); json_keys_check(json_object(root, "cursor"), {"sounds"}, "cursor");
object cursorParticles = json_object(cursor, "particles");
json_keys_check(cursor, {"sounds", "particles"}, "cursor");
if (!cursorParticles["grab"].error())
character.cursor.grabParticles = json_strings(cursorParticles, "grab");
json_keys_check(json_object(root, "menu"), {"sounds"}, "menu"); json_keys_check(json_object(root, "menu"), {"sounds"}, "menu");
for (auto [name, value] : json_object(root, "particles")) for (auto [name, value] : json_object(root, "particles"))
-2
View File
@@ -84,7 +84,6 @@ struct InteractArea
std::string icon; std::string icon;
std::string idleOnEnd; std::string idleOnEnd;
std::string name; std::string name;
std::vector<std::string> particles;
Sounds sounds; Sounds sounds;
float digestionClick = 0; float digestionClick = 0;
float digestionHover = 0; float digestionHover = 0;
@@ -283,7 +282,6 @@ struct Swap
struct Cursor struct Cursor
{ {
std::vector<std::string> grabParticles;
Anm2* anm2 = nullptr; Anm2* anm2 = nullptr;
}; };
+9
View File
@@ -1,5 +1,6 @@
#include "effects.h" #include "effects.h"
constexpr Spark RING_SPARK = {WHITE, {}, {}, {}, 0, 64, 20, 0, SPARK_RING};
constexpr float FLASH_FADE = 0.04f; constexpr float FLASH_FADE = 0.04f;
constexpr float FLOATER_RISE = 0.8f; constexpr float FLOATER_RISE = 0.8f;
constexpr float SPARK_DRAG = 0.95f; constexpr float SPARK_DRAG = 0.95f;
@@ -36,6 +37,14 @@ void Effects::spark_add(Spark spark)
sparks.push_back(spark); sparks.push_back(spark);
} }
// A white ring growing and fading where something was touched or hit.
void Effects::ring_add(Vec2 position)
{
Spark spark = RING_SPARK;
spark.position = position;
spark_add(spark);
}
// Throws count copies of a spark out in every direction, at up to speed. // Throws count copies of a spark out in every direction, at up to speed.
void Effects::burst_add(Spark spark, int count, float speed) void Effects::burst_add(Spark spark, int count, float speed)
{ {
+4 -2
View File
@@ -15,6 +15,7 @@ enum SparkShape
{ {
SPARK_CIRCLE, SPARK_CIRCLE,
SPARK_LINE, SPARK_LINE,
SPARK_RING,
SPARK_STAR SPARK_STAR
}; };
@@ -27,8 +28,8 @@ struct Floater
FloaterType type = FLOATER_CALORIES; FloaterType type = FLOATER_CALORIES;
}; };
// A glint, puff or line (from its position to its end) that drifts, falls (or rises) by its gravity, and fades over its // A glint, puff, line (from its position to its end) or ring (growing to its size) that drifts, falls (or rises) by its
// life. // gravity, and fades over its life.
struct Spark struct Spark
{ {
Color color; Color color;
@@ -54,4 +55,5 @@ public:
void floater_add(Vec2 position, float value, FloaterType type); void floater_add(Vec2 position, float value, FloaterType type);
void spark_add(Spark spark); void spark_add(Spark spark);
void burst_add(Spark spark, int count, float speed); void burst_add(Spark spark, int count, float speed);
void ring_add(Vec2 position);
}; };
+1 -1
View File
@@ -62,7 +62,7 @@ void Interactions::update(Play& play, Pointer pointer)
} }
play.audio->play(entry.sounds); play.audio->play(entry.sounds);
body.idle_override_set(entry.idleOnEnd); body.idle_override_set(entry.idleOnEnd);
play.particles_spawn(entry.particles, pointer.position); play.effects.ring_add(pointer.position);
if (entry.digestionClick > 0 && body.stats.calories > 0 && !body.stats.isDigesting) if (entry.digestionClick > 0 && body.stats.calories > 0 && !body.stats.isDigesting)
body.stats.digestionProgress += entry.digestionClick; body.stats.digestionProgress += entry.digestionClick;
body.actor.pulse_add(entry.layer, entry.scaleAmplitude, entry.scaleCycles, entry.scaleTime); body.actor.pulse_add(entry.layer, entry.scaleAmplitude, entry.scaleCycles, entry.scaleTime);
+2 -3
View File
@@ -10,7 +10,6 @@ constexpr float CRUMB_SPEED_Y_MIN = 2;
constexpr float CRUMB_SPIN = 15; constexpr float CRUMB_SPIN = 15;
constexpr Color GOLD = {1, 0.85f, 0.3f, 1}; constexpr Color GOLD = {1, 0.85f, 0.3f, 1};
constexpr Color TRAIL_COLOR = {1, 1, 1, 0.35f}; constexpr Color TRAIL_COLOR = {1, 1, 1, 0.35f};
constexpr const char* IMPACT_PARTICLE = "Circle";
constexpr float BITE_JIGGLE = 4; constexpr float BITE_JIGGLE = 4;
constexpr float IMPACT_SPEED = 12; constexpr float IMPACT_SPEED = 12;
constexpr float FANFARE_MIN = 0.75f; constexpr float FANFARE_MIN = 0.75f;
@@ -360,7 +359,7 @@ void Items::update(Play& play, Pointer pointer)
if (pointer.isClicked) if (pointer.isClicked)
{ {
audio.play(character.sounds[SOUND_GRAB]); audio.play(character.sounds[SOUND_GRAB]);
play.particles_spawn(character.cursor.grabParticles, pointer.position); play.effects.ring_add(pointer.position);
isJustHeld = true; isJustHeld = true;
} }
if (pointer.isDown) if (pointer.isDown)
@@ -394,7 +393,7 @@ void Items::update(Play& play, Pointer pointer)
if (impact > 0) if (impact > 0)
audio.play(character.sounds[SOUND_BOUNCE]); audio.play(character.sounds[SOUND_BOUNCE]);
if (impact >= IMPACT_SPEED) if (impact >= IMPACT_SPEED)
play.particles_spawn({IMPACT_PARTICLE}, position); play.effects.ring_add(position);
entity.isThrown &= vec2_length(entity.velocity) >= TRAIL_SPEED; entity.isThrown &= vec2_length(entity.velocity) >= TRAIL_SPEED;
if (entity.isThrown) if (entity.isThrown)
{ {
+8
View File
@@ -31,6 +31,8 @@ constexpr float BAR_SHAKE_SPEED = 40;
constexpr float FLOATER_SHADOW = 3; constexpr float FLOATER_SHADOW = 3;
constexpr float OVERSTUFFED_PULSE = 0.35f; constexpr float OVERSTUFFED_PULSE = 0.35f;
constexpr float OVERSTUFFED_SPEED = 6; constexpr float OVERSTUFFED_SPEED = 6;
constexpr float RING_START = 0.1f;
constexpr float RING_THICKNESS = 3;
constexpr float STAR_WAIST = 0.3f; constexpr float STAR_WAIST = 0.3f;
constexpr float BAR_WIDTH_MIN = 120; constexpr float BAR_WIDTH_MIN = 120;
constexpr float BUTTON_SIZE_MAX = 96; constexpr float BUTTON_SIZE_MAX = 96;
@@ -741,6 +743,12 @@ void Ui::effects_draw(Play& play, ImVec2 screen)
drawList->AddCircleFilled({at.x, at.y}, size, color); drawList->AddCircleFilled({at.x, at.y}, size, color);
continue; continue;
} }
if (spark.shape == SPARK_RING)
{
float radius = spark.size * view.a * (RING_START + (1 - RING_START) * (1 - fade));
drawList->AddCircle({at.x, at.y}, radius, color, 0, RING_THICKNESS * view.a);
continue;
}
if (spark.shape == SPARK_LINE) if (spark.shape == SPARK_LINE)
{ {
Vec2 end = view * spark.end; Vec2 end = view * spark.end;