Crystal Isle - Gameplay Demo

Overview

About the project

Crystal Isle is a Gameplay Demo created using Unity 2D. All of the gameplay seen in this demo was created by myself. The art assets were obtained from the Unity asset store. The gameplay mechanics in this demo include character controllers, AI controllers (NPC & AI), Combat system, Dialogue Systems, and Sign/Chest/Grass interactivity. Interaction with Chests and Grass includes randomized item drops. Additionally, the level was designed and created by me.

Date
January 18, 2023
My Role
Gameplay Programmer
See this Project & More!
The Game

A Fun Gameplay Experience

Crystal Isle is a gameplay artifact that was created to show of gameplay mechanics I’ve created in Unity 2D. The gameplay and level design were inspired by The Legend of Zelda developed by Nintendo and The Rusty Sword developed by Plow Games. As a huge fan of 2D top-down adventure games, I wanted to create this gameplay demo to best show my skills in this genre.

This project’s main goal is to show my skills in gameplay development. Thus, this project was created in under a week. In order to develop this gameplay demo, I studied other game’s mechanics and attempted to recreate and/or improve on them.

Impact

My Impact

I created a number of gameplay mechanics to make this demo come to life. I also implemented responsive UI for object interactivity. My impact on this demo are as follows.

  • Gameplay & UI mechanics:
        -
    Character controllers
       - NPC & Enemy controllers / behaviors.
       - Combat Mechanics.
       - Customizable Dialogue System.
       - Puzzle systems.
       - Object interaction (Chests, Signs, Grass).
       - Randomized item drops from chests & grass.
       - Audio Implementation.
       - Interactive UI that responds to player damage and player wallet.
       - Animated characters, NPCs & enemies using Unity’s animation blend tree.
       - Created custom death animation for enemies.
       - General bug fixing and resolving other Unity engine issues using C#.
  • Led the project by researching 2D top-down games and their gameplay as well as implementing a simple agile methodology to stay organized and on time.
  • Designed Demo’s level by Implementing art assets via Unity’s level editor.
Gameplay Mechanic Descriptions & Video Examples

Crystal Isle - Breakdown

The development of Crystal Isle took a little under a week to create. It was developed using C# in Unity. This section is to showcase videos & code snippets of the created mechanics.

Here are some examples of gameplay mechanics, features & AI code that I've been working on! Each description of the mechanic will have a video. If you'd like to see the code as well, it will be posted at the bottom of the page!

Chest Interaction Script

Here is a video of the chest mechanic. The chest mechanic uses a very simple animation that I created in Unity. Once the player presses the interact button, the animation plays. The item method "OpenChest" is attached to the opening frame of the animation. Once the chest opens, the method instantiates and a random item will appear and interact with the player depending on what the item is.

Dialogue System Scripts

For this gameplay demo, I wanted to develop a dialogue system that could be customizable and easy to use for other developers. In order to do this, I first created a scriptable object script for the dialogue data. This script uses a string array and pushes that into the Dialogue array variable. This script allows other developers to easily create a dialogue object in the inspector and add any text that they want. All they have to do is attach this dialogue asset to the Dialogue Activator script.

The next script is the Dialogue Activator (this attaches to the NPC). This script checks to see if the player is in range of the NPC. If they are, it references the player and instantiates the next script which is the Dialogue UI script. The Dialogue UI script is very similar to the sign script. When the player interacts with the NPC, this script sets the UI to active. The dialogue box as well as the dialogue data are then shown.

I wanted to make this dialogue system a little more fun and unique, so I also created the Typewriter Effect script for the dialogue. Without this script, the text would just be shown immediately. However, this script allows the text to be gradually shown letter by letter. The Typewriter Effect uses an IEnumerator to help loop through the string and gradually show the dialogue. The coroutine is then started in the Run method. This Run method is then called back in the Dialogue UI script. An additional IEnumerator is used in this script to help the player skip through the Typewriter Effect if they wish to quickly read the dialogue.

Character Controller Script

This is the character controller. The character controller is made up of 2 separate scripts. One scripts is for the player movement and calculating if the player is going to collide with something and the other script is for player animations. In the first script "PlayerController", I used the new input system from Unity. I used a Vector2 variable that holds the player movement input. I pass this value into the "OnMove" method via the new input system. I also added an extra method called "TryMove" that takes a vector 2 direction. This method checks to see if the character is colliding with anything. If not, the next movement can be calculated and allow the player to move. This method is especially important for avoiding the player getting caught on colliders.

The second script handles the player animations. I wanted to animate character/NPCs both by not using the blend tree and using it. The main character does not use an animation blend tree for movement. Instead it takes in two variables called "speed" and "orientation" to determine what animation to play. The player direction is first determined by using a Vector2 variable called movement. A series of IF statements is then used to determine if the movement variable is moving greater than or less than the value 0 in both the X and Y axis. Depending on the value, the respective "speed" and "orientation" values are updated and then fires the correct animation.

Combat Script & Health Scripts

