Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 259 additions & 3 deletions Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2165,10 +2165,266 @@ public void TODO_PlayerInput_CanSetUpSplitScreen_AndMaintainFixedNumberOfScreens

[Test]
[Category("PlayerInput")]
[Ignore("TODO")]
public void TODO_PlayerInput_CanSetUpSplitScreen_AndManuallyAllocatePlayersToScreens()
public void PlayerInput_CanSetUpSplitScreen_AndManuallyAllocatePlayersToScreens()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this very complex test :)

{
Assert.Fail();
var actions = InputActionAsset.FromJson(kActions);

var playerPrefab = new GameObject();
playerPrefab.SetActive(false);
playerPrefab.AddComponent<PlayerInput>();
playerPrefab.AddComponent<Camera>();
playerPrefab.GetComponent<PlayerInput>().camera = playerPrefab.GetComponent<Camera>();
playerPrefab.GetComponent<PlayerInput>().actions = actions;

var manager = new GameObject();
var managerComponent = manager.AddComponent<PlayerInputManager>();
managerComponent.notificationBehavior = PlayerNotifications.InvokeCSharpEvents;
managerComponent.joinBehavior = PlayerJoinBehavior.JoinPlayersManually;
managerComponent.playerPrefab = playerPrefab;
managerComponent.splitScreen = true;

var gamepad1 = InputSystem.AddDevice<Gamepad>();
var gamepad2 = InputSystem.AddDevice<Gamepad>();
var gamepad3 = InputSystem.AddDevice<Gamepad>();
var gamepad4 = InputSystem.AddDevice<Gamepad>();

var playerIndex = 0;

Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true),
Is.EquivalentTo(new[] { gamepad1, gamepad2, gamepad3, gamepad4 }));

// Join two players manually and make sure we get two screen side-by-side.
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad1);
playerIndex++;
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad2);
playerIndex++;

Assert.That(PlayerInput.all, Has.Count.EqualTo(2));

Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad2 }));
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true),
Is.EquivalentTo(new[] { gamepad3, gamepad4 }));

Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(1));

// Player #1: Upper Left.
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(1));

// Player #2: Upper Right.
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(1));

// Add one more player and make sure we got a 2x2 setup.
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad3);
playerIndex++;

Assert.That(PlayerInput.all, Has.Count.EqualTo(3));

Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad2 }));
Assert.That(PlayerInput.all[2].devices, Is.EquivalentTo(new[] { gamepad3 }));
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true),
Is.EquivalentTo(new[] { gamepad4 }));

Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(1));
Assert.That(PlayerInput.all[2].splitScreenIndex, Is.EqualTo(2));

// Player #1: Upper Left.
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #2: Upper Right.
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #3: Lower Left.
Assert.That(PlayerInput.all[2].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[2].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[2].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[2].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Join one more player and make sure we got a fully filled 2x2 setup.
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad4);
playerIndex++;

Assert.That(PlayerInput.all, Has.Count.EqualTo(4));

Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad2 }));
Assert.That(PlayerInput.all[2].devices, Is.EquivalentTo(new[] { gamepad3 }));
Assert.That(PlayerInput.all[3].devices, Is.EquivalentTo(new[] { gamepad4 }));
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true), Is.Empty);

Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(1));
Assert.That(PlayerInput.all[2].splitScreenIndex, Is.EqualTo(2));
Assert.That(PlayerInput.all[3].splitScreenIndex, Is.EqualTo(3));

// Player #1: Upper Left.
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #2: Upper Right.
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #3: Lower Left.
Assert.That(PlayerInput.all[2].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[2].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[2].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[2].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #4: Lower Right.
Assert.That(PlayerInput.all[3].camera.rect.x, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[3].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[3].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[3].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Unjoin the player in the upper right and make sure the other players stay where they are.
Object.DestroyImmediate(PlayerInput.all[1].gameObject);

Assert.That(PlayerInput.all, Has.Count.EqualTo(3));

Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad3 }));
Assert.That(PlayerInput.all[2].devices, Is.EquivalentTo(new[] { gamepad4 }));
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true),
Is.EquivalentTo(new[] { gamepad2 }));

Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(2));
Assert.That(PlayerInput.all[2].splitScreenIndex, Is.EqualTo(3));

