How to make Among Us in Unity | Part 4 — The Card Swipe Task

Welcome to the series that will teach you how to create a game similar to Among Us, in Unity3D Engine.

Redefine Gamedev
7 min readOct 29, 2020

This is the 4th part of the series. For the first part and the full index follow this link.

Get the Game Kit and start building an Among Us-like game in minutes!

Among Us, in Unity
Among Us, in Unity

Also, you might want to check How to Make Among Us in Unity series on my channel, Redefine Gamedev. If you prefer the video version, I highly recommend you check that one as well.

In this episode we will look how to make the Card Swipe Task. Complexity-wise, it will be a little more difficult than the previous Keypad Task.

Short Summary:

  • Setting up the scene
  • Drag card functionality
  • Swipe Points functionality
  • Putting everything together: The Swipe Task

Setting up the scene

Firstly, since we are going to use the Canvas to draw the task, make sure you have one in the scene. Don’t worry if you don’t have it! Follow these steps and it’s there Game Object > UI > Canvas.

Unity UI uses the Canvas component to draw everything related to UI.

Here (in the Canvas) let’s create a new empty game object and call it CardSwipe. This is where we will build our task.

Picture depicting the hierarchy for the card task
Card Swipe hierarchy

Visually, we should have something like this:

An image showing how the prefab card swipe should look like
Card swipe task prefab structure

Drag card functionality

The card is a game object that will receive the script called SwipeCard.cs — here we will implement the drag & drop functionality.

public class SwipeCard : MonoBehaviour, IDragHandler {

The most important part is that, in order to enable the Drag functionality, we need to implement the IDragHandler interface. This will need this function to be implemented:

public void OnDrag(PointerEventData eventData) {

Before proceeding with OnDrag, we need to get a reference to the canvas where this game object (the card) is. This is necessary because we will use the canvas to convert points from one frame of reference to another.

private Canvas _canvas;private void Awake() {
_canvas = GetComponentInParent<Canvas>();
}

Now, it’s time to see how we will process the drag event and the new position of the card.

Vector2 pos;RectTransformUtility.ScreenPointToLocalPointInRectangle(
_canvas.transform as RectTransform,
eventData.position,
_canvas.worldCamera,
out pos);
transform.position = _canvas.transform.TransformPoint(pos);

In pos we will store the new position where the mouse has been dragged. Unity calls OnDrag when a drag event happened. The mouse position is available in eventData.position.

Unfortunately, we cannot use the position as-is since it’s a different space than the canvas one. In order to translate the mouse position to a canvas position we will use the ScreenPointToLocalPointInRectangle functionality.

As you can see, it requires some canvas information. This is why we needed the canvas as a reference.

SwipeCard.cs

using UnityEngine;
using UnityEngine.EventSystems;
public class SwipeCard : MonoBehaviour, IDragHandler { private Canvas _canvas;

private void Awake() {
_canvas = GetComponentInParent<Canvas>();
}

public void OnDrag(PointerEventData eventData) {
Vector2 pos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
_canvas.transform as RectTransform,
eventData.position,
_canvas.worldCamera,
out pos);
transform.position = _canvas.transform.TransformPoint(pos);
}
}

If we attach the script to the card and play the scene we can see that the drag card functionality should work! It doesn’t do anything else yet, though. This is what the next steps are for.

Swipe Points functionality

To detect that a swipe was performed, we will use some invisible colliders situated conveniently on the magnetic band. We will check each step if the player swiped the card through each one of them in the correct order.

Let’s name the colliders SwipePoints, create a couple of them and arrange them one after another. I’ve attached an Image Component to better understand where they are located. The Image Component will be disabled when we finish implementing the task.

Image showing how swipe points are positioned in the hierarchy tab
Swipe Points in the hierarchy

Be sure to attach also a BoxCollider2D and make it trigger. This will enable us to test collisions between the card and each point.

Image showing what components are needed for the Swipe Point
Swipe Point Components

Regarding the SwipePoint.cs script, we need to have a reference to the SwipeTask.cs (the last script in this tutorial) which we will call when the card hits a particular swipe point (OnTriggerEnter2D).

SwipePoint.cs

public class SwipePoint : MonoBehaviour {

private SwipeTask _swipeTask;

private void Awake() {
_swipeTask = GetComponentInParent<SwipeTask>();
}
private void OnTriggerEnter2D(Collider2D other) {
_swipeTask.SwipePointTrigger(this);
}
}

Don’t worry if SwipePointTrigger does not exist, or even the SwipeTask. This is the final step which we will address in this tutorial.

Putting everything together: The Swipe Task

The final piece of the puzzle, the Swipe Task is the place that keeps track of the Swipe points, the current state of the task and checks if the player succeeded with it or not.

I have split this script into 3 major parts:

