2. Character Controller

The first thing we'll do is create a character controller.

This controller will handle:

  • Moving left and right
  • Jumping
  • Playing the right animations


Before this part of the tutrial, read the following article of the manual. It takes about 5 minutes and it will give you the very basic notions you need to know about graphs, machines and macros. 

Manual: Graphs, Machines & Macros

1. Create a flow machine

For the player controller, we will use a flow machine.

Select the Player object in the hierarchy, and click Add Component > Bolt > Flow Machine:

On your machine component, you first need to create a new macro for our player logic.

Save the macro under Macros / PlayerController:

The machine component should then look like this:


And the graph window should now display an default graph with Start and Update events:


Now that our machine is created, apply the changes to the player prefab:

We will repeat this process often in the tutorial for the different graphs we create. From now on, if you see "create a new macro for your graph", use the same process that we described here.

3. Calculate the movement

We want the character to move left and right, depending on the horizontal input axis. The horizontal input axis is a pre-configured Unity input shortcut that represents, for example, A and D on a keyboard, or the left joystick on a controller. When you go left, it returns -1, and when you go right, it returns +1. How fast to move will be controlled by a speed variable that we can tweak to adjust the gameplay. 

If you're not familiar with Unity input, remember you can see and edit the available axes and buttons from Edit > Project Settings > Input:


Let's get started.

Because this is the first time we create a variable and add units to our graph, we'll show you every step along with gifs. But to speed things up for the rest of the tutorial, after this section we'll only give you the steps and the final screenshots.

The first thing we need to do is create the speed variable on our player game object:

  1. Select the Player game object 
  2. Switch to the Object tab in the variables window
  3. Add a new variable named Speed
  4. Set its type to Float
  5. Give it a value of 5

For more information about variables, have a look at this article in the manual:

Manual: Variables

Then, we need to get the horizontal input axis. We can do that with the Get Axis unit. 

  1. Add the unit to your graph by right-clicking in an empty space and navigating to Codebase > Unity Engine > Input > Get Axis
  2. Type Horizontal in the axis name field.

You can also search for get axis and let the fuzzy finder to the work for you:

You will notice the new unit shows up as dimmed out. This is because we're not using its value anywhere yet, so Bolt warns us that is is currently useless by fading it out. If you want, you can disable this by toggling off  in the graph toolbar.

Next, we need to multiply this value with our speed object variable. We can use Bolt's contextual menu to make that easier.

  1. Drag and drop the value output port of the Get Axis unit to an empty space in the graph
  2. Choose Multiply
  3. Drag and drop the second port of the Multiply unit to an empty space in the graph
  4. Choose Variables > Get Object Variable
  5. Type Speed as the variable name

To complete our movement calculation:

  1. Add a Set Graph Variable unit (under Variables)
  2. Set its name to Movement
  3. Connect the result of the multiplication to its value input port
  4. Connect the Update node to its control input port


Note: Variable units have been improved in v.1.2 after this tutorial was written. They should look slightly different (with dropdowns), but they are functionally the same.

Let's recap what's happening here:

  1. At every frame (Update event)...
  2. ... we get the horizontal input axis (which is within -1 to +1)...
  3. ... we multiply it with the speed (so it becomes -5 to +5)...
  4. ... and store it in a variable called Movement.

Our player isn't moving yet, but we know by how much it should move.

Note two important things about the new movement variable:

  • We didn't create it beforehand like we did for the player's speed, because we didn't need to give it a default value. Bolt supports dynamic variables, meaning you can create new variables during play mode on the fly by just assigning them a value like we just did.
  • We used a graph variable instead of an object variable, because we will only ever need the movement inside this graph -- no need to share it with the outside world.

Whew. This was pretty boring, but now you know all the basics: creating graphs, variables and units. Now, we'll pick up some speed and actually make something happen.

4. Moving the player

The player prefab in the project already has a Rigidbody 2D component attached. All we have to do to make the player move is tell it at which velocity (speed) to go... and we just calculated that!

Velocity on 2D rigidbodies is a 2D vector: it has a X component for the horizontal speed, and a Y component for the vertical speed. Because we only want to affect the horizontal speed, we'll have to keep the vertical speed intact.

