-
Notifications
You must be signed in to change notification settings - Fork 1
two players can play on one keyboard #52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,31 @@ | ||
| using Automathon.Utility; | ||
| using System.Collections.Generic; | ||
| using UnityEngine; | ||
| using UnityEngine.InputSystem; | ||
|
|
||
| namespace Automathon.Game.Input | ||
| { | ||
| public class PlayerInputProvider : IInputProvider | ||
| { | ||
| private bool isGamepad; | ||
| public enum PlayerControlsType { LeftKeyboard, RightKeyboard, Gamepad } | ||
| public PlayerControlsType PlayerControls { get; private set; } | ||
| private InputAction dashAction; | ||
| private InputAction grenadeAction; | ||
| private InputAction shieldAction; | ||
| private InputAction shootAction; | ||
| private InputAction moveAction; | ||
| private InputAction aimAction; | ||
|
|
||
| private Dictionary<string, PlayerControlsType> schemeToControlsType = new Dictionary<string, PlayerControlsType> | ||
| { | ||
| { "Gamepad", PlayerControlsType.Gamepad }, | ||
| { "Keyboard_left", PlayerControlsType.LeftKeyboard }, | ||
| { "Keyboard_right", PlayerControlsType.RightKeyboard } | ||
| }; | ||
|
|
||
| public PlayerInputProvider(PlayerInput playerInput) | ||
| { | ||
| isGamepad = playerInput.currentControlScheme == "Gamepad"; | ||
| PlayerControls = schemeToControlsType[playerInput.currentControlScheme]; | ||
| dashAction = playerInput.actions["Dash"]; | ||
| grenadeAction = playerInput.actions["Grenade"]; | ||
| shieldAction = playerInput.actions["Shield"]; | ||
|
|
@@ -39,13 +50,13 @@ public Vector2Int GetMilliMovementDir() | |
|
|
||
| public Vector2Int GetMilliAimingDir() | ||
| { | ||
| if (isGamepad) | ||
| Vector2 aimingDir = aimAction.ReadValue<Vector2>(); | ||
| if (PlayerControls == PlayerControlsType.RightKeyboard) | ||
| { | ||
| Vector2 aimingDir = aimAction.ReadValue<Vector2>(); | ||
| return new Vector2Int((int)(aimingDir.x * 1000), (int)(aimingDir.y * 1000)); | ||
| Vector3 worldPos = aimingDir.ScreenToWorldSpace(); | ||
| return ((Vector2)worldPos).ToVector2IntScaled(); | ||
| } | ||
|
|
||
| return GetMilliMovementDir(); | ||
| return new Vector2Int((int)(aimingDir.x * 1000), (int)(aimingDir.y * 1000)); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is also some calculation here that could potentially be outsourced |
||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,31 +13,38 @@ public class TankSpawnerView : MonoBehaviour | |
| [SerializeField] private PlayerInputManager playerInputManager; | ||
| private Dictionary<PlayerInput, IInputProvider> inputProviders = new(); | ||
|
|
||
| private void Awake() | ||
| { | ||
| playerInputManager.onPlayerLeft += OnPlayerLeft; | ||
| } | ||
|
Comment on lines
+16
to
+19
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unless I missed it, i see no unsubscription: possible memory leak.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly I'm not sure how this code works, I did not write it and didn't quite look into it, I just assumed that it was preferable to subscribe to that event in Awake rather than doing it every frame in Update. |
||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, correct I believe |
||
| private void Update() | ||
| { | ||
| if (GameplayManager.State != GameplayManager.GameState.Lobby) | ||
| return; | ||
|
|
||
| playerInputManager.onPlayerLeft += OnPlayerLeft; | ||
|
|
||
| HandleGamepadJoinInput(); | ||
| HandleKeyboardJoinInput(); | ||
|
|
||
| if (Keyboard.current != null && Keyboard.current.escapeKey.wasPressedThisFrame) | ||
| if (Keyboard.current != null) | ||
| { | ||
| PlayerInput playerInputToRemove = null; | ||
|
|
||
| foreach (PlayerInput playerInput in inputProviders.Keys) | ||
| if (Keyboard.current.escapeKey.wasPressedThisFrame || Keyboard.current.deleteKey.wasPressedThisFrame) | ||
| { | ||
| if (playerInput.currentControlScheme == "Keyboard&Mouse") | ||
| bool isLeftPlayer = Keyboard.current.escapeKey.wasPressedThisFrame; | ||
| PlayerInput playerInputToRemove = null; | ||
|
|
||
| foreach (PlayerInput playerInput in inputProviders.Keys) | ||
| { | ||
| playerInputToRemove = playerInput; | ||
| break; | ||
| if ((isLeftPlayer && playerInput.currentControlScheme == "Keyboard_left") || (!isLeftPlayer && playerInput.currentControlScheme == "Keyboard_right")) | ||
| { | ||
| playerInputToRemove = playerInput; | ||
| break; | ||
| } | ||
| } | ||
|
Comment on lines
+33
to
43
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is still very painful to read, especially that if statement. I'm sure there are more elegant ways to write it. Consider using a Left/Right enum. This is a slight improvement ChatGPT suggested (there could be better ways though, for instance with a left/right enum) |
||
| } | ||
|
|
||
| if (playerInputToRemove != null) | ||
| OnPlayerLeft(playerInputToRemove); | ||
| if (playerInputToRemove != null) | ||
| OnPlayerLeft(playerInputToRemove); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's usually not a good practice to have a same method be both triggered by an event AND be triggered manually. Now here we're doing some weird stuff so not sure the core issue, but still a possibly relevant lesson: You would prefer using the following pattern:
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A potential issue yes, kinda linked to this comment |
||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -49,7 +56,12 @@ private void HandleKeyboardJoinInput() | |
| if (keyboard.eKey.wasPressedThisFrame || keyboard.wKey.wasPressedThisFrame || keyboard.aKey.wasPressedThisFrame || | ||
| keyboard.sKey.wasPressedThisFrame || keyboard.dKey.wasPressedThisFrame || keyboard.qKey.wasPressedThisFrame) | ||
| { | ||
| JoinKeyboardPlayer(); | ||
| JoinKeyboardPlayer(true); | ||
| } | ||
| else if (keyboard.upArrowKey.wasPressedThisFrame || keyboard.downArrowKey.wasPressedThisFrame || keyboard.leftArrowKey.wasPressedThisFrame || | ||
| keyboard.rightArrowKey.wasPressedThisFrame || keyboard.rightShiftKey.wasPressedThisFrame || keyboard.slashKey.wasPressedThisFrame) | ||
| { | ||
| JoinKeyboardPlayer(false); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -103,23 +115,24 @@ private void JoinGamepadPlayer(Gamepad gamepad) | |
| SpawnTank(playerInput); | ||
| } | ||
|
|
||
| private void JoinKeyboardPlayer() | ||
| private void JoinKeyboardPlayer(bool isLeft) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using booleans for keyboard players (left/right) is hard to read and maintain. Consider using a Left/Right enum. |
||
| { | ||
| if (PlayerInput.all.Count >= playerInputManager.maxPlayerCount) | ||
| return; | ||
|
|
||
| foreach (PlayerInput playerInputTemp in inputProviders.Keys) | ||
| { | ||
| if (playerInputTemp.currentControlScheme == "Keyboard&Mouse") | ||
| if ((isLeft && playerInputTemp.currentControlScheme == "Keyboard_left") || (!isLeft && playerInputTemp.currentControlScheme == "Keyboard_right")) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This still looks bad and looks almost duplicate to the logic from before, consider refactoring it into a single method |
||
| return; | ||
| } | ||
|
|
||
| // 2. Manually trigger the join | ||
| // We pass -1 for playerIndex to let Unity assign the next available index (0, 1, 2, etc.) | ||
| string controlScheme = isLeft ? "Keyboard_left" : "Keyboard_right"; | ||
| PlayerInput playerInput = playerInputManager.JoinPlayer( | ||
| playerIndex: -1, | ||
| splitScreenIndex: -1, | ||
| controlScheme: "Keyboard&Mouse", | ||
| controlScheme: controlScheme, | ||
| pairWithDevice: Keyboard.current | ||
| ); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,16 +44,22 @@ public override void Update() | |
| rigidbody.Velocity = movementInput * SPEED / 1000; | ||
|
|
||
| Vector2Int directionInput = InputProvider.GetMilliAimingDir(); | ||
| if (InputProvider is PlayerInputProvider playerInputProvider && playerInputProvider.PlayerControls == PlayerInputProvider.playerControlsType.Right) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AH. Your code doesn't compile but you made the PR anyway? 😭 |
||
| { | ||
| directionInput = new Vector2Int(directionInput.X - Position.X, directionInput.Y - Position.Y); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From a design point of view, I sure wouldn't want to play a top-down shooter... where you can't aim. |
||
| } | ||
| directionInput.NormalizeAtScale(1000); | ||
|
|
||
| if (directionInput != Vector2Int.Zero) | ||
| { | ||
| RotationMilli = directionInput.CalculateAngleMilliRad(); | ||
| rigidbody.AngularVelocityMilli = 0; | ||
|
|
||
| LastMilliDirection = directionInput; | ||
| LastMilliDirection.NormalizeAtScale(1000); | ||
| } | ||
| if (movementInput != Vector2Int.Zero) | ||
| { | ||
| RotationMilli = movementInput.CalculateAngleMilliRad(); | ||
| rigidbody.AngularVelocityMilli = 0; | ||
| } | ||
| } | ||
|
|
||
| private void Death() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,5 +3,6 @@ | |
| public static class WorldConstants | ||
| { | ||
| public const int SPACE_SCALE = 1000; | ||
| public const int CAMERA_DISTANCE = 10000; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be removed, see this comment |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is this issue - i believe it's out of scope for this PR, i suggest we fix in upcoming PR.