This is the combat system. This system is based off of the classic 2D top down adventure combat like in Zelda. The combat logic combines a number of scripts to ensure everything is working.

The first script is for the player's sword attack. I chose to use a Collider2D array that uses a Physics2D.OverlapCircleAll which takes in several variables. One of these variables includes a layer mask for enemies & grass. The player has 4 different circle colliders to the front, back, left and right of them. These circle colliders determine if an enemy with the "enemy" layer is in range. If they are, the TakeDamage method is called from the second script, the enemy script. This script deals a specific amount of damage to them. In addition to the damage method, a third script for knockback is called. The knockback script checks to see if the player attacked an enemy and if so, adds force against the enemy and launches them back. A timer is then used to determine how far the enemy is knocked back before they need to stop.

The enemy controller script is called when the player attacks the enemy and takes damage. Once enough damage is taken, the die method is called and a Boolean value lets the script know to play the death animation. In addition, the enemy controller also checks to see if it makes contact with the player. If so, the same is done to the player. The last script that is used, the health controller takes in a certain amount of damage and deals it to the player's health. In this case, the monster did 2 damage to the player.

The player's attack animation is determined via the animation controller discussed earlier. A variable called "Current Position" is updated when the player is facing a direction. Depending on the player's position, the respective attack animation will be called when the attack is fired.

Grass Script

Here is the grass logic to allow players to attack them with their swords and get items. Grass objects use nearly the same logic as the enemies for interactions. The player's SwordAttack script also accounts for another layer mask which is meant for grass objects. When the player attacks a piece of grass with the grass layer mask, the grass's script is called. This script works just like the enemy script. The grass has a integer variable for health and that value is decreased when the player attacks it. However, whenever the health value is set to 0, the RandomItem method is called. This method takes an array for objects and determines a random number from 0 to the length of the array. This number then determines if the player gets a random item or nothing at all.

If a player picks up a coin, the coin's value is checked and a method within the Wallet Manager is called to update the inventory and UI. Additionally, if the player picks up a heart piece, a method within the health controller is called to update the player's health.

Sign Script

The sign mechanic is a very simple script. To do this I created a UI canvas which has a dialogue box specifically for the signs in the game. The dialogue box UI is then placed in variable in the script. Additionally, the text for the sign is stored in a serialized variable to keep customizability. Finally a Boolean value is set to check if a player is in range. An on trigger enter/exit is used to set the Boolean value to true or false. When true, the player may press the interact button. This activates the sign's UI box and text. If the player presses the interact button again, the UI & text will disappear. The UI will also disappear if the player walks away. I decided to do this to avoid any potential bugs.

NPC Script

I created two separate NPC's for this gameplay demo. One NPC moves randomly in a bounded area and stops if a player gets close enough. The other is a stationary NPC. Both of these NPCs are interactable and will produce unique dialogue. This video represents the bounded NPC that moves in their designated area. In order to accomplish this bounded area, I created a rectangular 2D collider. This collider serves as the travel bounds for the NPC. For movement, this NPC uses a vector 3. The 2D collider is used with the method "Contains" which takes in the vector 3. If the NPC has a movement location within the 2D collider, an IF statement lets the AI know to move to that location. The update method is constantly checking these values. Once the NPC reaches their destination, a timer counts down and the "ChooseDifferentDirection" method is called and the NPC gets their new destination.

While the AI logic determines the next destination and helps it move to said destination, another two values called "ChangeDirection" and "UpdateAnimation" are used to help determine the direction of the NPC as well as updating their movement animations. The vector 3 variable checks to see where the NPC is moving on the X and Y axis and updates the animations accordingly. I used Unity's animation blend tree to help with these animations.

Gameplay Mechanic Code Examples

Chest Interaction Script

Here is the script of the chest mechanic.

Code for Chest Interaction

Character Controller & Character Animation Script

Here is the script of the character's controller & animation.

Character Controller Code
Character Animation Code (No Blend Tree Used)

Combat, Health and Knockback Scripts

These are the scripts responsible for the combat system. These scripts contain both player and enemy controllers as well as sword attack logic and knockback logic.

Sword Attack Code (1)
Sword Attack Code (2)
Enemy Controller Code
Attack Animation Logic Code
Knockback Code
Player Health Controller Code

Grass Script

This is the grass script. The script works very similar to the combat logic.

Grass Script

Sign Script

This is the sign script. While the UI is the same for the sign, it uses a completely different similar UI to display text from signs.

Sign Code

Wallet Manager Script

This script's main purpose is to update the player's wallet inventory when he/she picks up a coin.

Wallet Manager Script

Dialogue System Scripts

These 4 scripts were created to make a customizable dialogue system that uses scriptable dialogue objects. The scriptable object script allows developers to easily create their own dialogue data via the Unity Inspector. The other 2 scripts allow for the dialogue logic to work. Finally, the Typewriter Effect script allows for the gradual reveal of the dialogue text just like class pixel RPGs.

Scriptable Dialogue Object Code
Dialogue Activator Code
Dialogue UI Code
Typewriter Effect Code