Author Topic: Setting up and spawning a player  (Read 15043 times)

Braveheart

  • Guest
Setting up and spawning a player
« on: April 28, 2013, 07:32:25 PM »
All

I've set up a FPS controller as my player prefeb, I've added one of the following pieces of code to the scripts that are C# (I assume the Javascript scripts require something like the following also, but I can't figure out what that would be):

  1.         if(!TNManager.isThisMyObject) {
  2.                         enabled = false;       
  3.                 }

  1.         if(TNManager.isThisMyObject) {
  2.                         instance = this;       
  3.                 }

I've also set up an empty game object as my spawn point and attached to that a simple spawn script that calls:

  1. TNManager.Create(player, spawnpoint.position, spawnpoint.rotation);

To spawn players at the defined spawn point. (The player prefab has a TN Auto Sync attached to it. Where might I find information on using RFC instead like was mentioned in a TNet video?) However, there's two issues:

1. When more than one player is in the game, each player controls everyone else; and
2. When a player disconnects, their avatar remains in-game.

Could someone point me in the right direction here please?

Cheers

Braveheart

  • Guest
Re: Setting up and spawning a player
« Reply #1 on: April 29, 2013, 12:38:54 PM »
Okay, so I've been trying to write my own character controllers because I can't figure this out.  It's driving me nuts.  What I'm now doing is this:

Spawn Player code which is attached to an empty game object spawn point:

  1. using UnityEngine;
  2. using System.Collections;
  3. using TNet;
  4.  
  5. public class SpawnPlayer : MonoBehaviour {
  6.        
  7.         public GameObject player;
  8.         public GameObject spawnPoint;
  9.        
  10.         TNObject tno;  
  11.  
  12.         void OnNetworkJoinChannel (bool success, string message) {
  13.                 if(success) {  
  14.                         TNManager.Create(player, spawnPoint.transform.position, spawnPoint.transform.rotation);        
  15.                 }
  16.                
  17.                 else {
  18.                         print ("Error on joining world: " + message);  
  19.                 }
  20.         }
  21.        
  22.         // Use this for initialization
  23.         void Start () {  
  24.                         //tno.Send(1, TNet.Target.AllSaved);   
  25.         }
  26.        
  27.         // Update is called once per frame
  28.         void Update () {
  29.        
  30.         }
  31.        
  32.  [RFC(1)]
  33.         void Spawn() {
  34.                 TNManager.Create(player, spawnPoint.transform.position, spawnPoint.transform.rotation);
  35.         }
  36. }

(I tried putting the TNManager.Create() into the Start() method but that makes each player control every character.) And my character controller script, which contains camera switching:

  1. using UnityEngine;
  2. using System.Collections;
  3. //using TNet;
  4.  
  5. public class FirstPersonController : TNBehaviour {
  6.        
  7.         private Camera fpsCamera;
  8.         private Camera thirdPersonCamera;
  9.        
  10.         private bool firstPerson;
  11.         public float movementSpeed = 3.0f;
  12.         CharacterController cc;
  13.        
  14.         // Use this for initialization
  15.         void Start () {
  16.                
  17.                 if(TNManager.isThisMyObject) {
  18.                        
  19.                         cc = GetComponent<CharacterController>();
  20.                        
  21.                         fpsCamera = GameObject.Find("firstPersonCam").camera;
  22.                         thirdPersonCamera = GameObject.Find("thirdPersonCam").camera;
  23.                        
  24.                         fpsCamera.enabled = true;
  25.                         thirdPersonCamera.enabled = false;
  26.                         firstPerson = true;
  27.                 }
  28.         }
  29.        
  30.         // Update is called once per frame
  31.         void Update () {
  32.        
  33.                                 if(TNManager.isThisMyObject) {
  34.                        
  35.                         if(Input.GetButtonDown("Change Camera")) {
  36.                
  37.                         if(firstPerson == true) {
  38.                                        
  39.                                  thirdPersonCamera.transform.position = Vector3.Lerp(thirdPersonCamera.transform.position, transform.FindChild("ThirdPersonPoint").position, 5.0f);
  40.                              thirdPersonCamera.transform.rotation = transform.FindChild("ThirdPersonPoint").rotation;
  41.                                
  42.                                 fpsCamera.enabled = false;
  43.                                 thirdPersonCamera.enabled = true;
  44.                                 firstPerson = false;
  45.                         }
  46.                
  47.                 else {
  48.                                  fpsCamera.transform.position = Vector3.Lerp(fpsCamera.transform.position, transform.FindChild("FirstPersonPoint").position, 5.0f);
  49.                              fpsCamera.transform.rotation = transform.FindChild("FirstPersonPoint").rotation;
  50.                                        
  51.  
  52.                                 fpsCamera.enabled = true;
  53.                                 thirdPersonCamera.enabled = false;
  54.                                 firstPerson = true;
  55.                         }
  56.                 }
  57.                        
  58.                 float forwardSpeed = Input.GetAxis("Vertical") * movementSpeed;
  59.                 float sideSpeed = Input.GetAxis("Horizontal") * movementSpeed;
  60.                 float jumpHeight = 2.0f;
  61.                        
  62.                 bool jump = Input.GetButtonDown("Jump");
  63.                        
  64.                         if(jump) {
  65.                                 cc.SimpleMove(new Vector3(0, jumpHeight, 0));
  66.                         }
  67.                                        
  68.                 Vector3 speed = new Vector3(sideSpeed, 0, forwardSpeed); // 1st: L/R, 2nd: Up/Dwn, 3rd: Fwd/Bk
  69.                
  70.  
  71.                
  72.                 cc.SimpleMove(speed);
  73.                        
  74.                 }
  75.         }
  76. }
  77.  

