Skip to main content
Version: 5.x
Lens Studio
Bitmoji Runner Game

Part 1 - Control Animation with Swipe

Welcome to the first part of this tutorial on creating a Bitmoji Runner Game in Lens Studio! In this part we'll guide you through the steps to set up your project, import assets, create smooth animations, and write scripts to control your character. Let's get started!

Prerequisites

  • Before we begin, ensure that you have Lens Studio (version 5.2 or higher) installed on your computer.
  • You will also need a basic knowledge of programming; in particular JavaScript.
Section 1

Preview of the Final Result

What You'll Build in the First Part

Step 1

Before we dive into the tutorial, let's take a look at what you'll be building.

By the end of this part, you'll have a player character that smoothly moves left and right in response to swipe gestures. The movement will be controlled within a set boundary, ensuring the player doesn't go off-screen. You'll also learn how to manage animations and transitions dynamically as the player moves.

Loading
Next Section
Getting Started
Section 2

Getting Started

Let's open a new project in Lens Studio and import all needed assets

Step 1

Open Lens Studio, then click on + Default to create a new project

Step 2

From the Asset Library, import the Swipe Detection asset.
Install the following custom components:

  1. Animation State Manager.
  2. Bitmoji 3D.
Next, click the "+" sign in the Asset Browser, search for these custom components, and add them to your project.

The Animation State Manager is needed to control and manage the different animations of the player, such as transitioning between running or idle animations.

Step 3

Add the Swipe Detection prefab to the Scene Hierarchy.

Test it by swiping in different directions in the preview.

Step 4

Drag the 3D Bitmoji from the Asset Browser to the Scene Hierarchy. This creates a scene object with the 3D Bitmoji as a component.

In the Inspector panel, ensure that the Adapt to Mixamo option is enabled.

Enabling Adapt to Mixamo ensures compatibility with Mixamo animations, which is essential since we'll be importing animations from Mixamo for smooth playback and proper skeleton alignment.

Loading
Loading
Loading
Next Section
Importing and Organizing Animations
Section 3

Importing and Organizing Animations

Now we will import the animations, set up the Animation Player and organize the scene objects

Step 1

Import the following animations from Mixamo:

  • fast run.
  • left strafe.
  • right strafe
(or from here).

Create a folder named Animations - Mixamo in the Asset Browser and import these animations into this folder.

Organizing assets in the Asset Browser makes it easier to manage and locate files as your project grows, reducing clutter and improving workflow efficiency.

Step 2

Add an Animation Player to the 3D Bitmoji scene object and enable Autoplay to test each animation.

Step 3

Add the animations:

  • Left Strafe (name it Left).
  • Run (name it Run).
  • Right Strafe (name it Right).

Set Playback Mode to Loop for each animation.

We'll use these clip names (Left, Run, Right) later in the Animation State Manager to create transitions between the animations.

Step 4

Create a new scene object named Player. Add the 3D Bitmoji scene object as a child of Player.

The Player scene object will help organize everything related to the Player character, making it easier to manage position, movement, and animations by controlling the parent object.

Step 5

Rotate the Bitmoji object by 180 degrees on the Y axis to make the Bitmoji face the opposite direction.

Adjust the scale to make the Bitmoji smaller.

Loading
Loading
Loading
Next Section
Setting Up the Animation State Manager
Section 4

Setting Up the Animation State Manager

The main goal of these steps is to set up an Animation State Manager with a blend tree to achieve smooth transitions between different animation states based on directional input, and to ensure proper control of animation playback.

Step 1

Drag the Animation State Manager into the Scene Hierarchy. Then, in the Animation State Manager, add the Animation Player.

Step 2

Create a blend tree named RunBlendTree.
Add the clips and their threshold values:

  • Left: 0.20
  • Run: 0.50
  • Right: 0.80

Threshold is the value of the parameter that corresponds to the current animation clip being at full effect.
The threshold value should be between 0 and 1.

For more details, you can check the Animation State Manager guide for further explanation.

Step 3

Set the parameter to direction (type: float, value: 0), which will be used as the Blend Parameter for our blend tree.

Enable Normalize Clip Duration to ensure the clip lengths are aligned during blending moments.

We will use this direction parameter later in the PlayerController script to change the character's direction when the user swipes left or right.

Step 4

Set Up Transitions:
Enable Edit Transitions.

Add a transition from Entry to RunBlendTree with a transition duration of 0.

Set the condition name to direction (type: float, value: less than 1).

This step sets up the transition from Entry to RunBlendTree, triggered by the direction parameter.

Step 5

Since we are controlling the animations and transitions through the Animation State Manager, disable Autoplay in the Animation Player.

Loading
Loading
Loading
Next Section
Writing the PlayerController Script
Section 5

Writing the PlayerController Script

