Limiting area of chat and audio of the levels on same scene

Hi people,
I used very basic networking from M2H that one of networked computers is server and the other is client. When they collide with some game object I wanted make the one collided to move to next level (which is different scene file) while the other which didn’t touch the collider still staying at the scene where the game started.
Here is my original post for enquiring about this problem:
http://forum.unity3d.com/viewtopic.php?t=53911&highlight=scene

But Having read the post here, http://forum.unity3d.com/viewtopic.php?p=328244#328244, it says that:

So I have decided I’ve rather just make multiple levels on the same scene and move them using transform.position, but there is massive problem.

Chat system and Audio.

Since all the levels are in the same scene, chat entered from different level can still be seen by users on the other level.

Also, the audio that is played on one level still can be heard from other level.

So what I want is:

  1. Only users on the same level can see the chat they entered to each other.
  2. Users on the different level CANNOT see the chat entered from users on the other level.
  3. Audio played on the specific level cannot be heard from other level.

Can anyone achieve this?

You should store the info on which level the player is in and use that to determine which messages should be displayed and which audio should be played.

A really simple example for the chat:

var currentLevel:int;
var message:String;
var text:String;

function OnGUI(){
    GUILayout.BeginVertical();
    GUILayout.Label(message);
    text = GUILayout.TextField(text, 160);
    if(GUILayout.Button("Send")){
        if(Network.isServer){
            SendMessage(text, currentLevel);
        }else{
            networkView.RPC("SendMessage", RPCMode.Server, text, currentLevel);
        }
    }
    GUILayout.EndVertical();
}

@RPC
function SetMessage(newMessage:String, level:int){
    if(currentLevel == level){
        message = newMessage;
    }
}

@RPC
function SendMessage(message:String, level:int){
    networkView.RPC("SetMessage", RPCMode.Others, message, level);
    SetMessage(message, level);
}

@RPC
function SetLevel(level:int){
    currentLevel = level;
}

The SetLevel function should be called remotely only for the player who is changing level. I can’t guarantee this script works because I can’t test it right now, but it should give you some ideas.

um… I don’t quite understand. could you please explain the code you posted?

And just in case, this is my chat window code:

#pragma strict 

public var shadowDist : int = 1; 
public var activeChatLines : int = 10; 
public var chatfont : Font; 

//Global variable
public var inGameChatActive : boolean;// = false;
public var chatLineTimeout = 5.00;

var DelayTime: double;

// chat 
private var maxChatTextLen : int = 96; 
private var chatText : String = ""; 

private var chatEntries : Array = Array(); 
private var chatEntryTimeouts : Array = Array();

private var bottomLeftBox : Rect; //Rect (10, Screen.height-60, 400, 20); 
private var shadowChatBox : Rect;
private var activeChatBox : Rect;

private var activeChatString : String = ""; 
private var player: NetworkPlayer;
//private var lineHeight : int = 13; 

private var gs : GUIStyle; 

function Start() 
{ 
   gs = new GUIStyle(); 
   gs.font = chatfont; 
   
   	bottomLeftBox = Rect (10, Screen.height - 30, 500, 20); //Rect (10, Screen.height-60, 400, 20); 
	shadowChatBox = bottomLeftBox; 
	activeChatBox  = bottomLeftBox; 
   
 } 

function Update() 
{ 
   //Debug.Log("ChatEntryTimeouts Length: " + chatEntryTimeouts.length);
      
	  //Testing Time interval between consecutive chat entry
	  
if(chatEntryTimeouts.length == 1)	    
{
	Debug.Log("Chat Length timeout 0" + " :" + chatEntryTimeouts[0] + " Time.time: " +Time.time);
}else if(chatEntryTimeouts.length == 2)	    {
	Debug.Log("Chat Length timeout 0" + " :" + chatEntryTimeouts[0] + " Chat Length timeout 1" + " :" + chatEntryTimeouts[1] + " Time.time: " +Time.time);
} else if(chatEntryTimeouts.length == 3)	    {
	Debug.Log("Chat Length timeout 0" + " :" + chatEntryTimeouts[0] + " Chat Length timeout 1" + " :" + chatEntryTimeouts[1] +  " Chat Length timeout 2" + " :" + chatEntryTimeouts[2] + " Time.time: " +Time.time);
}
		
   if(Input.GetKeyDown (KeyCode.Return)) 
   { 
      if(/*Global.*/inGameChatActive  chatText!="") 
      { 
         // commands start with "/" like "/name Ethan" 
         if(chatText.StartsWith("/")) 
         {    
            var spaceIndex : int = chatText.IndexOf(" ", 0, chatText.length); 
            var commandName : String = ""; 
            var commandValue : String = ""; 
             
            if(spaceIndex==-1) 
            {       
               commandName = chatText.Substring(1, chatText.length-1); 
            } 
            else 
            {    
               commandName = chatText.Substring(1, spaceIndex-1); 
               commandValue = chatText.Substring(spaceIndex+1, chatText.length - (spaceIndex+1));       
            } 
             
            //Debug.Log("- -" + commandName + "- -" + commandValue + "- -"); 
            ParseChatCommand(commandName, commandValue); 
             
         } 
         else 
         { 
            // send text and close chat if it isnt a command 
            chatText = player.externalIP + ": " + player.externalPort + " says:  " + chatText; // Global.playerName 
            AddChatEntry(chatText); 
            networkView.RPC("AddChatEntry", RPCMode.Others, chatText); 
         }    
         chatText = ""; 
      } 
       
      // switch it 
      /*Global.*/inGameChatActive = /*!Global.*/!inGameChatActive; 
   } 
    
   // did oldest chat element ran out of lifetime? 
   if(chatEntryTimeouts.length > 0  Time.time > System.Convert.ToDouble(chatEntryTimeouts[0])) 
   { 
       Debug.Log("Entry Deleted");
	  chatEntries.RemoveAt(0); 
      chatEntryTimeouts.RemoveAt(0); 
      RebuildChatString(); 
   } 
} 