Here is the graph we need:

  • Get Graph Variable is located under Variables
  • Get Velocity and Set Velocity are located under Codebase > Unity Engine > Rigidbody 2D
  • Get Y and Create Vector 2 are located under Codebase > Unity Engine > Vector 2

If you have  enabled, you'll notice all of this graph is faded out. That's because we never specified when to set the velocity (the first arrow port on the Set Velocity node). Quite simply, we want to do this after we calculate the movement, so we can connect it with our previous set of units:


Now that our graph is getting a bit more complex, it would be a good time to start organizing bits of logics in group. The left part is used to calculate the movement, and the right part is used to set the velocity. By holding Ctrl and dragging, you can create groups than can be labeled:


We're ready to test! If you enter play mode now, you should be able to move the player with the keyboard or a controller:


If you keep the player selected while in play mode, you'll see our graph now animates its active nodes and connections:

5. Flip the direction

Next we'll add a new part to our graph to flip the player in the direction of the movement.

To do so, we only have to change the scale of the player game object on the X axis.

When going right (movement > 0), the scale should be +1, because the sprite is already facing right.

When going left (movement < 0), the scale should be -1, so the sprite gets flipped to face left.

When not moving (movement = 0), the scale should not change, so the player stays in the direction of the last movement.

The Y and Z axes of the scale should remain at 1.

Here is the graph we need:

  • Set Local Scale is located under Codebase > Unity Engine > Transform
  • Create Vector 3 is located under Codebase > Unity Engine > Vector 3
  • Branch and Select are located under Control
  • Comparison is located under Logic
  • Float literals will be at the root of the options if dragged contextually from the Select node

Then, connect the control input of the Branch node to the control output of our previous Set Velocity node on the left, and add a Flip group to keep things tidy:


If you play now, you should see the player flip:

6. Playing the animations

The last part of our movement graph will be to play the run animation.

The player prefab is already set up with a proper Unity animator controller. This controller has a Speed parameter that is used to transition between Idle and Walk states:


All we need to do on Bolt's end is to pass our movement speed to the animator. Because we're passing a speed and not a direction, we'll need to make our Movement variable absolute before passing it. This way, if we're going left at -5 movement, we'll tell the animator we're going at 5 speed.

  • Set Float is located under Codebase > Unity Engine > Animator
  • Absolute is located under Math > Scalar

To connect this part of the graph with our movement code, we'll need to add two connections:

  1. To the True port of our no-movement check, in case we skipped flipping the player
  2. To the output port of the Set Local Scale unit, in case we did flip the player


This way, whether or not we flip the player, we'll still update the animation. Bolt supports connecting multiple control outputs to a single control input for these kind of scenarios.

With an Animator group around or last part, your graph should now look a bit like this when zoomed out:


If you test now, the animations will play properly. Movement code: check. Hurray!

7. Jumping

Because our player is a physics rigidbody, implementing jump is as easy as adding an upwards vertical force.

First, create a new float object variable called Jump and give it a value of 12:

Then, below our movement graph, add a new group with the following units:

  • On Button Input is located under Events > Input
  • Add Force is located under Codebase > Rigidbody 2D > Add Force

Just like the Horizontal axis we used before, Jump is a default Unity input for new projects, mapped to Space on the keyboard. If you test your game now, you'll be able to jump!

8. Ground Check

There are two problems with our jump code:

  1. It doesn't change the animation sprite when you're in the air
  2. It allows you to jump again while you're already in the air

To fix this, we'll need to create a ground check. This part of the graph will use a raycast. This means we will throw a ray from the player's belly towards the ground, and check if we hit a platform within a small distance. If we did, it means the player is grounded; otherwise, it's in the air.

To make our raycast more reliable, we'll actually use what is called a circle cast. It's basically the same as a raycast, except you can give a thicker width (radius) to your ray. The node we need is called Circle Cast, under Codebase > Unity Engine > Physics 2D:

There are many options for it, depending on what parameters you need. In our case, we need the one with:

  • Origin: The source of the circle cast, in our case the player's position
  • Radius: The width or the circle cast, which we'll set to 0.3 for more reliability
  • Direction: The direction in which we'll cast, in our case down (-1 on the Y axis).
  • Distance: How far the circle cast will check until it stops, which we'll set to 1.1
  • Layer Mask: On which layer(s) it should check for a collision, which we'll set to Platforms only.

