Protect the Kitten Mini‑Game: Source Code Overview and Agora Voice Chat Integration
This article presents the complete Unity source code of the "Protect the Kitten" 2D mini‑game, explains its project structure and core scripts, and demonstrates how to integrate Agora's audio SDK to add simple voice‑chat functionality, with download links for the full project.
The article introduces a Unity 2D mini‑game called "Protect the Kitten", showing a short gameplay video and describing the core mechanic where the player moves a block with the mouse to shield a kitten from obstacles.
It then outlines the project's directory structure, listing folders such as _Prefabs , _Scenes , _Scripts , _Sprites , Animations , Common , Music_Sound , Plugins , and Resources , and explains the role of each folder in the game.
The core gameplay logic is handled by two controller scripts: MainController and HomeController . MainController manages background loading, obstacle spawning, level progression, and UI updates, while HomeController contains only simple UI handling.
Key portions of MainController are shown below:
public class MainController : BaseController {
public Transform backRegion, spawnRegion;
public BackItem backPrefab;
public List
obstaclePrefabs;
private int colorIndex = 0, backCount = 0;
private BackItem lastBack = null;
public enum GameState {START, LOADED, PLAYING, GAME_OVER, COMPLETED, GUIDE, SHOP, PAUSED};
public static GameState gameState = GameState.START, lastState = GameState.START;
// ... (other fields omitted for brevity)
protected override void Awake() {
base.Awake();
instance = this;
}
protected override void Start() {
base.Start();
SetupBackground();
LoadAllObstacles();
}
private void LoadAllObstacles() {
obstaclePrefabs = Resources.LoadAll
("GroupObstacles").ToList();
obstaclePrefabs.Sort((x, y) => Utils.GetGroupObIndex(x.name).CompareTo(Utils.GetGroupObIndex(y.name)));
}
private void SetupBackground() {
lastBack = SpawnNewBackground(Vector3.zero);
lastBack.SetUp(0, 5, true, true, 0);
backs.Add(lastBack);
// ... (background setup logic)
}
// ... (additional game logic omitted)
}The MyPlayer script is attached to the kitten object and handles sprite switching, collision detection, and visual effects when the kitten hits an obstacle.
public class MyPlayer : MonoBehaviour {
public SpriteRenderer icon;
public Sprite[] iconSprites;
public GameObject playerIconPrefab;
public GameObject bubble;
public GameObject[] bubbleParts;
void Start() { UpdateSprite(); }
public void UpdateSprite() {
int selectedType = CUtils.GetPlayerType();
icon.sprite = iconSprites[selectedType];
}
void OnCollisionEnter2D(Collision2D collision) {
if (collision.collider.tag == "Obstacle" && MainController.IsPlaying()) {
MainController.instance.CollideWithObstacle();
MainController.instance.CheckAndShowContinue();
icon.gameObject.SetActive(false);
GetComponent
().isTrigger = true;
bubble.SetActive(false);
foreach (GameObject p in bubbleParts) { p.SetActive(true); }
GetComponent
().SetTrigger("Break");
// ... (audio and visual effects)
}
}
// ... (reset and icon spawning omitted)
}To add voice chat, the article demonstrates importing Agora's Unity audio SDK and provides a complete script that initializes the SDK, handles permission requests, joins/leaves channels, and processes callbacks such as user join, leave, volume indication, and errors.
using UnityEngine;
using UnityEngine.UI;
#if (UNITY_2018_3_OR_NEWER)
using UnityEngine.Android;
#endif
using agora_gaming_rtc;
public class HelloUnity3D : MonoBehaviour {
private InputField mChannelNameInputField;
public Text mShownMessage;
public Button joinChannel;
public Button leaveChannel;
private IRtcEngine mRtcEngine = null;
[SerializeField]
private string AppID = "app_id";
void Awake() {
QualitySettings.vSyncCount = 0;
Application.targetFrameRate = 30;
CheckAppId();
}
void Start() {
#if (UNITY_2018_3_OR_NEWER)
if (!Permission.HasUserAuthorizedPermission(Permission.Microphone)) {
Permission.RequestUserPermission(Permission.Microphone);
}
#endif
joinChannel.onClick.AddListener(JoinChannel);
leaveChannel.onClick.AddListener(LeaveChannel);
mRtcEngine = IRtcEngine.GetEngine(AppID);
mRtcEngine.OnJoinChannelSuccess += (channelName, uid, elapsed) => {
string msg = string.Format("Joined channel uid:{0}, channel:{1}, version:{2}", uid, channelName, getSdkVersion());
Debug.Log(msg);
mShownMessage.text = msg;
};
// ... (other callbacks omitted for brevity)
mRtcEngine.SetChannelProfile(CHANNEL_PROFILE.CHANNEL_PROFILE_COMMUNICATION);
}
private void CheckAppId() {
Debug.Assert(AppID.Length > 10, "Please set your Agora AppId.");
}
public void JoinChannel() {
string channelName = "adc666"; // example channel
if (string.IsNullOrEmpty(channelName)) return;
mRtcEngine.JoinChannelByKey(null, channelName, "extra", 0);
}
public void LeaveChannel() {
mRtcEngine.LeaveChannel();
}
void OnApplicationQuit() {
if (mRtcEngine != null) IRtcEngine.Destroy();
}
public string getSdkVersion() { return IRtcEngine.GetSdkVersion(); }
// ... (mute handling omitted)
}The article provides a download link for the full project (https://download.csdn.net/download/zhangay1998/42304114) and notes that readers can obtain additional game source packages by following the public account instructions.
In summary, the piece shares the complete source of a simple Unity puzzle game, explains its architecture and key scripts, and shows a basic integration of Agora's voice SDK to enable multiplayer voice chat, offering a practical example for developers interested in Unity game development and real‑time communication.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.