Unity combines the sound network audio SDK to make a small game of [hitting the ground cat], and you can chat with your friends and roll the cat~

catalogue

preface

  • I just got in touch with the voice call SDK of the voice network two days ago. I think it's very interesting
  • Let's bring you a little game of "hitting the ground cat" today
  • Incidentally, access the sound network SDK to realize the function of a world chat channel!

[ground cat] games

This little game is actually very simple. It's still very interesting to get it done with three scripts!

Let's take a look at the renderings:

Let's talk about the production steps of this little game!

first ️⃣ Step 1: build scene and model configuration

This step is very simple. First, build a scene casually

Because it's a ground cat, we add some pits to let the kitten jump out and let us fight!

Then add a hammer on it and hit it when we click the mouse!

Then hide the kitten under the pit. Later, write a script to let him jump out and let us play

second ️⃣ Step: write a script to let the cat jump out automatically

The code is very simple. First declare several states of the cat, such as: below, above, beaten, etc

Then we write a judgment condition to let the cat do different things in different states!

The core code is as follows:

	enum State{
		UNDER_GROUND,
		UP,
		ON_GROUND,
		DOWN,
		HIT,
	}
	State state;

void Update () 
	{

		if (this.state == State.UP) 
		{
			transform.Translate (0, this.moveSpeed, 0);

			if (transform.position.y > TOP) 
			{
				transform.position = 
					new Vector3 (transform.position.x, TOP, transform.position.z);

				this.state = State.ON_GROUND;

				this.tmpTime = 0;
			}
		} 
		else if (this.state == State.ON_GROUND)
		{
			this.tmpTime += Time.deltaTime;

			if (this.tmpTime > this.waitTime) 
			{
				this.state = State.DOWN;
			}
		}
		else if (this.state == State.DOWN) 
		{
			transform.Translate (0, -this.moveSpeed, 0);

			if (transform.position.y < BOTTOM) 
			{
				transform.position = 
					new Vector3(transform.position.x, BOTTOM, transform.position.z);

				this.state = State.UNDER_GROUND;
			}
		}
	}

In this way, our kittens can display different effects according to different states!

third ️⃣ Step: click the code to hit

Because the effect we do is to hit the hammer wherever the mouse points So here's a script for the hammer to follow the coordinates of the mouse when he clicks!

The core code is as follows:

void Update () 
	{
		if(Input.GetMouseButtonDown(0))
		{
			Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
			RaycastHit hit;

			if (Physics.Raycast(ray, out hit, 100)) 
			{
				GameObject mole = hit.collider.gameObject;
					
				bool isHit = mole.GetComponent<MoleController> ().Hit ();

				// if hit the mole, show hummer and effect
				if (isHit) 
				{
					StartCoroutine (Hit (mole.transform.position));

					ScoreManager.score += 10;
				}
			}
		}
	}

fourth ️⃣ Step, add a script that randomly lets the kitten jump out

In the first step, we wrote that kittens will do different things according to different states

You also need to write a script to control the kitten's random jump out, so as to increase the playability of the game!

The core code is as follows:

IEnumerator Generate()
	{
		this.generate = true;

		while (this.generate) 
		{
			// wait to generate next group
			yield return new WaitForSeconds (1.0f);

			int n = moles.Count;
			int maxNum = (int)this.maxMoles.Evaluate ( GameManager.time );

			for (int i = 0; i < maxNum; i++) 
			{
				// select mole to up
				this.moles [Random.Range (0, n)].Up ();
								
				yield return new WaitForSeconds (0.3f);
			}
		}
	}

So our little game is finished! However, the SDK of the sound network has not been added to realize the function of a world chat channel

So keep looking down!

fifth ️⃣ Step: go to the voice network to download the SDK for audio calls, and create a project to obtain the APP ID

The address of the sound network is below. If you don't know, you can get to know it briefly~

Sound network official website: https://www.agora.io/cn/community/

First, you need to register after you go in. It's very simple~