1. Should I include the two cameras as part of the player prefab, or just have them in the scene ready to be set to the correct player object? Or does it not matter?

2. When I start up the game everything works as expected when there's one player in the game, as soon as another player joins though the first player loses all control of their character and only player two can control their character. The same happens when a third player joins; only they can control their character. And so on and so forth... Oddly, when player three leaves player two re-gains control, but player one doesn't when player two leaves. All players are also re-spawned when a new player enters.  Why is this all happening?
 
2.1 How can I get this all fixed up to where each player properly controls themselves and only themselves? 
2.2 How can I get the player's character to be removed when they disconnect?

Can someone please offer me some assistance!? I would greatly appreciate it.  My apologies for the double post but I wanted to add further detail and get my post noticed :P!
« Last Edit: April 29, 2013, 12:55:42 PM by Braveheart »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Setting up and spawning a player
« Reply #2 on: April 29, 2013, 05:26:10 PM »
Alright so starting from the top...

TNManager.isThisMyObject will only work correctly in Awake(). For any other place you need to check TNObject's isMine flag instead.

Do this and your original attempt should fall into place correctly.

For removal of player objects, you need to do it in OnNetworkPlayerLeft().

Braveheart

  • Guest
Re: Setting up and spawning a player
« Reply #3 on: April 29, 2013, 06:08:29 PM »
Alright so starting from the top...

TNManager.isThisMyObject will only work correctly in Awake(). For any other place you need to check TNObject's isMine flag instead.

Do this and your original attempt should fall into place correctly.

For removal of player objects, you need to do it in OnNetworkPlayerLeft().

Thank you for the reply! I've tried adding that to my Awake function in the FPS controller script.  I still get the same effect as before, when player two joins both players re-spawn and player one loses control of their character... arg! What am I missing?

I have two scenes, one for MainMenu (handles connecting to the server etc) and the other for the World (the actual game word in which spawning, sync etc are handled).  Both of these have TNManagers in them, is this correct or should only one scene contain one?

Could you give me an example of using tno.isMine? I have the following in my fps controller:

TNObject tno;

So if I then do tno.isMine, is this checking if the attached game object is mine?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Setting up and spawning a player
« Reply #4 on: April 29, 2013, 06:14:03 PM »
You can check tno.isMine anywhere you like. For example in the Update function just before you do actual FPS movement. Only proceed if tno.isMine.

In the example script you posted you are using TNObject.isThisMyObject in Update() -- which will not work as I explained. You need to replace all instances of that with tno.isMine instead.

Braveheart

  • Guest
