Skip to content

Commit 7c3ab2c

Browse files
authored
FIX: Ensure a specified splitScreenIndex passed in via JoinPlayer is set in PlayerInput (#2157)
1 parent e6254ab commit 7c3ab2c

File tree

3 files changed

+261
-4
lines changed

3 files changed

+261
-4
lines changed

Assets/Tests/InputSystem/Plugins/PlayerInputTests.cs

Lines changed: 259 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,10 +2165,266 @@ public void TODO_PlayerInput_CanSetUpSplitScreen_AndMaintainFixedNumberOfScreens
21652165

21662166
[Test]
21672167
[Category("PlayerInput")]
2168-
[Ignore("TODO")]
2169-
public void TODO_PlayerInput_CanSetUpSplitScreen_AndManuallyAllocatePlayersToScreens()
2168+
public void PlayerInput_CanSetUpSplitScreen_AndManuallyAllocatePlayersToScreens()
21702169
{
2171-
Assert.Fail();
2170+
var actions = InputActionAsset.FromJson(kActions);
2171+
2172+
var playerPrefab = new GameObject();
2173+
playerPrefab.SetActive(false);
2174+
playerPrefab.AddComponent<PlayerInput>();
2175+
playerPrefab.AddComponent<Camera>();
2176+
playerPrefab.GetComponent<PlayerInput>().camera = playerPrefab.GetComponent<Camera>();
2177+
playerPrefab.GetComponent<PlayerInput>().actions = actions;
2178+
2179+
var manager = new GameObject();
2180+
var managerComponent = manager.AddComponent<PlayerInputManager>();
2181+
managerComponent.notificationBehavior = PlayerNotifications.InvokeCSharpEvents;
2182+
managerComponent.joinBehavior = PlayerJoinBehavior.JoinPlayersManually;
2183+
managerComponent.playerPrefab = playerPrefab;
2184+
managerComponent.splitScreen = true;
2185+
2186+
var gamepad1 = InputSystem.AddDevice<Gamepad>();
2187+
var gamepad2 = InputSystem.AddDevice<Gamepad>();
2188+
var gamepad3 = InputSystem.AddDevice<Gamepad>();
2189+
var gamepad4 = InputSystem.AddDevice<Gamepad>();
2190+
2191+
var playerIndex = 0;
2192+
2193+
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true),
2194+
Is.EquivalentTo(new[] { gamepad1, gamepad2, gamepad3, gamepad4 }));
2195+
2196+
// Join two players manually and make sure we get two screen side-by-side.
2197+
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad1);
2198+
playerIndex++;
2199+
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad2);
2200+
playerIndex++;
2201+
2202+
Assert.That(PlayerInput.all, Has.Count.EqualTo(2));
2203+
2204+
Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
2205+
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad2 }));
2206+
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true),
2207+
Is.EquivalentTo(new[] { gamepad3, gamepad4 }));
2208+
2209+
Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
2210+
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(1));
2211+
2212+
// Player #1: Upper Left.
2213+
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
2214+
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0));
2215+
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2216+
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(1));
2217+
2218+
// Player #2: Upper Right.
2219+
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(0.5).Within(0.00001));
2220+
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0));
2221+
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2222+
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(1));
2223+
2224+
// Add one more player and make sure we got a 2x2 setup.
2225+
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad3);
2226+
playerIndex++;
2227+
2228+
Assert.That(PlayerInput.all, Has.Count.EqualTo(3));
2229+
2230+
Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
2231+
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad2 }));
2232+
Assert.That(PlayerInput.all[2].devices, Is.EquivalentTo(new[] { gamepad3 }));
2233+
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true),
2234+
Is.EquivalentTo(new[] { gamepad4 }));
2235+
2236+
Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
2237+
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(1));
2238+
Assert.That(PlayerInput.all[2].splitScreenIndex, Is.EqualTo(2));
2239+
2240+
// Player #1: Upper Left.
2241+
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
2242+
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
2243+
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2244+
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2245+
2246+
// Player #2: Upper Right.
2247+
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(0.5).Within(0.00001));
2248+
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
2249+
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2250+
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2251+
2252+
// Player #3: Lower Left.
2253+
Assert.That(PlayerInput.all[2].camera.rect.x, Is.EqualTo(0));
2254+
Assert.That(PlayerInput.all[2].camera.rect.y, Is.EqualTo(0));
2255+
Assert.That(PlayerInput.all[2].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2256+
Assert.That(PlayerInput.all[2].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2257+
2258+
// Join one more player and make sure we got a fully filled 2x2 setup.
2259+
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad4);
2260+
playerIndex++;
2261+
2262+
Assert.That(PlayerInput.all, Has.Count.EqualTo(4));
2263+
2264+
Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
2265+
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad2 }));
2266+
Assert.That(PlayerInput.all[2].devices, Is.EquivalentTo(new[] { gamepad3 }));
2267+
Assert.That(PlayerInput.all[3].devices, Is.EquivalentTo(new[] { gamepad4 }));
2268+
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true), Is.Empty);
2269+
2270+
Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
2271+
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(1));
2272+
Assert.That(PlayerInput.all[2].splitScreenIndex, Is.EqualTo(2));
2273+
Assert.That(PlayerInput.all[3].splitScreenIndex, Is.EqualTo(3));
2274+
2275+
// Player #1: Upper Left.
2276+
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
2277+
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
2278+
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2279+
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2280+
2281+
// Player #2: Upper Right.
2282+
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(0.5).Within(0.00001));
2283+
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
2284+
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2285+
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2286+
2287+
// Player #3: Lower Left.
2288+
Assert.That(PlayerInput.all[2].camera.rect.x, Is.EqualTo(0));
2289+
Assert.That(PlayerInput.all[2].camera.rect.y, Is.EqualTo(0));
2290+
Assert.That(PlayerInput.all[2].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2291+
Assert.That(PlayerInput.all[2].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2292+
2293+
// Player #4: Lower Right.
2294+
Assert.That(PlayerInput.all[3].camera.rect.x, Is.EqualTo(0.5).Within(0.00001));
2295+
Assert.That(PlayerInput.all[3].camera.rect.y, Is.EqualTo(0));
2296+
Assert.That(PlayerInput.all[3].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2297+
Assert.That(PlayerInput.all[3].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2298+
2299+
// Unjoin the player in the upper right and make sure the other players stay where they are.
2300+
Object.DestroyImmediate(PlayerInput.all[1].gameObject);
2301+
2302+
Assert.That(PlayerInput.all, Has.Count.EqualTo(3));
2303+
2304+
Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
2305+
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad3 }));
2306+
Assert.That(PlayerInput.all[2].devices, Is.EquivalentTo(new[] { gamepad4 }));
2307+
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true),
2308+
Is.EquivalentTo(new[] { gamepad2 }));
2309+
2310+
Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
2311+
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(2));
2312+
Assert.That(PlayerInput.all[2].splitScreenIndex, Is.EqualTo(3));
2313+
2314+
// Player #1: Upper Left.
2315+
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
2316+
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
2317+
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2318+
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2319+
2320+
// Player #3: Lower Left.
2321+
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(0));
2322+
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0));
2323+
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2324+
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2325+
2326+
// Player #4: Lower Right.
2327+
Assert.That(PlayerInput.all[2].camera.rect.x, Is.EqualTo(0.5).Within(0.00001));
2328+
Assert.That(PlayerInput.all[2].camera.rect.y, Is.EqualTo(0));
2329+
Assert.That(PlayerInput.all[2].camera.rect.width, Is.EqualTo(0.5).Within(0.00001));
2330+
Assert.That(PlayerInput.all[2].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2331+
2332+
// Join a new player but manually allocate the next index.
2333+
// The split-screen setup goes to 3x2 because we are adding it to the end leaving the second empty
2334+
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad2);
2335+
playerIndex++;
2336+
2337+
Assert.That(PlayerInput.all, Has.Count.EqualTo(4));
2338+
2339+
// PlayerInput.all is sorted by playerIndex so the player we just joined should be in the last slot.
2340+
Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
2341+
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad3 }));
2342+
Assert.That(PlayerInput.all[2].devices, Is.EquivalentTo(new[] { gamepad4 }));
2343+
Assert.That(PlayerInput.all[3].devices, Is.EquivalentTo(new[] { gamepad2 }));
2344+
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true), Is.Empty);
2345+
2346+
Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
2347+
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(2));
2348+
Assert.That(PlayerInput.all[2].splitScreenIndex, Is.EqualTo(3));
2349+
Assert.That(PlayerInput.all[3].splitScreenIndex, Is.EqualTo(4));
2350+
2351+
// Player #1: Upper Left.
2352+
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
2353+
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
2354+
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
2355+
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2356+
2357+
// Upper Middle will be empty
2358+
2359+
// Player #3: Upper Right.
2360+
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(2 * (1 / 3.0)).Within(0.00001));
2361+
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
2362+
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
2363+
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2364+
2365+
// Player #4: Lower Left.
2366+
Assert.That(PlayerInput.all[2].camera.rect.x, Is.EqualTo(0));
2367+
Assert.That(PlayerInput.all[2].camera.rect.y, Is.EqualTo(0));
2368+
Assert.That(PlayerInput.all[2].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
2369+
Assert.That(PlayerInput.all[2].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2370+
2371+
// Player #2: Lower Middle.
2372+
Assert.That(PlayerInput.all[3].camera.rect.x, Is.EqualTo(1 / 3.0).Within(0.00001));
2373+
Assert.That(PlayerInput.all[3].camera.rect.y, Is.EqualTo(0));
2374+
Assert.That(PlayerInput.all[3].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
2375+
Assert.That(PlayerInput.all[3].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2376+
2377+
// Join yet another player and make sure the split-screen setup goes to 3x2.
2378+
var gamepad5 = InputSystem.AddDevice<Gamepad>();
2379+
managerComponent.JoinPlayer(playerIndex, playerIndex, "Gamepad", gamepad5);
2380+
playerIndex++;
2381+
2382+
Assert.That(PlayerInput.all, Has.Count.EqualTo(5));
2383+
2384+
Assert.That(PlayerInput.all[0].devices, Is.EquivalentTo(new[] { gamepad1 }));
2385+
Assert.That(PlayerInput.all[1].devices, Is.EquivalentTo(new[] { gamepad3 }));
2386+
Assert.That(PlayerInput.all[2].devices, Is.EquivalentTo(new[] { gamepad4 }));
2387+
Assert.That(PlayerInput.all[3].devices, Is.EquivalentTo(new[] { gamepad2 }));
2388+
Assert.That(PlayerInput.all[4].devices, Is.EquivalentTo(new[] { gamepad5 }));
2389+
Assert.That(InputUser.GetUnpairedInputDevices().ToArray(dispose: true), Is.Empty);
2390+
2391+
Assert.That(PlayerInput.all[0].splitScreenIndex, Is.EqualTo(0));
2392+
Assert.That(PlayerInput.all[1].splitScreenIndex, Is.EqualTo(2));
2393+
Assert.That(PlayerInput.all[2].splitScreenIndex, Is.EqualTo(3));
2394+
Assert.That(PlayerInput.all[3].splitScreenIndex, Is.EqualTo(4));
2395+
Assert.That(PlayerInput.all[4].splitScreenIndex, Is.EqualTo(5));
2396+
2397+
// Player #1: Upper Left.
2398+
Assert.That(PlayerInput.all[0].camera.rect.x, Is.EqualTo(0));
2399+
Assert.That(PlayerInput.all[0].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
2400+
Assert.That(PlayerInput.all[0].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
2401+
Assert.That(PlayerInput.all[0].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2402+
2403+
// Upper Middle will be empty
2404+
2405+
// Player #3: Upper Right.
2406+
Assert.That(PlayerInput.all[1].camera.rect.x, Is.EqualTo(2 * (1 / 3.0)).Within(0.00001));
2407+
Assert.That(PlayerInput.all[1].camera.rect.y, Is.EqualTo(0.5).Within(0.00001));
2408+
Assert.That(PlayerInput.all[1].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
2409+
Assert.That(PlayerInput.all[1].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2410+
2411+
// Player #4: Lower Left.
2412+
Assert.That(PlayerInput.all[2].camera.rect.x, Is.EqualTo(0));
2413+
Assert.That(PlayerInput.all[2].camera.rect.y, Is.EqualTo(0));
2414+
Assert.That(PlayerInput.all[2].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
2415+
Assert.That(PlayerInput.all[2].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2416+
2417+
// Player #2: Lower Middle.
2418+
Assert.That(PlayerInput.all[3].camera.rect.x, Is.EqualTo(1 / 3.0).Within(0.00001));
2419+
Assert.That(PlayerInput.all[3].camera.rect.y, Is.EqualTo(0));
2420+
Assert.That(PlayerInput.all[3].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
2421+
Assert.That(PlayerInput.all[3].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
2422+
2423+
// Player #5: Lower Right.
2424+
Assert.That(PlayerInput.all[4].camera.rect.x, Is.EqualTo(2 * (1 / 3.0)).Within(0.00001));
2425+
Assert.That(PlayerInput.all[4].camera.rect.y, Is.EqualTo(0));
2426+
Assert.That(PlayerInput.all[4].camera.rect.width, Is.EqualTo(1 / 3.0).Within(0.00001));
2427+
Assert.That(PlayerInput.all[4].camera.rect.height, Is.EqualTo(0.5).Within(0.00001));
21722428
}
21732429

21742430
// https://fogbugz.unity3d.com/f/cases/1260625/

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ however, it has to be formatted properly to pass verification tests.
1515
- 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)
1616
- 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)
1717
- 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)
18+
- Fixed an issue when providing JoinPlayer with a specific split screen index. [ISXB-897](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-897)
1819

1920
## [1.14.0] - 2025-03-20
2021

Packages/com.unity.inputsystem/InputSystem/Plugins/PlayerInput/PlayerInput.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1831,7 +1831,7 @@ private void OnEnable()
18311831

18321832
// Split-screen index defaults to player index.
18331833
if (s_InitSplitScreenIndex >= 0)
1834-
m_SplitScreenIndex = splitScreenIndex;
1834+
m_SplitScreenIndex = s_InitSplitScreenIndex;
18351835
else
18361836
m_SplitScreenIndex = playerIndex;
18371837

0 commit comments

Comments
 (0)