using System; using System.Collections; using System.Collections.Generic; using PlayerInput; using UnityEngine; [SelectionBase] public class PlayerController : MonoBehaviour { public float Speed = 5; public float Gravity = 7; public enum State { Walking, Raking } private State state = State.Walking; private CharacterController charC; private AnimationHandler anim; // Use this for initialization void Start () { charC = GetComponent<CharacterController>(); anim = GetComponent<AnimationHandler>(); rakeTimer = new SimpleTimer(); rakeBackTween = new SimpleTween(); oldPos = transform.position; } private float velY = 0; public float RunCycleTime = 0.8f; public float RunFrameTime = 0.3f; public float RunFrameSpeedBoost = 1.4f; private float runCycle = 0.0f; public float PushRadius = 0.6f; public float PushForce = 300.0f; public float PushPower = 2.0f; private float rakeTime = 0.0f; public float TimeToPushRake = 0.3f; private SimpleTimer rakeTimer; private Vector3 rakeDir = new Vector2(); private Vector3 oldPos = new Vector3(); // Update is called once per frame void Update () { Vector3 dir = new Vector3(); if (input != null) { if (charC.isGrounded && state == State.Walking) { dir.x = input.Axis(InputSource<PlayerController>.InputAxis.MoveX); dir.z = input.Axis(InputSource<PlayerController>.InputAxis.MoveY); if (dir.magnitude > 0.3f) { dir.Normalize(); float speed = Speed; if (runCycle < RunFrameTime) { speed *= RunFrameSpeedBoost; } dir *= speed; float angle = Mathf.Atan2(dir.z, dir.x); if (angle < 0) angle += Mathf.PI * 2; if (angle < Mathf.PI / 2.0f) anim.SetDir(AnimationHandler.Direction.UpRight); if (angle < Mathf.PI && angle >= Mathf.PI / 2.0f) anim.SetDir(AnimationHandler.Direction.UpLeft); if (angle < Mathf.PI * 3.0f / 2.0f && angle >= Mathf.PI) anim.SetDir(AnimationHandler.Direction.DownLeft); if (angle >= Mathf.PI * 3.0f / 2.0f) anim.SetDir(AnimationHandler.Direction.DownRight); //Debug.Log("ANGLE: " + angle); runCycle += Time.deltaTime; while (runCycle >= RunCycleTime) { runCycle -= RunCycleTime; } int frame = runCycle < RunFrameTime ? 1 : 0; anim.SetFrame(frame); } else { dir.x = 0; dir.z = 0; anim.SetFrame(0); runCycle = 0.0f; } } } if (state == State.Walking) { dir.y = velY; velY -= Gravity * Time.deltaTime; gameObject.layer = LayerMask.NameToLayer("player_controller_no_collide"); charC.Move(dir * Time.deltaTime); gameObject.layer = LayerMask.NameToLayer("player_controller"); if (charC.isGrounded) { velY = 0; } } Vector3 moved = transform.position - oldPos; if (moved.magnitude > 0.7f * Time.deltaTime) { int layer = LayerMask.GetMask("leaf"); foreach (Collider c in Physics.OverlapSphere(transform.position, PushRadius, layer)) { LeafPhysics leaf = c.GetComponentInParent<LeafPhysics>(); if (leaf != null) { Vector3 toLeaf = leaf.transform.position - transform.position; float dist = toLeaf.magnitude; float power = Mathf.Pow(1.0f - dist / PushRadius, PushPower) * Time.deltaTime * PushForce; //toLeaf.Normalize(); toLeaf.y += UnityEngine.Random.Range(0.4f, 1.0f); leaf.Body.AddForce(toLeaf * (9.0f + UnityEngine.Random.Range(0, 9.0f)) * power * Time.deltaTime * 60); } } } if (state == State.Walking) { rakeDir = new Vector3(input.Axis(InputSource<PlayerController>.InputAxis.RakeX), 0, input.Axis(InputSource<PlayerController>.InputAxis.RakeY)); if (rakeDir.magnitude < 0.2f) { rakeTime = 0; } else { if (rakeTime >= 0) { rakeTime += Time.deltaTime; } } if (rakeTime >= 0 && rakeDir.magnitude > 0.7f && rakeTime < TimeToPushRake) { state = State.Raking; float angle = Mathf.Atan2(-rakeDir.z, -rakeDir.x); if (angle < 0) angle += Mathf.PI * 2; AnimationHandler.Direction rakeAnimDir = AnimationHandler.Direction.UpRight; if (angle < Mathf.PI / 2.0f) rakeAnimDir = AnimationHandler.Direction.UpRight; if (angle < Mathf.PI && angle >= Mathf.PI / 2.0f) rakeAnimDir = AnimationHandler.Direction.UpLeft; if (angle < Mathf.PI * 3.0f / 2.0f && angle >= Mathf.PI) rakeAnimDir = AnimationHandler.Direction.DownLeft; if (angle >= Mathf.PI * 3.0f / 2.0f) rakeAnimDir = AnimationHandler.Direction.DownRight; rakeTime = -1; anim.SetState("Rake", rakeAnimDir, 0); rakeTimer.Start(0.15f, Rake); } } oldPos = transform.position; } public float RakeBackDist = 0.8f; public float RakeBackTime = 0.2f; private SimpleTween rakeBackTween; private Vector3 rakeBackStart = new Vector3(); private Vector3 rakeBackEnd = new Vector3(); public float RakeReachDist = 0.6f; public float RakeReachRadius = 0.6f; public float RakeFlyForce = 100; private void Rake() { Vector3 rakeMove = rakeDir * RakeBackDist; rakeBackStart = transform.position; charC.Move(rakeMove); rakeBackEnd = transform.position; transform.position = rakeBackStart; rakeBackTween.Init(UpdateRakeBack, SimpleTween.QuadEaseInOut, 0, 1, RakeBackTime); rakeBackTween.OnFinish = FinishedRake; List<LeafPhysics> leafs = new List<LeafPhysics>(); int layer = LayerMask.GetMask("leaf"); foreach (Collider col in Physics.OverlapSphere(rakeBackStart - rakeDir * RakeReachDist, RakeReachRadius, layer)) { LeafPhysics leaf = col.GetComponentInParent<LeafPhysics>(); if (leaf != null) { leafs.Add(leaf); } } foreach (LeafPhysics leaf in leafs) { float rand = UnityEngine.Random.Range(0, 1); Vector3 startPos = leaf.transform.position; float dist = Vector3.Dot(startPos - transform.position, -rakeDir); dist += UnityEngine.Random.Range(-0.1f, 0.1f); Vector3 pull = rakeDir * dist; if (rand < 0.8f) { // pull the leaf back, and then destroy leaf.Body.isKinematic = true; pull.x += UnityEngine.Random.Range(-0.05f, 0.05f); pull.z += UnityEngine.Random.Range(-0.05f, 0.05f); float pullTime = RakeBackTime + UnityEngine.Random.Range(-0.04f, 0.04f); SimpleTween tween = new SimpleTween(v => { leaf.transform.position = startPos + pull * v; }, SimpleTween.TweenType.EaseLinear, 0, 1, pullTime); tween.OnFinish = () => { GameObject.Destroy(leaf.gameObject); }; } else { pull.Normalize(); pull = Quaternion.Euler(UnityEngine.Random.Range(-30, 30), UnityEngine.Random.Range(-30, 30), UnityEngine.Random.Range(-30, 30)) * pull; pull.y += 0.3f; leaf.Body.AddForce(pull * RakeFlyForce, ForceMode.Impulse); } } } private void FinishedRake() { state = State.Walking; anim.SetState("Stand", anim.Dir, anim.Frame); } private void UpdateRakeBack(float val) { Vector3 pos = transform.position; pos.x = rakeBackStart.x * (1 - val) + rakeBackEnd.x * val; pos.z = rakeBackStart.z * (1 - val) + rakeBackEnd.z * val; transform.position = pos; } private InputSource<PlayerController> input = null; private InputManager.PlayerInfo playerInfo; public void SetInput(InputSource<PlayerController> newPlayerInput, InputManager.PlayerInfo playerInfo) { this.input = newPlayerInput; this.playerInfo = playerInfo; } }