Once properly setup, our circle cast should look like this:

To get the layer mask dropdown, search for Layer Mask and choose Layer Mask Literal.

This graph can be read as: "Throw a ray downwards from my position with a 0.3 thickness, and check if it hits an object on the  Platforms layer within 1.1 units". 

Next, we need to analyze the result. Drag the little target output port to get the contextual menu open, and choose Raycast Hit 2D > Expose Raycast Hit 2D:


This will expose all the items in the raycast hit result. To check whether we actually hit a platform, we only need to check if the Collider is equal to Null (none). If it is, we didn't hit a platform and the player is in the air. If it isn't, we found a platform below our feet and the player is therefore grounded.


  • Not Equal is located under Logic
  • Null is located under Nulls

8.1 Preventing double jump

You can then use the result of our ground check to limit the jump to when the player is grounded:


Now, the player can't double jump anymore!

8.2 Setting the jump sprite

We also need change the sprite when the player is in the air. The animator controller is already configured to take a Grounded bool parameter. The only thing we need to do from Bolt is assign it. To do that, we'll copy-paste our ground check code at the end of our previous animator section, then use the Set Bool unit.

Now, if you test your game, the jump sprite should show up when in the air:

8.3 Reusing the ground check with a super unit

In scripting, there is a very important principle called DRY: Don't Repeat Yourself.

What we just did to change the jump sprite broke this principle: we copied and pasted the same part of our graph twice.

Now, if we wanted to make adjustments to our ground check code, we'd have to change two places every time. This may not seem so bad now, but what about when we'll have enemies doing multiple ground checks too? We'd have to update our graphs in three or four or even more places every time we make a change. Yikes.

Fortunately, Bolt provides a way to reuse the same graph in different places called Super Units. We will use super units to turn our ground check graph into a single unit that we will use for both the double-jump prevention and the jump sprite.

First, create a new macro with Assets > Create > Bolt > Flow Macro, and call it GroundCheck:




Then, copy the ground check units from the player graph, and paste them in the ground check graph:


Go back in the player graph, and delete your ground checks. Instead, drag & drop the new GroundCheck macro into your graph. It should appear as a single node, for example like this for the jump:


We have a problem here... Where is the result of the ground check? How can we connect it to the Branch node?

The reason it's not visible is because we haven't created an Output unit in our ground check macro. Let's do that now. From the player graph, just double click the Ground Check super unit to open its full graph. Notice the breadcrumbs in the toolbar let you navigate in nested graphs easily:


Next, add an Output unit, located under Nesting, and select it to display its graph inspector:


We will add a Value Output  for the result of the ground check. Set its key to groundedand its type to Boolean. If you want, you can give it a label and summary to add documentation to the graph inspector. Lastly, connect the new grounded port with the result of the ground check.


Navigate back to the parent player graph using the breadcrumbs in the toolbar. You'll see the super unit now has a grounded output port. Use that to connect it for both the double-jump prevention and the jump sprite animation:




If you play your game now, nothing should have changed. But your graph is now a lot cleaner, DRYer, and easier to maintain for the future. 

Conclusion

Finally, apply the changes to your prefab so that the object variables like Speed and Jump we created are automatically added on other player prefab instances in the other scenes.

This concludes the character controller. In this part, you learned how to:

  • Create machines and macros
  • Create and work with variables
  • Add units and connections
  • Reuse graphs with super units
  • Work with input, math, animation, physics and raycasting

Whew! The ice is broken, and you now know most of the basic concepts you need to use Bolt. Take a moment to review what you've learned, make sure you understand, and stretch your legs. Next up, we'll be adding a death mechanic to our games. 

This article was helpful for 68 people. Is this article helpful for you?

+2

8.1 Preventing double jump took me a long time to figure out that I need to delete "Jump" group we made before and replace it with "Add Force". There is no mention of that. Would be cool if You fix that!

+1

I got lost at that point too, I had no idea the "add force" group was supposed to replace "jump" either. Thank you for posting this!

+1

