Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New extension: TweenGroup #1029

Closed
wants to merge 1 commit into from
Closed

Conversation

github-actions[bot]
Copy link
Contributor

Description

Allows you to create a group of objects with tween behavior, performing tween on all of them.

How to use the extension

You need to create an object with the TweenGroup behavior. Then, you need to register some objects in it with the Register object action. These objects MUST HAVE the tween behavior. Then, you just add the wanted tween on the object with TweenGroup behavior and it will also propagate the same tween to the registered objects.

Checklist

  • I've followed all of the best practices.
  • I confirm that this extension can be integrated to this GitHub repository, distributed and MIT licensed.
  • I am aware that the extension may be updated by anyone, and do not need my explicit consent to do so.

What tier of review do you aim for your extension?

Community (Unreviewed)

Example file

Tween Group Example.zip

Extension file

TweenGroup.zip

@github-actions github-actions bot requested a review from a team as a code owner September 26, 2023 14:48
@github-actions github-actions bot added the ✨ New extension A new extension label Sep 26, 2023
@github-actions github-actions bot mentioned this pull request Sep 26, 2023
3 tasks
@D8H
Copy link
Contributor

D8H commented Sep 26, 2023

Thank you for submitting an extension.

What is the difference with using a tween action on objects picked by conditions?

@george-gca
Copy link
Contributor

george-gca commented Sep 26, 2023

This is to do the same tween in a group of elements. The benefits would be:

1 - encapsulation of the behavior in a single component responsible for the group
2 - cleaner list of events
3 - with it, you can chain tweens with a custom delay. So, for example, you create a group and want that all elements in it do a specific tween with 1s between each element
4 - you can do tween to relative positions, like, instead of every element goes to X = 40, make all elements add 40 to their current X position

You can check the demo for an example of how this would look.

@D8H
Copy link
Contributor

D8H commented Sep 27, 2023

How do you see this extension be used? Can you explain some real-life use-cases?

I noticed some issues:

  • all object instances "register" no matter the conditions
    image
  • I didn't find a way to choose instances order

@george-gca
Copy link
Contributor

george-gca commented Sep 28, 2023

A use case could be an inventory like menu from Zelda a link to the past. When you press a specified button, the menu would slide from one direction with an animation to the top of the screen, with the inverted animation to exit the screen. Another one would be something more cartoonish, where the player runs in one direction and some of its clothes take a little while to follow it, going piece by piece.

I don't think I understand what you mean with the first issue.

About the order of the objects, any suggestions? I could only think about the user adding them one by one in the specific order.

@arthuro555 arthuro555 added the 👨‍👩‍👧‍👦 Community extension An extension submission to be merged ASAP with a lightweight review. label Sep 28, 2023
@D8H
Copy link
Contributor

D8H commented Sep 28, 2023

A use case could be an inventory like menu from Zelda a link to the past. When you press a specified button, the menu would slide from one direction with an animation to the top of the screen, with the inverted animation to exit the screen.

I've never played this game, but I guess that to move a panel and its content together, I would use the Sticker behavior to stick the content to the panel or move a layer camera.
https://wiki.gdevelop.io/gdevelop5/extensions/sticker/

Another one would be something more cartoonish, where the player runs in one direction and some of its clothes take a little while to follow it, going piece by piece.

This case is probably too specific to require an extension. I don't understand how it would be done because the character is moving so it won't stay at the tween target.

I don't think I understand what you mean with the first issue.

Let's say there are 2 rows and you want to create one group for each.

About the order of the objects, any suggestions? I could only think about the user adding them one by one in the specific order.

I guess users would have to register one instance after the other if they want a specific order. The Stack Object behavior does something like this.
https://wiki.gdevelop.io/gdevelop5/extensions/object-stack/

Please feel free to challenge what I said and give other use-cases.

@george-gca
Copy link
Contributor

I've never played this game, but I guess that to move a panel and its content together, I would use the Sticker behavior to stick the content to the panel or move a layer camera.
https://wiki.gdevelop.io/gdevelop5/extensions/sticker/

Yes, this could be one solution, but using this extension also could be one. Of course, for this simple case, Sticker would be better.

This case is probably too specific to require an extension. I don't understand how it would be done because the character is moving so it won't stay at the tween target.

I stated this example because it was the first one that came in my mind. But think NPC for example, or a door, composed of multiple parts. When "opened", all parts would slide to the side, with a delay between them, but adding to their y position so they could keep their position one above the other. Of course it could also be done for the same position, so all the pieces collapse to the same space. The example I put in the demo was dominoes pieces falling and "pushing" the next one.

