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!