using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Unity.Netcode; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UIElements; namespace Game { public enum Side { Top, Bottom } public class Player : NetworkBehaviour { public UnityEngine.Object borderZonePrefab; private Transform borderZoneLeft, borderZoneRight; private const float BaseSpeed = 15; private const float SpeedMultiplier = 1.5f; // Unit distance from zero private readonly float baseBorder = Dimensions.Singleton.PlaySize.x / 2 * 0.85f; private readonly float borderSummand = Dimensions.Singleton.PlaySize.x / 2 * 0.15f; private const float BaseWidth = 6; private const float WidthMultiplier = 1.5f; protected bool goingLeftLinear, goingRightLinear; public Side Side { get; set; } private VisualElement Panel { get; set; } private List Modifications { get; } = new(); private int Score { get; set; } private float GetModified(ModEffect effect, float baseValue, float modValue, Func combineFunc, Func invertFunc) { return Modifications.Where(m => m.effect == effect) .Aggregate(baseValue, (current, mod) => combineFunc(current, mod.type switch { ModType.Buff => modValue, ModType.Nerf => invertFunc(modValue), _ => throw new ArgumentOutOfRangeException() }) ); } protected float Speed { get { float value = GetModified(ModEffect.Speed, BaseSpeed, SpeedMultiplier, (f, f1) => f * f1, f => 1 / f); return value; } } protected float Border { get { float value = GetModified(ModEffect.Border, baseBorder, borderSummand, (f, f1) => f + f1, f => -f); return Mathf.Clamp(value, Width / 2, Dimensions.Singleton.PlaySize.x / 2); } } protected float Width { get { float value = GetModified(ModEffect.Width, BaseWidth, WidthMultiplier, (f, f1) => f * f1, f => 1 / f); return Mathf.Clamp(value, 0.1f, Dimensions.Singleton.PlaySize.x); } } private float LeftEdge => X - Width / 2; private float RightEdge => X + Width / 2; protected float X => transform.position.x; protected float Y => transform.position.y; private void Update() { transform.localScale = new Vector3(Width, 1, 1); float borderV = Border; float borderZoneScaleX = Dimensions.Singleton.PlaySize.x / 2 - borderV; float pos = borderV + borderZoneScaleX / 2; borderZoneLeft.position = new Vector2(pos, transform.position.y); borderZoneRight.position = new Vector2(-pos, transform.position.y); borderZoneLeft.localScale = borderZoneRight.localScale = new Vector3(borderZoneScaleX, 1, 1); } protected void Start() { var y = Side switch { Side.Bottom => -Dimensions.Singleton.PlaySizeBoards.y / 2, Side.Top => Dimensions.Singleton.PlaySizeBoards.y / 2, _ => throw new ArgumentOutOfRangeException() }; transform.position = new Vector2(0, y); if (Side == Side.Top) transform.Rotate(transform.forward, 180); Panel = GameUI.Singleton.PlayerPanel(Side); UpdatePanel(); SpawnZones(); } private void SpawnZones() { borderZoneLeft = Instantiate(borderZonePrefab).GetComponent(); borderZoneRight = Instantiate(borderZonePrefab).GetComponent(); } public void GainScore() { Score++; UpdatePanel(); } private void UpdatePanel() { Panel.Q("score").text = Score.ToString(); } public IEnumerator ProcessModification(ModificationProperties properties) { Modifications.Add(properties); var element = GameUI.AddModification(Panel, properties); var doNothingTime = properties.activeDuration * 0.7f; var animateTime = properties.activeDuration * 0.3f; yield return new WaitForSeconds(doNothingTime); float current = 0; while (current < animateTime) { current += Time.deltaTime; element.style.opacity = new StyleFloat(1 - current / animateTime); yield return null; } element.RemoveFromHierarchy(); Modifications.Remove(properties); } protected void ClampInsideBorders() { if (LeftEdge < -Border) transform.Translate(Vector2.right * (-Border - LeftEdge), Space.World); if (RightEdge > Border) transform.Translate(Vector2.left * (RightEdge - Border), Space.World); } protected void TryLinearMove(float h) { var trans = new Vector2((goingLeftLinear ? -1 : 0) + (goingRightLinear ? 1 : 0), 0); trans *= Speed * h; transform.Translate(trans, Space.World); ClampInsideBorders(); } } }