using System.Collections; using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; using BigSock.UI; using BigSock.Item; using BigSock.Service; namespace BigSock { // Takes and handles input and movement for a player character public partial class PlayerController : Character { public const int SKILL_POINTS_PR_LVL = 3; // Skill points to gain pr level up. public const int SKILL_POINTS_START = 0; // Skill points to start with. public const float XP_SCALE_RATE = 3.0f; // Multiplier for xp gain, helps test system while game is tiny. public UtilBar utilBar; public float collisionOffset = 0.05f; public ContactFilter2D movementFilter; public GameObject attack; Vector2 movementInput; SpriteRenderer spriteRenderer; //Rigidbody2D rb; Animator animator; List<RaycastHit2D> castCollisions = new List<RaycastHit2D>(); bool canMove = true; // The abilities of the player. private List<AbilityEntity> _abilities = new List<AbilityEntity>(); // A list of the keycodes that correspond to each of the player's abilities. private List<List<KeyCode>> _keyMapping = new List<List<KeyCode>> { new List<KeyCode>{KeyCode.Space, KeyCode.Mouse0}, new List<KeyCode>{KeyCode.Z}, new List<KeyCode>{KeyCode.C}, new List<KeyCode>{KeyCode.LeftShift}, }; //protected IAttack _testAttack; //protected IAttack _testAttack2; //protected IAttack _testAttack3; //protected IAbility _dodge; public DateTime NextTimeCanAttack { get; private set; } = DateTime.Now; public PlayerController() { TryPickUpItem(ItemService.SINGLETON.Get(201)); TryPickUpItem(ItemService.SINGLETON.Get(105)); TryPickUpItem(ItemService.SINGLETON.Get(202)); TryPickUpItem(ItemService.SINGLETON.Get(101)); } /* Updates the list of the user's abilities. */ protected void SetAbilities(List<IAbility> neo) { var res = new List<AbilityEntity>(); for(int i = 0; i < neo.Count; ++i) res.Add(new AbilityEntity(neo[i], i, _keyMapping[i])); _abilities = res; //!! Put in updating he ui here. foreach(var ability in _abilities) { // AbilityUI.SetAbility(ability.Index, ability); ??? } } // Start is called before the first frame update protected override void Start() { base.Start(); utilBar?.WithXP((int)xp, (int)maxXp) ?.WithHealth(Convert.ToInt32(HP), Convert.ToInt32(MaxHP)); animator = GetComponent<Animator>(); spriteRenderer = GetComponent<SpriteRenderer>(); //!! DEBUG: Add item to player at start to test if it works. /* TryPickUpItem(ItemService.SINGLETON.Get(201)); TryPickUpItem(ItemService.SINGLETON.Get(201)); TryPickUpItem(ItemService.SINGLETON.Get(202)); TryPickUpItem(ItemService.SINGLETON.Get(101)); */ //var tmp = PrefabService.SINGLETON; //var tmp = SpriteService.SINGLETON; // Get the abilities and set them up. var aService = AbilityService.SINGLETON; var abilities = new List<IAbility> { aService.Get(104), aService.Get(102), aService.Get(101), aService.Get(201), }; SetAbilities(abilities); //_testAttack = (IAttack)AbilityService.SINGLETON.Get(104); //_testAttack2 = (IAttack)AbilityService.SINGLETON.Get(102); //_testAttack3 = (IAttack)AbilityService.SINGLETON.Get(101); //_dodge = AbilityService.SINGLETON.Get(201); _ = AudioService.SINGLETON; _ = SpriteService.SINGLETON; _ = PrefabService.SINGLETON; } private void FixedUpdate() { if(canMove) { // If movement input is not 0, try to move if(movementInput != Vector2.zero){ bool success = TryMove(movementInput); if(!success) { success = TryMove(new Vector2(movementInput.x, 0)); } if(!success) { success = TryMove(new Vector2(0, movementInput.y)); } animator.SetBool("isMoving", success); } else { animator.SetBool("isMoving", false); } // Set direction of sprite to movement direction var mouse = Camera.main.ScreenToWorldPoint(Input.mousePosition); var pos = transform.position; var temp = (mouse - pos); //temp.z = 0; //direction = temp.normalized; if(temp.x < 0) { spriteRenderer.flipX = true; } else if (temp.x > 0) { spriteRenderer.flipX = false; } } } // Dictionary that holds start times for charging abilities. //Dictionary<KeyCode, float> chargeStarts = new Dictionary<KeyCode, float>(); /* Triggers an ability if it should be. Need to add support for mouse buttons n shiet */ private void CheckAbilityInput(AbilityEntity ability) { var par = GetAbilityParam(Camera.main.ScreenToWorldPoint(Input.mousePosition)); // Check input on each key, stop if one was a success. foreach(var key in ability.Keys) if(CheckAbilityInput(key, ability)) break; // Update the UI. //> AbilityUI?.UpdateCharge(ability.Index, ability.ChargePercent); //> AbilityUI?.UpdateCooldown(ability.Index, ability.CooldownPercent); } private bool CheckAbilityInput(KeyCode key, AbilityEntity ability) { var par = GetAbilityParam(Camera.main.ScreenToWorldPoint(Input.mousePosition)); switch (ability.Ability.FireType) { // Standard: Press to fire. case FireType.Standard: if (Input.GetKeyDown(key)) { ability.Ability.Use(par); return true; } break; // FullAuto: Keep firing while key is down. case FireType.FullAuto: if (Input.GetKey(key)) { ability.Ability.Use(par); return true; } break; // Charge: Fire when let go. case FireType.Charge: // If pressed down: Store start time. if (Input.GetKeyDown(key)) { ability.ChargeStarted = Time.time; return true; } // If let go: Activate else if (Input.GetKeyUp(key)) { par.ChargeTime = ability.ChargeTime; var t = ability.Ability.Use(par); if (!t) { if (par.ChargeTime < ability.Ability.MinCharge) Debug.Log($"[PlayerController.CheckAbilityInput({key})] {ability.Ability.Name} not fired ({par.ChargeTime:N3} < {ability.Ability.MinCharge:N3})"); } return true; } break; default: break; } return false; } private void Update() { // Regenerate mana & stamina. Regenerate(); // Object w/ parameters for abilities. //var par = new AbilityParam{ // Actor = this, // TargetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition), // MovementDir = moveDir, //}; //// If pressed Soace or LMB: Regular attack. //if (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButton(0)) { // _testAttack.Use(par); //} // Check and update all abilities. foreach(var ability in _abilities) { CheckAbilityInput(ability); } // Check ability 1. //CheckAbilityInput(KeyCode.Space, _testAttack); //CheckAbilityInput(KeyCode.Mouse0, _testAttack); // Check ability 2. //CheckAbilityInput(KeyCode.Z, _testAttack2); // Check ability 3. //CheckAbilityInput(KeyCode.LeftShift, _dodge); //CheckAbilityInput(KeyCode.C, _testAttack3); //if(Input.GetKeyDown(KeyCode.Z)) Debug.Log($"[PlayerController.Update()] Z was pressed."); //if(Input.GetKeyUp(KeyCode.Z)) Debug.Log($"[PlayerController.Update()] Z was let go."); //if(Input.GetKeyUp(KeyCode.UpArrow)) Debug.Log($"[PlayerController.Update()] UpArrow was let go."); //if(Input.GetKeyUp(KeyCode.Space)) Debug.Log($"[PlayerController.Update()] Space was let go."); //// If pressed Z: Big attack. //if(Input.GetKey(KeyCode.Z)) { // _testAttack2.Use(par); //} //// If pressed X: dodge. //if(Input.GetKey(KeyCode.X)) { // _dodge.Use(par); //} //!! Code for testing the new item stuff. if (Input.GetKeyDown(KeyCode.M)) { var item = ItemService.SINGLETON.GetRandom(); // new ItemRunningShoes(); TryPickUpItem(item); } // Code for opening the menu. if (Input.GetKeyDown(KeyCode.I)) { GameObject canvas = GameObject.Find("Canvas"); GameObject oldPlayerMenu = GameObject.Find("PlayerMenu(Clone)"); if (canvas != null && oldPlayerMenu == null) { var playerMenu = PrefabService.SINGLETON.Instance("UI/PlayerMenu", canvas.transform); var invMen = playerMenu.transform.GetChild(1).transform.GetChild(0).GetComponent<InventoryPanel>(); var statMen = playerMenu.transform.GetChild(1).transform.GetChild(1).GetComponent<StatPanel>(); invMen.player = this; statMen.player = this; } } // Code for opening control scheme if (Input.GetKeyDown(KeyCode.L)) { GameObject canvas = GameObject.Find("Canvas"); GameObject oldControlScheme = GameObject.Find("ControlScheme(Clone)"); if (canvas != null && oldControlScheme == null) { var controlScheme = PrefabService.SINGLETON.Instance("UI/ControlScheme", canvas.transform); } } } /* Updates the modifiers to the character's stats. */ public override void UpdateModifiers(ICharacterStats modifiers = null) { base.UpdateModifiers(modifiers); utilBar?.WithMana(maxValue: (int)Stats.MaxMana) ?.WithStamina(maxValue: (int)Stats.MaxStamina); } /* Regenerates mana and stamina. */ protected override void Regenerate() { base.Regenerate(); utilBar?.WithMana(value: (int)Mana) ?.WithStamina(value: (int)Stamina); } private bool TryMove_OLD(Vector2 direction) { if(direction != Vector2.zero) { // Check for potential collisions int count = rb.Cast( direction, // X and Y values between -1 and 1 that represent the direction from the body to look for collisions movementFilter, // The settings that determine where a collision can occur on such as layers to collide with castCollisions, // List of collisions to store the found collisions into after the Cast is finished (float) MovementSpeed * Time.fixedDeltaTime + collisionOffset); // The amount to cast equal to the movement plus an offset if(count == 0){ rb.MovePosition(rb.position + direction * (float) MovementSpeed * Time.fixedDeltaTime); return true; } else { return false; } } else { // Can't move if there's no direction to move in return false; } // } void OnMove(InputValue movementValue) { movementInput = movementValue.Get<Vector2>(); } public void LockMovement() { canMove = false; } public void UnlockMovement() { canMove = true; } /* Method for what to do when the character takes damage. */ protected override void AfterDamage(IAttackStats attack) { base.AfterDamage(attack); utilBar?.WithHealth(Convert.ToInt32(HP)); } public void GainXp(float xp) { GiveXp(xp * XP_SCALE_RATE); CheckXp(); utilBar?.WithXP((int)this.xp); } /* Checks for, and handles, level-ups. */ private void CheckXp() { // If the character has leveled up. if(xp > maxXp) { level += 1; xp -= maxXp; maxXp = (level + 1) * 100; utilBar?.WithXP(maxValue: (int)maxXp); SkillPoints += SKILL_POINTS_PR_LVL; } /* To-do: - Maybe not flat skill points pr level. - Scale differently. (Separate function for getting xp requirement pr level) */ } public void OnDestroy() { Time.timeScale = 0; GameObject canvas = GameObject.Find("Canvas"); if (canvas != null) { PrefabService.SINGLETON.Instance("UI/EndScreen", canvas.transform); } } } /* Skills related code. */ public partial class PlayerController { /* The number of skill points the user has at their disposal. */ public int SkillPoints { get; set; } = SKILL_POINTS_START; /* The amount of points the user has currently spent on each skill. */ public Skills Skills { get; set; } = new Skills(); /* The maximum amount of points the user can spend on each skill. */ public Skills MaxSkills { get; set; } = new Skills{ HP = 10, SP = 10, MP = 10, Damage = 10, Speed = 10, Luck = 10, Concentration = 10, }; /* How much a stat will increas each skill point. */ public CharacterStats StatIncreasePrSkillLevel { get; protected set; } = new CharacterStats { //HP MaxHP = 3f, // MP MaxMana = 2f, RegenMana = 0.1f, // SP MaxStamina = 2f, RegenStamina = 0.1f, // Damage Damage = 0.1f, Knockback = 0.1f, // Speed MoveSpeed = 0.1f, AttackSpeed = 0.1f, // Luck CritChance = 0.05f, CritDamageModifier = 0.1f, // Concentration Range = 0.1f, ProjectileSpeed = 0.1f, //-- Accuracy Accuracy = 0.1f, }; } }