// Player #1: Upper Left.
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #3: Lower Left.
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #4: Lower Right.
Assert.That(PlayerInput.all[2].camera.rect.x, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[2].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[2].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[2].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Join a new player but manually allocate the next index.
// The split-screen setup goes to 3x2 because we are adding it to the end leaving the second empty
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad2);
playerIndex++;

Assert.That(PlayerInput.all, Has.Count.EqualTo(4));

// PlayerInput.all is sorted by playerIndex so the player we just joined should be in the last slot.
Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad3 }));
Assert.That(PlayerInput.all[2].devices, Is.EquivalentTo(new[] { gamepad4 }));
Assert.That(PlayerInput.all[3].devices, Is.EquivalentTo(new[] { gamepad2 }));
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true), Is.Empty);

Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(2));
Assert.That(PlayerInput.all[2].splitScreenIndex, Is.EqualTo(3));
Assert.That(PlayerInput.all[3].splitScreenIndex, Is.EqualTo(4));

// Player #1: Upper Left.
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Upper Middle will be empty

// Player #3: Upper Right.
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(2 * (1 / 3.0)).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #4: Lower Left.
Assert.That(PlayerInput.all[2].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[2].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[2].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[2].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #2: Lower Middle.
Assert.That(PlayerInput.all[3].camera.rect.x, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[3].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[3].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[3].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Join yet another player and make sure the split-screen setup goes to 3x2.
var gamepad5 = InputSystem.AddDevice<Gamepad>();
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad5);
playerIndex++;

Assert.That(PlayerInput.all, Has.Count.EqualTo(5));

Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad3 }));
Assert.That(PlayerInput.all[2].devices, Is.EquivalentTo(new[] { gamepad4 }));
Assert.That(PlayerInput.all[3].devices, Is.EquivalentTo(new[] { gamepad2 }));
Assert.That(PlayerInput.all[4].devices, Is.EquivalentTo(new[] { gamepad5 }));
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true), Is.Empty);

Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(2));
Assert.That(PlayerInput.all[2].splitScreenIndex, Is.EqualTo(3));
Assert.That(PlayerInput.all[3].splitScreenIndex, Is.EqualTo(4));
Assert.That(PlayerInput.all[4].splitScreenIndex, Is.EqualTo(5));

// Player #1: Upper Left.
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Upper Middle will be empty

// Player #3: Upper Right.
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(2 * (1 / 3.0)).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #4: Lower Left.
Assert.That(PlayerInput.all[2].camera.rect.x, Is.EqualTo(0));
Assert.That(PlayerInput.all[2].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[2].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[2].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #2: Lower Middle.
Assert.That(PlayerInput.all[3].camera.rect.x, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[3].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[3].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[3].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));

// Player #5: Lower Right.
Assert.That(PlayerInput.all[4].camera.rect.x, Is.EqualTo(2 * (1 / 3.0)).Within(0.00001));
Assert.That(PlayerInput.all[4].camera.rect.y, Is.EqualTo(0));
Assert.That(PlayerInput.all[4].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
Assert.That(PlayerInput.all[4].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
}

// https://fogbugz.unity3d.com/f/cases/1260625/
Expand Down
1 change: 1 addition & 0 deletions Packages/com.unity.inputsystem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ however, it has to be formatted properly to pass verification tests.
- Fixed an issue causing a number of errors to be displayed when using `InputTestFixture` in playmode tests with domain reloading disabled on playmode entry. [ISXB-1446](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1446)
- Fixed issue where user was not prompted to save changes when loading a second input actions asset into an already opened editor. [ISXB-1343](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1343)
- Fixed an issue on macOS which didn't detect up-left DPAD presses for Xbox controllers. [ISXB-810](https://issuetracker.unity3d.com/issues/macos-d-pad-upper-left-corner-is-not-logged-with-the-xbox-controller)
- Fixed an issue when providing JoinPlayer with a specific split screen index. [ISXB-897](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-897)

## [1.14.0] - 2025-03-20

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1831,7 +1831,7 @@ private void OnEnable()

// Split-screen index defaults to player index.
if (s_InitSplitScreenIndex >= 0)
m_SplitScreenIndex = splitScreenIndex;
m_SplitScreenIndex = s_InitSplitScreenIndex;
else
m_SplitScreenIndex = playerIndex;

Expand Down