Now we will create and organize a PlayerController script, modify swipe detection, and implement directional movement control for the Bitmoji based on user swipes.
The goal is to smoothly transition the player's position and animation direction when swiping left or right, with conditions ensuring the player remains on-screen.

Step 1

To get started, add a Script Component to the Player scene object.

Next, create a folder named Scripts in the Asset Browser — this helps us organize our resources efficiently.

Once the script is created, move it into the Scripts folder and rename it to PlayerController for better clarity and management.

Step 2

To control the player with swipe gestures, go to the Swipe Detection scene object and enable Show Debug Message to help monitor swipe inputs in the logger.

Then, change the script with API to be the PlayerController script, which allows us to control the player's movements.

Disable the Diagonal Swipes option, as we only need simple directional swipes.

Keep the left, right, up, and down functions unchanged, and finally, delete the Text Example scene object since it's no longer needed.

Step 3

Before we start writing the PlayerController script, take a look at the diagram to understand how swipes will trigger animations and movement in the game.

  • Swipe Detection: This listens for user swipes, such as a left swipe. Once a swipe is detected, it sends a Swipe Trigger to the PlayerController script.
  • PlayerController Script: Upon receiving the trigger, this script:
    • Moves the player into the new position based on the swipe direction.
    • Calculates the direction value, normalizes it and sends it to the Animation State Manager.
  • Animation State Manager: The system then compares the direction value with the threshold in the Animation State Manager. Based on this comparison, the appropriate animation (like Run or Left) is played.

Step 4

We want to write a script to control the direction of the Bitmoji on swipe, so we will have four swipe functions for all directions.

We will leave upSwipe and downSwipe empty for now and work on leftSwipe and rightSwipe.

Step 5

We need the Animation State Manager and the player as inputs.

These inputs are needed to control the player's animations and manage transitions, like switching between left, run, and right states.

Step 6

We also need an update event where the movement will happen.

The update event is used to manage the player's movement continuously, ensuring smooth transitions and animations based on user input.

Step 7

We will need a boolean variable to tell us if it is time to move, so we will create changeDir and set it to false at the beginning.

Step 8

Then we need the local position of the player and a target position.

We will check if the current position is less than or greater than zero to determine if we need to increase, decrease, or keep the x position value the same when the user swipes left or right.

We also need a target position that will calculate the movement based on steps to make it smooth over time.

In the beginning target position will be equal to current position.

Step 9

If the player's x position is 0, then it is in the middle. The player can move right or left.

We will start with the left swipe.
The user can swipe left and not make the player go out of the screen only if the x position is 0 or more.

If it is less than 0, then the player is already on the left of the screen and if we allow it to move left again, it will go out of the screen.

Step 10

We'll add a condition in the left swipe to check if currentPos.x >= 0.

If this condition is true, we set changeDir to true and start decreasing the x position over time to move the player to the left.

We'll create a step variable for managing movement, initializing it to 0 at the start of the script, and set it to -5 in the left swipe.

We chose -5 as a small, manageable number to move the player's x position incrementally to the left. This ensures smooth movement, as the change happens gradually with each frame in the onUpdate function and repeats until the player reaches the desired position.

Loading
Loading
PlayerController.js
PlayerController.js
PlayerController.js
PlayerController.js
PlayerController.js
Loading
PlayerController.js
Next Section
Understanding Movement Time and Progress
Section 6

Understanding Movement Time and Progress

Now that we have the swipe trigger and the direction check in place, it's time to handle the actual movement in the onUpdate function. To make the movement of the player feel natural and smooth, we need to control how the player moves from one position to another gradually.

Step 1

If we simply applied a large step, like step = -10, the player would instantly jump to the left side, which would feel unnatural and jarring.

To avoid this, we have introduced two key variables:

  • movementTime
  • currentMoveTime

If we do something like:
if (currentPos.x >= 0) {step = -15;}
The player will instantly snap to the left side, making the transition abrupt.

Step 2

When the game begins, these variables are initialized with their default values.

Step 3

When a swipe triggers, some of these variables will change. To initiate movement, changeDir will be set to true. Depending on whether the swipe is to the right or left, the step value will be either positive or negative.

Step 4

Then, in the first frame after changeDir is set to true in the swipe function, currentMoveTime will be checked to see if it is greater than or equal to movementTime.

If it's not, it will increment by 0.5, and targetPos.x will also increase by the step amount, moving the player to the right or left.

In the diagram shown beside, we are providing an example of the leftSwipe.

Step 5

In the second frame, currentMoveTime will be 0.5 and targetPos.x will be -5.

Since currentMoveTime is still less than movementTime, it will increase by 0.5 again, and targetPos.x will also decrease by the step value of -5 once more.

Step 6

