******

This forum is currently in read-only mode.
0 favourites
  • Here i go again.

    Add 4 Private variables to the object vault.

    X_to, number, 0

    Y_to, number, 0

    X_from, number, 0

    Y_from, number, 0

    go to the events editor.

    First we have to store the Position of the Head in variables before it moves to a new place.

    This has nothing to do with the X_head and Y_head variables we made earlier.

    They are not holding a position. The head will never be positioned at 0,-10.

    X_head and Y_head are holding "relative values"

    Relative values have not much meaning by there own. They relate to something. They only get a meaning by adding them to a absolute value. Like we added them to the Head's position to move the Head 10 pixels.

    The Values we use to remember Heads old position are absolute value's.

    We gonna store Heads X and Y in the variables X_to and Y_to. Because thats what the first body will jump to.

    So locate the comment "move head"

    there is the condition "every 100 milliseconds" and its sub condition always.

    Easier then adding a new sub tree to all this...

    is again go by the *lazy editing* way.

    Duplicate the always sub-event.

    Now you have a duplicate of the event and its actions. And on the right branch in the tree.

    We need to store the variables before the Head moves.

    So, delete the actions behind the first "always" sub event.

    And we are ready to code.

    hit new action behind the first "always" sub event.

    Step1: self object = Vault

    Step2: action = set value

    step3: parameters: private variable = X_to / value = Head.X

    finish

    Yes, Head.x not .x The self where "." refers to is Vault in this action not Head

    Duplicate that action.

    Double click it.

    step3: Private variable = Y_to / value = Head.Y

    finish

    There, now we we always know where the Head was before it moved.

    Now lets snap the first body to that position.

    Locate the comment "move body"

    Double click the "always" event under it.

    Automatically you land in step2 of the events wizard. Thats because "always" has no parameters. Another, you probably think coincidental, reason to make a structure with comments and "always"'s before starting to code. I will try always to start a tree of events with a flow condition.

    step2: condition : For Each Object (ordered)

    step3: parameters : select Body as object (its a pick condition) / Order expression = Body.UID /

    Mode = Ascending

    Finish

    Body.UID and not .UID because its a condition, conditions dont know "selfs", only actions do.

    what is the property UID ? it stands for Unique ID. Every object, made in the layout editor or/and made by events, will get an Unique ID, a number. The first made object will have a lower UID then the second made object. Not necessarily 1 and 2. But for sure ascending.

    For Each Object (ordered) is a pick condition.

    It well run trough the instances of the object chosen in the parameters step. One by one. And feed this instance as picked (one by one) to its sub-events and actions.

    It will do that in an order and direction you told it to do.

    In this case, it will pick the instances of the object Body. One by one, and feed them one by one to the sub-events and actions we gonna make for it.

    It acts as a Loop. And it will adjust its end to the count of instances for Body in this layout. In other words, we can add as many instances of the object body on runtime as it pleases us, the "For Each" will just adjust and take into account all instances.

    Now well the condition is in place. Now it needs actions.

    First we will store the position of the currently picked instance of Body in a variable. Before we move it.

    Lets *lazy edit* . Under the events moving the head u see the action

    Vault Set 'X_to' to Head 0 .X

    Duplicate it by CTRL + dragging it to the actions of the "For each" we are working on

    Double click the copy.

    step3: parameters: private variable = X_from / value is Body.x (self = Vault)

    finish

    Duplicate that action.

    Double click it

    step3: parameters: private variable = Y_from / value = Body.y

    finish

    There thats that.

    Now we stored its position, we can move the currently picked Body instance.

    click new action.

    step1: self = Vault

    step2: action = set x

    step3: parameters: it will be an expression.

    double click Vault in the expressions guide

    double click the expression "get private variable"

    Body.Value('Variable name') will be filled in (you can of course type all that too)

    change it to Vault.Value('X_to')

    finish

    Duplicate the action.

    double click

    click one step back to step2

    step2: action = set Y (select, and click next)

    step3: ahh that expression is still here, just change X_to in Y_to

    finish ...

    Now all we have to do is change point of view from the current picked instance of Body, to the point of view for the next instance the pick-condition will pick.

    For the next instance, the X_from will be the X_to. So all we have to do is store the value of X_from into X_to (same for Y)

    X_from is where the previous instance jumped from, and the point the next instance will jump to.

    Lets *lazy edit* this.

    Duplicate the "Vault Set 'X_to" and the Vault Set 'Y_to' actions from the "move head" events to the place of actions that we are working at.

    Double click the "Body: set 'X_to" action (2 actions back under this event)

    Copy the expression in it ( Vault.Value('X_to') )

    click cancel or finish

    double click the first duplicated action. the one that sets the X_to

    step3: just paste the clipboard content in the value. And change X_to in X_from

    finish

    A computer is made to copy and paste, and for nothing else !!!

    double click the second duplicated action.

    step3: just paste the clipboard content in the value. and change X_to into Y_from

    finish

    note: every time i make an expression, i will trow it in my clipboard. Usually turns out to be handy.

    Run all to check. And it looks like a big mess. And theoretical. The math is right.

    Most beginners stop here. At this point. (or at the next problem).

    And yet, there error is easy.

    We forgot the "every 100 milliseconds" condition. In other words .. Head and body run out of sync.

    Aha !!!

    OK lets sync them up. Add a another ""every 100 milliseconds" condition" ?

    Nah,

    lets not do that.

    Just drag the event tree with the "For each" loop up, under the second always that moves the head, and on the same tree level.

    Delete the "move body" comment.

    Edit the "move head" comment to "move head and body"

    there, run all again.

    Perfect!!!! Only a snake can not move backwards, lol. oh thats easy solved.

    And we will in next post.

    Here is how the events should look, if you ran in a problem, compare with is picture.

    Maybe it was my english, or you forgot a detail somewhere. So check up with this.

    <img src="http://usera.imagecave.com/j0h/tick/06_result.jpg">

    I do not want to post the .cap. Because i really need you to type and click all this.

    Else it is no tutorial. sorry ?

  • Actual, its funny to see that snake walk backwards.

    But, it has to go.

    Lets first analyze "backwards" ..

    The snake can not change direction to the right when we are all ready going left. = backwards.

    Not left when currently going right.

    Not up when currently going down.

    Not down when currently going up.

    When is the snake going right ? How do we know ?

    Well, when X_head = 10

    We go left when X_head = -10

    We go up when Y_head = -10

    and down when Y_head = 10

    When do we change direction ?

    Well when the corresponding key is pressed.

    So we just have to link the keys with a condition to X/Y_head variables.

    Lets add conditions based on this to the key inputs.

    STOP ! you yell. You said no conditions to key inputs.

    I meant, no conditions to key inputs on top of them. They will slow them down. And the event sheet looks like a mess.

    Key board and mouse detection conditions are triggers. Currently in construct they dont act as triggers yet.

    A trigger will pause the execution of events, run the action and sub events under a trigger condition, and when done with them, return in the events sheet where it paused.

    I am sure this will be implemented some day in construct. Therefor, today already i threat triggers as triggers.

    Rule 1: triggers will always be the first event in a tree.

    So lets add conditions to the keyboard triggers to LIMIT execution of its actions.

    NOT on top of the key conditions to limit the key inputs.

    You are allowed to place hundredths of sub_events under the key conditions, just not 1 on top.

    Select the condition "on key Right".

    Right click choose "insert new conditon"

    step1: object = vault

    step2: condition = "Compare a private variable"

    step3: private variable = X_head / comparison is "not equal to" / value = 10

    finish

    Now lets *lazy edit*

    Ctrl + drag that condition into every "on key" condition.

    then double click copy by copy to edit the conditions.

    Key left

    private variable = X_head / comparison is "not equal to" / value = -10

    key up

    private variable = Y_head / comparison is "not equal to" / value = 10

    key down

    private variable = Y_head / comparison is "not equal to" / value = -10

    Run all

    Yup, this is right. eh ?

    <img src="http://usera.imagecave.com/j0h/tick/07_more.jpg">

    In next post we bring in the pray for this hungry little snake.

  • go to the layout editor.

    Add a sprite from the butterfly animation that in the folder with sprites i provided for this tutorial.

    Any of the butterfly sprites will do.

    Yes this gonna be an animation, but a simple basic one.

    Name it "Butt", yes i like little joke in my events.

    Bite my butt, hahahaha, oopz.

    Set width and hight to 20. It is a bit to big now, compared to the snake.

    Not that its gonna look realistic. But though ........

    Place it outside the layout canvas. We will bring it on screen by an event.

    Now we add animation.

    With Butt selected, click the "animator" TAB on the organizer on the right.

    The Animator has two screen parts. On top you see the animations.

    Below the middle you see the sprites (frames) that make up the animation.

    On top you see "default" and a sub entry "angle:0�"

    "Default" is the name we will call the animation with in the events.

    In the animator "Default" acts as a folder, containing animations that match with the angle of the object.

    When we want to animate a walking man. We want him to have his nose to the right when he's walking to the right. This animation is different (mirrored) when he walks to the left, nose faced to the left.

    When u add an animation for 0�(faced right) and 180� (faced left), construct will automatically use the right animation when the angle of the object changes to left or rigtht.

    NOTE: You can mirror sprites by giving it a negative width (or hight) in its properties. Bet not to many people know this.

    But our animation will not change direction. It will not walk. The butterfly will just sit and wait patiently to be eaten by the snake.

    Told you, we will only use basic things in this game.

    So select the sub entry "angle: 0� attached to "default". (Yes you can change "default' to another name in the left properties pane, if it annoys you.)

    So select the sub entry "angle: 0� attached to "default".

    This is what actual is containing the animation frames.

    On the bottom part you will see one sprite, numbered 1. At the moment there is 1 frame in the animation. Right click it. Choose "import frames" from the contextual menu.

    The file explorer comes up. Point it to the folder containing all the butterfly's that i provided.

    Press CTRL+a to select them all. Or have your way clicking and selecting them all.

    Click open.

    Now you are confronted with a import wizard.

    I can not explain u everything in this wizard. I dont know it in depth yet. But there are not to many buttons and check boxes to figure it out, if you want to.

    For now, just click "import"

    The frames will be imported.

    And you can see them, and bring them in the picture editor by double clicking a frame.

    This why i say "one frame of an animation is also a sprite"

    The sprite is no more then a variable property of an object. This sprite will animate its face over time. And thats close to animate X over time. Same thing.

    Now with angle:0 still selected, change its speed in the properties on the left to 12.

    note:

    Initial its set on 50.

    To give you an idea about commonly used animation speeds :

    35 mm Cinema (the big movies) runs at 24 images / sec (a speed of 24)

    television in Europe runs at 25 full images / second

    in America thats 30 images / second

    Most .gif animations on the Internet are set to a speed of 12 images /second (most monitors are set to 60 hertz, and 60/12 gives a whole number)

    ok thats enough for now. Lets bring the butterfly with an event in the layout, and lets get it eaten by the snake.

  • Butt will jump to a random place on screen when the snake eats it.

    But that condition does not exist on start of the game. You will find yourself many times in that situation.

    Now you can do this. Create a global flow variable like Is_but_eaten. And give it the value "yes" when starting up the game.

    And make the Butt event move the Butt when that global variable is set to "yes"

    The variable gets set to "yes" when the snake eats the Butt. And will be set "no" right after the Butt is moved to another place.

    In general, sometimes you have to force conditions to happen at startup of the game, to get the flow nicely going.

    In this game we will keep things simple. But be aware of all this.

    We will not use a flow for moving the Butt.

    And we will use the "On layout start" condition to bring in the Butt for the first time.

    Every action, and sub events attached to "on start layout" will run between the moment that you run the game and the moment its screen pops up.

    Or when we restart the layout, in the moment between the screen changes.

    It will only run once, and be excluded from the top-down execution during the rest of the game.

    Right click the "start of layout" condition (C-spot), and add a sub condition "always" to it.

    click new action to this "always"

    step1: self = Butt

    step2: action = set X

    step3: parameter: will be an expression ..

    double click system object in the expression guide

    scroll some trough the expressions .. as you see this is heaven for the math freak

    locate "generate random number"

    double click it

    it will bring random(1.0) in the X field

    now change this to ((random(61) ) * 10 ) + 15

    we need the Butt also to be on the 10x10 grid

    not to close to the left edge of screen and in the middle of the grid ..

    screen width = 640 - 15 for the left border - 15 for the right border = 610

    610 / 10 (grid is 10 based) = 61

    so random(61) will generate a number between 0 and 61

    * 10 will give 10 based numbers

    +15 will place it in the middle of the grid, and not to short to the left side.

    click finish.

    Duplicate that action.

    Click back 1 step.

    step2: action = set Y

    step3: parameters : change the expression to ((random(46) ) * 10 ) + 15

    click finish

  • ...

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • If you run this as it is, the snake will move under the Butt object.

    I would rather have the Snake moving in front of the Butterfly.

    Go to the layout editor.

    Bring up the layer organizer on the left.

    Add a new layer on top, with the little green up arrow key.

    Drag the newly created layer One down, so it is in the middle of the 3 layers.

    Locate the Butt object in the object list in the layer organizer plane. Depending on the filter in the middle you might have to select another layer to see it.

    Then drag it from that list up into the middle layer (on upper half of the organizer)

    Now we have in the lowest Z-order layer, the bottom layer, the grid.

    On top of everything we have the Snakes head and its body.

    In between them we have the butterfly.

    The other objects are not visible, they dont really matter. But to be a good boy, u could organize them on a special layer, that you name "controls", or so.

    If the snakes body's instances are not on the most top layer, then also drag this object to the top layer.

    As you see, its easy to organize Z-orders in construct with layers.

  • Back to the Events editor.

    When the snake hits the Butt object. Butt will jump to a new random location.

    Currently, nothing happens if we move the snake over Butt.

    How does the snake know where the Butterfly is ?

    We can of course compare the Head's position to the Butt's position in an compare event. If they are at the same place, we can consider the Butt as eaten.

    Thats very basic. But lets not do it this way.

    There are also the system pick condition "object overlaps point" and "object collides with point"

    Its a pretty fast condition.

    We could use an expression to feed the X and Y of the Butt to the X and Y in the parameters of an "object overlaps point" system condition, and as object the Head.

    This pick condition will pick all instances of an object, and only the instances that overlaps the point given by the X and Y coordinates, will be feed to the sub events and actions.

    But lets not do it this way.

    Locate the comment "eat".

    Add a sub event to the "Always" condition thats already in place there.

    Step 1: base object = butterfly (we will move the butterfly)

    Step2: condition= Is overlapping another object

    step3: parameters: object is Head

    finish

    This is a pick condition. Its takes all instances of the object Butt, and when an instance will overlap with an instance of the object Head, both that instance of Butt and the instance of Head will be set as picked and be feed to the sub events and actions.

    When there is no object picked, i think, no actions and no sub event will run.

    Now just copy the 2 actions that randomly placed the object Butt in the "start of layout" event to here.

    Run this, play a little with it.

    And it will be like the Butterfly jumps away to early.

    Yes from the moment both overlap even with 1 pixels, then the conditions are met.

    Also the butterfly is a little bigger then the 10 based grid, so when ...

    the Head is not going besides it, they will overlap too.

    Go to the layout editor. Select the Butterfly. Locate "collision" in its properties. And change it to point.

    Run all again.

    Now the collision detection is only made when there middle points (the pivot points) overlap each other.

    And yes this is better.

    Under the collision options you will find 4 options.

    None = this object will not detect collision, AND will NOT be DETECTED BY OTHER objects.

    Point = Only the pivot point is used for detection.

    Bounding box = Only the bounding box is used to detect collisions.

    (when you select an object in the layout editor, the bounding come visible as a box of lines)

    Pixel = All pixels in the sprite are used as sensors to detect collision.

    Point will check only one point. which is the fastest detection.

    Bounding will only check the points defined by the math for a rectangle. Its a little slower then "point".

    Pixel will check every point of the sprite, when the sprite is very complicated, thats a slow kind of detection.

    Two objects that detect each other can have different detection methods. And the result is a combination of both.

    When one is on "bounding" and the other on "point". The detection well be made when the pivot point of that one overlaps the bounding box of that other.

  • At same time as the butterfly gets eaten, we add another body part.

    It dont really matter at where we create this new instance. Because, the "For Each" pick condition will find it and bring it to the right place.

    Just to avoid a flicker, we will create it out of screen.

    Since this happens under the same conditions that makes the Butt jump to a new location,

    we just add it as action on that place.

    add a new action the "Butt overlaps Head" event.

    step1: choose system object

    step2: action = create object

    step3: parameters: object = body / layer = 2 / X = -20 / y = -20

    finish

    Run all and play some with it.

    change the "eat" comment to "eat and grow"

    delete the "grow body" comment and its "always" pre-made event

  • Dude, Dudette ...

    Thats pretty much that we have done with ONLY 12 events. With Only 6 variables so far.

    Dont you think ?

    If you look at or original planning, there are only 2 more things to do.

    The dead situations, and the "let the player start over again" situations.

    The player will die if the Head will go out of screen, and if the Head bites own body.

    If its Dead, we will pop up a little message.

    And we will not move the head.

    We will not limit the key inputs, just keep the Head from moving.

    In other words, when its dead .. the other events need to know.

    Its time to bring a little flow in the game.

    Make global variable by ..

    Click project in the top menu,

    Click "manage variable" on the ribbon.

    The variable wizard pops up, and its the same as this one for "private variables"

    Make a variable as follow

    name = Player_Is

    type = text

    value = dead and alive

    That value dont really matter.

    Why ?

    well .. When you use a Global variable ..

    and the variable's value is essential for the game starting out the right way ...

    THEN YOU HAVE to initiate the variable in the events.

    And best place to do this is in the "start of layout" event.

    Add a new action under the actions randomly moving Butt in the "start layout" event.

    step1: object = system object (its holding the global variables)

    step2: action = Set value

    step3: global variable = Player_Is / value = "alive" (including the "'s )

    finish

    select the "ever milliseconds" condition (C-spot).

    Right click and "insert new condition"

    step 1: object = system object

    step2: condition = compare global variable

    step3: parameters: global variable = Player_Is / value = "alive"

    finish

    There will be no overlapping to detect, if the Head is not moving.

    So this event does not need this FLOW condition.

    Ok lets Kill the snake.

  • Locate the "always" under the comment "dead".

    Right click the event, and add a subevent.

    step1: object = Head

    Step2: condition = Object is outside layout

    finish

    Add an action to that.

    And just copy the action where we set Player_is in the "start layout"

    Change "alive" to "dead" in the action.

    *lazy editing* : )

    Select the sub event "is outside layout" (E-spot) .. CTRL+c, CTRL+v to duplicate it.

    Double click the condition to edit it.

    click one step back.

    step1: object = Head

    step2: condition = is overlapping another object

    step3: parameters: object = body

    finish

    Run all.

    uh oh .. problem.

    The snake does not move no more.

    ALWAYS when you add a collision detection, Run the events.

    To see if the Collision Method needs adjustments.

    Go to the layout editor.

    And change the collision method for each Body to "point"

    double click the "always" condition that starts the dead events to edit it

    step2: condition is compare.

    step3: parameters / value 1 = Vault.Value('X_head') + Vault.Value('Y_head') / comparison = different to / value 2 = 0

    finish

    Copy this condition also under the every 100 milliseconds event.

    This event will have 2 conditions then ..

    The every, the flow alive, and this event that holds the events till player input

    Run again, and now the snake moves again.

  • Select the "is global variable" condition under the "every 100"

    press CTRL + c

    select the last "always" condition

    press CTRL +v

    change the "alive" in the condition to "dead"

    Cant be easier.

    Another side effect of using this method is ....

    you force yourself to make a mental snapshot of the context that we used this global variable in ..

    by scrolling back to it, to copy it.

    The story of game, the flow, stays fresh in your mind.

    delete the always in that event.

    Now go to the layout editor. Add a new layer on top.

    Select the layer on top.

    add a sprite "02.png" from the oopz folder

    place it in the middle of the layout.

    toggle its properties "Invisible on start" (under appereance)

    Name it Oopz

    Bring up the Animation organizer on the right.

    Change "default" in "idle"

    Right click an empty spot in the upper part of the organizer.

    choose "add new animation" from context menu

    Name the animation "over"

    The animation, not the angle thingy

    a name is a properties, and those u change on the left .. member ?

    select the angle under "over"

    In the frame portion of the organize you see the number 1

    But there is no sprite/frame yet.

    Right click the "1" ...

    choose "import frames"

    only import the 01.png from the oopz folder.

    Back to the events editor.

    Add a sub event to the last event (is global variable = dead)

    step1: object = mouse and keyboard

    step2: condition = mouse is over object

    step2: object = Oopz

    finish

    add a new action to this.

    step1: self = Oopz

    step2: action = Set animation

    step3: name = "over" (including the "'s)

    finish

    Duplicate that EVENT.

    Right click the CONDITION in that event .. and invert condition

    change the "over" in the duplicated action to "idle"

    Copy the first sub event (the not inverted one)

    double click the condition of the copy to edit it

    one step back

    step2: condition = On object clicked

    step3: parameters: button = left / type = clicked / object = Oopz

    finish

    delete the action is there because of the copy.

    Add a new action to it.

    step1: object = Oopz

    step2: action = set visible

    step3: parameters = Invisible.

    finish

    CTRL+c, CTRL+v (copy) this event.

    In the first one ...

    double click the condition.

    click 2 times back

    step1: object = system object

    step2: condition = Trigger once while true

    finish

    double click the action to change invisible to visible.

    Add another action to the previous event, the "on left clicked event"

    step1: system object

    step2: action = Go to layout

    step3: parameters: layout = "layout 1" (including "'s) / transition = none / duration = 200

    Why duration ?

    Often if the layout has a big "on layout start event", it will crash if you keep the duration on zero.

    A none zero duration, till even 1000 or 2000 when the "on layout start" event includes loops,

    will prevent this crash.

  • <img src="http://usera.imagecave.com/j0h/snake/66.jpg">

    <img src="http://usera.imagecave.com/j0h/snake/02.jpg">

    <img src="http://usera.imagecave.com/j0h/snake/03.jpg">

    ...

  • tags: basic c0nstuct

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

  • Very VERY impressive work with this tutorial.

    This should be moved to the documentation project page right now instead of being lost in then infinite amount of "how do you create a mario game?"-kind of questions posted here.

  • Agreed, I moved it

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