This commit is contained in:
2025-06-16 15:14:23 +02:00
commit 074e590073
3174 changed files with 428263 additions and 0 deletions

View File

@ -0,0 +1,73 @@
using UnityEngine;
namespace Mirror.Examples.CouchCoop
{
public class CameraViewForAll : MonoBehaviour
{
public Transform cameraTransform;
public float camSpeed = 2.0f;
public float orthoSizeSpeed = 2.0f;
public Camera mainCamera;
public float cameraZ = -5;
public float cameraBufferX = 0.1f;
public float cameraBufferY = 0.1f;
public float minOrthographicSize = 0.1f;
public float targetYPosition = 4.5f; // Optional Y position if cameras rotated
private Vector2Int boundsMin;
private Vector2Int boundsMax;
private Vector3 targetCameraPosition;
private float targetOrthographicSize;
private void Update()
{
if (CouchPlayer.playersList.Count > 0)
{
CalculateBounds();
CalculateTargetCameraPosAndSize();
MoveCamera();
}
}
private void CalculateBounds()
{
boundsMin = new Vector2Int(int.MaxValue, int.MaxValue);
boundsMax = new Vector2Int(int.MinValue, int.MinValue);
foreach (GameObject player in CouchPlayer.playersList)
{
Vector3 playerPosition = player.transform.position;
boundsMin.x = Mathf.Min(boundsMin.x, Mathf.FloorToInt(playerPosition.x));
boundsMin.y = Mathf.Min(boundsMin.y, Mathf.FloorToInt(playerPosition.y));
boundsMax.x = Mathf.Max(boundsMax.x, Mathf.CeilToInt(playerPosition.x));
boundsMax.y = Mathf.Max(boundsMax.y, Mathf.CeilToInt(playerPosition.y));
}
boundsMin.x -= Mathf.FloorToInt(cameraBufferX);
boundsMin.y -= Mathf.FloorToInt(cameraBufferY);
boundsMax.x += Mathf.CeilToInt(cameraBufferX);
boundsMax.y += Mathf.CeilToInt(cameraBufferY);
}
private void CalculateTargetCameraPosAndSize()
{
float aspectRatio = (float)Screen.width / Screen.height;
float requiredOrthographicSizeX = Mathf.Max((boundsMax.x - boundsMin.x) / 2 / aspectRatio, minOrthographicSize / aspectRatio);
float requiredOrthographicSizeY = Mathf.Max(boundsMax.y - boundsMin.y / 2, minOrthographicSize);
targetOrthographicSize = Mathf.Max(requiredOrthographicSizeX, requiredOrthographicSizeY);
float cameraX = (boundsMax.x + boundsMin.x) / 2;
float cameraY = targetYPosition != 0.0f ? targetYPosition : (boundsMax.y + boundsMin.y) / 2;
targetCameraPosition = new Vector3(cameraX, cameraY, cameraZ);
}
private void MoveCamera()
{
cameraTransform.position = Vector3.Lerp(cameraTransform.position, targetCameraPosition, camSpeed * Time.deltaTime);
mainCamera.orthographicSize = Mathf.Lerp(mainCamera.orthographicSize, targetOrthographicSize, orthoSizeSpeed * Time.deltaTime);
}
}
}

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 73edff93783204b298f805477ae30ecd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 129321
packageName: Mirror
packageVersion: 96.0.1
assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/CameraViewForAll.cs
uploadId: 736421

View File

@ -0,0 +1,32 @@
using UnityEngine;
using UnityEngine.UI;
namespace Mirror.Examples.CouchCoop
{
public class CanvasScript : MonoBehaviour
{
public CouchPlayerManager couchPlayerManager; // Sets itself
public Button buttonAddPlayer, buttonRemovePlayer; // Make sure to attach these Buttons in the Inspector
private void Start()
{
buttonAddPlayer.onClick.AddListener(ButtonAddPlayer);
buttonRemovePlayer.onClick.AddListener(ButtonRemovePlayer);
}
private void ButtonAddPlayer()
{
if (couchPlayerManager == null)
{ Debug.Log("Start game first."); return; }
couchPlayerManager.CmdAddPlayer();
}
private void ButtonRemovePlayer()
{
if (couchPlayerManager == null)
{ Debug.Log("Start game first."); return; }
couchPlayerManager.CmdRemovePlayer();
}
}
}

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 8b76e63e8ad5c42d59aa6ccdda8cddbf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 129321
packageName: Mirror
packageVersion: 96.0.1
assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/CanvasScript.cs
uploadId: 736421

View File

