GDevelop-extensions
GDevelop-extensions copied to clipboard
New extension: TweenGroup
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
- [X] I've followed all of the best practices.
- [X] I confirm that this extension can be integrated to this GitHub repository, distributed and MIT licensed.
- [X] 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
Extension file
Thank you for submitting an extension.
What is the difference with using a tween action on objects picked by conditions?
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.
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
- I didn't find a way to choose instances order
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.
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.
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.
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 ๐
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
, andAddObjectMultiplierPositionXTween
, 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?
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 relativelyDo 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
.
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 relativelyDo 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 aAddObjectRelativePositionXTween
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?
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.
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:
With the extension:
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".
Bar in this case is an Object
, or a Object Group
?
Bar in this case is an
Object
, or aObject 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)
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?
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.
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.
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.
With the extension would not. It could be done like I said, register at the beginning of the scene, then just run actions.