  • Keeping track of the swipe points
  • Check if the task finished successfully or not
  • Turn on the green or red light, depending on the outcome

Keeping track of the swipe points

In order to check SwipePoint we are at the moment we need two things: the list of all the swipe points (which we will initialize in the scene by drag & drop) and the current index — the index of the current swipe point —

public List<SwipePoint> _swipePoints = new List<SwipePoint>();
private int _currentSwipePointIndex = 0;

Note: after implementing this, don’t forget to attach the script to the Swipe Task and assign the Swipe Points to the list. They also might need their script attached as well.

In the SwipePointTrigger, the function called from each SwipePoint when it detects the card moving on top of it, we need to check if it’s the current swipe point needed:

public void SwipePointTrigger(SwipePoint swipePoint) {
if (swipePoint == _swipePoints[_currentSwipePointIndex])

The Swipe Point list should be initialized with the points in the correct order for this to work.

If there is a match, we will increase the index — move to the next swipe point.

_currentSwipePointIndex++;

Lastly, we will also check if the current index has reached the final swipe point. This means that the sequence was successfully completed and the task is finished. Here we need to:

  • restart the task
  • turn on the Green light (since it was successful)
if (_currentSwipePointIndex >= _swipePoints.Count) {
_currentSwipePointIndex = 0;
StartCoroutine(FinishTask(true));
}

We don’t have yet the FinishTask coroutine. Let’s create one now:

public GameObject _greenOn;
public GameObject _redOn;
[...]private IEnumerator FinishTask(bool wasSuccessful) {
if (wasSuccessful) {
_greenOn.SetActive(true);
}
else {
_redOn.SetActive(true);
}

yield return new WaitForSeconds(1.5f);

_greenOn.SetActive(false);
_redOn.SetActive(false);
}

I opted for this to be a coroutine since we will need to keep either the green or red lights turned on for a specified amount of seconds.

Firstly, we enable the correct light based on the task’s outcome.

Next, we use WaitForSeconds to keep the light on for a duration of 1.5 seconds.

Lastly, after the time passed, we turn both lights off to revert to the original state.

But what happens if the player failed the task? Well, the player can fail the task by not completing it in a certain amount of time.

public float _countdownMax = 0.5f;
private float _countdown = 0;

We will define two variables, the first one public — to be adjusted in the inspector — and the second one holding the current countdown.

Next, in the Update function which is called every frame, we will decrease the countdown. If the countdown reaches 0, the player started the task — we know this if the current index is not 0 — and the final SwipePoint was not reached, we can conclude that the task is failed.

private void Update() {
_countdown -= Time.deltaTime;

if (_currentSwipePointIndex != 0 && _countdown <= 0) {
_currentSwipePointIndex = 0;
StartCoroutine(FinishTask(false));
}
}

If you run it now, the task should work properly.

Don’t forget to:

  • attach the scripts to the correct GameObjects
  • remove the images from the Swipe Points
  • make sure that the Card/Swipe Points have the correct colliders

SwipeTask.cs

public class SwipeTask : MonoBehaviour {   public List<SwipePoint> _swipePoints = new List<SwipePoint>();
public float _countdownMax = 0.5f;
public GameObject _greenOn;
public GameObject _redOn;
private int _currentSwipePointIndex = 0;
private float _countdown = 0;

private void Update() {
_countdown -= Time.deltaTime;

if (_currentSwipePointIndex != 0 && _countdown <= 0) {
_currentSwipePointIndex = 0;
StartCoroutine(FinishTask(false));
}
}
private IEnumerator FinishTask(bool wasSuccessful) {
if (wasSuccessful) {
_greenOn.SetActive(true);
}
else {
_redOn.SetActive(true);
}

yield return new WaitForSeconds(1.5f);

_greenOn.SetActive(false);
_redOn.SetActive(false);
}
public void SwipePointTrigger(SwipePoint swipePoint) {
if (swipePoint == _swipePoints[_currentSwipePointIndex]) {
_currentSwipePointIndex++;
_countdown = _countdownMax;
}
if (_currentSwipePointIndex >= _swipePoints.Count) {
_currentSwipePointIndex = 0;
StartCoroutine(FinishTask(true));
}
}
}

Want More?

You are covered! Head over to Youtube at Redefine Gamedev channel and check the video tutorial.

--

--