Coop Gameplay support with Input System

echtnice

Member
Unity: 2020
UCC: 2.2.3

I need several players in the game and would like to use the existing methods such as CameraUtility.FindCamera (m_GameObject); use.

Unfortunately, these fail because there is no camera on the second player and therefore no camera is set for this player in many places.

Another challenge is the player bound in the camera controller, with two and more players it is not clear how exactly the LookDirection() is calculated.

I have built in a few hacks to get everything running, what would be the right way to implement Coop support?
 
Last edited:
Could you give more specifics on exactly what kind of co-op support you're trying to achieve? I.e. is this an online coop game where each player controls their own character separately, in first person? Is it a top-down game where you want the camera to always show all characters as they move apart?
 
is a local game on a single screen like this one.
ss_4dcdd6d0cb38e3bcb747ac7cf69b6b608ae2d46a.1920x1080.jpg


I use the camera where I determine the camera position via the anchor.

When creating characters, a camera controller is searched for with the appropriate character. Think if it wouldn't make sense to add several CameraControllers to the camera and to adjust the places where it is used correctly.

currently I use a hack and reset the character before creating new characters in the camera controller.

It would be interesting to remove the character dependency from the CameraController.

I would be very happy about alternative solutions, then I can summarize the adjustments so that it can possibly be adopted.
 
I did a test of this with quite a simple hack for local coop single screen. created the characters with their own camera controllers and and had all the players register in a list, only player 1's camera was enabled. I altered the CameraController codes, so all the camera controllers looked for the same Anchor (think this code was also tweaked in the ViewType). The Anchor was unparented (UCC CameraController normally wants a parented anchor) gameobject that used separate code to position at the players centroid. It did leave all the players with their own camera controllers (all with the same settings doing their own thing in the same place), but seemed to work well. (I used Rewired for input). I did wonder if setting the players as AI might be an option, but I didnt pursue further.
I agree it would be useful if the CameraController could operate with a list of players.
 
