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?
Game Over and New Game Conditions
The game isn't quite ready to play yet. You still need to add some game logic, like what should happen when the battle is over?
Battle needs its own logic for when you consider a game to be over, as well as instructions for what to do when that happens.
It also needs instructions on how to start a new game, such as resetting the health of both creatures. You'll start by validating the game is actually over.
Game Over Check
Before executing a Game Over Action, you need a script that checks if the game has reached game over conditions. For GameManager to check these conditions no matter what game it's managing, you need to create an interface, so GameManager always knows what to expect.
In RW/Scripts/Common, create a new script called IGameOverCheck. Open it and replace the default code with:
public interface IGameOverCheck
{
bool IsGameOver(GameManager gm);
}
This interface defines one method that takes a GameManager
as an argument and returns a boolean.
Any script implementing this interface must have an IsGameOver
that returns true if the game over conditions are met. Even though it's small, interfaces like this can be a handy way of defining a type for a class without forcing it to inherit from a parent class.
Now all GameManager has to do is look for an IGameOverCheck
and call IsGameOver
to know whether or not to end the game. This also means any script using IGameOverCheck
can be as simple or as complex as needed.
Time to create a Game Over Check specific to Battle. Create a script in RW/Scripts/Battle called BattleGameOverCheck and open it.
BattleGameOverCheck uses the interface you created and defines the Battle scene's game over conditions.
The battle should end when one of the...Backpack...Demons...Badmons...
The battle should end when one of the Legally Distinct Pokémon-like Battle Creatures reaches 0 HP. :]
In BattleGameOverCheck, implement IGameOverCheck
as below:
using UnityEngine.UI;
public class BattleGameOverCheck : MonoBehaviour, IGameOverCheck
{
public Slider playerHealth;
public Slider opponentHealth;
public bool IsGameOver(GameManager gm)
{
if (playerHealth.value <= 0 || opponentHealth.value <= 0)
{
return true;
}
return false;
}
}
This Game Over Check looks at two different Sliders, representing the player's and opponent's health. In IsGameOver
, it returns true if either slider's value is less than or equal to 0. Otherwise, it returns false.
Game Over Action
Just like IGameOverCheck
, you need a common definition of what the GameManager should do if a game is over.
In RW/Scripts/Common, create a script called IGameOverAction.
public interface IGameOverAction
{
void Execute(GameManager gm);
}
Execute
, that takes a GameManager
.
Back in RW/Scripts/Battle, create a script called BattleGameOverAction:
public class BattleGameOverAction : MonoBehaviour, IGameOverAction
{
public GameObject gameOverPanel;
public void Execute(GameManager gm)
{
gameOverPanel.SetActive(true);
}
}
BattleGameOverAction implements IGameOverAction
and has a public reference to the GameOverPanel UI element. Execute
in BattleGameOverAction
activates the GameOverPanel.
While GameManager now knows how to end a game, you need to tell it how to start over.
New Game Action
Like the Game Over Action, you need to define what GameManager needs to prepare the scene for a new game.
In RW/Scripts/Common, create a script called INewGameAction, which is pretty much identical to IGameOverAction
:
public interface INewGameAction
{
void Execute(GameManager gm);
}
When a new Battle game starts, both health bars should reset and the game over panel should hide.
Now, in RW/Scripts/Battle, create a script called BattleNewGameAction.
BattleNewGameAction
implements INewGameAction
, as shown below:
using UnityEngine.UI;
public class BattleNewGameAction : MonoBehaviour, INewGameAction
{
public Slider playerHealth;
public Slider opponentHealth;
public GameObject gameOverPanel;
public void Execute(GameManager gm)
{
playerHealth.value = 100;
opponentHealth.value = 100;
gameOverPanel.SetActive(false);
}
}
It has public variables for both health sliders and the game over panel. In Execute
, set the both health bar values to 100 and deactivate the game over panel.
Back in the editor, add BattleGameOverCheck, BattleGameOverAction and BattleNewGameAction to the Managers/GameManager object and set their fields to the appropriate GameObjects:
In Battle Game Over Action set Game Over Panel to UI/BattleCanvas/GameOverPanel.
Then, in Battle Game Over Check set:
- Player Health to UI/BattleCanvas/Player/PlayerHealth.
- Opponent Health to UI/BattleCanvas/Opponent/OpponentHealth.
In Battle New Game Action set:
- Player Health to UI/BattleCanvas/Player/PlayerHealth.
- Opponent Health to UI/BattleCanvas/Opponent/OpponentHealth.
Finally, in Battle New Game Action set Game Over Panel to UI/BattleCanvas/GameOverPanel.
Revisiting the GameManager
Currently, GameManager is configured to handle incoming commands and run corresponding actions. But you need to expand it to use the last three interfaces you created.
Open RW/Scripts/Common/GameManager.cs. Add these private fields above Start
:
private IGameOverCheck gameOverCheck;
private IGameOverAction gameOverAction;
private INewGameAction newGameAction;
In Start
, use GetComponent
to assign these variables to scripts attached to this GameObject, as shown below:
gameOverCheck = GetComponent<IGameOverCheck>();
gameOverAction = GetComponent<IGameOverAction>();
newGameAction = GetComponent<INewGameAction>();
Then, in ResetGame
, call newGameAction.Execute
before setting the game state, passing this
as a reference to the GameManager
:
public void ResetGame()
{
if (gameState != GameState.Playing)
{
newGameAction.Execute(this); // 1
SetGameState(GameState.Playing);
}
}
In EndGame
, call gameOverAction.Execute
before setting the game state. Pass the keyword this
as a reference to the GameManager
:
public void EndGame()
{
if (gameState != GameState.GameOver)
{
gameOverAction.Execute(this);
SetGameState(GameState.GameOver);
}
}
Update FixedUpdate as shown below:
void FixedUpdate()
{
if (gameState == GameState.Playing)
{
if (gameOverCheck == null || !gameOverCheck.IsGameOver(this))
{
ChatMessage recentMessage = chat != null ? chat.ReadChat() : null;
IGameCommand command = recentMessage != null ?
CommandIsValid(recentMessage) : null;
if (command != null)
{
ChatCommand newCommand = new ChatCommand(recentMessage, command);
newCommands.Add(newCommand);
}
ProcessCommands();
}
else if (gameOverCheck.IsGameOver(this))
{
EndGame();
}
}
}
FixedUpdate
now checks if gameOverCheck
is null, or if gameOverCheck.IsGameOver
returns false. This prevents new commands from storing and processing if the game is currently over.
Now, it also includes a check if gameOverCheck.IsGameOver
returns true. If so, it calls EndGame
.
Go back into Unity. To trigger BattleNewGameAction, you need to link GameManager.ResetGame to UI/BattleCanvas/GameOverPanel/NewGameButton.
Select NewGameButton and find the On Click trigger list on the Button component. Add a new trigger. Drag GameManager into the empty object slot and select GameManager.ResetGame in the dropdown list.
That's it! Give it a try with some friends!