A 3D platformer with 2D gameplay based on the Brazilian Karajá tribe culture and style.
You fight your way through spirits that are threatening your village. Made in a 2.5-day game jam.
Notes
We spent the majority of the first day planning.
This was my first time properly working together with another programmer on a game.
Scripts
Below you can look at some of the scripts I wrote for this project.
The conventions are kind of all over the place since this project is a collaborated quick game jam prototype.
A quick sum-up:
Player.cs
GlideState.cs
Player.cs
Used for managing stats and for integrating the state machine.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using SOTDT.Gameplay.Entity.State; using SOTDT.Util; namespace SOTDT.Gameplay.Entity { public class Player : Damageable { #region Events private EventHandler m_GroundImpactEvent; private EventHandler m_RespawnEvent; public event EventHandler GroundImpactEvent { add { m_GroundImpactEvent += value; } remove { m_GroundImpactEvent -= value; } } public event EventHandler RespawnEvent { add { m_RespawnEvent += value; } remove { m_RespawnEvent -= value; } } #endregion Events #region Members private Rigidbody2D m_Rigidbody; private BoxCollider2D m_Collider; private Animator m_Animator; private Vector3 m_CurrentCheckpoint; private Vector3 m_OriginPos; private UIDeathText deathUI; #endregion Members #region Serialized Members [Header("Walking")] [SerializeField] private float m_WalkSpeed = 10.0f; [SerializeField] private int m_LastXDirection = 1; [Header("Jumping")] [SerializeField] private float m_AirborneSpeed = 5.0f; [SerializeField] private float m_JumpSpeed = 20.0f; [SerializeField] private float m_DoubleJumpSpeed = 30.0f; [SerializeField] private int m_MaxJumps = 2; [SerializeField] private int m_JumpsLeft; [Header("Gliding")] [SerializeField] private float m_GlideSpeed = 5.0f; [SerializeField] private float m_MaxGlideTime = 3.0f; [Header("Dive-kick")] [SerializeField] private float m_DiveHitRange = 1.0f; [SerializeField] private int m_DiveHitDamage = 2; [SerializeField] private Vector2 m_DiveVelocity; [Header("Punch Combo")] [SerializeField] private float m_MaxPunchComboTime = .3f; [SerializeField] private float m_PunchRange = 1.0f; [SerializeField] private int m_FirstPunchDamage = 1; [SerializeField] private int m_SecondPunchDamage = 2; [SerializeField] private int m_ThirdPunchDamage = 3; [Header("Misc.")] [SerializeField] private float m_GroundCheckRayLength = .05f; [SerializeField] private bool m_IsAirborne = false; [SerializeField] private IState m_State; [SerializeField] private bool m_PrintState = false; #endregion Serialized Members #region Properties public Rigidbody2D Rigidbody { get { return m_Rigidbody; } } public BoxCollider2D Collider { get { return m_Collider; } } public Animator Animator { get { return m_Animator; } } public float WalkSpeed { get { return m_WalkSpeed; } } public int LastXDirection { get { return m_LastXDirection; } set { m_LastXDirection = value; } } public float AirborneSpeed { get { return m_AirborneSpeed; } } public float JumpSpeed { get { return m_JumpSpeed; } } public float DoubleJumpSpeed { get { return m_DoubleJumpSpeed; } } public int MaxJumps { get { return m_MaxJumps; } } public int JumpsLeft { get { return m_JumpsLeft; } set { m_JumpsLeft = value; } } public float GlideSpeed { get { return m_GlideSpeed; } } public float MaxGlideTime { get { return m_MaxGlideTime; } } public float DiveHitRange { get { return m_DiveHitRange; } } public int DiveHitDamage { get { return m_DiveHitDamage; } } public Vector2 DiveVelocity { get { return m_DiveVelocity; } } public float MaxPunchComboTime { get { return m_MaxPunchComboTime; } } public float PunchRange { get { return m_PunchRange; } } public int FirstPunchDamage { get { return m_FirstPunchDamage; } } public int SecondPunchDamage { get { return m_SecondPunchDamage; } } public int ThirdPunchDamage { get { return m_ThirdPunchDamage; } } public float GroundCheckRayLength { get { return m_GroundCheckRayLength; } } public bool IsAirborne { get { return m_IsAirborne; } set { m_IsAirborne = value; } } public IState State { get { return m_State; } set { m_State = value; } } #endregion Properties private void Awake() { m_State = new IdleState(this); m_OriginPos = transform.position; m_CurrentCheckpoint = m_OriginPos; } private void Start() { deathUI = FindObjectOfType<UIDeathText>(); deathUI.RespawnEvent += OnRespawn; } private void Update() { m_State.Update(); if (m_PrintState) { print(m_State.ToString()); } Vector3 scale = transform.localScale; scale.x = m_LastXDirection; transform.localScale = scale; Vector3 origin = transform.position; RaycastHit2D hit = Physics2D.Raycast(origin, Vector3.down, m_GroundCheckRayLength); Debug.DrawRay(origin, Vector3.down * m_GroundCheckRayLength, Color.red); if (hit && m_IsAirborne && m_Rigidbody.velocity.y < .0f) { m_State = new IdleState(this); m_IsAirborne = false; EventUtil.Invoke(m_GroundImpactEvent, this, EventArgs.Empty); m_Animator.ResetTrigger("fall"); } } private void OnRespawn() { m_CurrentHealth = m_MaxHealth; transform.position = m_CurrentCheckpoint; EventUtil.Invoke(m_RespawnEvent, this, EventArgs.Empty); } } } |
GlideState.cs
Manages the gliding state.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace SOTDT.Gameplay.Entity.State { public class GlideState : IState { private Player player; private float timer = .0f; private bool blocked = false; public GlideState(Player player) { this.player = player; player.Animator.SetTrigger("glide"); timer = player.MaxGlideTime; } public void Update() { float xInput = Input.GetAxisRaw("Horizontal"); float yInput = Input.GetAxisRaw("Vertical"); Vector2 v = player.Rigidbody.velocity; /* * Dive kick */ if (yInput < .0f) { player.State = new DiveState(player); return; } /* * Sideways movement */ if (Mathf.Abs(v.x = xInput * player.GlideSpeed) > .01f) { player.LastXDirection = (int) Mathf.Sign(xInput); } if (Input.GetKey(KeyCode.Space) && timer > .0f) { player.Animator.SetTrigger("glide"); blocked = false; v.y = -0.2f; /* * Sideways movement */ if (Mathf.Abs(v.x = xInput * player.GlideSpeed) > .01f) { player.LastXDirection = (int) Mathf.Sign(xInput); } timer -= Time.deltaTime; } else { if (!blocked) { player.Animator.ResetTrigger("glide"); player.Animator.SetTrigger("fall"); v = Vector2.zero; blocked = true; } } player.Rigidbody.velocity = v; } } } |