for Beginners: From Object Picking to Containers

This forum is currently in read-only mode.
From the Asset Store
This is a single chapter from the "Construct Starter Kit Collection". It is the Student Workbook for its Workshop.
  • Containers are part of the "object picking" story.

    So, i have to tell you the story of objects (clones and instances) and how to pick them first,

    before i can start explaining containers.

    Most of it i explained already. But not in the way i am going to now.

    I am gonna make a point later in this topic. So the point will not be made in this post.

    As always i build the topic up.

    So do not ! take the .cap i post here as an example for good coding. It is only an illustration for this post, and for the sub-point that i try to make in this post.

    OK, download this, and fire it up.

    There are 7 different objects in that layout. They do have the same sprite. But that is only to make a good link to the next post.

    Those 7 objects are totally different. If they are clones from the same object, or objects i added starting from the same sprite. That does not matter in this post. We do not need to change the sprite / animation for each object and different.

    They are totally different because they have different names. Talk to those objects with events and actions is whole lotta work.

    And this overload in work starts already with in the preparation of this project.

    We have to make this object 7 times.

    7 times we have to place this object.

    7 times we have to give it a name.

    7 times we have to give it the "8 direction" behavior.

    7 times we have to change the behavior to "only up and down"

    14 times add a private variable

    Thats 7 times more chance to make an error. And its a real workload. Dont believe me, then start this from scratch, with any sprite you have laying around.

    And yet, what i actually want to do is simple.

    I want to select 1 of those 7 objects. When the object is selected i want it to be able to move it by the "8 directions" behavior. And only this object, and only up and down.

    Selection happens with the left and right arrow key.

    I want a selected object to be shown as selected by marking it by a rectangle.

    When unselected i want the object to jump back to its starting location.

    And that is all.

    Now look at the events sheet. Thats a whole bunch of events. And it takes a whole lot of time to make them. And even more concentration to not make NO error.

    It starts already in the "start of layout" event.

    The behavior for every object, except the starting object needs to be set to non active.

    Thats 7 lines already.

    We need to store the starting X and Y for each object in a variable, to be able to recall them.

    Thats 14 lines already.

    And, as i pointed to already, every global variable that acts as a flow variable should be initiated in the "start of layout" event.

    Then in line 11 and 12 you have the 2 key inputs. To do it this way, is my style.

    Then we have to make conditions for when the left arrow keys is pressed,

    and for when the right key arrow is pressed.

    And since we only can call those object by there 'names" in the wizards. That will be and event tree for each key and each object.

    2 events / object. Thats 14 events.

    Each event has 8 actions.

    Change the global variable 'selected' to the new selected object.

    Activate the behavior for the new selected object

    place the selector on the new selected object

    Place the previous selected object to its starting place for X

    Place the previous selected object to its starting place for Y

    Inactivate its behavior.

    Set its angle to zero.

    keep the next events from running by setting the global variable 'select' to "X"

    If you press the left arrow key, previous and next object will be different then when you press the right arrow key. Meaning, each event calls different objects.

    Thats a LOT of coding. Each event is different, to actual do the same thing. 14 x 7 = 94 actions. Just to do something simple like this. 94 chances to make an error.

    To be honest. If this would be the only way to code in construct, i would pass up.

    If all those events are needed to just do this, what i did in this .cap, then dont you even try to imagine how much years you will be bizzy to code a whole complete game.

    So we need another way to simplify all this. Bring the time to code down. And limit the chances to error out because doing repetitive and boring coding.

    The biggest help = using instances and containers. But also family's, Private variables and last but not least the "on layer" condition.

    In next post i do the same with instances.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Now take a look at this:

    download it and fire it up.

    First glance at the event. Wah ? Thats like 1/7th compared to the .cap in previous post.

    Yes sir, that what Instances are designed for.

    But lets start in the layout editor.

    The preparations for this project.

    I only had to add 1 object to the layout. (yes the selector also, blah)

    An instance you make by just copy and past. Thats it.

    But i made those instances by,

    selecting the first added object, right click it, choose "array past" from the contextual menu.

    Its 1D, 7 count.

    in the move X i filled the value 60.

    and i pressed ok.

    And that takes 5 seconds to do.

    Because they are instances of the same object.

    Adding a private variable has to be done only once on 1 of the objects.

    Adding a behavior has to be done only once on 1 of the objects.

    Not 7 times !

    And if you do this before making the instances, also the private variables initial values,

    and all the behavior properties will be exact the same in the copys.

    Again this 1/7th of the time to manage this. With 1/7th less chance on errors.

    In the events editor.

    Event 2 is a special advanced Loop.

    the "for each object ordered" loop that can be found in the system conditions.

    It runs trough all instances of the Bug,

    picks them one by one, here starting with the lowest X,

    and feeds the picked objects to its sub events and actions.

    So the action to deactivate the behavior we only have to put once.

    Storing the start X and Y we only have to do once.

    At same time we give the instances a identification number, to be able to pick them by comparing the private variable thats holding the value with the identification number.

    The private variable = 'My_number_is"

    The value we give it can be found in the system expressions = current loopindex

    The instance with the lowest X gets number 1. The next one get 2 .. and so on.

    In event 3 we initialize the global variables used for Flow.

    in event 4 we set the behavior of the first instance to active.

    This is a pick condition. It can be find in any objects conditions as "compare private variable".

    What it actual do is:

    It picks all instances of the object Bug...

    Runs trough the private variable thats given as parameter,

    and when the condition is true, here when "My_number_is" = 1,

    it will set that object as picked.

    So on our case, it picks out the first instance of the bug,

    and the action sets the behavior of that Bug to active.

    In event 5 and 6

    We add or subtract from the global variable 'selected' according the key thats hit.

    We have 7 objects, so if the variable gets out the range of 7, we make it loop back/forth

    Dont matter how many times u hit the arrow keys, 'selected' will be in between 1 to 7.

    Now we have only 2 conditions.

    Condition 1: Its "My_number_is" is the same as 'selected'.

    In that case the selector must jump to this objects position,

    its behavior must be active, and thats it !!!

    Condition 2: Its "My_number_is" not the same as 'selected'.

    In this case the objects behavior has to be deactivated,

    and the object needs to be placed at its starting position

    Now the global variable 'select' is not really needed. Its just one of my style elements.

    If i dont use it, the 2 conditions will run every tick.

    And every tick (by example) the behavior gets activated, because there will always be 1 object selected.

    I dont like to spend so much CPU cycles to do only this.

    When you hit the arrow key to select another bug, the variable 'select' gets set to "M",

    the M from Mark.

    When its "M" the 2 conditions run. Directly after they did there work,

    'select' gets set to "X", X for crossed out.

    The 2 conditions will now not run till hitting an arrow key brings 'select' back to "M"

    Of course, explaining all this takes more time then actual make this. I made it in 10 minutes.

    Plz, do not ask me how much time i took to make the .cap in previous post.

    Now, do you see the power of instances ?

  • Can I just ask why you put 'Always' in a subevent? It's redundant - the actions may as well be in the parent event.

    Doing this:

    + Event

    ----+ Always

    ----> (actions)

    Is identical to this

    + Event

    -> Actions

    Imagine writing code that said:

    if (event) {
        if (true) { // redundant!
            func();
        }
    }[/code:20eoptro]
  • Oh a lot of reasons, as there are ...

    Its a personal style and it suits me better then using groups. Those "always" events work as groups. And add the readability to the sheet.

    When you collapse them, the whole sheet takes less room. And when collapsed there sub events disapear without to much traces breaking my concentration when bizzy in the current event tree. Commented groups are perhaps better but ...

    They are such a big aid when you develop. Normal you start out with a bunch of events, step by step. And never build *serial*, but more *parallel* This means that the *Flow* will appear later in the development. *Flow* like, dead conditions and that kinda stuff. Its so much easier to just double click the "always" and change it to a flow condition, then to figure out which events make up a group and add a tree *up* to them. Should be clear if you read the way i build the simple snake game.

    And every thing is just a module till you release the game, and even then you will have to kick the bugs.

    It also allows to organize easier and better in sub events.

    You forget that Flow conditions when true, execute there actions AND SUB EVENTS. If you do not have a top event, then you can not have sub events. And sub events are heaven in organizing sheets. When you showed the advantages in your last post about construct. You mentioned the sub events as a better way to organize then MMF can do. And i very very agree with you !!!!!!!!

    For me it is so much easier to invert an "always" to keep a tree from running. Then to make a group and set the group non active. Even more handy then "toggle" event.

    See, its a system. A style system, but also a develop system. And i promises you, once you just do have "a system", and when this "system" keeps you out of little problems, and all the little elements seem to fit, one by one, you not only stick to it, there is *no other* way.

    Also, it is so much easier to explain. When u write a guide, its so much easier to remote navigate a reader in the sheet that you are building together.

    I guess, you have to develop something in this style to see the advantages, one by one.

    but strictly, they are nonessential, no. But then again. Comments are not too then. Groups are not too then. The function object is not too then. : )

  • To continue the Story.

    I hope i did not make you panic with the first post in this topic. I mean, i can imagine that you think: if thats the case ! i find another game maker !!!.

    LoL, sorry ?

    Yes there is a way to manage 7 different objects easy and comfortable.

    But, the time consuming preparations in the layout stay. And the chance to make an error there stays too.

    But for the events, wizard Ashley gave us the "Families". Families are a way to group objects.

    You add a object to a family in its properties under *groups* and deeper *families*. You can easy define you own families AND give them a personal thumbnail so they show up the way you want in the events.

    Once objects are in the same family, they act *almost* as they are instances of the same object in the events.

    look at this, download it and fire it up in construct.

    7 different objects. All 7 i made member of the family "Items". Then i just took the last .cap from previous post with the instances. And i changed all the referring to "bugs" into referring to "items" in the actions and events.

    And it runs as they where instances of the same object.

    As you see Families are a BIG help in PICKING objects. Thats is why they exist.

    But at the moment, Families have there limitations. There are properties that you can not acces to use in expressions trough a family.

    And You sure can not access any behavior properties in expressions trough a family.

    In the Current release .95.3

    So i kinda advice, not to use families when there are behaviors involved, and you plan to use the behaviors in a *advanced* way.

  • So since i advice you not to use Families when using advanced expressions for behaviors in the current release of construct (95.3) ...

    I made you go stuck in construct ?

    Naw, never. Construct is very flexible.

    But this means back to instances, and instances all have the same face, the same sprite ?

    Yes this is true.

    But, a sprite is no more then an objects properties. Almost all properties can be tweened in the events, or changed in the layout editor.

    And that is true for sprites also, in the form of animations. A sprite is also 1 frame of an animation.

    In this .cap

    I gave 1 instance 7 animations. Now all the instances of the same object have this animation.

    Its up to you to decide whats steels less of your time and concentration, and disallow you to make the lowest count of errors.....

    Or give one object 7 animations.

    Or give 7 objects a behavior with 20 behavior properties. And be forced to change them one by one when needed for the good flow of the game. Give 7 objects all those private variables, a normal game can run on 10 private variables. 10 * 7 = 70 times add a private variable. And this list is endless and unpredictable during developing a game.

    And in the events sheet there is only 1 action more. The action in event 2, that sets the animation to the loop counter translated to a string to match the animations name.

    And thats all !!!

  • Ah, thats interesting. I didn't imagine it'd come in useful! Personally, I like to stick with groups and toggling events, but your way is alright too!

  • Slowly moving to the use of containers.

    But, first lets create a situation where we dont have "containers" to use.

    You only realize the comfort of things when they are not available.

    There for.

    Lets do it all wrong first.

    A lot of beginners start a project this way.

    That are 6 different objects. Plz do not ask me to write the events to make this work.

    Thats would be to much.

  • Maxum ! hope u are not mad for using your sprites in this !

    OK, now. When a beginner gets stuck when starting from a layout as set in previous post,

    he/she usually moves to something similar to this .cap

    Do not take this as an example for good coding, and do not take this as an example for a well done user inter action. Its no more then illustrating this post.

    Well whats the problem you say ? This works as expected !

    Well,

    let me point you to the conditions picking the base and the turret.

    To do something with the thank, you need a condition to pick the Base AND a condition to pick the Turret. To make them move together, die together, get selected together and get unselected together.

    Thats 2 pick conditions for each move in the game. We also have to give the Tank AND the turret a identification number, to be able to pick them by.

    Now this is only a tank with 1 base, and 1 turret. Now imagine a spaceship, with 1 base, 4 turrets, 4 engines and 16 lights.

    That will run out of hand in a blink of an eye.

    On top, it will be more difficult to create more tanks on runtime.

    If you look close at event 25, then you will notice that if you mental figure out what it is doing, that its holding 2 erros.

    But it works, because, there can only be 1 tank target, so moment a bullet gets fired, it will ALWAYS hit the right tank.

    I knew this, but, at the end i let it be.

    Now lets dive in the comfortable and elegant use of containers. Next post coming up soon.

  • Look at this.

    It does exactly the same as previous .cap. But with easier pick events.

    You dont see the difference? OK lets walk you trough it.

    Starting in the layout. There is only 1 tank in the layout. 1 base + its turret.

    Both are in the same container.

    You make a container by adding objects to it under the *groups* properties, and deeper *containers*

    Why not name the container, as we name the families ?

    Well that would be definably make containers easier to understand, but limit its possibility.

    What can a container do for you ? It makes picking contained objects easier. Pick 1 object in a container and all objects in the container are marked as picked.

    Lets see this work. Go to the events editor.

    See event 2

    Creating An object thats part of a container will create all the other objects in the container in an urge to keep the container complete.

    As you see there is no action that creates a second turret.

    When you create an object, that object will be marked as "picked"

    Since the Base that we created is part of a container, and in that container is also the Turret, moving Turret will only move the Right turret, the one thats part of the container we just created.

    See event 4

    The loop walks trough the instances of object Base, and sets them picked one by one. But since base is part of a container that also contains a turret. The right turret instance will be set as *picked* too.

    If we can pick the right turret based on picking the right Base, then only Base needs a identification number in a private variable. Turret does not need one no more.

    see event 18

    We pick an instance of Base by comparing one of its private variables to a value.

    The variable is 'call_me', and this variable is holding the identification number for the instances.

    The value is 'selected', a global variable, thats holding the number representing which tank is selected.

    So it states: set the 'selected' base picked.

    But since Base is part of the container that is holding the Turret, also the right Turret will be automatically set as picked.

    So we can do actions for the right Base, and for the right Turret.

    As you see, there is no conditions that tries to pick the right Turret. We have no idea anyway which turret is sitting on top of this Base, because we did not even give the turrets an identification number.

    But the system knows because it knows in which container the Turret is sitting.

    See event 20

    We just picked the right Base, now we have the right Turret picked also. And the action will let the right Turret fire a bullet.

    See event 22.

    We only picked the right Base. Destroying this base will destroy all Turrets in that container.

    As you see there is no action to destroy any turret.

    Convinced to use containers? : )

  • Best tutorial ever, should be stickied!!!

    Even if I knew the most of this, this tutorial helped me picking certain istances.

    This is one of the most informative tutorials for the newbies, TheIstance! Make more!

  • Hi TheInstance,

    No that fine about the sprites, If it helps the other people learning Construct I am all for it.

  • tags: picking containers c0nstuct

    (just for me to find my *tuts* back)

  • Wow. Normally I don't bother to rate tutorials or anything, but this one was wonderful. I learned more from it than from the Ghost Shooter tutorial.. and even a little about using sub-events

  • Guess this story is a never ending story. Yup i have to add something to this topic.

    The follow .cap i stole from this topic. (i always misspell threat, so allow me to use 'topic' in stead )

    You can download it from there, or pick it from this link.

    Fire it up, and take a look at it.

    I am only interested in the event numbers 2, 3 and 4.

    Back then i saw the error in this. But i had no 'general' solution. With 'general' pointing to something that will work in all situations. I do now.

    Lets first analyze the problem.

    There are 3 objects in this project. Sprite, Sprite2 and Sprite3. Personal i do not like unnamed objects. But anywayz.

    All 3 objects are member of the group 'blue".

    So in events 2 .. 4. You see an attempt to set the gravity in the platform behavior for a certain object to zero, when the vectorY in its platform behavior is also zero.

    This looks ok j0h! Whats your problem now again !???

    Um, well, the syntax is right. And it does exactly what it is programmed to do.

    Namely, when the object sprite's VectorY = zero, it will set the gravity in ALL objects that are member of the family Blue to zero.

    And it does this in event 2 and 3 and 4, resulting in .. well i guess you can see that.

    Do not laughs ! I have done those kinda things myself. I am dead serious ! ( lol well ).

    Now lets upgrade this isolated little error to something 'general' to learn from.

    The condition in event number 2 is a (what i call) Flow Condition. It runs its Sub Events and Actions when the condition is true.

    But what we need here is a Pick Condition. In this case we need to take all the Blue objects, filter out those who's VectorY is not zero, and feed the left overs to the Sub Events and Actions.

    Yep, its a Picking Objects situation, why its on its place in this topic.

    We do have a small problem here though. The expression as used in the events in this .cap, can not be accessed using a Family.

    Thats is not a bug or so, thats rather a very normal thing. Imagine an object having 2 platform behaviors. And at same time being member of a family with 10 other objects, who have only 1 platform behavior attached. Now when accessing the expressions trough the family name, witch VectorY shall the system take ? The one of the first behavior or the one of the second behavior ?

    Anyway !

    We need a good Pick Condition to make this work.

    So lets convert *Flow* to *Pick*.

    Let me show you in steps "how to".

    Step 1.

    Make a private variable in the objects.

    Step2.

    Use the "for each object" system loop to walk trough the objects and set the private variable to the Expression. (in this case that would be to the VectorY in the platform behavior)

    It does not matter in what order the "for each" walks trough the objects, so do not worry about that.

    Step3.

    Now you can use the Pick Condition "Compare Private variable" to pick objects based on the stored expression.

    Problem solved ! : )

    You can see this work in this .cap

    Hope this was a help.

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)