In this tutorial I will show you how to create a chain of sprites that follow the head in a snake-ish way. You will learn:
- How to chain the sprites
- How to select 2 instances of the same object individually and add an action using both.
This tutorial is written for people who are comfortable working with Construct 2. If you don't know the basics of Construct 2, you might have trouble with this tutorial.
Note: the current state of the .capx is NOT production ready. Should you implement this in your own game, rework the creation of the chain as well as the angle. The capx assumes only one chain will exist at any time.
For this example I used a head with 8-direction behavior.
- Create a new object -> Sprite
- Add 8-direction behavior to it
I made a little green man as the head and called it snake.
Next we're going to create the tailpiece. We'll reuse this object later for all parts of the tail. I just used a smaller green square.
- Create a new object -> Sprite
- place it to the left of the head
I placed it 16 pixels left of the head. placing it further away is perfectly fine, but the effect may be less desirable.
To be able to pick 2 specific instances of the same object and eventually pin them to one another, we're going to create a family.
- Add family
- Add just the tailpiece
- name it something descriptive. I used tailpiece2
Since all tailpieces need to be able to pin, I added the pin behavior to the family.
- add behavior Pin to the family
Now that the project is set up, we can go on to the event sheets. I've created a event sheet called 'snake' and linked it to the layout we've set up.
- set the layout event sheet to the new event sheet (snake)
In this event sheet, we're going to use the start of layout event to generate the remaining tailpieces and pin everything together. Inside this event we create a sub-event and 2 local variables.
- Add event -> system -> on start of layout
- Add blank sub-event (press 'B' when event is selected)
- Add local variable (press 'V' when sub-event selected) -> name it uid1
- Add local variable (press 'V' when sub-event selected) -> name it uid2
It should look like this
The variable are going to be used to reference the 2 instances later on. First we're going to pin the first (and for now only) tailpiece to the head. The behavior is added to the family instead of the object, so pick the family when adding the action.
- in the sub-event, add action -> tailpiece2 -> Pin to object -> snake, ROPE STYLE!
- add action -> system -> set variable -> uid1 to tailpiece2.UID
The uid1 variable now contains the unique identifier for the next part to pin to. If you should start the project at this point, you would have a head with a very tiny tail, but you'd see what we're going for.
Since creating each part of the tail manually is tedious, we're going to add in a loop. This way you can just edit 1 variable to make the tail longer or shorter.
- Add another blank sub-event to On start of layout (select the event, then press 'B')
- Add a condition to this new sub-event (select it and press 'C') -> System -> For
We have no need for a name right now, and you could edit the end index to the amount of tailpieces you want. I used 18.
In this sub-event we're going to create the tailpiece objects, and set the position. After creation, we save their UID in uid2.
- add action -> System -> Create object -> tailpiece, layer: 0, X: tailpiece.X - (16 * loopindex), Y: tailpiece.Y
- add action -> System -> set variable -> uid2 to tailpiece.UID
This ensures that the existing tailpiece is used as starting point, and every tailpiece is 16px more to the left then the last one. It should look like this.
Now comes the tricky part. We have to tell Construct to repick all tailpieces, since it filters down to just 1 after creation. then pick one instance of tailpiece normally with the UID and another with the family and UID.
- Add sub-event to for
- Add condition to sub-event -> System -> Pick all tailpiece
- Add condition to sub-event -> tailpiece -> pick instance with UID uid1
- add condition to sub-event -> tailpiece2 -> pick instance with UID uid2
- Add action to sub-event -> tailpiece2 -> Pin to tailpiece ROPE STYLE!
- Add action to sub-event -> System -> Set variable -> uid1 to uid2
The new subevent will pick the correct instances of tailpiece and pin one to the other. The uid2 becomes uid1 for the next loop.
If you start the game now the little blocks will all be roped to the piece in front of them. Theres one more thing I would like though, which is turning each tailpiece to face the one in front of it.
- Add new event -> System -> every Tick
- Add condition -> System -> for each, tailpiece2
- Add sub-event -> System -> compare 2 values -> tailpiece2.IID > 0
- Add action to sub-event -> tailpiece2 -> set angle -> angle(Self.X, Self.Y, tailpiece2(tailpiece2.IID-1).X, tailpiece2(tailpiece2.IID-1).Y)
- Add another subevent to the original event -> system -> else
- add action to sub-event -> tailpiece2 -> set angle -> angle(tailpiece2.X, tailpiece2.Y, snake.X, snake.Y)
What this does is for each tailpiece, calculate the angle from it to the one in front and set its own angle to that. Unless it's the front one, in which case it sets its angle to face the head.
And thats it really, you can now start it up and see the glory that is your tail. I've included the .capx since this tutorial is probably really hard to follow.
- A lot of game use round object or different frames instead of just setting the angle. Those techniques can probably give a much nicer result in an actual game.
- Some game use gravity or other forces to make the tail not just stand still if the player doesn't move. I might update this tutorial with some of that if it seems interesting to people.
- My creation technique has some bold assumptions. The create event could probably be improved to be more modular. This should allow the create event to be dropped into a new level without breaking everything. Again, I can upate this tutorial if desired.
Thanks to LiquidMetal for the inspiration to this tutorial :)
Should you find errors in this tutorial, please leave a comment.