Since I created all the individual functions with some variations, basically all tweens that you could be done separately could be encapsulated into a single behavior. One thing that I did was add some variations, for example, AddObjectPositionXTween, AddObjectRelativePositionXTween, and AddObjectMultiplierPositionXTween, as can be seen below.

image

If a group contains 2 objects, one with x1 = 5 and the other x2 = 10, they would behave like this (note that there are more params to these functions, like easing function, duration, delay, etc, but I will focus on the x here):

Function Params Final Values
AddObjectPositionXTween X: 20 x1 = 20, x2 = 20
AddObjectRelativePositionXTween X: 20 x1 = 25, x2 = 30
AddObjectMultiplierPositionXTween MultiplyX: 20 x1 = 100, x2 = 200

Let's say there are 2 rows and you want to create one group for each.

For this case, there should be a group for each row.

I guess users would have to register one instance after the other if they want a specific order. The Stack Object behavior does something like this.
https://wiki.gdevelop.io/gdevelop5/extensions/object-stack/

Currently the RegisterObject appends the new object to the end of the list. I could also create a function for the user to set the index if you think will be useful.

Please feel free to challenge what I said and give other use-cases.

Of course. Open development is not enforcing ideas, is discussing them to create better solutions 🎉

@D8H
Copy link
Contributor

D8H commented Sep 30, 2023

But think NPC for example, or a door, composed of multiple parts. When "opened", all parts would slide to the side, with a delay between them, but adding to their y position so they could keep their position one above the other. Of course it could also be done for the same position, so all the pieces collapse to the same space. The example I put in the demo was dominoes pieces falling and "pushing" the next one.

Without an extension, it could be done like this:

  • Put an hidden Door instance Behind the Bar instances
  • Set the delay (or an index) in a variable of Bar
  • Pick the Bar in collision with the Door (or use links)
  • Iterate on each instance and use the "wait" action according to the variable
  • Use Bar.X() to choose the targeted X relatively

Do you see a way the extension could make this easier?

Since I created all the individual functions with some variations, basically all tweens that you could be done separately could be encapsulated into a single behavior. One thing that I did was add some variations, for example, AddObjectPositionXTween, AddObjectRelativePositionXTween, and AddObjectMultiplierPositionXTween, as can be seen below.

This is a huge work.
What is the purpose of AddObjectMultiplierPositionXTween? I mean, when does a position need to be multiplied?

@george-gca
Copy link
Contributor

Without an extension, it could be done like this:

  • Put an hidden Door instance Behind the Bar instances
  • Set the delay (or an index) in a variable of Bar
  • Pick the Bar in collision with the Door (or use links)
  • Iterate on each instance and use the "wait" action according to the variable
  • Use Bar.X() to choose the targeted X relatively

Do you see a way the extension could make this easier?

Supposing that the door is composed of 3 parts (different objects), you could add a TweenGroupBehavior to the first part, then register the 2 other parts as part of that group in the beginning of the scene. When the door is opening, simply apply a AddObjectRelativePositionXTween action to the first element, setting the value that would be added to the x of all the individual parts and the delay. When wanting to move back to the previous position, do the same action giving negative x value. At least it seems simpler to me. I won't need to add actions to iterate on each instance, use wait, and other specifics, since these are all encapsulated.

This is a huge work. What is the purpose of AddObjectMultiplierPositionXTween? I mean, when does a position need to be multiplied?

I can't think of a really good example now, but think of a billiards table, but all the balls have different sizes and masses. If I hit the white ball that is huge in another ball that is medium sized, and that hits another one that is smaller, since they all have different masses and sizes, they would move a different value. The white ball would move a maximum of x, the medium one 2x, and the smallest one 3x, for example. Of course in this example all of this could be calculated with a physics engine, but it could also be made by adjusting the params of a AddObjectMultiplierPositionXTween.

@D8H
Copy link
Contributor

D8H commented Oct 1, 2023

Without an extension, it could be done like this:

  • Put an hidden Door instance Behind the Bar instances
  • Set the delay (or an index) in a variable of Bar
  • Pick the Bar in collision with the Door (or use links)
  • Iterate on each instance and use the "wait" action according to the variable
  • Use Bar.X() to choose the targeted X relatively

Do you see a way the extension could make this easier?