Re: Setting up and spawning a player
« Reply #5 on: April 29, 2013, 06:58:30 PM »
Ok - I've changed to tno.isMine.  I'm still getting the same effect as before though, when player two joins player one loses control of their character.  And I can't get the player object to delete properly upon a player leaving/closing the game, meaning when I re-join I'm getting only partial control of the camera which is completely odd (up down control).  Below is my FPS controller attached to each player:

  1. using UnityEngine;
  2. using System.Collections;
  3. using TNet;
  4.  
  5. public class FirstPersonController : TNBehaviour {
  6.        
  7.         private Camera fpsCamera;
  8.         private Camera thirdPersonCamera;
  9.        
  10.         private bool firstPerson = true;
  11.         public float movementSpeed = 3.0f;
  12.        
  13.         public float mouseSensitivity = 6.0f;
  14.         float verticalRot = 0;
  15.         private float UpDownRange = 60.0f;
  16.        
  17.         CharacterController cc;
  18.        
  19.         TNObject tno;
  20.  
  21.        
  22.         void Awake() {
  23.                         if(TNManager.isThisMyObject) {
  24.                                 tno = this.GetComponent<TNObject>();
  25.                 }
  26.                
  27.                 else this.enabled = false;     
  28.         }
  29.         // Use this for initialization
  30.         void Start () {
  31.                                 if(tno.isMine) {
  32.                 Screen.lockCursor = true;
  33.                
  34.                 cc = GetComponent<CharacterController>();
  35.                        
  36.                 fpsCamera = GameObject.Find("firstPersonCam").camera;
  37.                 thirdPersonCamera = GameObject.Find("thirdPersonCam").camera;
  38.                        
  39.                         fpsCamera.enabled = true;
  40.                         thirdPersonCamera.enabled = false;
  41.                         firstPerson = true;
  42.                        
  43.                 }
  44.         }
  45.        
  46.        
  47.         void OnNetworkPlayerLeft(Player p) {
  48.                 TNManager.Destroy(gameObject);         
  49.         }
  50.        
  51. void OnNetworkDisconnect() {
  52.         if(tno.isMine) {
  53.                 TNManager.Destroy(gameObject); 
  54.                 TNManager.Destroy(tno);
  55.         }
  56.         }
  57.        
  58.        
  59.         void Update () {
  60.        
  61.                 if(!tno.isMine) {
  62.                         this.enabled = false;
  63.                 }
  64.                
  65.                 if(tno.isMine) {
  66.                                                        
  67.                         // CHANGE CAMERA PERSPECTIVE
  68.                        
  69.                         if(Input.GetButtonDown("Change Camera")) {
  70.                
  71.                         if(firstPerson == true) {
  72.                                        
  73.                                  thirdPersonCamera.transform.position = Vector3.Lerp(thirdPersonCamera.transform.position, transform.FindChild("ThirdPersonPoint").position, 5.0f);
  74.                              thirdPersonCamera.transform.rotation = transform.FindChild("ThirdPersonPoint").rotation;
  75.                                
  76.                                 fpsCamera.enabled = false;
  77.                                 thirdPersonCamera.enabled = true;
  78.                                 firstPerson = false;
  79.                         }
  80.                
  81.                 else {
  82.                                  fpsCamera.transform.position = Vector3.Lerp(fpsCamera.transform.position, transform.FindChild("FirstPersonPoint").position, 5.0f);
  83.                              fpsCamera.transform.rotation = transform.FindChild("FirstPersonPoint").rotation;
  84.                                        
  85.  
  86.                                 fpsCamera.enabled = true;
  87.                                 thirdPersonCamera.enabled = false;
  88.                                 firstPerson = true;
  89.                         }
  90.                 }
  91.                        
  92.                
  93.             // ROTATION
  94.                        
  95.                         float rotUpDown = Input.GetAxis("Mouse Y") * mouseSensitivity;
  96.                         float rotLeftRight = Input.GetAxis("Mouse X") * mouseSensitivity;
  97.                        
  98.                         transform.Rotate(0, rotLeftRight, 0);
  99.                        
  100.                         verticalRot -= Input.GetAxis("Mouse Y") * mouseSensitivity;
  101.                        
  102.                         if(firstPerson == true) {              
  103.                                         UpDownRange = 60.0f;
  104.                         }
  105.                         else {
  106.                                    UpDownRange = 30.0f;
  107.                         }
  108.                        
  109.                                                
  110.                         verticalRot = Mathf.Clamp(verticalRot, -UpDownRange, UpDownRange);
  111.                                
  112.  
  113.                                 if(firstPerson == true) {
  114.                                 fpsCamera.transform.localRotation = Quaternion.Euler(verticalRot, 0, 0);                               
  115.                         }
  116.                        
  117.                         else {
  118.                                 thirdPersonCamera.transform.localRotation = Quaternion.Euler(verticalRot, 0, 0);       
  119.                         }
  120.  
  121.                 // MOVEMENT
  122.                        
  123.                 float forwardSpeed = Input.GetAxis("Vertical") * movementSpeed;
  124.                 float sideSpeed = Input.GetAxis("Horizontal") * movementSpeed;
  125.                 float jumpHeight = 2.0f;
  126.                        
  127.                 bool jump = Input.GetButtonDown("Jump");
  128.                        
  129.                         if(jump) {
  130.                                 cc.Move(new Vector3(0, jumpHeight, 0));
  131.                         }
  132.                                        
  133.                 Vector3 speed = new Vector3(sideSpeed, 0, forwardSpeed); // 1st: L/R, 2nd: Up/Dwn, 3rd: Fwd/Bk
  134.                                
  135.                 speed = transform.rotation * speed;    
  136.        
  137.                        
  138.                 if(Input.GetMouseButton(1)) {           // MOUSE BUTTON 2              
  139.                 }  
  140.                                
  141.                 cc.SimpleMove(speed);
  142.                        
  143.                 }
  144.                
  145.                 else this.enabled = false;
  146.         }
  147. }
  148.  