@ -0,0 +1,129 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace Mirror.Examples.CouchCoop
{
public class CouchPlayer : NetworkBehaviour
{
public Rigidbody rb;
public float movementSpeed = 3;
public float jumpSpeed = 6;
private float movementVelocity;
private bool isGrounded;
public CouchPlayerManager couchPlayerManager;
private KeyCode jumpKey = KeyCode.Space; // Check CouchPlayerManager for controls
private KeyCode leftKey = KeyCode.LeftArrow;
private KeyCode rightKey = KeyCode.RightArrow;
[SyncVar(hook = nameof(OnNumberChangedHook))]
public int playerNumber = 0;
public Text textPlayerNumber;
// a list of players, is used for camera
public readonly static List<GameObject> playersList = new List<GameObject>();
public void Start()
{
playersList.Add(this.gameObject);
// print("playersList: " + playersList.Count);
SetPlayerUI();
}
public void OnDestroy()
{
playersList.Remove(this.gameObject);
// print("playersList: " + playersList.Count);
}
public override void OnStartAuthority()
{
this.enabled = true;
if (isOwned)
{
#if UNITY_2022_2_OR_NEWER
couchPlayerManager = GameObject.FindAnyObjectByType<CouchPlayerManager>();
#else
// Deprecated in Unity 2023.1
couchPlayerManager = GameObject.FindObjectOfType<CouchPlayerManager>();
#endif
// setup controls according to the pre-sets on CouchPlayerManager
jumpKey = couchPlayerManager.playerKeyJump[playerNumber];
leftKey = couchPlayerManager.playerKeyLeft[playerNumber];
rightKey = couchPlayerManager.playerKeyRight[playerNumber];
}
}
void Update()
{
if (!Application.isFocused) return;
if (isOwned == false) { return; }
// you can control all local players via arrow keys and space bar for fun testing
// otherwise check and set individual controls in CouchPlayerManager script.
if (isGrounded == true)
{
if (Input.GetKey(KeyCode.Space) || Input.GetKeyDown(jumpKey))
{
#if UNITY_6000_0_OR_NEWER
rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpSpeed);
#else
rb.velocity = new Vector2(rb.velocity.x, jumpSpeed);
#endif
}
}
movementVelocity = 0;
if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(leftKey))
{
movementVelocity = -movementSpeed;
}
if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(rightKey))
{
movementVelocity = movementSpeed;
}
#if UNITY_6000_0_OR_NEWER
rb.linearVelocity = new Vector2(movementVelocity, rb.linearVelocity.y);
#else
rb.velocity = new Vector2(movementVelocity, rb.velocity.y);
#endif
}
[ClientCallback]
void OnCollisionExit(Collision col)
{
if (isOwned == false) { return; }
isGrounded = false;
}
[ClientCallback]
void OnCollisionStay(Collision col)
{
if (isOwned == false) { return; }
isGrounded = true;
}
void OnNumberChangedHook(int _old, int _new)
{
//Debug.Log(name + " - OnNumberChangedHook: " + playerNumber);
SetPlayerUI();
}
public void SetPlayerUI()
{
// called from hook and in start, to solve a race condition
if (isOwned)
{
textPlayerNumber.text = "Local: " + playerNumber;
}
else
{
textPlayerNumber.text = "Remote: " + playerNumber;
}
}
}
}

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 1931e6adfa27e41bbbea220a6436c0e9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: ''
assetBundleName: ''
assetBundleVariant: ''
AssetOrigin:
serializedVersion: 1
productId: 129321
packageName: Mirror
packageVersion: 96.0.1
assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayer.cs
uploadId: 736421

View File