For this type of use case, a good approach would be to have a single anchor transform that the CameraController uses, which you manually control via. a script to always be in the center point of all the characters (e.g. getting the average position of all the characters' positions), then you'd probably need to also adjust the screen-distance of the camera based on the characters' distance from each other to ensure all the characters stay in view.
 
The problem isn't the anchor. The problem is that the CameraController has a character. And the LookDirection is determined on the basis of this dependency. Camera Utility does not find the correct camera. What would the right camera be in this case? Always the MainCamera? or own for each player?

In MeinCamera case Player2 gets the LookDirection from Player1 and that is not correct. If I create several cameras and then adjust the code in some places, is that a valid approach?

C#:
 Adventure.cs
var lookRotation = Quaternion.LookRotation (m_LookSource.Transform.rotation *
                 new Vector3 (characterHorizontalMovement, 0, characterForwardMovement) .normalized, m_CharacterLocomotion.Up);
             return MathUtility.ClampInnerAngle (MathUtility.InverseTransformQuaternion (m_Transform.rotation, lookRotation) .eulerAngles.y);

m_LookSource on Player2 will it be the MainCamera? and what if it isn't? What happens if I implement my own implementation on the character? Do I need my own MovementTypes?

What have I tried:

C#:
        CameraUtility
        private static UnityEngine.Camera SearchForCamera(GameObject character)
        {
            Shared.Camera.ICamera cameraController;
            UnityEngine.Camera mainCamera;
            if ((mainCamera = UnityEngine.Camera.main) != null &&
                (cameraController = mainCamera.GetComponent<Shared.Camera.ICamera>()) != null && (character == null || cameraController.Character == character)) {
                return mainCamera;
            }
            var cameras = UnityEngine.Object.FindObjectsOfType<Camera>();
            for (int i = 0; i < cameras.Length; ++i) {
                var iCamera = cameras[i].GetComponent<Shared.Camera.ICamera>();
                if (iCamera == null) {
                    continue;
                }
                ////HACK
                if (iCamera.Character == null && (iCamera as MonoBehaviour).name.StartsWith("Player") && mainCamera != null && mainCamera.GetComponent<Shared.Camera.ICamera>().Character != null)
                    iCamera.Character = character;
                ////HACK
                if (character == null || iCamera.Character == character) {
                    return cameras[i];
                }
            }
            return null;
        }


public interface ICamera
    {
        //HACK -  need some hack to change character for camera search
        GameObject Character { get; set; }
    }

With these changes I can assign the camera controller for each player, so that in the CharacterIK and other areas, when the camera is queried, a camera is found. But I think that it is not the right way.

It would be logical if it were the MainCamera. Unfortunately there is a dependency on only one character and that is not so ideal.


Update: Forgot to say, with this event I was able to change the LookSource to the MainCamera. But it doesn't feel like a good solution to me.

C#:
EventHandler.ExecuteEvent<ILookSource>(player2.gameObject, "OnCharacterAttachLookSource", Camera.main.GetComponent<ILookSource>());
 
Last edited:
would it be possible to add a method to the CameraController to be able to set the anchor programmatically?

public void OverrideAnchor (Transform anchor)
{
m_Anchor = anchor;
}

or to extend the method InitializeAnchor and a flag that custom Anchor that are not in the character can be supported.

private bool IsCustomAnchor;
 
Last edited:
I'd definitely recommend sticking to a single camera which you move to the desired position as I described above (probably using a custom view type). For rotating the characters, you could use the LocalLookSource component, as you can set the Target property to any transform you want.

One thing you'd need to make sure you do manually in the correct order is to set the CameraController's Character property to null, then immediately add/enable the character's LocalLookSource. I've tested this in the demo scene, and as long as you call cameraController.Character = null; immediately followed by characterLookSource.enabled = true; (with the LocalLookSource initially disabled) it should be fine.
 
I can confirm that the above suggestion given by @Andrew does not fix the issue and using that method causes all characters to move in incorrect directions.
 
This is what I would try (I have not verified if this works).

I would make a new object in the scene, (a grandparent... it isn't the child of any other object). I would then put the main camera object in that object. I would then make a second camera, a duplicate of the first. I would have the second camera disabled by default. The reference to the player on this new camera references the second player (who I would have in the scene but disabled). The reference to the camera on the 2nd player is this 2nd camera. You will need to carefully look through both the camera scripts and the player scripts to make sure any needed references are properly set.

When a 2nd player joins locally, this 2nd camera remains disabled. You only use the first camera, and will have to either make a script to slide the camera into the center of the two players, or make a script to prevent the 2nd player from walking off screen. When a 2nd player joins remotely, this camera is enabled and is the camera that is rendered for the remote player.


Both networking, and making this solution work well, require a lot of programming knowledge. This is the way it is with any highly customized use of a Unity Asset. Networking is notoriously difficult, and while Mirror/Pun/MLAPI make it easier than it used to be, it is still an order of magnitude harder than anything else.
 
@DavidC Thank you so much for the reply and the suggestions, I truly appreciate it. I just wanted to check, Im using Cinemachine on my Camera so it is childed under an empty game object along with its accompanying Virtual Camera. My camera doesnt follow any players though, I only have one room and other than the slight cinemachine hovers, my Camera stays static. Would my Hierarchy and Cinemachine setup cause a conflict that doesnt have a workaround?
 
The Camera Controller currently does not support multiple targets. It does sound like this is a more popular request though and I have it on my feature request list. I will try to get it in one of the next updates. I haven't tried this setup yet but @DavidC's suggestion could work. If you also have a Camera Controller that supports this you could implement your own ILookSource for that camera controller.
 
@Justin Thank you so much for the reply and the consideration, it really means a lot and it would really help to get an stable official setup going.

The thing is my setup is also quite specific, my Characters don't move in the look direction and the only way I can get that working with my own workaround is by using Init Character on Awake on the Camera, so I have to have more than one Camera that is turned on, each with their own Camera Controller component set to their respective Character and all Camera Anchors set to the same empty game object (with no Anchor code removed). I then also only have one camera be showing any visible layers, with the other cameras set to display Nothing and to Dont Clear.

This allows my multiple characters to work on one camera, although I need to set a different forward axis for each CameraController/Player, otherwise the Movement/Look directions aren't correct for each character. That's the only way I can get everything working correctly for my needs so far and I just hope the different forward direction for each CameraController/Player doesnt cause any weird issues.
 
Ok, I think something I set up with my second player and camera controller is messing up my audio now.

Only certain sounds play and some sounds don't want to play, this seems to affect the 2nd player's weapon sounds especially.

I only have one Audio Listener in the scene does the Camera Controller do anything specific with the Listener?
 
Ok, I managed to fix the sound issues by not using the Explosion script on my Fx objects that I spawn via the Object Pool and instead just Destroy them manually (via the Playmaker Opsive Destroy Action).
 
@Justin Thank you so much for the reply and the consideration, it really means a lot and it would really help to get an stable official setup going.

The thing is my setup is also quite specific, my Characters don't move in the look direction and the only way I can get that working with my own workaround is by using Init Character on Awake on the Camera, so I have to have more than one Camera that is turned on, each with their own Camera Controller component set to their respective Character and all Camera Anchors set to the same empty game object (with no Anchor code removed). I then also only have one camera be showing any visible layers, with the other cameras set to display Nothing and to Dont Clear.

This allows my multiple characters to work on one camera, although I need to set a different forward axis for each CameraController/Player, otherwise the Movement/Look directions aren't correct for each character. That's the only way I can get everything working correctly for my needs so far and I just hope the different forward direction for each CameraController/Player doesnt cause any weird issues.
That sounds like a fine workaround to me.
 
Top