And the spawn script:

  1. using UnityEngine;
  2. using System.Collections;
  3. using TNet;
  4.  
  5. public class SpawnPlayer : MonoBehaviour {
  6.        
  7.         public GameObject player;
  8.         public GameObject spawnPoint;
  9.        
  10.         FirstPersonController fp;
  11.        
  12.         TNObject tno;
  13.        
  14.         void Awake() {
  15.                 if(TNManager.isThisMyObject) {
  16.                                
  17.         }      
  18.         }
  19.        
  20.         void OnNetworkJoinChannel (bool success, string message) {
  21.                 if(success) {          
  22.                         TNManager.Create(player, spawnPoint.transform.position, spawnPoint.transform.rotation);        
  23.                 }
  24.                
  25.                 else {
  26.                         print ("Error on joining world: " + message);  
  27.                 }
  28.         }
  29.                
  30.         // Update is called once per frame
  31.         void Update () {
  32.  
  33.         }
  34.        
  35.  [RFC(1)]
  36.         void Spawn() {
  37.                 TNManager.Create(player, spawnPoint.transform.position, spawnPoint.transform.rotation);
  38.         }
  39. }
  40.  


What am I missing!?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Setting up and spawning a player
« Reply #6 on: April 29, 2013, 08:25:20 PM »
Your Awake() function is not needed at all. "tno" is already set for you when you derive from TNBehaviour.

Prior to doing a destroy in OnNetworkPlayerLeft you need to check -- did this player own this script before? If so, destroy it, and only then. I recommend saving the "player owner" in Start(). You currently destroy every script when a single player leaves.

OnNetworkDisconnect() is not going to do anything in your case either. If you get disconnected, you should load a disconnect level (or the main menu), not destroy anything. When you're disconnected, destroying objects is pointless. It's not like you are going to sync this with other players. After all, you're disconnected by this point.

I strongly suggest you watch the "making a multiplayer game from scratch" training video for TNet. It covers most of what you are trying to do.

You can also grab the entire example project for it here: http://www.tasharen.com/tnet/TNetExample2.unitypackage

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Setting up and spawning a player
« Reply #7 on: April 29, 2013, 08:55:08 PM »
P.S. You know that one of the flags on the Create() function is "persistent", meaning the object will be automatically destroyed when the player leaves if this is set to 'false'?

Braveheart

  • Guest
Re: Setting up and spawning a player
« Reply #8 on: April 30, 2013, 02:48:14 AM »
Yeah I figured NetworkDisconect wouldn't do anything, I was just trying all the methods to see if anything worked as expected.  How would I save the player owner in Start()? When a single player joins then leaves, networkPlayerLeave doesn't destroy anything.  When there's two players and any leave, it only destroys one player.

I didn't know of Persistent in Create()... that saves me a headache lol!  What I don't understand though is still when a second player joins player one is losing all control except for pitch control over a camera.  Should the spawn script be attached to the player object too?  I may have to try setting up a really basic spawn a simple cube that moves left and right and get everything working on that first.

I watched the video and I'm trying to piece together things on my end with the video and examples in mind, but it's proving difficult as they're two different games.

Sorry for all these questions, I'm just trying to wrap my head around how this all works so I can start building things properly.  It seems like it should be pretty straightforward yet there's a lot of unexpected and odd behaviour, I'm probably overlooking something really simple.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Setting up and spawning a player
« Reply #9 on: April 30, 2013, 07:30:04 AM »
Each player joining should result in a new player instance, and it should only be managed by the player that created it. This is handled like that in the video tutorial (and the package I linked). It certainly does sound like you are overlooking something simple.

Braveheart

  • Guest