@ -0,0 +1,69 @@
using UnityEngine;
using Mirror;
namespace Mirror.Examples.CouchCoop
{
public class CouchPlayerManager : NetworkBehaviour
{
// reference to UI that should be in the scene
public CanvasScript canvasScript;
// for multiple player prefabs, currently not implemented, remember to add these into Network Managers Prefab array.
public GameObject[] playerPrefabs;
public int totalCouchPlayers = 0;
// ignore key controls 0, we will always start at 1
public KeyCode[] playerKeyJump;
public KeyCode[] playerKeyLeft;
public KeyCode[] playerKeyRight;
// store a list of players so we know which to remove later
// can be non sync-list, but may be useful for future features
readonly SyncList<GameObject> couchPlayersList = new SyncList<GameObject>();
public override void OnStartAuthority()
{
// hook up UI to local player, for cmd communication
#if UNITY_2022_2_OR_NEWER
canvasScript = GameObject.FindAnyObjectByType<CanvasScript>();
#else
// Deprecated in Unity 2023.1
canvasScript = GameObject.FindObjectOfType<CanvasScript>();
#endif
canvasScript.couchPlayerManager = this;
}
[Command]
public void CmdAddPlayer()
{
if (totalCouchPlayers >= playerKeyJump.Length-1)
{
Debug.Log(name + " - No controls setup for further players.");
return;
}
totalCouchPlayers += 1;
Transform spawnObj = NetworkManager.startPositions[Random.Range(0, NetworkManager.startPositions.Count)];
GameObject playerObj = Instantiate(playerPrefabs[0], spawnObj.position, spawnObj.rotation);
CouchPlayer couchPlayer = playerObj.GetComponent<CouchPlayer>();
couchPlayer.playerNumber = totalCouchPlayers;
NetworkServer.Spawn(playerObj, connectionToClient);
couchPlayersList.Add(playerObj);
}
[Command]
public void CmdRemovePlayer()
{
if (totalCouchPlayers <= 0)
{
Debug.Log(name + " - No players to remove for that connection.");
return;
}
totalCouchPlayers -= 1;
NetworkServer.Destroy(couchPlayersList[couchPlayersList.Count - 1]);
couchPlayersList.RemoveAt(couchPlayersList.Count - 1);
}
}
}

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 32f263c662d1e4d33870c9411461bbd0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 129321
packageName: Mirror
packageVersion: 96.0.1
assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/CouchPlayerManager.cs
uploadId: 736421

View File

@ -0,0 +1,79 @@
using UnityEngine;
using Mirror;
namespace Mirror.Examples.CouchCoop
{
public class MovingPlatform : NetworkBehaviour
{
public Transform endTarget;
public float moveSpeed = 0.5f;
// allows for on demand syncing of stopping and starting platform movement, change via server
// note,sync vars changed via inspector do not sync. This is optional feature, can be removed
[SyncVar]
public bool moveObj = true;
// optional fancy features
public bool moveStopsUponExit = false;
public bool moveStartsUponCollision = false;
private Vector3 startPosition;
private Vector3 endPosition;
void Awake()
{
startPosition = transform.position;
endPosition = endTarget.position;
}
void Update()
{
if (moveObj)
{
float step = moveSpeed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, endPosition, step);
if (Vector3.Distance(transform.position, endPosition) < 0.001f)
{
endPosition = endPosition == startPosition ? endTarget.position : startPosition;
if (isServer)
{
RpcResyncPosition(endPosition == startPosition ? (byte)1 : (byte)0);
}
}
}
}
[ClientRpc]
void RpcResyncPosition(byte _value)
{
//print("RpcResyncPosition: " + _value);
transform.position = _value == 1 ? endTarget.position : startPosition;
}
// optional
[ServerCallback]
private void OnCollisionEnter(Collision collision)
{
if (moveStartsUponCollision)
{
if (collision.gameObject.tag == "Player")
{
moveObj = true;
}
}
}
// optional
[ServerCallback]
private void OnCollisionExit(Collision collision)
{
if (moveStopsUponExit)
{
if (collision.gameObject.tag == "Player")
{
moveObj = false;
}
}
}
}
}

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 6c2bc1b05e6794a419ce8e1091f59a05
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 129321
packageName: Mirror
packageVersion: 96.0.1
assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/MovingPlatform.cs
uploadId: 736421

View File

@ -0,0 +1,49 @@
using UnityEngine;
using Mirror;
namespace Mirror.Examples.CouchCoop
{
public class PlatformMovement : NetworkBehaviour
{
// A separate script to handle platform behaviour, see its partner script, MovingPlatform.cs
private bool onPlatform;
private Transform platformTransform;
private Vector3 lastPlatformPosition;
public override void OnStartAuthority()
{
this.enabled = true;
}
void FixedUpdate()
{
if (onPlatform)
{
Vector3 deltaPosition = platformTransform.position - lastPlatformPosition;
transform.position += deltaPosition;
lastPlatformPosition = platformTransform.position;
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Finish")
{
platformTransform = collision.gameObject.GetComponent<Transform>();
lastPlatformPosition = platformTransform.position;
onPlatform = true;
}
}
private void OnCollisionExit(Collision collision)
{
// ideally set a Platform tag, but we'l just use a Unity Pre-set.
if (collision.gameObject.tag == "Finish")
{
onPlatform = false;
platformTransform = null;
}
}
}
}

View File

@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 19882c332836048ada1935c7fb20283b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 129321
packageName: Mirror
packageVersion: 96.0.1
assetPath: Assets/Mirror/Examples/CouchCoop/Scripts/PlatformMovement.cs
uploadId: 736421