The "Jump" Group is just renamed to "Add Force" since jumping is just an add force function.  You don't have to delete that group, you can just rename it.

I'm still stuck on that, the instructions for this aren't very clear, esp for beginners.

+4

Yeah this is a bit tricky for beginners. You have to create a new layer and name it "Platforms" and apply that layer to the 3 platforms in the game under "Level" in the hierarchy. Then go back to the bolt editor and in your Ground Check group find Layer Mask and select the "Platforms" layer you made.

 Also make sure that the Player gameobject layer is set to default. 

I cannot achieve this:

8.1 Preventing double jump

The character is still able to make double jump.

I am trying this tutorial through script, can some one post a code version for double jump checking.

This is to check strength of VS tool.

:)

I can't find Vector2>Get Y...

What is in your options for Codebase > Unity Engine > Vector 2?

What show up if you search for Get Y?

I have the same issue here. Has Get Y been changed to just Y? I've been searching for Get Y for a long time and am starting to think I either don't have it, or its name has been changed.

Has Get Velocity been changed to GetPointVelocity? Again, can't find what I'm looking for following the tutorial...


I have same problem with Y and Velocity

Rigidbody2D.velocity (Get) -> Y   =  nothing gives

Hi thanks for the tutorial. Can anyone help me why the parented camera doesnt flip when we are flipping the player? i am trying to create one from scratch but my camera flips . did i miss something in the tutorial? some help will be very much appreciated

Nevermind it wasnt a problem at all unless i parent another object to the camera itself. i will try to figure out something as its not part of this tutorial. :)

+2

I'm pretty excited to learn how to program, but early on I'm already having an issue where Unity doesn't seem to be accepting my spacebar input for Jump. I press space and nothing happens; all other controls work. Project Input shows Jump is mapped to space (although it seemed to be mapped to x axis originally before I fixed that.) Either way, nothing happens. Is something wrong?

Aha! I think I figured it out. In the tutorial, it says Rigidbody 2D is found in Codebase. If I use the one under Player instead, it works.

I reached the part where I test the left and right movement, but upon entering Play Mode and pressing A/D nothing happens. I check the console and I get this message:

