Skills Showcased

Godot: In-Engine Tools - Languages:C#

Role: System Designer // UI Programmer

Description Group project using Godot (A game engine that uses C#) where I served as lead designer. Original concept for 2048 Knight was an RPG interpretation of the mobile game 2048 essentially inspired by its grid based desgin. Some of my roles on the team involved designing the UI and multiple systems. As the scope for the project was only a few weeks of the course the scope was incredibly small especially when considering learning an engine in that time. But showcases my role as designer in which I created proof of concepts through desgin documents. Addtionally, implemented the final UI for the game, including the health bar, inventory system and more. Attached below is a link to google drive that shows design documents and process along with a short demo.

🛠 Scripts I wrote

As the designer I aided in the completion of our design documents but additionally, with my technical background, implemented a few core systems to aid the developers on the team including the pause/quit menu, item and inventory systems.


📁 Godot Scripts

Helper functions for Pause Menu
extends Control

@onready var main = $"../../"


func _on_resume_pressed():
	main.pauseMenu()


func _on_quit_pressed():
	get_tree().quit()
Place holder player character for testing purposes
extends CharacterBody2D

@export var MAX_SPEED = 300
@export var ACCELERATION = 1500
@export var FRICTION = 1200

@onready var axis = Vector2.ZERO



func _physics_process(delta):
	move(delta)

func get_input_axis():
	axis.x=int(Input.is_action_pressed("move_right")) - int(Input.is_action_pressed("move_left"))
	axis.y=int(Input.is_action_pressed("move_down")) - int(Input.is_action_pressed("move_up"))
	return axis.normalized()


func move(delta):
	
	axis = get_input_axis()
	
	if axis == Vector2.ZERO:
		apply_friction(FRICTION * delta)
		pass #apply friction
		
	else:
		apply_movement(axis * ACCELERATION * delta)
		pass #apply movement
		
	move_and_slide()
	
func apply_friction(amount):
	if velocity.length() > amount:
		velocity -= velocity.normalized() * amount
		
	else:
		velocity = Vector2.ZERO
		
func apply_movement(accel):
	velocity += accel
	velocity = velocity.limit_length(MAX_SPEED)
Main PauseMenu testing script

extends Node2D

@onready var PauseMenu = $Camera2D/PauseMenu
var paused = false

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	if Input.is_action_just_pressed("pause"):
		pauseMenu()
		
		
func pauseMenu():
	if paused:
		PauseMenu.hide()
		Engine.time_scale = 1
	else:
		PauseMenu.show()
		Engine.time_scale = 0
			
	paused= !paused

Rewritten Pausemenu scripts to accommodate for LTS Godot version

extends Control

var is_paused = false setget set_is_paused

func _unhandled_input(event):
	if event.is_action_pressed("pause"):
		self.is_paused = !is_paused

func set_is_paused(value):
	is_paused = value
	get_tree().paused = is_paused
	visible = is_paused




func _on_Resume_pressed():
	self.is_paused = false


func _on_Quit_pressed():
	get_tree().quit()

[gd_scene load_steps=2 format=2]

[ext_resource path="res://PauseMenu2.gd" type="Script" id=1]

[node name="PauseMenu2" type="Control"]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 1 )

