Lucky Shot
Lucky Shot
My Role - Sole Developer and Designer
Developed enemy AI behaviour for 3 enemy types.
Conceptualised and implemented 6 different weapon types.
Developed a high-score system for the game.
Developed the entire code base, including a difficult curve algorithm.
Composed the soundtrack for the game.
Lucky Shot was Ranked 353 in Enjoyment among 6117 submissions.
Link to Game Jam Submission - https://itch.io/jam/gmtk-jam-2022/rate/1622740
Key Features -
Clean and intuitive UI, communicating all 6 weapons to the player and the weapon change timer (it also turns red when it's about to change).
A common energy meter for all weapons that is used to provide balance.
Player weapon's aim indicator to help line up shots (it became essential to add for some weapons to be enjoyed properly).
Design Highlights -
Difficulty curve based on a Harmonic Progression to reduce the rate of increase of difficulty as score increases.
The random weapon generator ensures a new weapon is selected each time.
Reduced lifetimes of enemies with increased spawn rate to prevent overcrowding.
Various direct and indirect approaches for the enemies to keep the players engaged.
Code Snippets -
The following code snippets showcase some of my programming work in Unity, showcasing problem-solving skills and the importance of efficiency and simplicity.
Difficulty Curve -
// Declaring Score and difficulty as static variables to be used by other classes in the project
public static float score;
public static float difficulty = 0f;
// Start is called before the first frame update
void Start()
{
difficulty = 0f;
}
// Update is called once per frame
void Update()
{
// Is triggered by another function to not increase difficulty and score when the game is paused
if (!PauseMenu.isPaused)
{
score += Time.deltaTime;
difficulty += (Time.deltaTime / (1+ (int)(score/60) ) );
}
}
Rotating Enemy AI Behavior Code -
Transform player;
float baseSpeed = 15f;
float speed = 15f;
float time = 0f;
Vector3 moveDirection;
float turnSmoothVelocity;
float turnSmoothTime = 0.05f;
[SerializeField]
Transform center;
[SerializeField]
GameObject explosion;
// Start is called before the first frame update
void Start()
{
player = GameObject.Find("Player").transform;
time = 0f;
moveDirection = transform.forward;
ChangeDirection();
}
// Update is called once per frame
void Update()
{
// Initiating the speed based on the difficulty scaling
speed = baseSpeed + ((PlayerMovement.difficulty * baseSpeed) / 175);
float targetAngle = Mathf.Atan2(moveDirection.x, moveDirection.z) * Mathf.Rad2Deg;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
// Rotates the enemy around a center point
transform.rotation = Quaternion.Euler(0f, angle, 0f);
transform.position = Vector3.MoveTowards(transform.position, transform.position + transform.forward, speed * Time.deltaTime);
// Moving the centre point towards the player so that the enemy revolving around it hits the player
Vector3 faceDirection = player.position - center.position;
if (faceDirection.magnitude > 6.6f)
{
transform.position = Vector3.MoveTowards(transform.position, transform.position + faceDirection.normalized, speed * Time.deltaTime * 0.4f);
}
else if (faceDirection.magnitude < 6f)
{
transform.position = Vector3.MoveTowards(transform.position, transform.position + faceDirection.normalized, speed * Time.deltaTime * -0.2f);
}
// Destroys the game object after a certain time has elapsed
time += Time.deltaTime;
if (time > 20f)
{
GameObject explosionobj = Instantiate(explosion, transform.position, transform.rotation);
Destroy(gameObject);
}
}
void ChangeDirection()
{
StartCoroutine("ChangeDirectionWait");
}
IEnumerator ChangeDirectionWait()
{
yield return new WaitForSeconds(0.1f);
Vector3 newDirection = (transform.forward * 4) + (transform.right * 1) ;
moveDirection = newDirection.normalized;
ChangeDirection();
}
Learning Outcomes -
Learned how to balance weapons with very different strengths using a common resource and why it's so important to do so.
Prioritising polish over content, the initial plan had 5 enemies; however, I decided to polish the game, menu, sound and the existing 3 enemies to ship a complete product instead of trying to jam the most content possible.
Learned how to incorporate player feedback well, many suggestions from the play-testers focused on solutions that either wouldn't work or would take too much time. I learned to focus on their issue and not their solution to fix the issue in the most efficient way possible. In this case, it was adding the energy bar for balance instead of reworking all 6 weapons from scratch to make them balanced.
Check out Lucky Shot, on itch.io. It's available for download for windows.
Itch.io Link - https://chirag050.itch.io/lucky-shot