Then find the place to download the SDK: https://docs.agora.io/cn/All/downloads?platform=Unity

The sound network supports many platforms. Anyway, all the platforms I know cooperate with the sound network. I have to say that the sound network is still very powerful!

Then we find Unity's audio SDK to download

Drop in when downloading the SDK Console Create a project

Since we are used for testing, just select the debugging mode directly. You can refer to the official website document to see the difference between the two: https://docs.agora.io/cn/Agora%20Platform/token?platform=All%20Platforms

After successful creation, click the APP ID button to copy it, which will be used in the following code!

sixth ️⃣ Step: connect the sound network audio SDK to the project

In the previous step, we have completed the audio SDK, and there is also an example project

We can learn when it is convenient for us to access!

Here, we can directly put the downloaded SDK into our project

Then we create a new script to manage the world chat channel!

The core code is as follows:

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;//Channel number
    public Text mShownMessage;//Tips
    private Text versionText;//Version number
    public Button joinChannel;//Join the room
    public Button leaveChannel;//Leave the room
    private Button muteButton;//Mute

    private IRtcEngine mRtcEngine = null;

    // After entering the App ID, delete it outside the App ID##
    [SerializeField]
    private string AppID = "app_id";

    void Awake()
    {
        QualitySettings.vSyncCount = 0;
        Application.targetFrameRate = 30;
        //muteButton.enabled = false;
        CheckAppId();
    }

    // Initialize
    void Start()
    {
#if (UNITY_2018_3_OR_NEWER)
        // Judge whether there is microphone permission. If there is no permission, take the initiative to apply for permission
			if (!Permission.HasUserAuthorizedPermission(Permission.Microphone))
			{
            Permission.RequestUserPermission(Permission.Microphone);
            } 

#endif
        joinChannel.onClick.AddListener(JoinChannel);
        leaveChannel.onClick.AddListener(LeaveChannel);
        //muteButton.onClick.AddListener(MuteButtonTapped);

        mRtcEngine = IRtcEngine.GetEngine(AppID);
        //versionText.GetComponent().text = "Version : " + getSdkVersion();

        //Callback after adding channel successfully
        mRtcEngine.OnJoinChannelSuccess += (string channelName, uint uid, int elapsed) =>
        {
            string joinSuccessMessage = string.Format("Add channel callback uid: {0}, channel: {1}, version: {2}", uid, channelName, getSdkVersion());
            Debug.Log(joinSuccessMessage);
            mShownMessage.GetComponent<Text>().text = (joinSuccessMessage);
            //muteButton.enabled = true;
        };

        //Leave channel callback. 
        mRtcEngine.OnLeaveChannel += (RtcStats stats) =>
        {
            string leaveChannelMessage = string.Format("Leave channel callback time {0}, tx: {1}, rx: {2}, tx kbps: {3}, rx kbps: {4}", stats.duration, stats.txBytes, stats.rxBytes, stats.txKBitRate, stats.rxKBitRate);
            Debug.Log(leaveChannelMessage);
            mShownMessage.GetComponent<Text>().text = (leaveChannelMessage);
            //muteButton.enabled = false;
            // Reset mute key status
            //if (isMuted)
           // {
          //      MuteButtonTapped();
            //}
        };

        //The remote user joins the callback of the current channel. 
        mRtcEngine.OnUserJoined += (uint uid, int elapsed) =>
        {
            string userJoinedMessage = string.Format("Remote user joins current channel callback uid {0} {1}", uid, elapsed);
            Debug.Log(userJoinedMessage);
            mShownMessage.GetComponent<Text>().text = (userJoinedMessage);
        };

        //The remote user leaves the current channel for callback. 
        mRtcEngine.OnUserOffline += (uint uid, USER_OFFLINE_REASON reason) =>
        {
            string userOfflineMessage = string.Format("Remote user leaving current channel callback uid {0} {1}", uid, reason);
            Debug.Log(userOfflineMessage);
            mShownMessage.GetComponent<Text>().text = (userOfflineMessage);
        };

        // 	User volume prompt callback. 
        mRtcEngine.OnVolumeIndication += (AudioVolumeInfo[] speakers, int speakerNumber, int totalVolume) =>
        {
            if (speakerNumber == 0 || speakers == null)
            {
                Debug.Log(string.Format("Local user volume prompt callback   {0}", totalVolume));
            }

            for (int idx = 0; idx < speakerNumber; idx++)
            {
                string volumeIndicationMessage = string.Format("{0} onVolumeIndication {1} {2}", speakerNumber, speakers[idx].uid, speakers[idx].volume);
                Debug.Log(volumeIndicationMessage);
            }
        };

        //User mute prompt callback
        mRtcEngine.OnUserMutedAudio += (uint uid, bool muted) =>
        {
            string userMutedMessage = string.Format("User mute prompt callback uid {0} {1}", uid, muted);
            Debug.Log(userMutedMessage);
            mShownMessage.GetComponent<Text>().text = (userMutedMessage);
        };

        //Warning callback occurred
        mRtcEngine.OnWarning += (int warn, string msg) =>
        {
            string description = IRtcEngine.GetErrorDescription(warn);
            string warningMessage = string.Format("Warning callback occurred {0} {1} {2}", warn, msg, description);
            Debug.Log(warningMessage);
        };

        //Error callback occurred
        mRtcEngine.OnError += (int error, string msg) =>
        {
            string description = IRtcEngine.GetErrorDescription(error);
            string errorMessage = string.Format("Error callback occurred {0} {1} {2}", error, msg, description);
            Debug.Log(errorMessage);
        };

        // The current call statistics callback is triggered every two seconds.
        mRtcEngine.OnRtcStats += (RtcStats stats) =>
        {
            string rtcStatsMessage = string.Format("onRtcStats callback duration {0}, tx: {1}, rx: {2}, tx kbps: {3}, rx kbps: {4}, tx(a) kbps: {5}, rx(a) kbps: {6} users {7}",
                stats.duration, stats.txBytes, stats.rxBytes, stats.txKBitRate, stats.rxKBitRate, stats.txAudioKBitRate, stats.rxAudioKBitRate, stats.userCount);
            //Debug.Log(rtcStatsMessage);

            int lengthOfMixingFile = mRtcEngine.GetAudioMixingDuration();
            int currentTs = mRtcEngine.GetAudioMixingCurrentPosition();

            string mixingMessage = string.Format("Mixing File Meta {0}, {1}", lengthOfMixingFile, currentTs);
            //Debug.Log(mixingMessage);
        };

        //Voice route has changed callback. (effective only on mobile platforms)
        mRtcEngine.OnAudioRouteChanged += (AUDIO_ROUTE route) =>
        {
            string routeMessage = string.Format("onAudioRouteChanged {0}", route);
            Debug.Log(routeMessage);
        };

        //Token expiration callback
        mRtcEngine.OnRequestToken += () =>
        {
            string requestKeyMessage = string.Format("OnRequestToken");
            Debug.Log(requestKeyMessage);
        };

        // Network interrupt callback (triggered only after successful establishment)
        mRtcEngine.OnConnectionInterrupted += () =>
        {
            string interruptedMessage = string.Format("OnConnectionInterrupted");
            Debug.Log(interruptedMessage);
        };

        // Network connection loss callback
        mRtcEngine.OnConnectionLost += () =>
        {
            string lostMessage = string.Format("OnConnectionLost");
            Debug.Log(lostMessage);
        };

        // Set Log level
        mRtcEngine.SetLogFilter(LOG_FILTER.INFO);

        // 1. Set it to free speech mode, which is often used for one-to-one or group chat
        mRtcEngine.SetChannelProfile(CHANNEL_PROFILE.CHANNEL_PROFILE_COMMUNICATION);

        //2. Set to live mode, which is suitable for chat rooms or interactive video streaming.
        //mRtcEngine.SetChannelProfile (CHANNEL_PROFILE.CHANNEL_PROFILE_LIVE_BROADCASTING);

        //3. Set to game mode. This profile uses a lower bit rate codec and consumes less power. It is applicable to game scenes where all game players can talk freely.
        //mRtcEngine.SetChannelProfile(CHANNEL_PROFILE.CHANNEL_PROFILE_GAME);

        //Set user roles in the live broadcast scenario. 
        //mRtcEngine.SetClientRole (CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
    }

    private void CheckAppId()
    {
        Debug.Assert(AppID.Length > 10, "First, please Game Controller Fill in your name on the object AppId. .");
        GameObject go = GameObject.Find("AppIDText");
        if (go != null)
        {
            Text appIDText = go.GetComponent<Text>();
            if (appIDText != null)
            {
                if (string.IsNullOrEmpty(AppID))
                {
                    appIDText.text = "AppID: " + "UNDEFINED!";
                    appIDText.color = Color.red;
                }
                else
                {
                    appIDText.text = "AppID: " + AppID.Substring(0, 4) + "********" + AppID.Substring(AppID.Length - 4, 4);
                }
            }
        }
    }

    /// 
    ///Join channel
    /// 
    public void JoinChannel()
    {
        // Obtain the channel name from the input box of the interface
        string channelName = "adc666";

        // Obtain the channel name from the input box of the interface
        //string channelNameOld = mChannelNameInputField.text.Trim();

        Debug.Log(string.Format("Obtain the channel name from the input box of the interface {0}", channelName));

        if (string.IsNullOrEmpty(channelName))
        {
            return;
        }
        // Join channel
        // channelKey: dynamic secret key. We didn't select the Token mode at first, so null can be passed in here; Otherwise, the Token generated by the server needs to be passed in
        // channelName: channel name
        // info: the developer's attached information (not necessary) will not be transmitted to other users in the channel
        // uid: user ID, 0 is automatically assigned
        mRtcEngine.JoinChannelByKey(channelKey: null, channelName: channelName, info: "extra", uid: 0);

        //Join channels and set publish and subscribe status. 
        //mRtcEngine.JoinChannel(channelName, "extra", 0);
    }

    /// 
    ///Leave channel
    /// 
    public void LeaveChannel()
    {
        // Leave channel
        mRtcEngine.LeaveChannel();

        string channelName = "abc666";
        Debug.Log(string.Format("left channel name {0}", channelName));
    }

    void OnApplicationQuit()
    {
        if (mRtcEngine != null)
        {
            // Destroy IRtcEngine
            IRtcEngine.Destroy();
        }
    }

    /// 
    ///Query SDK version number. 
    /// 
    /// 
    public string getSdkVersion()
    {
        string ver = IRtcEngine.GetSdkVersion();
        return ver;
    }


    bool isMuted = false;
    void MuteButtonTapped()
    {
        //Set mute or unmute
        string labeltext = isMuted ? "Mute" : "Unmute";
        Text label = muteButton.GetComponentInChildren<Text>();

        if (label != null)
        {
            label.text = labeltext;
        }
        isMuted = !isMuted;
        // Set mute (stop pushing local audio)
        mRtcEngine.EnableLocalAudio(!isMuted);
        Debug.Log("Mute method execution completed");
    }
}

Here I have set the default channel, which means that everyone enters one channel to chat when they click

But this is not good! It's convenient here. That's it~

Here we are done. We have realized the function of adding the world chat channel to this little game of hitting the ground cat!

Although the function may not be perfect, you'll be familiar with it after using it a few more times. Hey, hey!

summary

  • In this paper, I made a simple ground cat game and accessed the audio SDK of the sound network
  • There are still many areas that need to be improved for the small projects that they have worked overtime
  • This article briefly introduces it, which is still very interesting ha ha! I'll see you next time!

Posted by daxxy on Tue, 16 Nov 2021 20:02:34 -0800