In the third frame, currentMoveTime will be 1 and targetPos.x will be -10.

Now, when currentMoveTime is checked against movementTime, they will be equal.

As a result, currentMoveTime will reset to its default value, which is 0, and the movement will stop.

Loading
Next Section
Implementing Smooth Player Movement with the onUpdate Function
Section 7

Implementing Smooth Player Movement with the onUpdate Function

Let's walk through how to write the onUpdate function, which will handle the movement of the player based on swipes.

Step 1

At the start of the script, we'll create two variables:

  • currentMoveTime, set to 0 to track progress.
  • and
  • movementTime, set to 1 as a starting point.

You can adjust movementTime later to ensure it moves the player just enough without going off-screen.

Step 2

In the onUpdate function, we'll start by adding a condition to check if the player is in the process of changing direction (based on a swipe).

If the player is moving (changeDir is true), we'll also check if the movement has lasted long enough by comparing currentMoveTime with movementTime.

If the duration has exceeded the time limit, we'll stop the movement by resetting currentMoveTime to 0 and setting changeDir to false to signal the movement has finished.

Step 3

But if we're still within the allowed movement time, we'll gradually increase currentMoveTime by 0.5 on each frame
and update the targetPos.x by adding the step value.

This will make the player move smoothly left or right depending on the swipe direction.

Step 4

Finally, we'll apply the updated target position to the player's transform, ensuring the player's position is updated correctly on the screen.

Step 5

You can now test and see that the player moves left successfully when you swipe left.

If you swipe left again, the player stays in position and doesn't go off the screen.

However, when you swipe right, the player doesn't move yet.

Step 6

To make the player move right on a right swipe, we'll use similar logic to the left swipe.

In the rightSwipe function, movement should only happen if currentPos.x is less than or equal to 0, meaning the player is on the left side or in the middle of the screen.

Step 7

The step value should be positive (set to 5) to increase the x position and move the player to the right.

Set changeDir to true to start the movement.

PlayerController.js
PlayerController.js
PlayerController.js
PlayerController.js
Loading
PlayerController.js
PlayerController.js
Next Section
Synchronizing Animation with Swipe Direction
Section 8

Synchronizing Animation with Swipe Direction

Now that the player moves with swipes, we need to update the Bitmoji's direction.

Step 1

Now we can see that the player's x position changes when we swipe left or right, but the direction of the Bitmoji remains the same.

We need to change the direction parameter value to switch between left, right, and run animations.

We created the direction parameter earlier when setting up the RunBlendTree in the Animation State Manager.
We'll now use it to control the character's animation direction based on swipes.

Step 2

For that, we will need currentDir and targetDir variables set to 0 at the beginning.

Step 3

The target direction will change in the swipe function:

in the left swipe, it will be -1; in the right swipe, it will be 1.

Step 4

In the update function, if no swipe is happening, the target direction should remain at 0.

To handle this, in the else block where changeDir is false, simply reset targetDir to 0.

Step 5

We will update currentDir to be between the current direction, which is now 0, and the target direction, which will become 1 or -1, or remain 0 if no swipe happened.

To do this, we use MathUtils.lerp to gradually interpolate between currentDir and targetDir.

The 0.3 is the interpolation factor, controlling how quickly the transition happens. A higher value makes the transition faster, while a lower value slows it down.

Step 6

Next, we'll update the animation state to match the player's current direction.

We do this by using the setParameter method, passing the name of the parameter direction and its value, which is the normalized current direction.

The expression (currentDir + 1) / 2 normalizes the currentDir value, which ranges from -1 to 1, into a range between 0 and 1.
This is necessary because the animation system expects values within this range for smooth transitions between left, right, and run animations.

Loading
PlayerController.js
PlayerController.js
PlayerController.js
PlayerController.js
PlayerController.js
Next Section
Final Tweaks and Project Organization
Section 9

Final Tweaks and Project Organization

Refining Movement and Organizing Your Project

Step 1

Now that your Bitmoji movement is functional, you can fine-tune the values to get the desired effect.

For example, try adjusting the movementTime from 1 to 1.5 to make the Bitmoji move further to the left and right when swiping.

Step 2

Additionally, ensure that your project stays organized as it grows.

Group related objects under main scene objects to make navigation easier, especially when the project becomes more complex with additional assets and components.

Loading
Summary
Finish & Review

Summary

In this part of the Bitmoji Runner Game tutorial, you've set up the core movement for your Bitmoji character, allowing it to move left and right based on swipe gestures. By adjusting parameters like the direction and movement time, you've created smooth transitions between animations. Additionally, you've learned the importance of keeping your project organized as it grows.

Tip: Don't forget to experiment with different movement settings and ensure all your assets are neatly organized as we move into more complex gameplay elements in the next part!

Was this page helpful?
Yes
No