function OnGUI() 
{ 
   gs.normal.textColor = Color(0.0, 0.0, 0.0); 
   GUI.Label(shadowChatBox, activeChatString, gs); 

   gs.normal.textColor = Color(1.0, 1.0, 0.0); 
   GUI.Label(activeChatBox, activeChatString, gs); 
    
   if(/*Global.*/inGameChatActive) 
   { 
      GUI.FocusControl("chatInput"); 
       
      GUI.SetNextControlName("chatInput"); 
      chatText = GUI.TextField(bottomLeftBox, chatText, maxChatTextLen);
   } 
} 

@RPC // clients + server 
public function AddChatEntry(str : String) 
{ 
	//audio.Play(); 
	
   chatEntries.Add(str); 
   
   chatEntryTimeouts.Add(Time.time + System.Convert.ToDouble(/*Global.*/chatLineTimeout)); 
   

   if(chatEntries.length > activeChatLines) //if chat entry entered is more than active chat lines (10 for now), delete latest entry.
   { 
       chatEntries.RemoveAt(0); 
      chatEntryTimeouts.RemoveAt(0); 
   } 
       
   RebuildChatString(); 
} 

function RebuildChatString() 
{       
   var i : int = 0; 
    
   activeChatString = ""; 

       
   // WRITE ACTIVE CHAT LABEL TEXT 
   activeChatBox.height = (chatEntries.length+1) * gs.lineHeight; 
   activeChatBox.y = bottomLeftBox.y - activeChatBox.height; 
    
   shadowChatBox = activeChatBox; 
   shadowChatBox.y += shadowDist; 
   shadowChatBox.x += shadowDist; 
    
   for(i = 0; i<chatEntries.length; ++i) 
   { 
      activeChatString += chatEntries[i] + "\n"; 
   } 
} 

function ParseChatCommand(commandName : String, commandValue : String) 
{    
   switch(commandName) 
   {       
      case "name": 
       
         // TODO do sth with command /name 
          
         break; 
          
      default: 
       
         // TODO 
          
         break; 
   } 
}

You need to keep track of which level the player is on. Add a variable to your chat script for it, it can be anything really, a string with the level name, an int with the level number or something like that. When the player moves to another level update the variable accordingly. You also could give the variable to your player script and just read it from there. When you send a message you need to pass that variable on as a parameter along with the actual message. Then on the receiving end check if the received level identifier is the same as the one on the receiver and display the message only if it is.

You can do this with the following changes to your script:

To the beginning of the script add the variable for keeping track of which level the player is on(I’m using a string here, use an int if you want to):

var currentLevel:String;

In the Update function change the following lines:

AddChatEntry(chatText);
networkView.RPC("AddChatEntry", RPCMode.Others, chatText);

To:

AddChatEntry(chatText, currentLevel);
networkView.RPC("AddChatEntry", RPCMode.Others, chatText, currentLevel);

And change the AddChatEntry function to:

@RPC // clients + server
public function AddChatEntry(str : String, level : String)
{
   if(level == currentLevel){
      //audio.Play();
   
      chatEntries.Add(str);
   
      chatEntryTimeouts.Add(Time.time + System.Convert.ToDouble(/*Global.*/chatLineTimeout));
   

      if(chatEntries.length > activeChatLines) //if chat entry entered is more than active chat lines (10 for now), delete latest entry.
      {
         chatEntries.RemoveAt(0);
         chatEntryTimeouts.RemoveAt(0);
      }
       
      RebuildChatString();
   }
}

Again I can’t test the changes myself because I’m at work (yeah I’m being really productive).

Thanks for a quick response for such a long question!

Now i’m kinda getting idea but once I implemented the script above i get:

Maybe it’s because RPC thing itself can’t get more than one parameter? I tried making array containing these two strings and let AddChatEntry to accept array as parameter, but there was no use :frowning:

RPCs can have as many parameters as you want. Are you sure you changed the function declaration for AddChatEntry to include the level parameter?

Oh! sorry boys, I actually made new script to apply the code written above and added to the object. Although I unchecked the old script, it was still functioning somehow.

Although Limit Area of chatting range is stil not successful.

Currently I have set this script onto the plane of level… (where my characters stand on)

var ChatArea: ChatWindow;
function OnMouseDown()
{
	GameObject.Find("EnterPad").collider.isTrigger = false;
}

function OnCollisionEnter()
{
	ChatArea.currentLevel = "Lobby";
}

and Different String when colliding with plane on other level.

But this doesn’t work because It changes currentLevel value of client too! so even if I move to different level, server and client users can still talk to each other. :frowning: