Skip to content

Commit

Permalink
Added a "keep area" checkbox to the sprite transformation panel.
Browse files Browse the repository at this point in the history
- This allows for easy "squash and stretch" effects.
  • Loading branch information
Espyo committed May 16, 2024
1 parent 512044d commit a052058
Show file tree
Hide file tree
Showing 13 changed files with 116 additions and 39 deletions.
1 change: 1 addition & 0 deletions Manual/content/changelog.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ <h2 id="0.26.0">0.26.0</h2>
<ul>
<li><span class="cl-a">Added</span> a tint color property to <a href="animation.html">sprites</a>.</li>
<li><span class="cl-a">Added</span> the ability for frames of animation to interpolate their transformation data (sprite translation, sprite rotation, etc.) from one to the next.</li>
<li><span class="cl-a">Added</span> a "keep area" checkbox to the sprite transformation panel. This is useful for "squash and stretch" effects.</li>
<li><span class="cl-a">Added</span> the ability to hold Shift while pressing the play/stop button in the animation editor in order to start from the beginning.</li>
</ul>
</li>
Expand Down
2 changes: 2 additions & 0 deletions Source/documents/Todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ Next tasks (roughly sorted most important first)
Mobs for decorative pebbles, stones, and sticks
More particles
Dust particles while walking
Dust poof when a leader lands from a height
There should be some petal particle effects when a Pikmin loses their maturity
Paper bags should do one final puff of dust when they finish their squashing animation. The particles should also be more brown than white
More across the board
Expand Down Expand Up @@ -221,6 +222,7 @@ Next tasks (roughly sorted most important first)
Move area loading to area_data::load_from_data_node
Add the new common content properties to everything in the engine
A way for the user to set a background texture for the animation editor instead of the plain green
A small "Got it!" for the score bar, to mark the medal you have
Format the whole code with Astyle, once #563 is fixed
This setup seemed to work ok, or at least as a start:
"astyle.cmd_options": [
Expand Down
3 changes: 3 additions & 0 deletions Source/source/game_states/animation_editor/editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ class animation_editor : public editor {
//Keep the aspect ratio when resizing the current sprite?
bool cur_sprite_keep_aspect_ratio = true;

//Keep the total area when resizing the current sprite?
bool cur_sprite_keep_area = false;

//The current transformation widget.
transformation_widget cur_transformation_widget;

Expand Down
4 changes: 4 additions & 0 deletions Source/source/game_states/animation_editor/event_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ void animation_editor::handle_lmb_drag(const ALLEGRO_EVENT &ev) {
&cur_sprite->angle,
1.0f / game.cam.zoom,
cur_sprite_keep_aspect_ratio,
cur_sprite_keep_area,
-FLT_MAX,
is_alt_pressed
)
Expand All @@ -393,6 +394,7 @@ void animation_editor::handle_lmb_drag(const ALLEGRO_EVENT &ev) {
nullptr,
1.0f / game.cam.zoom,
true,
false,
ANIM_EDITOR::HITBOX_MIN_RADIUS * 2.0f,
is_alt_pressed
);
Expand All @@ -413,6 +415,7 @@ void animation_editor::handle_lmb_drag(const ALLEGRO_EVENT &ev) {
nullptr,
1.0f / game.cam.zoom,
false,
false,
ANIM_EDITOR::HITBOX_MIN_RADIUS * 2.0f,
is_alt_pressed
);
Expand All @@ -437,6 +440,7 @@ void animation_editor::handle_lmb_drag(const ALLEGRO_EVENT &ev) {
&cur_sprite->top_angle,
1.0f / game.cam.zoom,
top_keep_aspect_ratio,
false,
ANIM_EDITOR::TOP_MIN_SIZE,
is_alt_pressed
);
Expand Down
23 changes: 16 additions & 7 deletions Source/source/game_states/animation_editor/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2485,7 +2485,7 @@ void animation_editor::process_gui_panel_sprite_top() {
if(
process_gui_size_widgets(
"Size", cur_sprite->top_size, 0.01f,
top_keep_aspect_ratio, ANIM_EDITOR::TOP_MIN_SIZE
top_keep_aspect_ratio, false, ANIM_EDITOR::TOP_MIN_SIZE
)
) {
changes_mgr.mark_as_changed();
Expand Down Expand Up @@ -2601,10 +2601,8 @@ void animation_editor::process_gui_panel_sprite_transform() {
//Sprite scale value.
if(
process_gui_size_widgets(
"Scale",
cur_sprite->scale,
0.005f,
cur_sprite_keep_aspect_ratio,
"Scale", cur_sprite->scale,
0.005f, cur_sprite_keep_aspect_ratio, cur_sprite_keep_area,
-FLT_MAX
)
) {
Expand Down Expand Up @@ -2634,10 +2632,21 @@ void animation_editor::process_gui_panel_sprite_transform() {
}

//Keep aspect ratio checkbox.
ImGui::Checkbox("Keep aspect ratio", &cur_sprite_keep_aspect_ratio);
ImGui::Unindent();
if(ImGui::Checkbox("Keep aspect ratio", &cur_sprite_keep_aspect_ratio)) {
cur_sprite_keep_area = false;
}
set_tooltip("Keep the aspect ratio when resizing the sprite.");

//Keep area checkbox.
if(ImGui::Checkbox("Keep area", &cur_sprite_keep_area)) {
cur_sprite_keep_aspect_ratio = false;
};
ImGui::Unindent();
set_tooltip(
"Keeps the same total area when resizing the sprite.\n"
"Useful for squash and stretch effects."
);

//Sprite angle value.
cur_sprite->angle = normalize_angle(cur_sprite->angle);
if(
Expand Down
4 changes: 4 additions & 0 deletions Source/source/game_states/area_editor/event_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,7 @@ void area_editor::handle_lmb_drag(const ALLEGRO_EVENT &ev) {
nullptr,
1.0f / game.cam.zoom,
false,
false,
MISSION::EXIT_MIN_SIZE,
is_alt_pressed
);
Expand All @@ -1486,6 +1487,7 @@ void area_editor::handle_lmb_drag(const ALLEGRO_EVENT &ev) {
&selection_angle,
1.0f / game.cam.zoom,
false,
false,
AREA_EDITOR::SELECTION_TW_PADDING * 2.0f,
is_alt_pressed
);
Expand Down Expand Up @@ -1677,6 +1679,7 @@ void area_editor::handle_lmb_drag(const ALLEGRO_EVENT &ev) {
&shadow_angle,
1.0f / game.cam.zoom,
selected_shadow_keep_aspect_ratio,
false,
-FLT_MAX,
is_alt_pressed
)
Expand All @@ -1700,6 +1703,7 @@ void area_editor::handle_lmb_drag(const ALLEGRO_EVENT &ev) {
nullptr,
1.0f / game.cam.zoom,
reference_keep_aspect_ratio,
false,
5.0f,
is_alt_pressed
);
Expand Down
19 changes: 12 additions & 7 deletions Source/source/game_states/area_editor/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1332,12 +1332,17 @@ void area_editor::process_gui_panel_details() {
);

//Tree shadow size value.
process_gui_size_widgets(
"Size", selected_shadow->size,
1.0f, selected_shadow_keep_aspect_ratio,
-FLT_MAX,
[this] () { register_change("tree shadow size change"); }
);
point shadow_size = selected_shadow->size;
if(
process_gui_size_widgets(
"Size", shadow_size,
1.0f, selected_shadow_keep_aspect_ratio, false,
-FLT_MAX
)
) {
register_change("tree shadow size change");
selected_shadow->size = shadow_size;
};
set_tooltip(
"Width and height of the tree shadow.",
"", WIDGET_EXPLANATION_DRAG
Expand Down Expand Up @@ -5684,7 +5689,7 @@ void area_editor::process_gui_panel_tools() {
//Reference size value.
process_gui_size_widgets(
"Size", reference_size, 1.0f,
reference_keep_aspect_ratio,
reference_keep_aspect_ratio, false,
AREA_EDITOR::REFERENCE_MIN_SIZE
);
set_tooltip(
Expand Down
83 changes: 65 additions & 18 deletions Source/source/game_states/editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1385,17 +1385,17 @@ bool editor::process_gui_mob_type_widgets(
* ImGui::DragFloat2. 1.0f for default.
* @param keep_aspect_ratio If true, changing one will change the other
* in the same ratio.
* @param keep_area If true, changing one will change the other
* such that the total area is preserved.
* @param min_size Minimum value that either width or height is allowed
* to have. Use -FLT_MAX for none.
* @param pre_change_callback Callback to call when the width or height is
* changed, before it actually changes.
* @return Whether the user changed one of the values.
*/
bool editor::process_gui_size_widgets(
const char* label, point &size, const float v_speed,
const bool keep_aspect_ratio,
const float min_size,
const std::function<void()> &pre_change_callback
const bool keep_area,
const float min_size
) {
bool ret = false;
point new_size = size;
Expand All @@ -1404,19 +1404,18 @@ bool editor::process_gui_size_widgets(
label, (float*) &new_size, v_speed, min_size, FLT_MAX
)
) {
if(pre_change_callback) {
pre_change_callback();
}

if(
!keep_aspect_ratio ||
size.x == 0.0f || size.y == 0.0f ||
new_size.x == 0.0f || new_size.y == 0.0f
) {
//Just change them, and forget about keeping the aspect ratio.

bool free_resize = !keep_aspect_ratio && !keep_area;
bool values_valid =
size.x != 0.0f && size.y != 0.0f &&
new_size.x != 0.0f && new_size.y != 0.0f;

if(free_resize || !values_valid) {
//Just change them, forget about keeping the aspect ratio or area.
new_size.x = std::max(min_size, new_size.x);
new_size.y = std::max(min_size, new_size.y);
} else {

} else if(keep_aspect_ratio) {
//Keep the aspect ratio.
float ratio = size.x / size.y;
if(new_size.x != size.x) {
Expand All @@ -1434,9 +1433,27 @@ bool editor::process_gui_size_widgets(
}
new_size.x = new_size.y * ratio;
}

} else {
//Keep the area.
double area = size.x * size.y;
if(new_size.x != size.x) {
//Must adjust Y.
if(min_size != -FLT_MAX) {
new_size.x = std::max(min_size, new_size.x);
}
new_size.y = area / new_size.x;
} else {
//Must adjust X.
if(min_size != -FLT_MAX) {
new_size.y = std::max(min_size, new_size.y);
}
new_size.x = area / new_size.y;
}

}
size = new_size;

size = new_size;
ret = true;
}

Expand Down Expand Up @@ -2673,6 +2690,8 @@ bool editor::transformation_widget::handle_mouse_down(
* @param angle Angle. If nullptr, no rotation handling will be performed.
* @param zoom Zoom the widget's components by this much.
* @param keep_aspect_ratio If true, aspect ratio is kept when resizing.
* @param keep_area If true, keep the same total area.
* Used for squash and stretch.
* @param min_size Minimum possible size for the width or height.
* Use -FLT_MAX for none.
* @param lock_center If true, scaling happens with the center locked.
Expand All @@ -2681,8 +2700,8 @@ bool editor::transformation_widget::handle_mouse_down(
*/
bool editor::transformation_widget::handle_mouse_move(
const point &mouse_coords, point* center, point* size, float* angle,
const float zoom, const bool keep_aspect_ratio, const float min_size,
const bool lock_center
const float zoom, const bool keep_aspect_ratio, const bool keep_area,
const float min_size, const bool lock_center
) {
if(!center) return false;

Expand Down Expand Up @@ -2776,6 +2795,34 @@ bool editor::transformation_widget::handle_mouse_move(
scale_to_use = std::max(min_size / old_size.x, scale_to_use);
scale_to_use = std::max(min_size / old_size.y, scale_to_use);
new_size = old_size * scale_to_use;

} else if(keep_area && old_size.x != 0.0f && old_size.y != 0.0f) {
bool by_x;
float w_scale = new_size.x / old_size.x;
float h_scale = new_size.y / old_size.y;
double old_area = old_size.x * old_size.y;
if(!scaling_y) {
by_x = true;
} else if(!scaling_x) {
by_x = false;
} else {
if(fabs(w_scale) < fabs(h_scale)) {
by_x = true;
} else {
by_x = false;
}
}
if(by_x) {
if(min_size != -FLT_MAX) {
new_size.x = std::max(min_size, new_size.x);
}
new_size.y = old_area / new_size.x;
} else {
if(min_size != -FLT_MAX) {
new_size.y = std::max(min_size, new_size.y);
}
new_size.x = old_area / new_size.y;
}
}

switch(moving_handle) {
Expand Down
5 changes: 3 additions & 2 deletions Source/source/game_states/editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ class editor : public game_state {
const point &mouse_coords, point* center, point* size, float* angle,
const float zoom = 1.0f,
const bool keep_aspect_ratio = false,
const bool keep_area = false,
const float min_size = -FLT_MAX,
const bool lock_center = true
);
Expand Down Expand Up @@ -626,8 +627,8 @@ class editor : public game_state {
);
bool process_gui_size_widgets(
const char* label, point &size, const float v_speed,
const bool keep_aspect_ratio, const float min_size,
const std::function<void()> &pre_change_callback = nullptr
const bool keep_aspect_ratio, const bool keep_area,
const float min_size
);
void process_gui_status_bar_text();
void process_gui_unsaved_changes_dialog();
Expand Down
1 change: 1 addition & 0 deletions Source/source/game_states/gui_editor/event_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ void gui_editor::handle_lmb_drag(const ALLEGRO_EVENT &ev) {
nullptr,
1.0f / game.cam.zoom,
false,
false,
0.10f,
is_alt_pressed
);
Expand Down
2 changes: 1 addition & 1 deletion Source/source/game_states/gui_editor/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ void gui_editor::process_gui_panel_item() {
//Size values.
if(
process_gui_size_widgets(
"Size", cur_item_ptr->size, 0.10f, false, 0.10f
"Size", cur_item_ptr->size, 0.10f, false, false, 0.10f
)
) {
changes_mgr.mark_as_changed();
Expand Down
6 changes: 3 additions & 3 deletions Source/source/mobs/mob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ const float CARRY_SWAY_X_TRANSLATION_AMOUNT = 2.0f;
const float CARRY_SWAY_Y_TRANSLATION_AMOUNT =
CARRY_SWAY_X_TRANSLATION_AMOUNT / 2.0f;

//How much to change the scale by during a damage squash-and-stretch animation.
//How much to change the scale by during a damage squash and stretch animation.
const float DAMAGE_SQUASH_AMOUNT = 0.04f;

//Duration of the damage squash-and-stretch animation.
//Duration of the damage squash and stretch animation.
const float DAMAGE_SQUASH_DURATION = 0.25f;

//When a mob shakes during delivery, this is the shake multiplier.
Expand Down Expand Up @@ -1388,7 +1388,7 @@ void mob::do_attack_effects(
attack_sfx_config
);

//Damage squash-and-stretch animation.
//Damage squash and stretch animation.
if(damage_squash_time == 0.0f) {
damage_squash_time = MOB::DAMAGE_SQUASH_DURATION;
}
Expand Down
2 changes: 1 addition & 1 deletion Source/source/mobs/mob.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ class mob {
//If not LARGE_FLOAT, compare the Z with this to shrink/grow the sprite.
float height_effect_pivot = LARGE_FLOAT;

//Time left in the current damage squash-and-stretch animation.
//Time left in the current damage squash and stretch animation.
float damage_squash_time = 0.0f;

//Particle generators attached to it.
Expand Down

0 comments on commit a052058

Please sign in to comment.