How to Create a Twitch Chat Game with Unity
Learn to integrate the Twitch Chat API into your Unity game, so viewers can interact with the game during streaming. By Harrison Hutcheon.
        
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How to Create a Twitch Chat Game with Unity
45 mins
- Getting Started
- The Twitch Chat Script
- Reading in Chat Messsages From Twitch
- Parsing Chat Commands
- Parsing and Storing Commands
- The Game Manager
- Validating Commands
- Testing Commands
- Your Twitch Audience and You
- Audience vs Audience
- Audience vs Game
- Audience vs Streamer
- Common Design Challenges
- Delay
- Audience Interaction
- Streamer Interaction
- Where's the Fun?
- Exploring the Sample Scene
- Creating Commands
- Expanding the Vote Script
- Game Over and New Game Conditions
- Game Over Check
- Game Over Action
- New Game Action
- Revisiting the GameManager
- Using What You've Learned
- Where to Go From Here?
Parsing and Storing Commands
Create a script in RW/Scripts/Common called IGameCommand. It’s short and sweet:
using System.Collections.Generic;
public interface IGameCommand
{
    string CommandString { get; } 
    string ShortString { get; }  
}
IGameCommand has a CommandString field, which stores the string required to execute it. For example, Battle has users vote for in-game options, so a CommandString for a vote command would be !vote. 
Additionally, IGameCommand has a ShortString field, holding a shorthand version of the command. For example, a command with a CommandString of !vote could have the ShortString !v. 
In RW/Scripts/Common, create a script called ChatCommand. 
If a ChatMessage contains a valid command, its data is stored in a ChatCommand. Import the System namespace (and System.Collections.Generic if it wasn’t added by default). Then give ChatCommand the [System.Serializable] decorator and create the fields shown below:
using System.Collections.Generic;
using System;
[System.Serializable]
public class ChatCommand
{
    public IGameCommand command; // 1
    public string username; // 2 
    public DateTime timestamp; // 3 
    public List<string> arguments; // 4 
    //...
These fields store the:
- Command script for the command the user submitted.
- Username of the user that submitted the command.
- Exact time the user submitted the command, which can be useful for logging user actions and debugging gameplay issues.
- Arguments submitted with the command.
ChatCommand needs a constructor and two methods: Execute and ParseCommandArguments. Insert these below the public fields:
public ChatCommand(ChatMessage message, IGameCommand submittedCommand) // 1
{
    arguments = new List<string>(); // 2
    command = submittedCommand; // 3
    username = message.user; 
    timestamp = DateTime.Now; 
    ParseCommandArguments(message); // 4
}
public void ParseCommandArguments(ChatMessage message)
{
    string[] splitMessage = message.message.Split();
  
    if (splitMessage.Length > 1)
    {
        for (int i = 1; i < splitMessage.Length; i++)
        {
            arguments.Add(splitMessage[i]);
        }
    }
}
Here's a code breakdown:
- The constructor takes two arguments: ChatMessageandIGameCommand.
- Then it instantiates argumentsto a newList.
- Next, it assigns submittedCommandtocommand,message.usertousernameand setstimestamptoDateTime.Now.
- Finally, it calls ParseCommandArgumentsand passes inmessage.
ParseCommandArguments splits the message to isolate any values after the command string and adds them to arguments. For example, if a user submits !vote 1, then 1 is the stored argument.
The Game Manager
The GameManager is your app's the brain. It uses your scripts to read incoming messages, parse commands and execute valid commands in-game.
In RW/Scripts/Common, create GameManager. Then attach GameManager to Managers/GameManager in the scene hierarchy.

Open the GameManager script. Above the GameManager class, declare an enum called GameState. Give it two values: Playing and GameOver:
public enum GameState
{
    Playing,
    GameOver
}
In the GameManager class, add:
public GameState gameState; // 1
public ChatCommand currentCommand; // 2 
private TwitchChat chat; // 3
private List<ChatCommand> newCommands; // 4
private IGameCommand[] gameCommands; // 5
These fields hold:
- An enum that identifies the game's current state.
- The command the game manager is currently executing.
- A reference to TwitchChatsoGameManagercan read in chat messages.
- The list of user submitted commands.
- An array of valid game commands, attached to the same object as the GameManager.
Next, implement Start and a private SetGameState as shown below:
void Start()
{
    gameCommands = GetComponents<IGameCommand>();
  
    newCommands = new List<ChatCommand>();
    chat = gameObject.GetComponent<TwitchChat>(); 
  
    SetGameState(GameState.Playing); 
}
private void SetGameState(GameState newGameState)
{
    gameState = newGameState;
}
Start initializes some of the class's fields and sets the default game state. SetGameState takes a GameState and sets the gameState field.
Now, create a public method called ResetGame:
public void ResetGame()
{
    if (gameState != GameState.Playing)
    {
        SetGameState(GameState.Playing);
    }
}
If it's not already set to Playing, ResetGame sets gameState to Playing. Later, this method will return the game to its original state, so a new game can start.
Create a public method called EndGame and implement it as below:
public void EndGame()
{
    if (gameState != GameState.GameOver)
    {
        SetGameState(GameState.GameOver);
    }
}
If it's not already set to GameOver, EndGame sets gameState to GameOver. Later, this method will do everything needed when a game is over, such as displaying a scoreboard.
Next, open IGameCommand. Add this method signature to the bottom of the interface:
bool Execute(string username, List<string> arguments, GameManager gm = null);
Now IGameCommand has a method called Execute that returns a boolean and takes three parameters:
- A string storing the username of the player that submitted the command.
- The Listof strings storing arguments passed with the command. For example, an argument for !vote would be the option's number. So, the user would submit the command !vote 1.
- A GameManager, set to null by default.
Now, go back into ChatCommand. Add the following at the bottom of the class:
public bool Execute(GameManager gm)
{
    return command.Execute(username, arguments, gm);
}
Execute calls command.Execute, passing in the required variables: username, arguments and GameManager. It also returns a boolean indicating if the command was successful.
Of course, you need to check that any incoming chat message matches a valid command.
Validating Commands
Back in GameManager, create a private method called CommandIsValid that takes a ChatMessage and returns an IGameCommand, as shown below:
private IGameCommand CommandIsValid(ChatMessage chatMessage) 
{
    if(chatMessage != null) 
    {
        string commandString = chatMessage.message.Split()[0]; // 1
        foreach (IGameCommand command in gameCommands) // 2
        {
            if (commandString == command.CommandString || commandString == command.ShortString) // 3
            {
                return command;
            }
        }
    }       
    return null; // 4
}
In this code:
- 
CommandIsValidsplits theChatMessageand gets the first string to check if its a valid command string, for example !vote.
- It loops through each command in gameCommands.
- If the command string matches a IGameCommand'sCommandStringorShortString, then it returns the command.
- If it doesn't find a match, it returns null.
Now, replace Update with FixedUpdate. Declare a private method ProcessCommands after it. Implement them both as below:
void FixedUpdate()
{
    if (gameState == GameState.Playing) //1
    {
        ChatMessage recentMessage = chat.ReadChat(); //2
        IGameCommand command = CommandIsValid(recentMessage); //3
        if (command != null) //4
        {
            ChatCommand newCommand = new ChatCommand(recentMessage, command); //5
            newCommands.Add(newCommand);
        }
        ProcessCommands(); //6
                  
    }
}
private void ProcessCommands()
{
    if (newCommands.Count > 0)
    {
        newCommands[0].Execute(this); //7
        newCommands.RemoveAt(0);
    }
}
In FixedUpdate, the code:
- Checks if gameStateisGameState.Playing.
- Calls chat.ReadChatand stores the returnedChatMessagein a variable calledrecentMessage.
- Then checks if the command is valid by calling CommandIsValid, passing inrecentMessage. It stores what returns in aIGameCommandcalledcommand.
- Checks if commandisn't null, meaning your app received a valid command.
- Then creates a new ChatCommand, passing in the required variables.
- Calls ProcessCommandsto execute the stored commands.
In ProcessCommands, the code:
- Gets the oldest command in newCommandsand callsExecute, then removes that command from the list.
That's all you need to read and execute incoming commands! Time to test all this code!