Supposing that the door is composed of 3 parts (different objects), you could add a TweenGroupBehavior to the first part, then register the 2 other parts as part of that group in the beginning of the scene. When the door is opening, simply apply a AddObjectRelativePositionXTween action to the first element, setting the value that would be added to the x of all the individual parts and the delay. When wanting to move back to the previous position, do the same action giving negative x value. At least it seems simpler to me. I won't need to add actions to iterate on each instance, use wait, and other specifics, since these are all encapsulated.

Considering that the extension allows to register instances, the loop would still be needed to register instances. I guess it only encapsulates a mapping from an index and a delay and relative position calculus which are a multiplication and a division. To me, the extension looks overly-complicated for this. Maybe I missed something.

The event solution is probably more flexible as it allows to:

  • do some actions when each bar starts to move, play a sound for instance
  • use delays that are not linear

It also has the advantage to use concepts already known by users. I guess beginners won't find this solution easily but making an animation with pixels is probably a better solution most of the time anyway.

Do you see any other use-case?

@george-gca
Copy link
Contributor

Yes, the event solution is more flexible, but sometimes you don't need all that flexibility, and just want a simpler way to do things. Also I believe this solution is easier for beginners than doing a loop every time. For instance, I still don't know how I would do a loop through various different objects. I believe I would have to create a group with them, so I could get every instance of them, right?

You are thinking isolated animations, that happens once, but think about animations that happens more than once, and different animations. You would need to do a loop for each animation, and do all those steps again and again, creating a lot of events in the event sheet. By using the behavior you only need the loop once, while registering the objects in the TweenGroup. After that, you only need to apply the tweens, and the loop per elements and other peculiarities will be hidden.

@D8H
Copy link
Contributor

D8H commented Oct 1, 2023

Yes, the event solution is more flexible, but sometimes you don't need all that flexibility, and just want a simpler way to do things. Also I believe this solution is easier for beginners than doing a loop every time. For instance, I still don't know how I would do a loop through various different objects. I believe I would have to create a group with them, so I could get every instance of them, right?

Without the extension:
image

With the extension:
image

Both look as complicated.

You are thinking isolated animations, that happens once, but think about animations that happens more than once, and different animations. You would need to do a loop for each animation, and do all those steps again and again, creating a lot of events in the event sheet. By using the behavior you only need the loop once, while registering the objects in the TweenGroup. After that, you only need to apply the tweens, and the loop per elements and other peculiarities will be hidden.

Not really, events can be factorized using an extension dedicated to a game. For the case of the door, the events can be moved into an action "Play the Door animation with Bar".

@george-gca
Copy link
Contributor

Bar in this case is an Object, or a Object Group?

@D8H
Copy link
Contributor

D8H commented Oct 2, 2023

Bar in this case is an Object, or a Object Group?

An Object, but it can be a group if there is several kind of doors.

Actually for the "with extension" events, it would need to loop on an index to register instances in order (which makes it more complicated)

@george-gca
Copy link
Contributor

george-gca commented Oct 2, 2023

How it would look like if you were to do that with different objects, but each with a single instance? You would need to create a group so that you could know which specific objects to use right?

@D8H
Copy link
Contributor

D8H commented Oct 2, 2023

How it would look like if you were to do that with different objects, but each with a single instance? You would need to create a group so that you could know which specific objects to use right?

I suggest to never do this. If there are 20 doors in the level, it would need 20 * 4 objects and as much events. This is not scalable. Instances must be used.

@george-gca
Copy link
Contributor

In the example of the door I gave, the door was composed by 3 different parts, meaning 3 different objects with different assets. That's why I was talking about different objects.

@D8H
Copy link
Contributor

D8H commented Oct 2, 2023

In the example of the door I gave, the door was composed by 3 different parts, meaning 3 different objects with different assets. That's why I was talking about different objects.

Ho, ok, a Door, a Bar1, a Bar2 and a Bar3 for each door. Yes, that would work, but the 2 codes with or without the extension would still be as much complicated.

@george-gca
Copy link
Contributor

With the extension would not. It could be done like I said, register at the beginning of the scene, then just run actions.

@arthuro555
Copy link
Member

I agree with davy, this is unnecessarily complex and doesn't solve anything that isn't already solved by object picking. If this works for you that's fine, but for the extension gallery, it's redundant and confusing for users, so we cannot accept this extension I'm afraid.

@arthuro555 arthuro555 closed this Dec 16, 2024
@arthuro555 arthuro555 added the ❌ Rejected A rejected extension label Dec 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
👨‍👩‍👧‍👦 Community extension An extension submission to be merged ASAP with a lightweight review. ✨ New extension A new extension ❌ Rejected A rejected extension
Projects
Status: Rejected
Development

Successfully merging this pull request may close these issues.

3 participants