Re: Setting up and spawning a player
« Reply #10 on: April 30, 2013, 12:15:42 PM »
Okay, I still can't figure this out.

I've had a run through the example project you posted above (the one from the tutorial video) and I've copy-pasted a lot of it into a test scene to try and get this working.  I have:

PlayerControl.cs (attached to the player prefab which is referenced in the TNManager in the MainMenu scene):

  1. using UnityEngine;
  2. using System.Collections;
  3. using TNet;
  4.  
  5. public class PlayerControl : TNBehaviour {
  6.  
  7.         static public PlayerControl instance;
  8.        
  9.         CharacterController cc;
  10.        
  11.         Vector3 mTarget = Vector3.zero;
  12.        
  13.          private Vector3 moveDirection = Vector3.zero;
  14.        
  15.                 public Vector3 target
  16.         {
  17.                 set
  18.                 {
  19.                         tno.Send(5, TNet.Target.AllSaved, value);
  20.                 }
  21.         }
  22.        
  23.        
  24.                 void Awake ()
  25.         {
  26.                 if (TNManager.isThisMyObject)
  27.                 {
  28.                         instance = this;               
  29.                         cc = GetComponent<CharacterController>();
  30.                 }
  31.         }
  32.        
  33.                 void Update ()
  34.         {
  35.                 if(tno.isMine) {       
  36.                         cc.SimpleMove(new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")));
  37.                 }
  38.                
  39.                 else {
  40.                         transform.position = Vector3.MoveTowards(transform.position, mTarget, 3f * Time.deltaTime);    
  41.                 }
  42.         }
  43.        
  44.                 void OnNetworkPlayerJoin (Player p)
  45.         {
  46.                 tno.Send(6, p, transform.position);
  47.         }
  48.        
  49.         [RFC(5)]
  50.         void OnSetTarget (Vector3 pos)
  51.         {
  52.                 mTarget = pos;
  53.         }
  54.  
  55.         [RFC(6)]
  56.         void OnSetTargetImmediate (Vector3 pos)
  57.         {
  58.                 transform.position = pos;      
  59.         }
  60. }
  61.  

PlayerSpawn.cs (which is attached to an empty game object marking the spawn point in the World scene):

  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. public class PlayerSpawn : MonoBehaviour {
  5.        
  6.         public GameObject player;
  7.         public GameObject spawnPoint;
  8.        
  9.         void Start() {         
  10.         }
  11.         void OnNetworkJoinChannel (bool success, string message) {
  12.                 if(success) {    
  13.                         TNManager.Create(player, spawnPoint.transform.position, spawnPoint.transform.rotation, false); 
  14.                 }
  15.                
  16.                 else {
  17.                         print ("Error on joining world: " + message);  
  18.                 }
  19.         }
  20. }
  21.  

This works for one player.  As soon as a second player joins both players begin controlling the same character and the new character flies off to Vector3.zero. Why is that? Getting closer...
« Last Edit: April 30, 2013, 12:43:43 PM by Braveheart »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Setting up and spawning a player
« Reply #11 on: April 30, 2013, 10:31:12 PM »
You check tno.isMine correctly in update, but you have an "else" fallback that happens on the non-owned objects that lerps the position to mTarget, which is never set anywhere. Instead you use cc.SimpleMove, and you never sync its position, or update mTarget.

Braveheart

  • Guest
Re: Setting up and spawning a player
« Reply #12 on: May 01, 2013, 06:08:59 AM »
Finally, it works! Thanks.

Some other things, when another player spawns they start to move towards vector3.Zero but then immediately sync to the correct position. What would cause the delay? Also the movement sync lags every now and again, I'm guessing I'd solve this with local prediction (if player 1 was moving on positive X keep doing that until further update received)?

And how would I go about having new players request via an RFC to be spawned, have the host (acting like an authoritive server) do the TNManager.Create()? Because surely if I do just that the player object will belong to the host player, right? So how would I pass ownership of the player object back to the player who had requested the spawn?

Thanks!
« Last Edit: May 01, 2013, 06:27:01 AM by Braveheart »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Setting up and spawning a player
« Reply #13 on: May 02, 2013, 03:36:35 AM »
Players should spawn themselves using TNManager.Create. Player should own their own avatar, not the host.

Braveheart

  • Guest
Re: Setting up and spawning a player
« Reply #14 on: May 02, 2013, 06:09:08 AM »
Is it not possible then to have a client send an RFC requesting to move have the host do the moving via sending an RFC to everyone?