[node name="ColorRect" type="ColorRect" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
color = Color( 0.231373, 0.298039, 0.286275, 0.368627 )

[node name="CenterContainer" type="CenterContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0

[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
margin_left = 835.0
margin_top = 463.0
margin_right = 1085.0
margin_bottom = 617.0
custom_constants/separation = 30

[node name="PauseText" type="Label" parent="CenterContainer/VBoxContainer"]
margin_right = 250.0
margin_bottom = 14.0
rect_min_size = Vector2( 20, 0 )
text = "Paused"
align = 1

[node name="Control" type="Control" parent="CenterContainer/VBoxContainer"]
margin_top = 44.0
margin_right = 250.0
margin_bottom = 54.0
rect_min_size = Vector2( 0, 10 )

[node name="Resume" type="Button" parent="CenterContainer/VBoxContainer"]
margin_top = 84.0
margin_right = 250.0
margin_bottom = 104.0
rect_min_size = Vector2( 250, 0 )
text = "Resume"

[node name="Quit" type="Button" parent="CenterContainer/VBoxContainer"]
margin_top = 134.0
margin_right = 250.0
margin_bottom = 154.0
text = "Quit"

[connection signal="pressed" from="CenterContainer/VBoxContainer/Resume" to="." method="_on_Resume_pressed"]
[connection signal="pressed" from="CenterContainer/VBoxContainer/Quit" to="." method="_on_Quit_pressed"]
Inventory and item system scripts
extends Node2D

const SlotClass = preload("res://Slot1.gd")
onready var inventory_slots = $GridContainer
var holding_item = null

func _ready():
	for inv_slot in inventory_slots.get_children():
		inv_slot.connect("gui_input", self, "slot_gui_input", [inv_slot])
		
func slot_gui_input(event: InputEvent, slot: SlotClass):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT && event.pressed:
			if holding_item != null:
				if !slot.item:
					slot.putIntoSlot(holding_item)
					holding_item = null
				else:
					var temp_item = slot.item
					slot.pickFromSlot()
					temp_item.global_position = event.global_position
					slot.putIntoSlot(holding_item)
					holding_item = temp_item
			elif slot.item:
				holding_item = slot.item
				slot.pickFromSlot()
				holding_item.global_position = get_global_mouse_position()
					
func _input(event):
	if holding_item:
		holding_item.global_position = get_global_mouse_position()
[gd_scene load_steps=6 format=2]

[ext_resource path="res://default_inventory_background.png" type="Texture" id=1]
[ext_resource path="res://item_slot_default_background.png" type="Texture" id=2]
[ext_resource path="res://Slot1.gd" type="Script" id=3]
[ext_resource path="res://Inventory.gd" type="Script" id=4]

[sub_resource type="StyleBoxTexture" id=1]
texture = ExtResource( 2 )
region_rect = Rect2( 0, 0, 18, 18 )

[node name="Inventory" type="Node2D"]
script = ExtResource( 4 )

[node name="TextureRect" type="TextureRect" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = 149.0
margin_top = 83.0
margin_right = 460.0
margin_bottom = 259.0
texture = ExtResource( 1 )

[node name="GridContainer" type="GridContainer" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = 236.0
margin_top = 105.0
margin_right = 353.0
margin_bottom = 194.0
custom_constants/vseparation = 5
custom_constants/hseparation = 5
columns = 4

[node name="Slot1" type="Panel" parent="GridContainer"]
margin_right = 25.0
margin_bottom = 25.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot2" type="Panel" parent="GridContainer"]
margin_left = 30.0
margin_right = 55.0
margin_bottom = 25.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot3" type="Panel" parent="GridContainer"]
margin_left = 60.0
margin_right = 85.0
margin_bottom = 25.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot4" type="Panel" parent="GridContainer"]
margin_left = 90.0
margin_right = 115.0
margin_bottom = 25.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot5" type="Panel" parent="GridContainer"]
margin_top = 30.0
margin_right = 25.0
margin_bottom = 55.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot6" type="Panel" parent="GridContainer"]
margin_left = 30.0
margin_top = 30.0
margin_right = 55.0
margin_bottom = 55.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot7" type="Panel" parent="GridContainer"]
margin_left = 60.0
margin_top = 30.0
margin_right = 85.0
margin_bottom = 55.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot8" type="Panel" parent="GridContainer"]
margin_left = 90.0
margin_top = 30.0
margin_right = 115.0
margin_bottom = 55.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot9" type="Panel" parent="GridContainer"]
margin_top = 60.0
margin_right = 25.0
margin_bottom = 85.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot10" type="Panel" parent="GridContainer"]
margin_left = 30.0
margin_top = 60.0
margin_right = 55.0
margin_bottom = 85.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot11" type="Panel" parent="GridContainer"]
margin_left = 60.0
margin_top = 60.0
margin_right = 85.0
margin_bottom = 85.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

[node name="Slot12" type="Panel" parent="GridContainer"]
margin_left = 90.0
margin_top = 60.0
margin_right = 115.0
margin_bottom = 85.0
rect_min_size = Vector2( 25, 25 )
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )

Item script only takes into account two different items for testing beta purposes


extends Node2D

func _ready():
	if randi() % 2 == 0:
		$TextureRect.texture = load("res://Slime Potion.png")
	else:
		$TextureRect.texture = load("res://Tree Branch.png")


[gd_scene load_steps=3 format=2]

[ext_resource path="res://Item.gd" type="Script" id=1]
[ext_resource path="res://Slime Potion.png" type="Texture" id=2]

[node name="Item" type="Node2D"]
z_index = 1
script = ExtResource( 1 )

[node name="TextureRect" type="TextureRect" parent="."]
margin_right = 40.0
margin_bottom = 40.0
mouse_filter = 2
texture = ExtResource( 2 )

Updates the item slots animation depending on if an item is placed in it or not


extends Panel

var default_tex = preload("res://item_slot_default_background.png")
var empty_tex = preload("res://item_slot_empty_background.png")
var default_style: StyleBoxTexture = null
var empty_style: StyleBoxTexture = null

var ItemClass = preload("res://Item.tscn")
var item = null

func _ready():
	default_style = StyleBoxTexture.new()
	empty_style = StyleBoxTexture.new()
	default_style.texture = default_tex
	empty_style.texture = empty_tex
	
	
	if randi() % 2 == 0:
		item = ItemClass.instance()
		add_child(item)
	refresh_style()

func pickFromSlot():
	remove_child(item)
	var inventoryNode = find_parent('Inventory')
	inventoryNode.add_child(item)
	item = null
	refresh_style()
	
func putIntoSlot(new_item):
	item = new_item
	item.position = Vector2(0,0)
	var inventoryNode = find_parent("Inventory")
	inventoryNode.remove_child(item)
	add_child(item)
	refresh_style()	

func refresh_style():
	if item == null:
		set('custom_styles/panel', empty_style)
	else:
		set('custom_styles/panel', default_style)