ArgumentException: No variable name specified.
Parameter name: variable
Bolt.VariableDeclarations.Get (System.String variable)
Bolt.GetVariable.Get (Ludiq.Recursion recursion)
Bolt.Unit+<>c__DisplayClass56_0`1[System.Object].<ValueOutput>b__0 (Ludiq.Recursion recursion)
Bolt.ValueOutput.GetValue (Ludiq.Recursion recursion)
I'm unable to specify the variables in Get Variable. I'm confused and I don't know how to fix this problem. :(

Hello!

 I had the same problem and found out i wrote horizontal instead of Horizontal with capital H at the beggining, 


check your writting is the same as the tutorial!

Hope this helps!


I checked to see if mine was the same but it appears that I already spelled Horizontal correctly and with a H.

did you solve the problem? i got the same error

Im afraid not, sorry. I abandoned the tutorial a few weeks ago; figured there's no point following a tutorial for a previous version of Bolt.

I ran into a problem here: Layer Mask: On which layer(s) it should check for a collision, which we'll set to Platforms only.

There was no 'Platforms' layer option in the drop down. I looked and there didn't seem to be any layer in the project called Platforms. I created one, and put the platforms on it, and it seems to be working - is this the correct solution, or did I miss something that was already there?

That is the solution, but you should have had that set up from Section 1.3.  You might want to double back and check your layers to make sure you aren't missing any others.

I'm working on a platformer for a university class and I'm completly new to game making. For a reason (I don't really want to explain now, it's complicated) I don't want to flip my character, but assign different animations for left and right. So instead of a flip, I need to define L and R for my Animator. Any ideas how to do this? Deadline is soon, so I really appreciate fast help: )

Thanks.

In section #5 can someone explain the purpose of the "Branch" node. I'm new to programming. Purely as a novice, it makes sense that if A < B it would flip the scale to -1/1. That said, if I remove the "branch" it clearly breaks. 

But I don't understand is why. If I remove the branch, I see signal is getting passed on (from the A <B comparison to the Select. To me it reads as if a signal is being allowed to pass, despite no movment (thus being neither greater or less than). Which is confusing to me.  Appreciate any help. 

The BRANCH is for "Check" if the condition is true or false.

What are you doing in in 4.1 there is not Codebase option i can see i am using 1.2.2 bolt version

There is not Option for Codebase when i select the player and right click in the Graph editor why is this happening??

I'm having the same issue. This is what it's giving me:

+1

When reopening the project I realized the Bolt wizard appeared again. In the Wizard, make sure you click generate under the Types tab. It resolved the issue for me.

Indeed, it just means your unit options database was not generated yet. You can also generate it from Tools > Bolt > Build Unit Options.

This Visual Scripting Tool is Useless i'd Prefer to Write Code over this. the Interface is Poor, it slows down the Unity Editor. Today is my 2nd day with Bolt. and i am leaving today. I could have used my money elsewhere.

Hi Nalayak, I'm sorry Bolt does not meet your expectations. Can you explain tell me more about why you feel the interface is poor in a private ticket? Thanks!

I liked the tutorial and I'm enjoying getting used to Bolt, I must note that the walking animation had a terrible keyframe setup and the character "blinked" out of existence at frame 8 or 9.  Went back and fixed in it the animator. Other than that everything seemed to work as explained.

Hi Christian, thanks for the report, fixing this & reuploading the template package.

+1

Tutorial is great (I much prefer text based tutorials to video ones), but for anyone struggling with the initial jump not doing anything please note that setting this to 12 is not enough to get the initial imported character off the ground. You'll either need to lower his mass, or change the jump value to 300.

This helped me thanks.

Hi, in item 8, part "search for Layer Mask and choose Layer Mask Literal." Dont have option the platform, have other mode?

resolve, "name to layer" and add string, sorry

Hi, could someone please help me out. I was able to move/jump just fine until adding the "preventing double jump" lines. here's what my current state looks like. I'm using the most current version.
+1

Well, it's zoomed out, so I can't see the details, but what's the problem?  It looks like the nodes match, so what's wrong?

+1

Same issue here. I've followed the instructions and it seems to add velocity to the jump rather than stopping the ability to jump until in contact with the ground. This means that the first jump is approx doubled and all subsequent jumps in the air are with normal force.

Strangely, "Add force" is what the group is called in the instructions so it seems to be doing that task. However this doesn't prevent double jump in my build


here is another photo of the same build slightly zoomed in to see the values


  • Float literals will be at the root of the options if dragged contextually from the Select node

I can't find those...

A+ on this tutorial - It took a while, but I made it through! 

Great job :)


If anyone is confused on how to navigate the Graph window:

 - Focus Graph Object Quickly:  Zoom out, click graph object, zoom back in.

 - Moving the Graph Canvas Background without moving the elements:  Hold ALT + Left Mouse Click Drag

- Create a Group:  Holt CTRL + Left Mouse Click Drag  (create a square).

- Resize Group:  Use the corners of the group with your mouse to see the resize icons just like window resizing.


After you learn how to do the above, learning how to do the rest will be easier to figure out.


Anyone figure out how to properly set up jump and how to properly set up the ground check? I can get jump to work, but have a variable of 12 has my just bump up. The ground check, I can in some instances, do a double jump. 

Any assistance? 

+1

@Drumit84 Hopefully this helps...

I noticed that 12 is used because it's the amount of force to be applied. It could be 15 or even 20 depending how high you want to go. 

1. Make sure your Jump isn't set to "Force"... It should be "Impulse".

2. Your Ground Check is basically just an invisible check of the distance between the Character and the Platforms. Note that "Spikes" aren't considered a Platform, so when you touch those you can't jump anymore.

3. Double Jump is happening because when you Jump it's supposed to do a "Ground Check" first. If the "Ground Check" says "I am on the ground" then you can jump. If you're not on the ground, it should say "I am NOT on the ground" which would then prevent the jump.

How to get it working  ...  I know this is not helpful... sorry :(   but without seeing what your Graphs look like I can't really tell you what you're missing or where you went wrong...

Trust me, it's confusing to get into Raycasting and other things like 2D Collision at the 2nd part of the tutorial, but for things we don't understand, we just have to make sure we follow the tutorial EXACTLY as it is setup. 

My biggest recommendation is to back-track to the point where you know your character is working correctly and interacting correctly, and then proceed with tracing your steps past that point (versus their screenshots).

If you click the screenshot images above they should enlarge -- It's imperative that you match your Graphs exactly as their screenshots are, and if something is confusing that you don't understand, just ignore it and match their Graphs to get the project working. 

Advice:   Go back and make sure you match up your Graphs to their Graphs and test each section until you finally get it working.

If you do not understand how Ray casting or Collision works, here's a little bit of a description based on what I understand about it...

Ray casting (or Circle Casting) is an invisible bubble from POINT A -> to POINT B  (or the size of the bubble). The concept is to expand the size of this invisible barrier until it interacts with another object... Such as a bubble growing in a room (a huge bubble) starting from Player # 1, which eventually gets so big it touches Player # 2 (which causes the Ray cast to interact with that object since it touched it).   This is used in games for things like shooting bullets at players, or in this case creating a ray cast of 1.1 in length from your character to see if it touches a Platform, ie:  Ground Check.

Collision is simple to understand. Is Object A touching Object B?  But also, what else is Object A or Object B touching can be handled by Collision. You could be colliding with 10 things at the same time... Such as:  1) you're colliding with the platform (because you're walking on it).... 2) You may have entered a cloud of smoke (you're colliding with that cloud of smoke, ie: an Object of smoke).  The list goes on, such as colliding with a wall, preventing players from passing through walls, etc.


The instructions do not work from the very beginning.  I never get the items in the "Graph" that I am supposed to get after selecting the "Player" object and performing the "Add Component"  to add the "Flow Machine".  My experience with Bolt, so far, has been terrible.  All of the instructions for installation and usage of the product are either incorrect or incomplete.

Hi JSchaum!

This was indeed changed in v.1.3, I updated the instructions in this part and will review all the other parts for outdated instructions. Thanks for bringing it up!

I was able to get from Page 1 through Page 7 before stopping - but not because things were bad (or not working out for me) but because I had gathered enough tutorial for now to learn how things work.

Some of these issues are not bolt, they're Unity itself. Sometimes clicking on the object should automatically fill the graph window, but clicking it again, or clicking on another item and clicking back does the trick - or clicking Edit Graph on the right does it. 

You have to get used to it. But Bolt works great, there's nothing wrong with it - and if there is you should help improve the product by providing bug reports since we don't know what version of Unity you're using, etc.

"Float literals will be at the root of the options if dragged contextually from the Select node"


No, they're not! Please help as I got stuck and can't move on... Contextual menu starts with "string", there're no float/int variables and I've looked everywhere!

Temp solution (if anybody else feels like stuck) is to create two Object variables with "1" and "-1" float values and use them for flipping part. Still, wondering what causes this error...

Okay, I got it sorted out. Looks like it was caused by some issues during importing Bolt into Unity. I went to Tools/Bolt/Unit Options Wizard, performed setup with all default options, rebuilt unit database and it worked fine!

I'm having some trouble with the walk animation. It works, but when I stop moving either left or right rather than stoping in the idle position it flickers rapidly between the walk and idle states.

I notice that when that happens my movement variable for the animation is not resetting to 0.

But rather stuck at some arbitrary number between 0 and 5 or 0 and -5, depending upon which direction I'm moving. The variable comes from the earliest nodes where basic movement was defined.

Which reads as 0 here, but as 0.17 where it's trying to animate.

Help?

Figured it out. I had the flow going from the Vector 3 (Create Vector 3) to the Animator (Set Float). 

Instead I needed to have the Vector 3 (Create Vector 3) plugged into Transform (Set Local Scale) and from there the flow goes to Animator (Set Float).


Though now my question is why? 

Ah, okay, after further examination of the Flow Graph the answer is obvious. The flow never enters those nodes that end with the Vector 3 (Create Vector 3). All of those nodes are just setting up the information for Transform (Set Local Scale) and the preceding Branch. Thus the flow cannot continue from that point. Makes sense.

When I search for layer mask i dont find it

OMG this is meant to be an easier option for non programmers!?!?, needsalot more guides there isnt even a basic flappy guide out there for bolt and seems quite abit more hassle then playmaker for now