commit 645272872c81cccf6700fd5424d94e2086d34dbf Author: Kayne Ruse Date: Fri Mar 8 09:54:14 2019 +1100 Open-sourced some code diff --git a/Last Ember - ab8f4ff.rar b/Last Ember - ab8f4ff.rar new file mode 100644 index 0000000..9d0606d Binary files /dev/null and b/Last Ember - ab8f4ff.rar differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..8107057 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# Last Ember - Open Source + +In this repository are the parts of the game Last Ember that I created myself. This includes the C# scripts, and a few placeholder sprites. Everything else is too tied up to release as open source. + +This game was written in C# for Unity 2018.3.0f2. + +I've included a build of the game that shows off almost everything created so far. + +You can run by double-tapping a direction, jump, wall jump, look up and crouch. There were going to be other moves, but we didn't get around to implementing them. + +## Libraries and Tools Used + +* Carbon Input - https://assetstore.unity.com/packages/tools/input-management/unified-input-manager-56980 +* SpriterDotNet - https://github.com/loodakrawa/SpriterDotNet + +## Credits + +* Kayne Ruse - Programming, Management +* Evan Hartshorn - Art, Game Design +* Shy Monster (Luis Paez, Hayden Blades) - Audio, Music + +Special thanks to Feldi - sorry we didn't get to work with you! + +## $5 Patrons + +* Seth Robinson + +## Contact + +If you have any questions, you're welcome to ask here: + +kayneruse@gmail.com + +https://discord.gg/FQmz8TN + +## Copyright + +Copyright (c) 2019 KR Game Studios + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/Scripts/Game Objects/AudioController.cs b/Scripts/Game Objects/AudioController.cs new file mode 100644 index 0000000..ce0c708 --- /dev/null +++ b/Scripts/Game Objects/AudioController.cs @@ -0,0 +1,212 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class AudioController : MonoBehaviour { + //public structures + public enum Mode { + NONE, + ONCE, + LOOP, + JUMP + } + + public struct AudioContainer { + public AudioSource source; + public Mode mode; + public float jumpStart; + public float jumpEnd; + } + + //internals + Dictionary audioDictionary = new Dictionary(); + static bool initialized = false; + + //monobehaviour methods + void Start() { + if (initialized) { + Destroy(gameObject); + } + + initialized = true; + + DontDestroyOnLoad(gameObject); + } + + void Update() { + foreach(KeyValuePair iter in audioDictionary) { + //handle the jump points + if (iter.Value.mode == Mode.JUMP && iter.Value.jumpStart >= 0f && iter.Value.jumpEnd > 0f) { + if (iter.Value.source.time >= iter.Value.jumpEnd) { + iter.Value.source.time = iter.Value.jumpStart; + } + } + } + } + + void OnDestroy() { + foreach(KeyValuePair iter in audioDictionary) { + Resources.UnloadAsset(iter.Value.source.clip); + Destroy(iter.Value.source); + } + } + + //public access members + public void Load(string name, string filename) { + AudioContainer container = new AudioContainer(); + + container.source = gameObject.AddComponent(typeof(AudioSource)) as AudioSource; + container.source.clip = Resources.Load(filename) as AudioClip; + container.source.volume = 0f; + container.mode = Mode.NONE; + + audioDictionary[name] = container; + } + + public bool Unload(string name) { + if (!audioDictionary.ContainsKey(name)) { + return false; + } + + AudioContainer container = audioDictionary[name]; + + Resources.UnloadAsset(container.source.clip); + Destroy(container.source); + + audioDictionary.Remove(name); + return true; + } + + //controls + public void Play(string name, Mode mode = Mode.ONCE, float jumpStart = -1f, float jumpEnd = -1f) { + AudioContainer container = audioDictionary[name]; + + container.source.Play(); + container.source.loop = mode == Mode.LOOP; + container.source.volume = 1f; + container.mode = mode; + container.jumpStart = jumpStart; + container.jumpEnd = jumpEnd; + audioDictionary[name] = container; + } + + public void Pause(string name) { + AudioContainer container = audioDictionary[name]; + + container.source.Pause(); + } + + public void Unpause(string name, Mode mode = Mode.ONCE, float jumpStart = -1f, float jumpEnd = -1f) { + AudioContainer container = audioDictionary[name]; + + if (container.source.isPlaying) { + container.source.UnPause(); + } else { + Play(name, mode, jumpStart, jumpEnd); + } + } + + public void Stop(string name) { + AudioContainer container = audioDictionary[name]; + + container.source.Stop(); + container.mode = Mode.NONE; + + audioDictionary[name] = container; + } + + public void StopAll() { + List names = new List(); + foreach(KeyValuePair iter in audioDictionary) { + names.Add(iter.Key); + } + + foreach(string name in names) { + Stop(name); + } + } + + //fade controls + public void FadeIn(string name, float seconds) { + StartCoroutine(FadeInCallback(audioDictionary[name].source, 1f/seconds)); + } + + IEnumerator FadeInCallback(AudioSource source, float amountPerSecond) { + source.volume = 0; + while (source.volume < 1f) { + yield return new WaitForSeconds(0.1f); + source.volume += amountPerSecond / 10f; + } + } + + public void FadeOut(string name, float seconds) { + StartCoroutine(FadeOutCallback(audioDictionary[name].source, 1f/seconds)); + } + + IEnumerator FadeOutCallback(AudioSource source, float amountPerSecond) { + while (source.volume > 0f) { + yield return new WaitForSeconds(0.1f); + source.volume -= amountPerSecond / 10f; + } + } + + //hybrid controls + public void PlayFadeIn(string name, float seconds, Mode mode = Mode.ONCE, float jumpStart = -1f, float jumpEnd = -1f) { + FadeIn(name, seconds); + Play(name, mode, jumpStart, jumpEnd); + } + + public void PauseFadeOut(string name, float seconds) { + FadeOut(name, seconds); + StartCoroutine(PauseFadeOutCallback(name, seconds)); + } + + public void PauseFadeOutAll(float seconds, List exclude = null) { + foreach(KeyValuePair iter in audioDictionary) { + if (exclude != null && exclude.Contains(iter.Key)) { + continue; + } + FadeOut(iter.Key, seconds); + StartCoroutine(PauseFadeOutCallback(iter.Key, seconds)); + } + } + + IEnumerator PauseFadeOutCallback(string name, float seconds) { + yield return new WaitForSeconds(seconds); + Pause(name); + } + + public void UnpauseFadeIn(string name, float seconds, Mode mode = Mode.ONCE, float jumpStart = -1f, float jumpEnd = -1f) { + Unpause(name, mode, jumpStart, jumpEnd); + FadeIn(name, seconds); + } + + public void StopFadeOut(string name, float seconds) { + FadeOut(name, seconds); + StartCoroutine(StopFadeOutCallback(name, seconds)); + } + + public void StopFadeOutAll(float seconds, List exclude = null) { + foreach(KeyValuePair iter in audioDictionary) { + if (exclude != null && exclude.Contains(iter.Key)) { + continue; + } + FadeOut(iter.Key, seconds); + StartCoroutine(StopFadeOutCallback(iter.Key, seconds)); + } + } + + IEnumerator StopFadeOutCallback(string name, float seconds) { + yield return new WaitForSeconds(seconds); + Stop(name); + } + + //status + public bool GetPlaying(string name) { + return audioDictionary[name].source.isPlaying; + } + + public Mode GetMode(string name) { + return audioDictionary[name].mode; + } +} diff --git a/Scripts/Game Objects/CameraController.cs b/Scripts/Game Objects/CameraController.cs new file mode 100644 index 0000000..8999e25 --- /dev/null +++ b/Scripts/Game Objects/CameraController.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class CameraController : MonoBehaviour { + //public access members + public GameObject targetObject; + public Vector3 offset; + public float lerpSpeed = 2f; + + Vector2 peek = new Vector2(0, 0); + + //private members + Vector3 virtualLocation; + + void Start() { + virtualLocation = transform.position; + } + + void Update() { + //only continue if the target has been set + if (targetObject == null) { + return; + } + + //cache the position we want to move to + Vector3 targetPosition = targetObject.transform.position + offset + new Vector3(peek.x, peek.y, 0f); + + //If the distance is small, short circuit the lerp, so we don't have sudden pops in camera motion. + if ((targetPosition - virtualLocation).sqrMagnitude > 0.01f) { + //Interpolate to the target location. + virtualLocation = Vector3.Lerp(virtualLocation, targetPosition, lerpSpeed * Time.deltaTime); + + //Snap to pixel coordinates + Vector3 snapped = virtualLocation; + + snapped.x = Mathf.Round(snapped.x * 100) / 100; + snapped.y = Mathf.Round(snapped.y * 100) / 100; + + snapped.z = transform.position.z; //BUGFIX + + transform.position = snapped; + } + } + + public Vector2 GetPeek() { + return peek; + } + + public void SetPeek(Vector2 newPeek, float delay = 0.5f) { + peek = new Vector2(0f, 0f); + StartCoroutine(SetPeekAfter(delay, newPeek)); //NOTE: a delay to peeking, for smooth gameplay + } + + IEnumerator SetPeekAfter(float delay, Vector2 addition) { + yield return new WaitForSeconds(delay); + peek = addition; + } + + public void ResetPeek() { + peek = new Vector2(0, 0); + } +} \ No newline at end of file diff --git a/Scripts/Game Objects/Creatures/Cockatoo/CockatooController.cs b/Scripts/Game Objects/Creatures/Cockatoo/CockatooController.cs new file mode 100644 index 0000000..7a56a4c --- /dev/null +++ b/Scripts/Game Objects/Creatures/Cockatoo/CockatooController.cs @@ -0,0 +1,178 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Creatures { + public class CockatooController : MonoBehaviour, ICreature { + //public access members + public GameObject projectilePrefab; + + //components + Rigidbody2D rigidBody; + + //gameplay + const float moveForce = 10f; + const float maxSpeed = 2.5f; + + int _horizontalMoveDirection; + public int HorizontalMoveDirection { + get { + return _horizontalMoveDirection; + } + set { + _horizontalMoveDirection = value; + if (_horizontalMoveDirection >= 0) { + transform.localScale = new Vector2(Mathf.Abs(transform.localScale.x), Mathf.Abs(transform.localScale.y)); + } else { + transform.localScale = new Vector2(-Mathf.Abs(transform.localScale.x), Mathf.Abs(transform.localScale.y)); + } + } + } + + public int VerticalMoveDirection { get; set; } + public int DamageValue { get; set; } + + int _healthValue; + public int HealthValue { + get { + return _healthValue; + } + set { + _healthValue = value; + if (_healthValue <= 0) { + Destroy(gameObject); + } + } + } + + //internals + float initialPositionY; + + bool detectedPlayer; + float detectionDistance = 4f; + float lastDetection = float.NegativeInfinity; + float detectionDelay = 2f; + + void Awake() { + rigidBody = GetComponent(); + + HorizontalMoveDirection = -1; + VerticalMoveDirection = 0; + + HealthValue = 1; + DamageValue = 1; + + initialPositionY = rigidBody.position.y; + + rigidBody.position = new Vector2(rigidBody.position.x, rigidBody.position.y + 0.5f); + + StartCoroutine(BigFlap(5f)); + } + + void FixedUpdate() { + HandleDetection(); + HandleVerticalMoveDirection(); + HandleMovement(); + } + + void OnCollisionEnter2D(Collision2D collision) { + Vector2 normal = collision.GetContact(0).normal; + + if (collision.gameObject.tag == "Monster") { + //turn around + if (SameSign(collision.gameObject.GetComponent().HorizontalMoveDirection, HorizontalMoveDirection) || collision.gameObject.GetComponent().HorizontalMoveDirection == 0) { + rigidBody.velocity = new Vector2(0f, rigidBody.velocity.y); + HorizontalMoveDirection = -HorizontalMoveDirection; + } + } + + //collision with the player (when the player is not bouncing) + if (collision.gameObject.tag == "Player" && normal != Vector2.down) { + //turn around + rigidBody.velocity = new Vector2(0f, rigidBody.velocity.y); + HorizontalMoveDirection = -HorizontalMoveDirection; + } + } + + void HandleDetection() { + bool detectedPlayer = Physics2D.Linecast(transform.position, transform.position + new Vector3((transform.localScale.x > 0 ? 1 : -1) * detectionDistance, -detectionDistance, 0), 1 << LayerMask.NameToLayer("Player")); + + if (detectedPlayer && Time.time - lastDetection > detectionDelay) { + lastDetection = Time.time; + + GameObject go = Instantiate(projectilePrefab, transform.position, Quaternion.identity); + + go.GetComponent().HorizontalMoveDirection = HorizontalMoveDirection; + go.GetComponent().VerticalMoveDirection = -1; + go.GetComponent().DamageValue = DamageValue; + } + } + + void HandleVerticalMoveDirection() { + if (rigidBody.position.y >= initialPositionY) { + VerticalMoveDirection = -1; + } else if (rigidBody.position.y < initialPositionY) { + VerticalMoveDirection = 1; + } + } + + void HandleMovement() { + //turn around if stopped + if (Mathf.Abs(rigidBody.velocity.x) < 0.1f) { + StartCoroutine(SetDirectionIfNotMovingAfter(-HorizontalMoveDirection, 0.1f)); + } + + //move the entity in this direction, if not at max speed + if (Mathf.Abs(rigidBody.velocity.x) < maxSpeed) { + rigidBody.AddForce(Vector2.right * HorizontalMoveDirection * moveForce); + } + + //move the entity in the correct direction vertically + if (rigidBody.velocity.y * VerticalMoveDirection < maxSpeed) { + rigidBody.AddForce(Vector2.up * VerticalMoveDirection * moveForce); + } + + //slow the entity down when it's travelling too fast + if (Mathf.Abs (rigidBody.velocity.x) > maxSpeed) { + rigidBody.velocity = new Vector2 (Mathf.Sign (rigidBody.velocity.x) * maxSpeed, rigidBody.velocity.y); + } + + if (Mathf.Abs (rigidBody.velocity.y) > maxSpeed) { + rigidBody.velocity = new Vector2 (rigidBody.velocity.x, Mathf.Sign (rigidBody.velocity.y) * maxSpeed); + } + } + + //utilities + IEnumerator SetDirectionIfNotMovingAfter(int direction, float delay) { + yield return new WaitForSeconds(delay); + //turn around if stopped + if (Mathf.Abs(rigidBody.velocity.x) < 0.1f) { + HorizontalMoveDirection = direction; + } + } + + //BUGFIX + IEnumerator BigFlap(float delay) { + while (true) { + yield return new WaitForSeconds(delay); + rigidBody.AddForce(Vector2.up * VerticalMoveDirection * moveForce * 5f); + } + } + + void OnDrawGizmos() { + Gizmos.color = Color.red; + Gizmos.DrawLine(transform.position, transform.position + new Vector3((transform.localScale.x > 0 ? 1 : -1) * detectionDistance, -detectionDistance, 0)); + } + + bool SameSign(float num1, float num2) { + if (num1 > 0 && num2 > 0) { + return true; + } + if (num1 < 0 && num2 < 0) { + return true; + } + //if either is zero, return false + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Game Objects/Creatures/Cockatoo/CockatooProjectileController.cs b/Scripts/Game Objects/Creatures/Cockatoo/CockatooProjectileController.cs new file mode 100644 index 0000000..c2b485e --- /dev/null +++ b/Scripts/Game Objects/Creatures/Cockatoo/CockatooProjectileController.cs @@ -0,0 +1,60 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Creatures { + public class CockatooProjectileController : MonoBehaviour { + //public access members + public int HorizontalMoveDirection { get; set; } + public int VerticalMoveDirection { get; set; } + public int DamageValue { get; set; } + + //internal members + Rigidbody2D rigidBody; + const float moveForce = 10f; + const float maxSpeed = 5f; + + DamagerController damagerController; + + void Start() { + rigidBody = GetComponent(); + + damagerController = GetComponent(); + + damagerController.PushOnTriggerEnter((Collider2D collider) => { + if (collider.gameObject.tag == "Player") { + collider.gameObject.GetComponent().HealthValue -= DamageValue; + } + + Destroy(gameObject); + }); + } + + void FixedUpdate() { + HandleMovement(); + + //handle grapphics + transform.localScale = new Vector2(Mathf.Abs(transform.localScale.x) * HorizontalMoveDirection, transform.localScale.y); + } + + void HandleMovement() { + //move the entity in this direction, if not at max speed + if (Mathf.Abs(rigidBody.velocity.x) < maxSpeed) { + rigidBody.AddForce(Vector2.right * HorizontalMoveDirection * moveForce); + } + + if (Mathf.Abs(rigidBody.velocity.y) < maxSpeed) { + rigidBody.AddForce(Vector2.up * VerticalMoveDirection * moveForce); + } + + //slow the entity down when it's travelling too fast + if (Mathf.Abs (rigidBody.velocity.x) > maxSpeed) { + rigidBody.velocity = new Vector2 (Mathf.Sign (rigidBody.velocity.x) * maxSpeed, rigidBody.velocity.y); + } + + if (Mathf.Abs (rigidBody.velocity.y) > maxSpeed) { + rigidBody.velocity = new Vector2 (rigidBody.velocity.x, Mathf.Sign (rigidBody.velocity.y) * maxSpeed); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Game Objects/Creatures/ICreature.cs b/Scripts/Game Objects/Creatures/ICreature.cs new file mode 100644 index 0000000..f318a10 --- /dev/null +++ b/Scripts/Game Objects/Creatures/ICreature.cs @@ -0,0 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Creatures { + public interface ICreature { + //flags used to control other monsters + int HorizontalMoveDirection { get; set; } + int VerticalMoveDirection { get; set; } + + //used by the combad system + int DamageValue { get; set; } + int HealthValue { get; set; } + } +} \ No newline at end of file diff --git a/Scripts/Game Objects/Creatures/Kuribo/KuriboController.cs b/Scripts/Game Objects/Creatures/Kuribo/KuriboController.cs new file mode 100644 index 0000000..64e078f --- /dev/null +++ b/Scripts/Game Objects/Creatures/Kuribo/KuriboController.cs @@ -0,0 +1,127 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Creatures { + public class KuriboController : MonoBehaviour, ICreature { + //components + Rigidbody2D rigidBody; + + //gameplay + const float moveForce = 10f; + const float maxSpeed = 2.5f; + + public int HorizontalMoveDirection { get; set; } + public int VerticalMoveDirection { get; set; } + public int DamageValue { get; set; } + + int _healthValue; + public int HealthValue { + get { + return _healthValue; + } + set { + _healthValue = value; + if (_healthValue <= 0) { + Destroy(gameObject); + } + } + } + + //internals + DamagerController damagerController; + + void Awake() { + rigidBody = GetComponent(); + + HorizontalMoveDirection = -1; + VerticalMoveDirection = 0; + + HealthValue = 1; + DamageValue = 1; + } + + void Start() { + damagerController = GetComponentInChildren(); + + damagerController.PushOnTriggerEnter((Collider2D collider) => { + if (collider.gameObject.tag == "Player") { + //deal damage to the player + collider.gameObject.GetComponent().HealthValue -= DamageValue; + + //NOTE: not every damager will deal damage + } + }); + } + + void FixedUpdate() { + HandleMovement(); + } + + void OnCollisionEnter2D(Collision2D collision) { + //handle bouncing on a monster + Vector2 normal = collision.GetContact(0).normal; + + if (collision.gameObject.tag == "Monster") { + if (normal == Vector2.up) { + //bounce + rigidBody.AddForce(new Vector2(0f, 480f)); + } else { + //turn around + if (SameSign(collision.gameObject.GetComponent().HorizontalMoveDirection, HorizontalMoveDirection) || collision.gameObject.GetComponent().HorizontalMoveDirection == 0) { + rigidBody.velocity = new Vector2(0f, rigidBody.velocity.y); + HorizontalMoveDirection = -HorizontalMoveDirection; + } + } + } + + //collision with the player (when the player is not bouncing) + if (collision.gameObject.tag == "Player" && normal != Vector2.down) { + //turn around + rigidBody.velocity = new Vector2(0f, rigidBody.velocity.y); + HorizontalMoveDirection = -HorizontalMoveDirection; + } + } + + void HandleMovement() { + //turn around if stopped + if (Mathf.Abs(rigidBody.velocity.x) < 0.1f) { + StartCoroutine(SetDirectionIfNotMovingAfter(-HorizontalMoveDirection, 0.1f)); + } + + //move the entity in this direction, if not at max speed + if (Mathf.Abs(rigidBody.velocity.x) < maxSpeed) { + rigidBody.AddForce(Vector2.right * HorizontalMoveDirection * moveForce); + } + + //slow the entity down when it's travelling too fast + if (Mathf.Abs (rigidBody.velocity.x) > maxSpeed) { + rigidBody.velocity = new Vector2 (Mathf.Sign (rigidBody.velocity.x) * maxSpeed, rigidBody.velocity.y); + } + + if (Mathf.Abs (rigidBody.velocity.y) > maxSpeed) { + rigidBody.velocity = new Vector2 (rigidBody.velocity.x, Mathf.Sign (rigidBody.velocity.y) * maxSpeed); + } + } + + //utilities + IEnumerator SetDirectionIfNotMovingAfter(int direction, float delay) { + yield return new WaitForSeconds(delay); + //turn around if stopped + if (Mathf.Abs(rigidBody.velocity.x) < 0.1f) { + HorizontalMoveDirection = direction; + } + } + + bool SameSign(float num1, float num2) { + if (num1 > 0 && num2 > 0) { + return true; + } + if (num1 < 0 && num2 < 0) { + return true; + } + //if either is zero, return false + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Game Objects/Creatures/Wolf/WolfController.cs b/Scripts/Game Objects/Creatures/Wolf/WolfController.cs new file mode 100644 index 0000000..15ce8d6 --- /dev/null +++ b/Scripts/Game Objects/Creatures/Wolf/WolfController.cs @@ -0,0 +1,173 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Creatures { + public class WolfController : MonoBehaviour, ICreature { + //components + SpriteRenderer spriteRenderer; + Rigidbody2D rigidBody; + + //gameplay + const float moveForce = 10f; + const float walkSpeed = 2.5f; + const float runSpeed = 5f; + float maxSpeed; + + int _horizontalMoveDirection; + public int HorizontalMoveDirection { + get { + return _horizontalMoveDirection; + } + set { + _horizontalMoveDirection = value; + if (_horizontalMoveDirection >= 0) { + transform.localScale = new Vector2(Mathf.Abs(transform.localScale.x), Mathf.Abs(transform.localScale.y)); + } else { + transform.localScale = new Vector2(-Mathf.Abs(transform.localScale.x), Mathf.Abs(transform.localScale.y)); + } + } + } + + public int VerticalMoveDirection { get; set; } + public int DamageValue { get; set; } + + int _healthValue; + public int HealthValue { + get { + return _healthValue; + } + set { //TODO: flash red + _healthValue = value; + if (_healthValue <= 0) { + Destroy(gameObject); + } + } + } + + //internals + DamagerController damagerController; + + bool detectedPlayer = false; + float detectionDistance = 10f; + + void Awake() { + spriteRenderer = GetComponent(); + rigidBody = GetComponent(); + + HorizontalMoveDirection = 1; + VerticalMoveDirection = 0; + + HealthValue = 1; + DamageValue = 1; + } + + void Start() { + damagerController = GetComponentInChildren(); + + damagerController.PushOnTriggerEnter((Collider2D collider) => { + if (collider.gameObject.tag == "Player") { + //deal damage to the player + collider.gameObject.GetComponent().HealthValue -= DamageValue; + + //flip direction after a bite + HorizontalMoveDirection = -HorizontalMoveDirection; + + //NOTE: not every damager will deal damage + } + }); + + damagerController.gameObject.SetActive(false); + } + + void FixedUpdate() { + HandleDetection(); + HandleMovement(); + } + + void OnCollisionEnter2D(Collision2D collision) { + //handle bouncing on a monster + Vector2 normal = collision.GetContact(0).normal; + + if (collision.gameObject.tag == "Monster") { + if (normal == Vector2.up) { + //bounce + rigidBody.AddForce(new Vector2(0f, 480f)); + } else { + //turn around + if (SameSign(collision.gameObject.GetComponent().HorizontalMoveDirection, HorizontalMoveDirection) || collision.gameObject.GetComponent().HorizontalMoveDirection == 0) { + rigidBody.velocity = new Vector2(0f, rigidBody.velocity.y); + HorizontalMoveDirection = -HorizontalMoveDirection; + } + } + } + + //collision with the player (when the player is not bouncing) + if (collision.gameObject.tag == "Player" && normal != Vector2.down) { + //turn around + rigidBody.velocity = new Vector2(0f, rigidBody.velocity.y); + HorizontalMoveDirection = -HorizontalMoveDirection; + } + } + + void HandleDetection() { + detectedPlayer = Physics2D.Linecast(transform.position, transform.position + new Vector3(transform.localScale.x * detectionDistance, 0, 0), 1 << LayerMask.NameToLayer("Player")); + + if (detectedPlayer) { + maxSpeed = runSpeed; + spriteRenderer.color = Color.red; + damagerController.gameObject.SetActive(true); + } else { //no see the play + maxSpeed = walkSpeed; + spriteRenderer.color = Color.white; + damagerController.gameObject.SetActive(false); + } + } + + void HandleMovement() { + //turn around if stopped + if (Mathf.Abs(rigidBody.velocity.x) < 0.1f) { + StartCoroutine(SetDirectionIfNotMovingAfter(-HorizontalMoveDirection, 0.1f)); + } + + //move the entity in this direction, if not at max speed + if (Mathf.Abs(rigidBody.velocity.x) < maxSpeed) { + rigidBody.AddForce(Vector2.right * HorizontalMoveDirection * moveForce); + } + + //slow the entity down when it's travelling too fast + if (Mathf.Abs (rigidBody.velocity.x) > maxSpeed) { + rigidBody.velocity = new Vector2 (Mathf.Sign (rigidBody.velocity.x) * maxSpeed, rigidBody.velocity.y); + } + + if (Mathf.Abs (rigidBody.velocity.y) > maxSpeed) { + rigidBody.velocity = new Vector2 (rigidBody.velocity.x, Mathf.Sign (rigidBody.velocity.y) * maxSpeed); + } + } + + //utilities + IEnumerator SetDirectionIfNotMovingAfter(int direction, float delay) { + yield return new WaitForSeconds(delay); + //turn around if stopped + if (Mathf.Abs(rigidBody.velocity.x) < 0.1f) { + HorizontalMoveDirection = direction; + } + } + + void OnDrawGizmos() { + Gizmos.color = Color.red; + Gizmos.DrawLine(transform.position, transform.position + new Vector3(transform.localScale.x * detectionDistance, 0, 0)); + } + + bool SameSign(float num1, float num2) { + if (num1 > 0 && num2 > 0) { + return true; + } + if (num1 < 0 && num2 < 0) { + return true; + } + //if either is zero, return false + return false; + } + } +} diff --git a/Scripts/Game Objects/DamagerController.cs b/Scripts/Game Objects/DamagerController.cs new file mode 100644 index 0000000..850dd09 --- /dev/null +++ b/Scripts/Game Objects/DamagerController.cs @@ -0,0 +1,49 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class DamagerController : MonoBehaviour { + public delegate void CallbackHandler(Collider2D collider); + + List onTriggerEnter = new List(); + List onTriggerStay= new List(); + List onTriggerExit = new List(); + + //public access members + public void PushOnTriggerEnter(CallbackHandler callback) { + onTriggerEnter.Add(callback); + } + + public void PushOnTriggerStay(CallbackHandler callback) { + onTriggerStay.Add(callback); + } + + public void PushOnTriggerExit(CallbackHandler callback) { + onTriggerExit.Add(callback); + } + + public void PurgeLists() { + onTriggerEnter.Clear(); + onTriggerStay.Clear(); + onTriggerExit.Clear(); + } + + //monobehaviour members + void OnTriggerEnter2D(Collider2D collider) { + foreach(CallbackHandler callback in onTriggerEnter) { + callback(collider); + } + } + + void OnTriggerStay2D(Collider2D collider) { + foreach(CallbackHandler callback in onTriggerStay) { + callback(collider); + } + } + + void OnTriggerExit2D(Collider2D collider) { + foreach(CallbackHandler callback in onTriggerExit) { + callback(collider); + } + } +} diff --git a/Scripts/Game Objects/PlayerController.cs b/Scripts/Game Objects/PlayerController.cs new file mode 100644 index 0000000..8524aad --- /dev/null +++ b/Scripts/Game Objects/PlayerController.cs @@ -0,0 +1,715 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using SpriterDotNetUnity; + +public class PlayerController : MonoBehaviour { + //internal components + GameObject spriteObject; + UnityAnimator animator; + Rigidbody2D rigidBody; + BoxCollider2D currentBoxCollider; + + //constants + const float deadZone = 0.25f; + + //gameplay + [Header("Movement Settings")] + public float moveForce = 10f; + public float jumpForce = 400; + public float maxSpeed = 3f; + public float fallSpeed = 8f; + public float dashMultiplier = 2f; + public float straightJumpVerticalMultiplier = 1.1f; + public float straightJumpHorizontalMultiplier = 0.5f; +// public float rollingJumpVerticalMultiplier = 1.0f; +// public float rollingJumpHorizontalMultiplier = 1.0f; + public float jumpMaxSpeedMultiplier = 1.1f; + public float wallJumpMaxSpeedMultiplier = 0.5f; + public float wallHuggedMultiplier = 0.5f; + + //basic movement + float horizontalInput = 0f; + float verticalInput = 0f; + bool jumping = false; + bool grounded = false; + bool wallHugged = false; + bool wallJumping = false; + const float groundedProjection = 0.08f; + + //dashing movement + float dashValue = 0f; + float dashTime = float.NegativeInfinity; + bool dashLatch = true; + + //movement modifiers + float horizontalModifier = 1f; + float verticalModifier = 1f; + float dashModifier = 1f; + float maxSpeedModifier = 1f; + + //combat + DamagerController[] damagerControllers; + HUDCanvas hud; + bool invulnerable = false; + + public int DamageValue { get; set; } + public int HealthValue { + set { + //prevent damage while invulnerable + if (value < hud.FlameLevel && invulnerable) { + return; + } + + //check death + if (value < 0) { + Debug.Log("YOU DIED"); + } + + //trigger hitstun if damage taken + if (value < hud.FlameLevel) { + StartCoroutine(TriggerHitStun(0.8f)); + } + + //set the graphics + hud.FlameLevel = value; + } + get { + return hud.FlameLevel; + } + } + + //graphical modifiers + float prevTimeScale; + float prevLocalScaleX; + + //gameplay + float friction = 0f; + + void Awake() { + rigidBody = GetComponent(); + currentBoxCollider = GetComponent(); + prevTimeScale = Time.timeScale; //BUGFIX: waking when unpaused + prevLocalScaleX = transform.localScale.x; + } + + void Start() { + //BUGFIX: Set the sprite sorting order + GetComponentsInChildren()[0].SortingLayer = "Player"; + + //get the HUD + hud = Object.FindObjectOfType(); + + DamageValue = 1; + HealthValue = 4; + + //get and disable the damagers + damagerControllers = GetComponentsInChildren(); + foreach(DamagerController dmgr in damagerControllers) { + dmgr.gameObject.SetActive(false); + + dmgr.PushOnTriggerEnter((Collider2D collider) => { + if (collider.gameObject.tag == "Monster" && collider.gameObject.GetComponent().HealthValue > 0) { + collider.gameObject.GetComponent().HealthValue -= DamageValue; + hud.SparkLevel++; + + //bounce on attack + Vector2 normal = collider.bounds.ClosestPoint(transform.position) - transform.position; + normal.Normalize(); + + if (normal.y < 0f) { + jumping = true; + } + } + }); + } + } + + void Update() { + if (Time.timeScale > 0f && Time.timeScale == prevTimeScale && HandleAnimation()) { + HandleInput(); + } + prevTimeScale = Time.timeScale; + + //Debug.LogFormat("{0} {1}", animator.CurrentAnimation.Name, currentBoxCollider.size.y); + + //handle gameplay + if (friction >= 1f) { + hud.SparkLevel++; + friction -= 1f; + } + + if (animator.CurrentAnimation.Name != "Run" && animator.CurrentAnimation.Name != "Wall Slide") { + friction = 0f; + } + } + + void FixedUpdate() { + HandleMovement(); + } + + void OnCollisionEnter2D(Collision2D collision) { + //handle bouncing on a monster + Vector2 normal = collision.GetContact(0).normal; + + if (collision.gameObject.tag == "Monster") { + if (normal == Vector2.up) { + //bounce + jumping = true; + } + } + } + + void HandleInput() { + //determine if on the ground (using coyote time) + bool trueGrounded; + trueGrounded = Physics2D.Linecast(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x), -groundedProjection, 0), 1 << LayerMask.NameToLayer("Ground")); + trueGrounded |= Physics2D.Linecast(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x + currentBoxCollider.size.x / 2.1f), -groundedProjection, 0), 1 << LayerMask.NameToLayer("Ground")); + trueGrounded |= Physics2D.Linecast(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x - currentBoxCollider.size.x / 2.1f), -groundedProjection, 0), 1 << LayerMask.NameToLayer("Ground")); + + if (trueGrounded) { + grounded = true; + } else { + StartCoroutine(SetGroundedWithDelay(false, 0.1f)); //coyote physics: 100ms + } + + //determine wall hugging + wallHugged = Physics2D.Linecast(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x + currentBoxCollider.size.x / 2 + groundedProjection), currentBoxCollider.size.y * 0.05f, 0), 1 << LayerMask.NameToLayer("Ground")); + wallHugged &= Physics2D.Linecast(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x + currentBoxCollider.size.x / 2 + groundedProjection), currentBoxCollider.size.y * 0.5f, 0), 1 << LayerMask.NameToLayer("Ground")); + wallHugged &= Physics2D.Linecast(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x + currentBoxCollider.size.x / 2 + groundedProjection), currentBoxCollider.size.y * 0.95f, 0), 1 << LayerMask.NameToLayer("Ground")); + + //reset multipliers under regular conditions + if (trueGrounded && !jumping) { + horizontalModifier = 1f; + verticalModifier = 1f; + maxSpeedModifier = 1f; + } + + //get inputs + verticalInput = GamePad.GetAxis(CAxis.LY); + horizontalInput = GamePad.GetAxis(CAxis.LX); + + //determine vertical input + if (Mathf.Abs(verticalInput) < deadZone) { //no input + verticalInput = 0f; + + //handle stop crouching + if (animator.CurrentAnimation.Name == "Crouch") { + animator.Play("Crouch to Idle"); + } + } else { //yes input + if (verticalInput < 0) { //looking up + if (grounded && animator.CurrentAnimation.Name == "Idle" && Mathf.Abs(horizontalInput) < deadZone) { + animator.Play("Idle to Lookup"); + } + } else { //crouching down + //from rolling jump to crouch + if (grounded && animator.CurrentAnimation.Name == "Rolling Jump") { + animator.Play("Crouch"); + } + else if (grounded && Mathf.Abs(rigidBody.velocity.y) > 0.0001f) { //explicitly don't check for animation here; "Straight Jump Landing" passes through here for some reason + animator.Play("Rolling Jump"); + } + //if not already crouching + else if (grounded && animator.CurrentAnimation.Name != "Crouch" && animator.CurrentAnimation.Name != "Idle to Crouch") { + animator.Play("Idle to Crouch"); + } + } + } + + //determine if walking + if (Mathf.Abs(horizontalInput) < deadZone) { //no input + //reset multipliers under regular conditions + if (grounded && !jumping) { + dashModifier = 1f; + if (animator.CurrentAnimation.Name == "Run") { + animator.Play("Walk"); + } + } + + if (dashLatch) { + //capture the time of last release for dashing + dashTime = Time.time; + dashLatch = false; + } + + //stop walking + horizontalInput = 0f; + if (animator.CurrentAnimation.Name == "Walk") { + //animator.Play("Walk to Idle"); //TODO: enable this + animator.Play("Idle"); //TODO: remove this (why?) + } + } else { //yes input + if (animator.CurrentAnimation.Name == "Crouch") { + //TODO: slides/rolls + + horizontalInput = horizontalInput > 0 ? 0.0001f : -0.0001f; //TMP + } else if (animator.CurrentAnimation.Name == "Lookup") { + animator.Play("Lookup to Idle"); + } else if (wallHugged && !grounded && (animator.CurrentAnimation.Name != "Brace on Wall" && animator.CurrentAnimation.Name != "Wall Slide" && animator.CurrentAnimation.Name != "Wall Kick")) { + animator.Play("Brace on Wall"); + } else { + //check if dashing + if (Time.time - dashTime < 0.2f && SameSign(horizontalInput, dashValue) && grounded && !dashLatch) { + dashModifier = dashMultiplier; + horizontalInput = maxSpeed * dashModifier * (horizontalInput > 0 ? 1 : -1); + animator.Play("Run"); + StartCoroutine(BuildingFriction("Run", 0.05f)); + } + + //capture the value for dashing + dashValue = horizontalInput; + + //BUGFIX + dashLatch = true; + } + + //BUGFIX: landing into a run + if (animator.CurrentAnimation.Name == "Idle" && dashModifier != 1f) { + animator.Play("Run"); + StartCoroutine(BuildingFriction("Run", 0.05f)); + } + + //start walking + if (animator.CurrentAnimation.Name == "Idle") { + animator.Play("Idle to Walk"); + } + + //flip direction + if (Time.timeScale > 0f) { + prevLocalScaleX = transform.localScale.x; + transform.localScale = new Vector3(horizontalInput > 0 ? 1 : -1, 1, 1); + + //play turning animations + if (prevLocalScaleX != transform.localScale.x) { + if (animator.CurrentAnimation.Name == "Idle" || animator.CurrentAnimation.Name == "Idle to Walk" || animator.CurrentAnimation.Name == "Walk" || animator.CurrentAnimation.Name == "Lookup to Idle") { + animator.Play("Ground Turn"); + } + + if (animator.CurrentAnimation.Name == "Straight Jump Rising" || animator.CurrentAnimation.Name == "Straight Jump Crest" || animator.CurrentAnimation.Name == "Straight Jump Falling") { + animator.Play("Straight Jump Turn"); + } + + if (animator.CurrentAnimation.Name == "Rolling Jump") { + animator.Play("Rolling Jump Turn"); + } + } + } + } + + //determine if jumping + if (GamePad.GetState().Pressed(CButton.A) && grounded) { + jumping = true; + + maxSpeedModifier = jumpMaxSpeedMultiplier; + + if (animator.CurrentAnimation.Name == "Crouch") { + animator.Play("Rolling Jump"); + } + else if (Mathf.Abs(horizontalInput) < deadZone) { + animator.Play("Begin Straight Jump"); + horizontalModifier = straightJumpHorizontalMultiplier; + verticalModifier = straightJumpVerticalMultiplier; + } else { + animator.Play("Begin Rolling Jump"); + //horizontalModifier = rollingJumpHorizontalMultiplier; + //verticalModifier = rollingJumpVerticalMultiplier; + } + } + + if (GamePad.GetState().Pressed(CButton.A) && !grounded && wallHugged && (animator.CurrentAnimation.Name == "Brace on Wall" || animator.CurrentAnimation.Name == "Wall Slide")) { + wallJumping = true; + + maxSpeedModifier = jumpMaxSpeedMultiplier; + + animator.Play("Wall Kick"); + } + + //determine if attacking on the ground + if (GamePad.GetState().Pressed(CButton.B) && grounded) { + if (verticalInput < -deadZone) { //yes up input + if (animator.CurrentAnimation.Name == "Run") { + animator.Play("Grounded Upward Slash"); //TODO: replace with "Running Upward Slash" + } else { + animator.Play("Grounded Upward Slash"); + } + StartCoroutine(EnableDamagerForPeriod(0, 0.3f)); + } else { //no vertical input + if (animator.CurrentAnimation.Name == "Run") { + animator.Play("Grounded Forward Slash"); //TODO: replace with "Running Forward Slash" + } else { + animator.Play("Grounded Forward Slash"); + } + StartCoroutine(EnableDamagerForPeriod(1, 0.3f)); + } + } + + //determine if attacking in the air + if (GamePad.GetState().Pressed(CButton.B) && !grounded) { + if (verticalInput < -deadZone) { //yes up input + animator.Play("Airborn Upward Slash"); + StartCoroutine(EnableDamagerForPeriod(0, 0.3f)); + } else if (verticalInput > deadZone) { //yes down input + animator.Play("Airborn Downward Slash"); + StartCoroutine(EnableDamagerForPeriod(2, 0.3f)); + } else { //no vertical input + animator.Play("Airborn Forward Slash"); + StartCoroutine(EnableDamagerForPeriod(1, 0.3f)); + } + } + + //determine if releasing the attack button + if (GamePad.GetState().Released(CButton.B)) { + foreach (DamagerController dmgr in damagerControllers) { + dmgr.gameObject.SetActive(false); + } + } + + //BUGFIX: prevent crouch-gliding and slash-gliding + if (grounded && (animator.CurrentAnimation.Name == "Crouch")) { + horizontalInput = 0f; + dashModifier = 1f; + } + + //BUGFIX: falling animations after walking/running off a cliff + if (rigidBody.velocity.y < -0.0001f && (animator.CurrentAnimation.Name == "Walk" || animator.CurrentAnimation.Name == "Run")) { + animator.Play("Straight Jump Falling"); + } + } + + void HandleMovement() { + //stop the player if input in that direction has been removed + if (horizontalInput * rigidBody.velocity.x <= 0 && grounded) { + rigidBody.velocity = new Vector2 (rigidBody.velocity.x * 0.85f, rigidBody.velocity.y); + } + + //move in the inputted direction, if not at max speed + if (horizontalInput * rigidBody.velocity.x < maxSpeed * dashModifier * maxSpeedModifier) { + rigidBody.AddForce (Vector2.right * horizontalInput * moveForce * horizontalModifier); + } + + //slow the player down when it's travelling too fast + if (Mathf.Abs (rigidBody.velocity.x) > maxSpeed * dashModifier * maxSpeedModifier) { + rigidBody.velocity = new Vector2 (Mathf.Sign (rigidBody.velocity.x) * maxSpeed * dashModifier * maxSpeedModifier, rigidBody.velocity.y); + } + + if (rigidBody.velocity.y < -fallSpeed * (wallHugged ? wallHuggedMultiplier : 1f)) { + rigidBody.velocity = new Vector2 (rigidBody.velocity.x, Mathf.Sign (rigidBody.velocity.y) * fallSpeed * (wallHugged ? wallHuggedMultiplier : 1f)); + } + + //jump up + if (jumping) { + rigidBody.velocity = new Vector2(rigidBody.velocity.x, 0f); //max v-jump speed + rigidBody.AddForce (new Vector2 (0f, jumpForce * verticalModifier)); + jumping = false; + } + + if (wallJumping) { + rigidBody.velocity = new Vector2(0f, 0f); //wall-jump from zero + rigidBody.AddForce (new Vector2 (-transform.localScale.x * maxSpeed * jumpForce, jumpForce * verticalModifier)); + maxSpeedModifier = wallJumpMaxSpeedMultiplier; + wallJumping = false; + } + } + + bool HandleAnimation() { + if (spriteObject == null) { + foreach (Transform child in transform) { + if (child.name == "Ember") { + spriteObject = child.gameObject; + break; + } + } + } + + if (animator == null && spriteObject != null) { + animator = spriteObject.GetComponent().Animator; + animator.AnimationFinished += HandleAnimationTransitions; + } + + //determine statue state + if (!PauseManager.Instance.Paused && animator.CurrentAnimation.Name == "Statue" && + ( + //NOTE: carbon input really needs an "any key" + //any face button + GamePad.GetState().Pressed(CButton.A) || GamePad.GetState().Pressed(CButton.B) || GamePad.GetState().Pressed(CButton.X) || GamePad.GetState().Pressed(CButton.Y) || //only pressed this loop + //any axis + Mathf.Abs(GamePad.GetAxis(CAxis.LX)) >= deadZone || Mathf.Abs(GamePad.GetAxis(CAxis.LY)) >= deadZone || Mathf.Abs(GamePad.GetAxis(CAxis.RX)) >= deadZone || Mathf.Abs(GamePad.GetAxis(CAxis.RY)) >= deadZone + ) + ) { + animator.Play("Statue to Idle"); + return false; + } + + if (animator.CurrentAnimation.Name == "Statue to Idle") { + return false; + } + + //switch from regular animations to transition animations + if (animator.CurrentAnimation.Name == "Straight Jump Rising" && rigidBody.velocity.y <= 0) { + animator.Play("Straight Jump Crest"); + } + + if (animator.CurrentAnimation.Name == "Straight Jump Falling" && rigidBody.velocity.y >= 0) { + animator.Play("Straight Jump Landing"); + } + + if (animator.CurrentAnimation.Name == "Rolling Jump" && grounded) { + animator.Play("Straight Jump Landing"); //deliberately reuse this + } + + //start looking up + if (animator.CurrentAnimation.Name == "Idle" && verticalInput < 0 && Mathf.Abs(rigidBody.velocity.x) < 0.0001f) { + animator.Play("Idle to Lookup"); + } + + //stop looking up + if (animator.CurrentAnimation.Name == "Lookup" && verticalInput >= 0) { + animator.Play("Lookup to Idle"); + } + + //BUGFIX: bouncing off of a wall + if (!grounded && !wallHugged && animator.CurrentAnimation.Name == "Wall Slide") { + animator.Play("Rolling Jump"); + } + + //if ever simply falling (or attacking) + if (!grounded && !wallHugged && rigidBody.velocity.y < 0 && animator.CurrentAnimation.Name != "Straight Jump Crest" && animator.CurrentAnimation.Name != "Straight Jump Turn" && animator.CurrentAnimation.Name != "Rolling Jump Turn" && animator.CurrentAnimation.Name != "Rolling Jump" && animator.CurrentAnimation.Name != "Airborn Upward Slash" && animator.CurrentAnimation.Name != "Airborn Downward Slash" && animator.CurrentAnimation.Name != "Airborn Forward Slash") { + animator.Play("Straight Jump Falling"); + } + + //hit a wall + if (animator.CurrentAnimation.Name != "Brace on Wall" && animator.CurrentAnimation.Name != "Wall Slide" && animator.CurrentAnimation.Name != "Wall Kick" && wallHugged && !grounded) { + animator.Play("Brace on Wall"); + } + + //reach the bottom of a wall-slide (or hit the ground when turning) + if ((animator.CurrentAnimation.Name == "Brace on Wall" || animator.CurrentAnimation.Name == "Wall Slide" || animator.CurrentAnimation.Name == "Straight Jump Turn" || animator.CurrentAnimation.Name == "Rolling Jump Turn") && grounded) { + animator.Play("Straight Jump Landing"); + } + + //if bouncing + if (animator.CurrentAnimation.Name == "Straight Jump Landing" && !grounded && rigidBody.velocity.y > 0f) { + animator.Play("Begin Rolling Jump"); + } + + //handle bounding box + if ( + animator.CurrentAnimation.Name == "Crouch" || + animator.CurrentAnimation.Name == "Idle to Crouch" || + animator.CurrentAnimation.Name == "Rolling Jump" || + animator.CurrentAnimation.Name == "Begin Rolling Jump" || + (rigidBody.velocity.y > 0 && animator.CurrentAnimation.Name == "Straight Jump Landing") || + animator.CurrentAnimation.Name == "Brace on Wall" || + animator.CurrentAnimation.Name == "Wall Slide" || + animator.CurrentAnimation.Name == "Wall Kick" + ) { + //half box + if (currentBoxCollider != GetComponents()[1]) { + currentBoxCollider.enabled = false; + currentBoxCollider = GetComponents()[1]; + currentBoxCollider.enabled = true; + } + } else { + //full box + if (currentBoxCollider != GetComponents()[0]) { + currentBoxCollider.enabled = false; + currentBoxCollider = GetComponents()[0]; + currentBoxCollider.enabled = true; + } + } + + //peek with the camera + CameraController camController = Object.FindObjectOfType(); + if (camController.GetPeek() == Vector2.zero) { + if (animator.CurrentAnimation.Name == "Lookup") { + camController.SetPeek(new Vector2(0f, 4f)); + } + if (animator.CurrentAnimation.Name == "Crouch") { + camController.SetPeek(new Vector2(0f, -4f)); + } + } + if (camController.GetPeek() != Vector2.zero) { + if (animator.CurrentAnimation.Name != "Lookup" && animator.CurrentAnimation.Name != "Crouch") { + camController.ResetPeek(); + } + } + + return true; + } + + //internal callbacks + void HandleAnimationTransitions(string name) { + //NOTE: This handles the end of transitional animations + switch(name) { + case "Statue to Idle": + animator.Play("Idle"); + break; + + case "Idle to Walk": + animator.Play("Walk"); + break; + + case "Walk to Idle": + animator.Play("Idle"); + break; + + case "Begin Straight Jump": + animator.Play("Straight Jump Rising"); + break; + + case "Straight Jump Crest": + animator.Play("Straight Jump Falling"); + break; + + case "Straight Jump Landing": + animator.Play("Idle"); + break; + + case "Begin Rolling Jump": + animator.Play("Rolling Jump"); + break; + + case "Idle to Crouch": + animator.Play("Crouch"); + break; + + case "Crouch to Idle": + animator.Play("Idle"); + break; + + case "Idle to Lookup": + animator.Play("Lookup"); + break; + + case "Lookup to Idle": + animator.Play("Idle"); + break; + + case "Brace on Wall": + animator.Play("Wall Slide"); + StartCoroutine(BuildingFriction("Wall Slide", 0.1f)); + break; + + case "Wall Kick": + animator.Play("Rolling Jump"); + break; + + case "Grounded Forward Slash": + animator.Play("Idle"); + break; + + case "Grounded Upward Slash": + if (verticalInput < -deadZone && Mathf.Abs(rigidBody.velocity.x) < 0.0001f) { + animator.Play("Lookup"); + } else { + if (dashModifier != 1f) { + animator.Play("Run"); + StartCoroutine(BuildingFriction("Run", 0.05f)); + } else { + animator.Play("Idle"); + } + } + break; + + case "Airborn Upward Slash": + case "Airborn Downward Slash": + case "Airborn Forward Slash": + if (rigidBody.velocity.y > 0f) { + animator.Play("Straight Jump Rising"); + } else { + animator.Play("Straight Jump Falling"); + } + break; + + case "Ground Turn": + animator.Play("Idle"); + break; + + case "Straight Jump Turn": + if (rigidBody.velocity.y > 0f) { + animator.Play("Straight Jump Rising"); + } else { + animator.Play("Straight Jump Falling"); + } + break; + + case "Rolling Jump Turn": + animator.Play("Rolling Jump"); + break; + } + } + + //utilities + void OnDrawGizmos() { + if (currentBoxCollider != null) { + Gizmos.color = Color.red; + Gizmos.DrawLine(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x), -groundedProjection, 0)); + Gizmos.DrawLine(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x + currentBoxCollider.size.x / 2.1f), -groundedProjection, 0)); + Gizmos.DrawLine(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x - currentBoxCollider.size.x / 2.1f), -groundedProjection, 0)); + + Gizmos.color = Color.red; + Gizmos.DrawLine(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x + currentBoxCollider.size.x / 2 + groundedProjection), currentBoxCollider.size.y * 0.05f, 0)); + Gizmos.DrawLine(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x + currentBoxCollider.size.x / 2 + groundedProjection), currentBoxCollider.size.y * 0.5f, 0)); + Gizmos.DrawLine(transform.position + new Vector3(currentBoxCollider.offset.x, currentBoxCollider.offset.y, 0), transform.position + new Vector3(transform.localScale.x * (currentBoxCollider.offset.x + currentBoxCollider.size.x / 2 + groundedProjection), currentBoxCollider.size.y * 0.95f, 0)); + } + } + + bool SameSign(float num1, float num2) { + if (num1 > 0 && num2 > 0) { + return true; + } + if (num1 < 0 && num2 < 0) { + return true; + } + //if either is zero, return false + return false; + } + + IEnumerator SetGroundedWithDelay(bool value, float delay) { + yield return new WaitForSeconds(delay); + grounded = value; + } + + IEnumerator EnableDamagerForPeriod(int index, float delay) { + damagerControllers[index].gameObject.SetActive(true); + yield return new WaitForSeconds(delay); + damagerControllers[index].gameObject.SetActive(false); + } + + IEnumerator BuildingFriction(string animation, float increment) { + while (animator.CurrentAnimation.Name == animation) { + friction += increment; + yield return new WaitForSeconds(0.1f); + } + } + + IEnumerator TriggerHitStun(float delay) { + invulnerable = true; + StartCoroutine(TriggerHitStunGraphic(0.1f, delay - 0.1f)); + yield return new WaitForSeconds(delay); + invulnerable = false; + } + + IEnumerator TriggerHitStunGraphic(float redDelay, float opacityDelay) { + SpriteRenderer[] spriteRenderers = GetComponentsInChildren(); + + //flash red + foreach (var renderer in spriteRenderers) { + renderer.color = Color.red; + } + + yield return new WaitForSeconds(redDelay); + + foreach (var renderer in spriteRenderers) { + renderer.color = Color.white; + renderer.material.color = new Color(1f, 1f, 1f, 0.75f); + } + + yield return new WaitForSeconds(opacityDelay); + + foreach (var renderer in spriteRenderers) { + renderer.material.color = Color.white; + } + } +} diff --git a/Scripts/Game Objects/Spawners/ProximitySpawner.cs b/Scripts/Game Objects/Spawners/ProximitySpawner.cs new file mode 100644 index 0000000..1bb7c61 --- /dev/null +++ b/Scripts/Game Objects/Spawners/ProximitySpawner.cs @@ -0,0 +1,36 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class ProximitySpawner : MonoBehaviour { + //public access members + public GameObject prefab; + public string targetTag; + public float minDistance = 4f; + public float maxDistance = 10f; + public bool destroyIfTooFar = false; + + //private members + Transform targetTransform; + GameObject spawnedObject; + + void Start() { + targetTransform = GameObject.FindWithTag(targetTag).transform; + } + + void Update() { + //get the distance + float distance = Vector3.Distance(transform.position, targetTransform.position); + + //destroy if the player is too far away + if (destroyIfTooFar && distance > maxDistance) { + Destroy(spawnedObject); + return; //skip out on the next check + } + + //check the distance, check the spawned object + if (distance > minDistance && distance < maxDistance && spawnedObject == null) { + spawnedObject = Instantiate(prefab); + } + } +} diff --git a/Scripts/Game Objects/Spawners/TimedSpawner.cs b/Scripts/Game Objects/Spawners/TimedSpawner.cs new file mode 100644 index 0000000..789dba0 --- /dev/null +++ b/Scripts/Game Objects/Spawners/TimedSpawner.cs @@ -0,0 +1,27 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class TimedSpawner : MonoBehaviour { + //inspector access elements + public GameObject prefab; + public float spawnDelay = 10f; + public int maxSpawns = 3; + + //private members + float lastSpawnTime = float.NegativeInfinity; + List spawnList = new List(); + + //TODO: maybe all spawners should shut off (and monsters become inactive) when the player is too far away. + void Update() { + //prune the list + spawnList.RemoveAll(spawn => spawn == null); + + //spawn if enough time has passed + if (Time.time - lastSpawnTime > spawnDelay && spawnList.Count < maxSpawns) { + lastSpawnTime = Time.time; + + spawnList.Add(Instantiate(prefab, transform.position, Quaternion.identity, transform)); + } + } +} diff --git a/Scripts/Game Objects/Structures/HazardController.cs b/Scripts/Game Objects/Structures/HazardController.cs new file mode 100644 index 0000000..fbafa12 --- /dev/null +++ b/Scripts/Game Objects/Structures/HazardController.cs @@ -0,0 +1,28 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Structures { + public class HazardController : MonoBehaviour { + //internals + int DamageValue { get; set; } + DamagerController damagerController; + + void Awake() { + DamageValue = 1; + } + + void Start() { + damagerController = GetComponent(); + + damagerController.PushOnTriggerStay((Collider2D collider) => { + if (collider.gameObject.tag == "Player") { + //deal damage to the player + collider.gameObject.GetComponent().HealthValue -= DamageValue; + + //NOTE: not every damager will deal damage + } + }); + } + } +} \ No newline at end of file diff --git a/Scripts/Game Objects/Structures/Pedestal.cs b/Scripts/Game Objects/Structures/Pedestal.cs new file mode 100644 index 0000000..3bf6f17 --- /dev/null +++ b/Scripts/Game Objects/Structures/Pedestal.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Structures { + public class Pedestal : MonoBehaviour { + public string name; + public SaveHandler SaveHandler { set; get; } + + void OnCollisionEnter2D(Collision2D collision) { + if (collision.gameObject.tag == "Player") { + SaveFileManager.LoadedSaveSlot.currentLocation = name; + SaveHandler.saveMenuAvailable = true; + } + } + + void OnCollisionExit2D(Collision2D collision) { + if (collision.gameObject.tag == "Player") { + SaveHandler.saveMenuAvailable = false; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Managers/ConfigurationManager.cs b/Scripts/Managers/ConfigurationManager.cs new file mode 100644 index 0000000..763cfb4 --- /dev/null +++ b/Scripts/Managers/ConfigurationManager.cs @@ -0,0 +1,61 @@ +using System; +using System.IO; +using UnityEngine; + +[Serializable()] +public class ConfigurationManager { + //singleton members + private static ConfigurationManager singletonObject = null; + public static ConfigurationManager Instance { + get { + if (singletonObject == null) { + string fname = Path.Combine(Application.persistentDataPath, "configuration.json"); + new ConfigurationManager(fname); //NOTE: singleton object assigned elsewhere + } + return singletonObject; + } + } + + //serializable fields (these can be null, so handle that elsewhere) + public string textSpeed; + public float volume; + + //private internal members + static bool initialized = false; //BUGFIX: stack overflow + static string dataPath; + + //methods + private ConfigurationManager(string fname) { + if (!initialized) { + initialized = true; + LoadData(fname); + dataPath = fname; + } + } + + public void CleanUp() { + SaveData(Instance, dataPath); + } + + void LoadData(string fname) { + if (!File.Exists(fname)) { + singletonObject = JsonUtility.FromJson ("{}"); + return; + } + + StreamReader streamReader = File.OpenText(fname); + string jsonString = streamReader.ReadToEnd(); + streamReader.Close(); + singletonObject = JsonUtility.FromJson (jsonString); + + //reset statics + initialized = true; + } + + void SaveData(ConfigurationManager configMgr, string fname) { + string jsonString = JsonUtility.ToJson(configMgr); + StreamWriter streamWriter = File.CreateText(fname); + streamWriter.Write(jsonString); + streamWriter.Close(); + } +} diff --git a/Scripts/Managers/PauseManager.cs b/Scripts/Managers/PauseManager.cs new file mode 100644 index 0000000..67d20ba --- /dev/null +++ b/Scripts/Managers/PauseManager.cs @@ -0,0 +1,65 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class PauseManager { + //singleton members + private static PauseManager singletonObject = null; + public static PauseManager Instance { + get { + if (singletonObject != null) { + return singletonObject; + } else { + return singletonObject = new PauseManager(); + } + } + set { + singletonObject = value; + } + } + + //paused controller + bool paused = false; + public bool Paused { + get { + return paused; + } + set { + paused = value; + TriggerLists(); + } + } + + public delegate void CallbackHandler(); + + List onPausedList = new List(); + List onResumeList = new List(); + + private PauseManager() {} + + public void PushOnPaused(CallbackHandler callback) { + onPausedList.Add(callback); + } + + public void PushOnResume(CallbackHandler callback) { + onResumeList.Add(callback); + } + + public void PurgeLists() { + onPausedList.Clear(); + onResumeList.Clear(); + } + + void TriggerLists() { + if (Paused) { + foreach(CallbackHandler callback in onPausedList) { + callback(); + } + } + else { + foreach(CallbackHandler callback in onResumeList) { + callback(); + } + } + } +} diff --git a/Scripts/Managers/SaveFileManager.cs b/Scripts/Managers/SaveFileManager.cs new file mode 100644 index 0000000..f6b4bed --- /dev/null +++ b/Scripts/Managers/SaveFileManager.cs @@ -0,0 +1,80 @@ +using System; +using System.IO; +using UnityEngine; + +public class SaveFileManager { + //public structures + [Serializable()] + public class SaveSlot { + //serializable fields (these can be null, so handle that elsewhere) + public string currentLocation; //name of the pedestal + public float secondsPlaying; + public string awardImage; //TODO: award image + + //abilities + public bool flameBody; + public bool chargeSwipe; + public bool wallSlide; + public bool flameProjectile; + public bool flameWings; + } + + //singleton members + private static SaveFileManager singletonObject = null; + public static SaveFileManager Instance { + get { + if (singletonObject == null) { + singletonObject = new SaveFileManager(); + } + return singletonObject; + } + } + + //private internal members + // + + private SaveFileManager() { + // + } + + //public members + public static string saveSlotFileName; //NOT part of the save structure; only one can be loaded into the game at a time + public static SaveSlot LoadedSaveSlot { get; set; } + + //methods + public static SaveSlot LoadData(string fname) { + if (!File.Exists(fname)) { + return JsonUtility.FromJson ("{}"); + } + + StreamReader streamReader = File.OpenText(fname); + string jsonString = streamReader.ReadToEnd(); + streamReader.Close(); + + return JsonUtility.FromJson (jsonString); + } + + public static void SaveData(SaveSlot save, string fname) { + string jsonString = JsonUtility.ToJson(save); + + StreamWriter streamWriter = File.CreateText(fname); + streamWriter.Write(jsonString); + streamWriter.Close(); + } + + public static SaveSlot CreateBlankSaveSlot() { + SaveSlot saveSlot = new SaveSlot(); + + saveSlot.currentLocation = "Start"; + saveSlot.secondsPlaying = 0f; + saveSlot.awardImage = ""; + + saveSlot.flameBody = false; + saveSlot.chargeSwipe = false; + saveSlot.wallSlide = false; + saveSlot.flameProjectile = false; + saveSlot.flameWings = false; + + return saveSlot; + } +} diff --git a/Scripts/Scenes/Gameplay/PlayerAudio.cs b/Scripts/Scenes/Gameplay/PlayerAudio.cs new file mode 100644 index 0000000..ea6a04c --- /dev/null +++ b/Scripts/Scenes/Gameplay/PlayerAudio.cs @@ -0,0 +1,73 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using SpriterDotNetUnity; + +//DOCS: this is intended for Ember's foot step sounds + +public class PlayerAudio : MonoBehaviour { + //public members + public AudioClip[] leftFootsteps; + public AudioClip[] rightFootsteps; + public AudioClip jumpSound; + public AudioClip landSound; + + //internal members + GameObject spriteObject; + UnityAnimator animator; + AudioSource audioSource; + + void Start() { + audioSource = GetComponent(); + } + + void Update() { + //spriter object is handled as an animation + HandleAnimation(); + } + + // Update is called once per frame + void HandleAnimation() { + if (spriteObject == null) { + foreach (Transform child in transform) { + if (child.name == "Ember") { + spriteObject = child.gameObject; + break; + } + } + } + + if (animator == null && spriteObject != null) { + animator = spriteObject.GetComponent().Animator; + animator.EventTriggered += AudioTriggers; + } + + } + + void AudioTriggers(string name) { + switch(name) { + case "S: footstep left": + audioSource.PlayOneShot(leftFootsteps[PickASlot(leftFootsteps.Length)]); + break; + + case "S: footstep right": + audioSource.PlayOneShot(rightFootsteps[PickASlot(rightFootsteps.Length)]); + break; + + case "S: jump": + audioSource.PlayOneShot(jumpSound); + break; + + case "S: land": + audioSource.PlayOneShot(landSound); + break; + } + } + + int PickASlot(int length) { + for (int i = 0; i < length; i++) { + if (Random.Range(0, 2) == 0) return i; + } + return 0; + } +} diff --git a/Scripts/Scenes/Gameplay/Startups/Debugger.cs b/Scripts/Scenes/Gameplay/Startups/Debugger.cs new file mode 100644 index 0000000..828f83a --- /dev/null +++ b/Scripts/Scenes/Gameplay/Startups/Debugger.cs @@ -0,0 +1,32 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Startups { + public class Debugger : MonoBehaviour { + AudioController audioController; + + void Start() { + audioController = Object.FindObjectOfType(typeof(AudioController)) as AudioController; + + audioController.Load("rockstar", "Audio/Music/EngineTest"); + audioController.Load("forest_ambience", "Audio/Music/Forest_Ambience"); + audioController.Load("forest_background", "Audio/Music/Forest_Background"); + + audioController.Play("rockstar", AudioController.Mode.JUMP, 5f, 15); + +// StartCoroutine(DebugLoopMusic(10f)); + } + + IEnumerator DebugLoopMusic(float duration) { + for(;;) { + audioController.PauseFadeOutAll(3f, new List {"forest_background"}); + audioController.UnpauseFadeIn("forest_background", 3f, AudioController.Mode.LOOP); + yield return new WaitForSeconds(duration); + audioController.PauseFadeOutAll(3f, new List {"forest_ambience"}); + audioController.UnpauseFadeIn("forest_ambience", 3f, AudioController.Mode.LOOP); + yield return new WaitForSeconds(duration); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Scenes/Gameplay/Startups/FPSDisplay.cs b/Scripts/Scenes/Gameplay/Startups/FPSDisplay.cs new file mode 100644 index 0000000..4408d5f --- /dev/null +++ b/Scripts/Scenes/Gameplay/Startups/FPSDisplay.cs @@ -0,0 +1,29 @@ +using UnityEngine; +using System.Collections; + +//DOCS: http://wiki.unity3d.com/index.php/FramesPerSecond + +namespace Startups { + public class FPSDisplay : MonoBehaviour { + float deltaTime = 0.0f; + + void Update() { + deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f; + } + + void OnGUI() { + int w = Screen.width, h = Screen.height; + + GUIStyle style = new GUIStyle(); + + Rect rect = new Rect(0, 0, w, h * 2 / 100); + style.alignment = TextAnchor.UpperLeft; + style.fontSize = h * 2 / 100; + style.normal.textColor = new Color (0.0f, 0.0f, 0.5f, 1.0f); + float msec = deltaTime * 1000.0f; + float fps = 1.0f / deltaTime; + string text = string.Format("{0:0.0} ms ({1:0.} fps)", msec, fps); + GUI.Label(rect, text, style); + } + } +} \ No newline at end of file diff --git a/Scripts/Scenes/Gameplay/Startups/PauseMenuHandler.cs b/Scripts/Scenes/Gameplay/Startups/PauseMenuHandler.cs new file mode 100644 index 0000000..b51d099 --- /dev/null +++ b/Scripts/Scenes/Gameplay/Startups/PauseMenuHandler.cs @@ -0,0 +1,40 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Startups { + public class PauseMenuHandler : MonoBehaviour { + public Canvas pauseMenuCanvas; + public Canvas optionsMenuCanvas; + public Canvas saveMenuCanvas; + + PauseManager pauseManager; + + void Start() { + pauseManager = PauseManager.Instance; + pauseManager.Paused = false; + + pauseManager.PushOnPaused(() => { + pauseMenuCanvas.gameObject.SetActive(true); + Time.timeScale = 0f; + }); + + pauseManager.PushOnResume(() => { + pauseMenuCanvas.gameObject.SetActive(false); + optionsMenuCanvas.gameObject.SetActive(false); + saveMenuCanvas.gameObject.SetActive(false); + Time.timeScale = 1f; + }); + } + + void OnDestroy() { + pauseManager.PurgeLists(); + } + + void Update() { + if (GamePad.GetState().Pressed(CButton.Start)) { + pauseManager.Paused = !pauseManager.Paused; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Scenes/Gameplay/Startups/SaveHandler.cs b/Scripts/Scenes/Gameplay/Startups/SaveHandler.cs new file mode 100644 index 0000000..4dae939 --- /dev/null +++ b/Scripts/Scenes/Gameplay/Startups/SaveHandler.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +public class SaveHandler : MonoBehaviour { + public GameObject playerObject; + public Dictionary pedestalDictionary = new Dictionary(); + + public bool saveMenuAvailable = false; + + public float startTime = 0f; + + void Start() { + //create the save file if it doesn't exist + if (SaveFileManager.LoadedSaveSlot == null) { + SaveFileManager.saveSlotFileName = Path.Combine(Application.persistentDataPath, DateTime.Now.ToString("yyyyMMddTHHmmss") + ".sav"); + SaveFileManager.LoadedSaveSlot = SaveFileManager.CreateBlankSaveSlot(); + +// SaveFileManager.SaveData(SaveFileManager.LoadedSaveSlot, SaveFileManager.saveSlotFileName); + } + + //initialize the game world with the given save data + startTime = Time.time; + + //convert the array into a quick-search dictionary + Structures.Pedestal[] pedestals = GameObject.FindObjectsOfType(); + foreach(Structures.Pedestal pedestal in pedestals) { + pedestal.SaveHandler = this; + pedestalDictionary[pedestal.name] = pedestal; + } + + //place the player on their saved pedestal + playerObject.transform.position = pedestalDictionary[SaveFileManager.LoadedSaveSlot.currentLocation].gameObject.transform.position; + } +} diff --git a/Scripts/Scenes/MainMenu/Startups/ConfigHandler.cs b/Scripts/Scenes/MainMenu/Startups/ConfigHandler.cs new file mode 100644 index 0000000..f702c58 --- /dev/null +++ b/Scripts/Scenes/MainMenu/Startups/ConfigHandler.cs @@ -0,0 +1,11 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Startups { + public class ConfigHandler : MonoBehaviour { + void OnDestroy() { + ConfigurationManager.Instance.CleanUp(); + } + } +} \ No newline at end of file diff --git a/Scripts/Scenes/MonkeyBusiness/EmberAnimationCycle.cs b/Scripts/Scenes/MonkeyBusiness/EmberAnimationCycle.cs new file mode 100644 index 0000000..2073294 --- /dev/null +++ b/Scripts/Scenes/MonkeyBusiness/EmberAnimationCycle.cs @@ -0,0 +1,158 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +//Must include Spriter Namespace +using SpriterDotNetUnity; + +enum animationMode +{ + lookUp, + lookDown, + move, + straightJump, + rollingJump, +} + +public class EmberAnimationCycle : MonoBehaviour +{ + /* + * Instead of putting the script on Spriter's automatically generated prefab, which will cause it to be unset every + * time Evan tweaks the damn animations, we put the control scripts on a seperate gameobject which becomes a parent + * of the Spriter prefab and take a reference to the Spriter object so we can manipulate it. + */ + public GameObject Ember; + + // This is the actual thing we use to animate the character. + UnityAnimator anim; + + void Start() + { + } + + bool slash = false; + animationMode mode = animationMode.lookUp; + + void Update() + { + if (Ember == null) + { + foreach (Transform child in transform) + { + if (child.name == "Ember") { Ember = child.gameObject; break;} + } + } + + if (anim == null) + { + anim = Ember.GetComponent().Animator; + //This event is fired whenever an animation ends. + anim.AnimationFinished += animationTransitions; + } + + if (Input.anyKeyDown) + { + //Advance the animation. + if (anim.CurrentAnimation.Name == "Statue") anim.Play("Statue to Idle"); + else if (anim.CurrentAnimation.Name == "Idle") + { + switch (mode) + { + case animationMode.move: + anim.Play("Idle to Walk"); + mode = animationMode.straightJump; + break; + case animationMode.straightJump: + anim.Play("Begin Straight Jump"); + mode = animationMode.rollingJump; + break; + case animationMode.rollingJump: + anim.Play("Begin Rolling Jump"); + mode = animationMode.lookUp; + break; + case animationMode.lookUp: + if (!slash) + { + anim.Play("Grounded Forward Slash"); + slash = true; + } + else + { + slash = false; + anim.Play("Idle to Lookup"); + mode = animationMode.lookDown; + } + break; + case animationMode.lookDown: + anim.Play("Idle to Crouch"); + mode = animationMode.move; + break; + } + } + else if (anim.CurrentAnimation.Name == "Walk") anim.Play("Run"); + else if (anim.CurrentAnimation.Name == "Run") anim.Play("Idle"); + else if (anim.CurrentAnimation.Name == "Straight Jump Rising") + { + if (!slash) + { + anim.Play("Airborn Upward Slash"); + slash = true; + } + else + { + anim.Play("Straight Jump Crest"); + slash = false; + } + } + else if (anim.CurrentAnimation.Name == "Straight Jump Falling" + || anim.CurrentAnimation.Name == "Rolling Jump") + { + if (!slash) + { + if (anim.CurrentAnimation.Name == "Straight Jump Falling") anim.Play("Airborn Forward Slash"); + else anim.Play("Airborn Downward Slash"); + slash = true; + } + else + { + anim.Play("Straight Jump Landing"); + slash = false; + } + } + else if (anim.CurrentAnimation.Name == "Crouch") anim.Play("Crouch to Idle"); + else if (anim.CurrentAnimation.Name == "Lookup") + { + if (!slash) + { + anim.Play("Grounded Upward Slash"); + slash = true; + } + else + { + anim.Play("Lookup to Idle"); + slash = false; + } + } + } + } + + void animationTransitions(string name) + { + //We check to see if it's one of our transition animations and if so advance to the animation + // we are transitioning to. + if (name == "Statue to Idle") anim.Play("Idle"); + else if (name == "Idle to Walk") anim.Play("Walk"); + else if (name == "Begin Straight Jump") anim.Play("Straight Jump Rising"); + else if (name == "Straight Jump Crest") anim.Play("Straight Jump Falling"); + else if (name == "Begin Rolling Jump") anim.Play("Rolling Jump"); + else if (name == "Straight Jump Landing") anim.Play("Idle"); + else if (name == "Idle to Crouch") anim.Play("Crouch"); + else if (name == "Crouch to Idle") anim.Play("Idle"); + else if (name == "Idle to Lookup") anim.Play("Lookup"); + else if (name == "Lookup to Idle") anim.Play("Idle"); + else if (name == "Grounded Forward Slash") anim.Play("Idle"); + else if (name == "Grounded Upward Slash") anim.Play("Lookup"); + else if (name == "Airborn Upward Slash") anim.Play("Straight Jump Rising"); + else if (name == "Airborn Forward Slash") anim.Play("Straight Jump Falling"); + else if (name == "Airborn Downward Slash") anim.Play("Rolling Jump"); + } +} diff --git a/Scripts/User Interface/Dialog/DialogCanvas.cs b/Scripts/User Interface/Dialog/DialogCanvas.cs new file mode 100644 index 0000000..f74b696 --- /dev/null +++ b/Scripts/User Interface/Dialog/DialogCanvas.cs @@ -0,0 +1,110 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +namespace DialogSystem { + public class DialogCanvas : MonoBehaviour { + //public access references + public Image dialogPanel; + public TextMeshProUGUI dialogText; + + //internal variables + bool visible; + List internalTextList; + + //fine-tuning the interface + float speed = 0.25f; + float speedCharCount = 0; + + void Start() { + SetVisible(false); + } + + void Update() { + if (!PauseManager.Instance.Paused && visible) { + HandleInput(); + } + } + + void FixedUpdate() { + if (visible) { + ProcessSpeed(); + ProcessText(); + } + } + + public void SetVisible(bool b) { + visible = b; + + dialogPanel.gameObject.SetActive(visible); + dialogText.gameObject.SetActive(visible); + } + + public bool GetVisible() { + return visible; + } + + public void SetText(List stringList, bool setVisible = true) { + internalTextList = stringList; + dialogText.text = ""; + SetVisible(setVisible); + } + + void HandleInput() { + if (GamePad.GetState().Pressed(CButton.A)) { + if (internalTextList[0].Length > speedCharCount) { + //skip the text scroll + speedCharCount = internalTextList[0].Length; + } else { + //skip to the next "page" + internalTextList.RemoveAt(0); + speedCharCount = 0; + + //if there isn't another "page", go dormant + if (internalTextList.Count == 0) { + SetVisible(false); + } + } + } + } + + void ProcessSpeed() { + switch(ConfigurationManager.Instance.textSpeed) { + case "Fast": + speed = 1f; + break; + + case "Normal": + speed = 0.25f; + break; + + case "Slow": + speed = 0.1f; + break; + } + } + + void ProcessText() { + //if the list of text has run out + if (internalTextList.Count == 0) { + SetVisible(false); + return; + } + + SetVisible(true); + + //only show the first "speedCharCount" characters + string thisLine = internalTextList[0]; + if (speedCharCount >= thisLine.Length) { + dialogText.text = thisLine; + return; + } + speedCharCount += speed; + thisLine = thisLine.Substring(0, (int)Mathf.Floor(speedCharCount)); + + dialogText.text = thisLine; + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/HUD/HUDCanvas.cs b/Scripts/User Interface/HUD/HUDCanvas.cs new file mode 100644 index 0000000..2ba3297 --- /dev/null +++ b/Scripts/User Interface/HUD/HUDCanvas.cs @@ -0,0 +1,76 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +public class HUDCanvas : MonoBehaviour { + //public access members + public Sprite[] sparkSprites; + public Sprite[] flameSprites; + + //public properties + int _sparkLevel = 0; + public int SparkLevel { + get { + return _sparkLevel; + } + set { + _sparkLevel = value; + if (_sparkLevel < 0) { + _sparkLevel = 0; + } + if (_sparkLevel > sparkSprites.Length * (flameSprites.Length - 1)) { + _sparkLevel = sparkSprites.Length * (flameSprites.Length - 1); + } + } + } + public int FlameLevel { + get { + return _sparkLevel / sparkSprites.Length; + } + set { + _sparkLevel = value * sparkSprites.Length + _sparkLevel % sparkSprites.Length; + while(_sparkLevel < 0) { + _sparkLevel += sparkSprites.Length; + } + while(_sparkLevel > sparkSprites.Length * (flameSprites.Length - 1)) { + _sparkLevel -= 1; + } + } + } + + //internal members + Image[] childImages; + + void Start() { + childImages = GetComponentsInChildren(); + } + + void Update() { + HandleGraphics(); + DebugHandleInput(); + } + + void HandleGraphics() { + childImages[0].sprite = sparkSprites[SparkLevel % sparkSprites.Length]; + childImages[1].sprite = flameSprites[SparkLevel / sparkSprites.Length]; + } + + void DebugHandleInput() { + if (Input.GetKeyDown("1")) { + SparkLevel--; + } + + if (Input.GetKeyDown("2")) { + SparkLevel++; + } + + if (Input.GetKeyDown("3")) { + FlameLevel--; + } + + if (Input.GetKeyDown("4")) { + FlameLevel++; + } + } +} diff --git a/Scripts/User Interface/Menus/ConfirmationMenu/ConfirmDelete.cs b/Scripts/User Interface/Menus/ConfirmationMenu/ConfirmDelete.cs new file mode 100644 index 0000000..61f647d --- /dev/null +++ b/Scripts/User Interface/Menus/ConfirmationMenu/ConfirmDelete.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +namespace MenuSystem { + public class ConfirmDelete : MenuOption { + //public access members + public string fileName; + public GameObject loadCanvas; + public GameObject confirmationCanvas; + + public override void Execute() { + File.Delete(fileName); + confirmationCanvas.SetActive(false); + loadCanvas.SetActive(true); + } + + public override void Scroll(float x) { + //DO NOTHING + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/ConfirmationMenu/ConfirmLoad.cs b/Scripts/User Interface/Menus/ConfirmationMenu/ConfirmLoad.cs new file mode 100644 index 0000000..b66e813 --- /dev/null +++ b/Scripts/User Interface/Menus/ConfirmationMenu/ConfirmLoad.cs @@ -0,0 +1,30 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.UI; + +namespace MenuSystem { + public class ConfirmLoad : MenuOption { + //public access members + public SaveFileManager.SaveSlot saveData; + public string fileName; + + void Update() { + if (transform.childCount > 0) { + //BUGFIX: I don't know why this is disabled here + transform.GetChild(0).GetComponent().enabled = true; + } + } + + public override void Execute() { + SaveFileManager.saveSlotFileName = fileName; + SaveFileManager.LoadedSaveSlot = saveData; + SceneManager.LoadScene("Gameplay"); + } + + public override void Scroll(float x) { + //DO NOTHING + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/LoadMenu/LoadCanvas.cs b/Scripts/User Interface/Menus/LoadMenu/LoadCanvas.cs new file mode 100644 index 0000000..a74bdc7 --- /dev/null +++ b/Scripts/User Interface/Menus/LoadMenu/LoadCanvas.cs @@ -0,0 +1,40 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; +using UnityEngine.UI; + +namespace MenuSystem { + public class LoadCanvas : MonoBehaviour { + //public access members + public GameObject saveSlotPrefab; + public GameObject confirmationCanvas; + + void OnEnable() { + //load the save objects + DirectoryInfo info = new DirectoryInfo(Application.persistentDataPath); + + //create the load menu + foreach(var file in info.GetFiles("*.sav")) { + GameObject saveSlot = Instantiate(saveSlotPrefab) as GameObject; + saveSlot.transform.SetParent(transform); //BUGFIX: unity bug + saveSlot.GetComponent().SetSaveSlotInfo(SaveFileManager.LoadData(file.FullName)); + + saveSlot.GetComponent().fileName = file.FullName; + saveSlot.GetComponent().loadCanvas = transform.gameObject; + saveSlot.GetComponent().confirmationCanvas = confirmationCanvas; + } + + //Move the "back" option to the bottom + transform.GetChild(0).SetAsLastSibling(); + } + + void OnDisable() { + foreach (Transform child in transform) { + if (child.GetComponent() != null) { + GameObject.Destroy(child.gameObject); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/LoadMenu/SaveSlot.cs b/Scripts/User Interface/Menus/LoadMenu/SaveSlot.cs new file mode 100644 index 0000000..fc366a4 --- /dev/null +++ b/Scripts/User Interface/Menus/LoadMenu/SaveSlot.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using TMPro; + +namespace MenuSystem { + public class SaveSlot : MenuOption { + public string fileName; + public GameObject loadCanvas; + public GameObject confirmationCanvas; + + //private access members + SaveFileManager.SaveSlot saveData; + + public void SetSaveSlotInfo(SaveFileManager.SaveSlot saveSlot) { + TextMeshProUGUI[] texts = GetComponentsInChildren(true); + + texts[0].text = saveSlot.currentLocation; + + TimeSpan time = TimeSpan.FromSeconds(saveSlot.secondsPlaying); + texts[1].text = time.ToString(@"hh\:mm\:ss"); + + saveData = saveSlot; + } + + public override void Execute() { + //show a confirmation canvas + confirmationCanvas.transform.GetChild(0).GetComponent().saveData = saveData; + confirmationCanvas.transform.GetChild(0).GetComponent().fileName = fileName; + confirmationCanvas.transform.GetChild(1).GetComponent().fileName = fileName; + + //BUGFIX: move the cursor somewhere safe + transform.Find("Cursor").SetParent(confirmationCanvas.transform.GetChild(0)); + + //BUGFIX: wait a frame to show the confirmation page, to make sure the cursor is safe + StartCoroutine(DoStuffNextFrame()); + } + + IEnumerator DoStuffNextFrame() { + yield return null; + loadCanvas.SetActive(false); + confirmationCanvas.SetActive(true); + } + + public override void Scroll(float x) { + //DO NOTHING + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/MainMenuOptions/Quit.cs b/Scripts/User Interface/Menus/MainMenuOptions/Quit.cs new file mode 100644 index 0000000..fa50f12 --- /dev/null +++ b/Scripts/User Interface/Menus/MainMenuOptions/Quit.cs @@ -0,0 +1,12 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace MenuSystem { + class Quit : MenuOption { + override public void Execute() { + Application.Quit(); + Debug.Log("Quit called"); + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/MainMenuOptions/StartGame.cs b/Scripts/User Interface/Menus/MainMenuOptions/StartGame.cs new file mode 100644 index 0000000..b49faf5 --- /dev/null +++ b/Scripts/User Interface/Menus/MainMenuOptions/StartGame.cs @@ -0,0 +1,12 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace MenuSystem { + class StartGame : MenuOption { + override public void Execute() { + SceneManager.LoadScene("Gameplay"); + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/MenuCanvas.cs b/Scripts/User Interface/Menus/MenuCanvas.cs new file mode 100644 index 0000000..fe3dc40 --- /dev/null +++ b/Scripts/User Interface/Menus/MenuCanvas.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace MenuSystem { + public class MenuCanvas : MonoBehaviour { + //public access members + public Image cursorImage; + public bool floating = false; + + //private members + MenuOption[] menuOptions = null; + + //fine-tuned input + const float deadZone = 0.25f; + const float inputDelay = 0.5f; + const float scrollDelay = 0.1f; + float lastInputX = float.NegativeInfinity; + float lastInputY = float.NegativeInfinity; + + void OnEnable() { + menuOptions = GetComponentsInChildren(); + + //set up the cursor + menuOptions[0].hover = true; + RectTransform rt = cursorImage.GetComponent(); + rt.SetParent(menuOptions[0].transform); + rt.offsetMin = new Vector2(0, 0); + rt.offsetMax = new Vector2(0, 0); + + HandleGraphics(); + } + + void OnDisable() { + //BUGFIX: reset this menu tree if closing the menu + foreach (Transform child in transform) { + child.gameObject.SetActive(true); + } + } + + void Update() { + //BUGFIX: remove all non-active elements + menuOptions = Array.FindAll(menuOptions, (MenuOption option) => option.gameObject.active); + + HandleInput(); + HandleGraphics(); + } + + void HandleInput() { + //press a button + if (GamePad.GetState().Pressed(CButton.A)) { + foreach(MenuOption option in menuOptions) { + if (option.hover) { + option.Execute(); + } + } + return; + } + + //scroll left or right + if (Mathf.Abs(GamePad.GetAxis(CAxis.LX)) >= deadZone && Time.unscaledTime - lastInputX > scrollDelay) { + lastInputX = Time.unscaledTime; + + foreach(MenuOption option in menuOptions) { + if (option.hover) { + option.Scroll(GamePad.GetAxis(CAxis.LX)); + } + } + return; + } + + //keyboard/gamepad scroll up + if (GamePad.GetAxis(CAxis.LY) < -deadZone && Time.unscaledTime - lastInputY > inputDelay) { + lastInputY = Time.unscaledTime; + + //move the cursor one up + for (int i = 1; i < menuOptions.Length; i++) { + //find the current hovered item + if (menuOptions[i].hover) { + //move the hover up + menuOptions[i].hover = false; + menuOptions[i-1].hover = true; + break; + } + } + } + + //keyboard/gamepad scroll down + if (GamePad.GetAxis(CAxis.LY) > deadZone && Time.unscaledTime - lastInputY > inputDelay) { + lastInputY = Time.unscaledTime; + + //move the cursor one down + for (int i = 0; i < menuOptions.Length - 1; i++) { + //find the current hovered item + if (menuOptions[i].hover) { + //move the hover down + menuOptions[i].hover = false; + menuOptions[i+1].hover = true; + break; + } + } + } + + //deadzone reset lastInputX + if (Mathf.Abs(GamePad.GetAxis(CAxis.LX)) < deadZone) { + lastInputX = float.NegativeInfinity; + } + + //deadzone reset lastInputY + if (Mathf.Abs(GamePad.GetAxis(CAxis.LY)) < deadZone) { + lastInputY = float.NegativeInfinity; + } + } + + void HandleGraphics() { + bool hoverSet = false; + + //update the graphics + foreach(MenuOption option in menuOptions) { + if (option.hover) { + if (hoverSet) { + option.hover = false; + continue; + } + + RectTransform rt = cursorImage.GetComponent(); + rt.SetParent(option.transform); + rt.anchorMin = new Vector2(0, 0); + rt.anchorMax = new Vector2(1, 1); + rt.offsetMin = new Vector2(0, 0); + rt.offsetMax = new Vector2(0, 0); + hoverSet = true; + } + } + + if (floating) { + float offset = cursorImage.transform.position.y - Screen.height / 2; + transform.position = new Vector2(transform.position.x, transform.position.y - offset); + } + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/MenuOption.cs b/Scripts/User Interface/Menus/MenuOption.cs new file mode 100644 index 0000000..a7992dd --- /dev/null +++ b/Scripts/User Interface/Menus/MenuOption.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +namespace MenuSystem { + public class MenuOption : MonoBehaviour { + //if this option is being hovered over, logically + public bool hover = false; + + public virtual void Execute() { + //DO NOTHING + } + + public virtual void Scroll(float x) { + //DO NOTHING + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/OptionsOptions/TextSpeed.cs b/Scripts/User Interface/Menus/OptionsOptions/TextSpeed.cs new file mode 100644 index 0000000..ffd32b7 --- /dev/null +++ b/Scripts/User Interface/Menus/OptionsOptions/TextSpeed.cs @@ -0,0 +1,37 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using TMPro; + +namespace MenuSystem { + public class TextSpeed : MenuOption { + //component references + ConfigurationManager configManager; + TextMeshProUGUI text; + + void Start() { + configManager = ConfigurationManager.Instance; + text = GetComponent(); + configManager.textSpeed = (configManager.textSpeed != null && configManager.textSpeed != "" ? configManager.textSpeed : "Normal"); + text.text = configManager.textSpeed; + } + + override public void Execute() { + switch(configManager.textSpeed) { + case "Normal": + configManager.textSpeed = "Slow"; + break; + + case "Slow": + configManager.textSpeed = "Fast"; + break; + + case "Fast": + configManager.textSpeed = "Normal"; + break; + } + + text.text = configManager.textSpeed; + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/OptionsOptions/Volume.cs b/Scripts/User Interface/Menus/OptionsOptions/Volume.cs new file mode 100644 index 0000000..154d2b6 --- /dev/null +++ b/Scripts/User Interface/Menus/OptionsOptions/Volume.cs @@ -0,0 +1,40 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using TMPro; + +namespace MenuSystem { + public class Volume : MenuOption { + //component references + ConfigurationManager configManager; + TextMeshProUGUI text; + + void Start() { + configManager = ConfigurationManager.Instance; + text = GetComponent(); + configManager.volume = (configManager.volume != null && configManager.volume != 0 ? configManager.volume : 100f); + text.text = configManager.volume.ToString(); + + UpdateMasterVolume(); + } + + public override void Execute() { + //DO NOTHING + } + + public override void Scroll(float x) { + //DO NOTHING + configManager.volume += x; + + configManager.volume = Mathf.Clamp(configManager.volume, 0f, 100f); + + text.text = configManager.volume.ToString(); + + UpdateMasterVolume(); + } + + void UpdateMasterVolume() { + AudioListener.volume = configManager.volume / 100f; + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/PauseMenuOptions/QuitToMainMenu.cs b/Scripts/User Interface/Menus/PauseMenuOptions/QuitToMainMenu.cs new file mode 100644 index 0000000..c4adf9f --- /dev/null +++ b/Scripts/User Interface/Menus/PauseMenuOptions/QuitToMainMenu.cs @@ -0,0 +1,13 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace MenuSystem { + public class QuitToMainMenu : MenuOption { + public override void Execute() { + SceneManager.LoadScene("MainMenu"); + PauseManager.Instance.Paused = false; + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/PauseMenuOptions/ReturnToGame.cs b/Scripts/User Interface/Menus/PauseMenuOptions/ReturnToGame.cs new file mode 100644 index 0000000..c937951 --- /dev/null +++ b/Scripts/User Interface/Menus/PauseMenuOptions/ReturnToGame.cs @@ -0,0 +1,11 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace MenuSystem { + public class ReturnToGame : MenuOption { + public override void Execute() { + PauseManager.Instance.Paused = false; + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/SaveMenu/Heading.cs b/Scripts/User Interface/Menus/SaveMenu/Heading.cs new file mode 100644 index 0000000..af120f8 --- /dev/null +++ b/Scripts/User Interface/Menus/SaveMenu/Heading.cs @@ -0,0 +1,17 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; +using TMPro; + +namespace MenuSystem { + public class Heading : MonoBehaviour { + void Start() { + TextMeshProUGUI text = GetComponent(); + + if (!File.Exists(SaveFileManager.saveSlotFileName)) { + text.text = "Save The Game?"; + } + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/SaveMenu/HideMeIf.cs b/Scripts/User Interface/Menus/SaveMenu/HideMeIf.cs new file mode 100644 index 0000000..6a7c607 --- /dev/null +++ b/Scripts/User Interface/Menus/SaveMenu/HideMeIf.cs @@ -0,0 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace MenuSystem { + public class HideMeIf : MonoBehaviour { + public SaveHandler saveHandler; + + void OnEnable() { + if (!saveHandler.saveMenuAvailable) { + gameObject.SetActive(false); + } + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/SaveMenu/SaveGame.cs b/Scripts/User Interface/Menus/SaveMenu/SaveGame.cs new file mode 100644 index 0000000..8e656fe --- /dev/null +++ b/Scripts/User Interface/Menus/SaveMenu/SaveGame.cs @@ -0,0 +1,27 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace MenuSystem { + public class SaveGame : MenuOption { + public SaveHandler saveHandler; + + public Canvas oldMenu; + public Canvas newMenu; + + public override void Execute() { + //calculate playtime + SaveFileManager.LoadedSaveSlot.secondsPlaying += Time.time - saveHandler.startTime; + saveHandler.startTime = Time.time; + + //save the game + SaveFileManager.SaveData(SaveFileManager.LoadedSaveSlot, SaveFileManager.saveSlotFileName); + oldMenu.gameObject.SetActive(false); + newMenu.gameObject.SetActive(true); + } + + public override void Scroll(float x) { + //DO NOTHING + } + } +} \ No newline at end of file diff --git a/Scripts/User Interface/Menus/SwitchMenus.cs b/Scripts/User Interface/Menus/SwitchMenus.cs new file mode 100644 index 0000000..79eae56 --- /dev/null +++ b/Scripts/User Interface/Menus/SwitchMenus.cs @@ -0,0 +1,16 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace MenuSystem { + class SwitchMenus : MenuOption { + public Canvas oldMenu; + public Canvas newMenu; + + override public void Execute() { + oldMenu.gameObject.SetActive(false); + newMenu.gameObject.SetActive(true); + } + } +} \ No newline at end of file diff --git a/Sprites/Creatures/Cockatoo.png b/Sprites/Creatures/Cockatoo.png new file mode 100644 index 0000000..e3a9ad2 Binary files /dev/null and b/Sprites/Creatures/Cockatoo.png differ diff --git a/Sprites/Creatures/Cockatoo_Projectile.png b/Sprites/Creatures/Cockatoo_Projectile.png new file mode 100644 index 0000000..b4e23f2 Binary files /dev/null and b/Sprites/Creatures/Cockatoo_Projectile.png differ diff --git a/Sprites/Creatures/Wolf.png b/Sprites/Creatures/Wolf.png new file mode 100644 index 0000000..3cd48b3 Binary files /dev/null and b/Sprites/Creatures/Wolf.png differ diff --git a/Sprites/Creatures/kuribo.png b/Sprites/Creatures/kuribo.png new file mode 100644 index 0000000..10de025 Binary files /dev/null and b/Sprites/Creatures/kuribo.png differ diff --git a/Sprites/Structures/pedestal.png b/Sprites/Structures/pedestal.png new file mode 100644 index 0000000..72098f2 Binary files /dev/null and b/Sprites/Structures/pedestal.png differ diff --git a/Sprites/Tilesets/Debug Tileset.png b/Sprites/Tilesets/Debug Tileset.png new file mode 100644 index 0000000..530d861 Binary files /dev/null and b/Sprites/Tilesets/Debug Tileset.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00000.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00000.png new file mode 100644 index 0000000..52941ca Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00000.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00001.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00001.png new file mode 100644 index 0000000..0974b7d Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00001.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00002.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00002.png new file mode 100644 index 0000000..ecf137a Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00002.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00003.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00003.png new file mode 100644 index 0000000..b21067c Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00003.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00004.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00004.png new file mode 100644 index 0000000..82c567c Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00004.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00005.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00005.png new file mode 100644 index 0000000..016c070 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00005.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00006.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00006.png new file mode 100644 index 0000000..9e19044 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00006.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00007.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00007.png new file mode 100644 index 0000000..8b3728b Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00007.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00008.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00008.png new file mode 100644 index 0000000..f1d46f8 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00008.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00009.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00009.png new file mode 100644 index 0000000..e767aee Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00009.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00010.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00010.png new file mode 100644 index 0000000..dc006da Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00010.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00011.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00011.png new file mode 100644 index 0000000..2fc9ce5 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00011.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00012.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00012.png new file mode 100644 index 0000000..7b13c35 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00012.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00013.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00013.png new file mode 100644 index 0000000..08930af Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00013.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00014.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00014.png new file mode 100644 index 0000000..20eb4db Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00014.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00015.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00015.png new file mode 100644 index 0000000..6ef9d30 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00015.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00016.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00016.png new file mode 100644 index 0000000..a0e2ff9 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00016.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00017.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00017.png new file mode 100644 index 0000000..40eeefd Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00017.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00018.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00018.png new file mode 100644 index 0000000..c01a2cd Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00018.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00019.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00019.png new file mode 100644 index 0000000..b8a8e94 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00019.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00020.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00020.png new file mode 100644 index 0000000..b0820f2 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00020.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00021.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00021.png new file mode 100644 index 0000000..8980711 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00021.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00022.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00022.png new file mode 100644 index 0000000..035ee26 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00022.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00023.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00023.png new file mode 100644 index 0000000..89d170a Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00023.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00024.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00024.png new file mode 100644 index 0000000..5319f77 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00024.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00025.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00025.png new file mode 100644 index 0000000..7a4834d Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00025.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00026.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00026.png new file mode 100644 index 0000000..7f521c9 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00026.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00027.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00027.png new file mode 100644 index 0000000..78896eb Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00027.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00028.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00028.png new file mode 100644 index 0000000..fad0ecc Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00028.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00029.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00029.png new file mode 100644 index 0000000..ffa9e9b Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00029.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00030.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00030.png new file mode 100644 index 0000000..128c835 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00030.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00031.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00031.png new file mode 100644 index 0000000..73dc895 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00031.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00032.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00032.png new file mode 100644 index 0000000..80b7cc9 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00032.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00033.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00033.png new file mode 100644 index 0000000..7f1ce59 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00033.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00034.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00034.png new file mode 100644 index 0000000..18427ae Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00034.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00035.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00035.png new file mode 100644 index 0000000..d609ee1 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00035.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00036.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00036.png new file mode 100644 index 0000000..df2e6e8 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00036.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00037.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00037.png new file mode 100644 index 0000000..b48cb68 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00037.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00038.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00038.png new file mode 100644 index 0000000..2803d57 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00038.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00039.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00039.png new file mode 100644 index 0000000..ab3b69c Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00039.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00040.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00040.png new file mode 100644 index 0000000..632ab58 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00040.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00041.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00041.png new file mode 100644 index 0000000..39d3556 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00041.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00042.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00042.png new file mode 100644 index 0000000..83886d0 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00042.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00043.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00043.png new file mode 100644 index 0000000..5ac5f91 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00043.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00044.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00044.png new file mode 100644 index 0000000..73b49bf Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00044.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00045.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00045.png new file mode 100644 index 0000000..f3b016c Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00045.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00046.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00046.png new file mode 100644 index 0000000..bd2ab4d Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00046.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00047.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00047.png new file mode 100644 index 0000000..2c4c8cc Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00047.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00048.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00048.png new file mode 100644 index 0000000..0f3ca4a Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00048.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00049.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00049.png new file mode 100644 index 0000000..552dd5f Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00049.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00050.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00050.png new file mode 100644 index 0000000..601ccb1 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00050.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00051.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00051.png new file mode 100644 index 0000000..672b400 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00051.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00052.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00052.png new file mode 100644 index 0000000..87497db Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00052.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00053.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00053.png new file mode 100644 index 0000000..44b8eaa Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00053.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00054.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00054.png new file mode 100644 index 0000000..e50fcf0 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00054.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00055.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00055.png new file mode 100644 index 0000000..65d653d Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00055.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00056.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00056.png new file mode 100644 index 0000000..7cbc5d4 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00056.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00057.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00057.png new file mode 100644 index 0000000..85aa06e Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00057.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00058.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00058.png new file mode 100644 index 0000000..6212dc8 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00058.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00059.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00059.png new file mode 100644 index 0000000..be320ad Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00059.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00060.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00060.png new file mode 100644 index 0000000..0456fc8 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00060.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00061.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00061.png new file mode 100644 index 0000000..40b5505 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00061.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00062.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00062.png new file mode 100644 index 0000000..6e45442 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00062.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00063.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00063.png new file mode 100644 index 0000000..9d068f1 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00063.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00064.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00064.png new file mode 100644 index 0000000..0a63189 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00064.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00065.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00065.png new file mode 100644 index 0000000..3d5aa3c Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00065.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00066.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00066.png new file mode 100644 index 0000000..9e447bc Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00066.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00067.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00067.png new file mode 100644 index 0000000..bd21f92 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00067.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00068.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00068.png new file mode 100644 index 0000000..45879f5 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00068.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00069.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00069.png new file mode 100644 index 0000000..d5ec136 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00069.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00070.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00070.png new file mode 100644 index 0000000..40af569 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00070.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00071.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00071.png new file mode 100644 index 0000000..c9e38dd Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00071.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00072.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00072.png new file mode 100644 index 0000000..3b2d2dd Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00072.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00073.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00073.png new file mode 100644 index 0000000..640a053 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00073.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00074.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00074.png new file mode 100644 index 0000000..fb73d22 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00074.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00075.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00075.png new file mode 100644 index 0000000..b77dfbe Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00075.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00076.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00076.png new file mode 100644 index 0000000..9c51e66 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00076.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00077.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00077.png new file mode 100644 index 0000000..37666ff Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00077.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00078.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00078.png new file mode 100644 index 0000000..29cd4cb Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00078.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00079.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00079.png new file mode 100644 index 0000000..f10e1fb Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00079.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00080.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00080.png new file mode 100644 index 0000000..756fd3c Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00080.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00081.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00081.png new file mode 100644 index 0000000..6cb3d4b Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00081.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00082.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00082.png new file mode 100644 index 0000000..b94ca5f Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00082.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00083.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00083.png new file mode 100644 index 0000000..e8712eb Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00083.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00084.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00084.png new file mode 100644 index 0000000..91ba1cc Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00084.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00085.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00085.png new file mode 100644 index 0000000..70813b5 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00085.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00086.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00086.png new file mode 100644 index 0000000..9236407 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00086.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00087.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00087.png new file mode 100644 index 0000000..9f9a072 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00087.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00088.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00088.png new file mode 100644 index 0000000..77c223c Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00088.png differ diff --git a/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00089.png b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00089.png new file mode 100644 index 0000000..bc38a64 Binary files /dev/null and b/Sprites/Tilesets/Waterfall/Waterfall Loop/Waterfall_00089.png differ diff --git a/Sprites/User Interface/cursor.png b/Sprites/User Interface/cursor.png new file mode 100644 index 0000000..74e64cc Binary files /dev/null and b/Sprites/User Interface/cursor.png differ diff --git a/Sprites/User Interface/flame.png b/Sprites/User Interface/flame.png new file mode 100644 index 0000000..314b607 Binary files /dev/null and b/Sprites/User Interface/flame.png differ diff --git a/Sprites/User Interface/sparks.png b/Sprites/User Interface/sparks.png new file mode 100644 index 0000000..f5fe750 Binary files /dev/null and b/Sprites/User Interface/sparks.png differ