Salty Game Engine

1 / 2
Engine interface with multiple tabs
2 / 2
Exposed variables being edited in engine

A lightweight 2D C++ game engine, developed for the creation of browser games.

I developed this engine to better understand of architecture of the engines I use (mainly Unity). It was my main project for about a year, and I still occasionally update it. I also used it to make a game for the GMTK game jam this past summer.

I followed an ECS tutorials to get the core structure right, and then built my own systems on top of it. The two features I am most proud of are the undo history system, and a native C++ scripting system that behaves similarly to Unity scripts (with exposed variables in the engine UI). A simple player movement script example is shown below.

#pragma once
#include "SaltyEngine.h"

class PlayerMovement : public IScript {
private: 
    SF_ float speed;
    SF_ Rigidbody* rb;

    float jumpTimer = 0.0f; 
    SF_ Sound jumpSound;
public:
    // Initialization will be handled by engine (including that of SF_ variables)
    PlayerMovement(Entity* entity, Transform* transform, std::vector& serializedVars);

    void Start() override;
    void Update(float dt) override;
};
#include "PlayerMovement.h"

// Called before the first frame of Update()
void PlayerMovement::Start(){
    Audio::Load(sound);
    Camera::position = transform->position;
}

// Called every frame before Render() 
void PlayerMovement::Update(float dt){
    if(Input::KeyHeld[KEY_A]){
        transform->position.x -= dt * speed;
    }
    if(Input::KeyHeld[KEY_D]){
        transform->position.x += dt * speed;
    }
    Camera::position.x = transform->position.x;

    jumpTimer -= dt;
    if(Input::KeyDown[KEY_W] && jumpTimer <= 0){
        jumpTimer = 1.0f;
        rb->velocity.y = 3.0f;
        Audio::Play(jumpSound);
    }
}

Twenty-Four Puzzle

1 / 3
Matchstick particle effect + burn shader
2 / 3
Scissors Animation
3 / 3
Title Screen

A dark cabin, a locked door, a somewhat spooky monster, and all you have to do to escape is... math? Alternate between free move sections where you explore the cabin, and puzzle sections sitting at the table. Will you be able to escape the cabin?

I solo-developed Twenty-Four over a summer, with a focus on learning more about Unity's particle system and shader graph. I mainly used them to juice up card interactions (such as burning one with a match, or adding a glimmer when performing basic arithmetic). This made the puzzle actions feel more engaging, rather than just having the user look at numbers and symbols on a screen.

I also learned some valuable lessons about playtesting and puzzle design. Small quality-of-life additions (like having a level counter, to display how far from the next item players were) proved to be necessary to motivate players to keep going. The overall difficulty curve still ended up being far too difficult, and in hindsight I should have allocated more time to adjusting that rather than continuing to add mechanics.

Multiplayer Prototype

1 / 2
Networked item pickup and throw
2 / 2
Greyboxing for lower valley area

I am currently developing a P2P multiplayer game using Unity and Steamworks (for their relay servers). Players can connect to each other directly through Steam invite.

So far I have implemented basic networked player movement and a server-authoritative item pickup/throw system (although in this case, the server is the hosting player). When a player tries to pickup an item, they will send a request RPC to the host. The host decides if the pickup is valid, and then hands off ownership of the object to that player. This avoids duplication and keeps state consistent between players.

[ServerRpc(RequireOwnership = false)]
public void Pickup(PlayerController playerController, NetworkConnection conn = null)
{
	// If owned by server (no one is holding)
	if(base.OwnerId == -1)
	{
		base.GiveOwnership(conn);
		PickupObserver();
		playerController.ConfirmPickup(conn, this);
	}
	else
	{
		playerController.FailedPickup(conn);
	}
}

// Updates physics on client side
[ObserversRpc]
private void PickupObserver()
{
	if(_rb && _boxCollider)
	{
		_rb.isKinematic = true;
		_rb.useGravity = false;
		_boxCollider.enabled = false;
	}
}

I am using this project to explore how to build small networked systems. It is still in early development, but my current focus is on implementing new gameplay mechanics for each of the areas I have greyboxed out.

Hand Rehab App

1 / 3
Hand in Unity editor
2 / 3
Hand pose captured normally
3 / 3
Same pose with exaggerated angles

For my Bachelor's research project I developed an application in Unity.

This project explores using a Leap Motion sensor to assist in hand rehabilitation. By capturing the user's hand motion in real time, we build a 3D hand model that mirrors and exaggerates the user's gestures. The application uses forward kinematics and quaternion-based rotations to calculate joint positions and orientations, allowing for both accurate tracking and controlled exaggeration of motion for clinical purposes.

Additional smoothing techniques are applied to compensate for the Leap Motion's tracking limitations. Metrics such as range of motion, repetition speed, and fatigue level are tracked over time to provide quantitative feedback to users and therapists. Whilst the goal of the application was to create a visually intuitive application to support the recovery of fine motor skills through interactive exercises; the technical goal was to make the the underlying representation of the hand anatomically plausible even during exaggeration of motion.

Elements

Text

This is bold and this is strong. This is italic and this is emphasized. This is superscript text and this is subscript text. This is underlined and this is code: for (;;) { ... }. Finally, this is a link.


Heading Level 2

Heading Level 3

Heading Level 4

Heading Level 5
Heading Level 6

Blockquote

Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan faucibus. Vestibulum ante ipsum primis in faucibus lorem ipsum dolor sit amet nullam adipiscing eu felis.

Preformatted

i = 0;

while (!deck.isInOrder()) {
    print 'Iteration ' + i;
    deck.shuffle();
    i++;
}

print 'It took ' + i + ' iterations to sort the deck.';

Lists

Unordered

  • Dolor pulvinar etiam.
  • Sagittis adipiscing.
  • Felis enim feugiat.

Alternate

  • Dolor pulvinar etiam.
  • Sagittis adipiscing.
  • Felis enim feugiat.

Ordered

  1. Dolor pulvinar etiam.
  2. Etiam vel felis viverra.
  3. Felis enim feugiat.
  4. Dolor pulvinar etiam.
  5. Etiam vel felis lorem.
  6. Felis enim et feugiat.

Icons

Actions

Table

Default

Name Description Price
Item One Ante turpis integer aliquet porttitor. 29.99
Item Two Vis ac commodo adipiscing arcu aliquet. 19.99
Item Three Morbi faucibus arcu accumsan lorem. 29.99
Item Four Vitae integer tempus condimentum. 19.99
Item Five Ante turpis integer aliquet porttitor. 29.99
100.00

Alternate

Name Description Price
Item One Ante turpis integer aliquet porttitor. 29.99
Item Two Vis ac commodo adipiscing arcu aliquet. 19.99
Item Three Morbi faucibus arcu accumsan lorem. 29.99
Item Four Vitae integer tempus condimentum. 19.99
Item Five Ante turpis integer aliquet porttitor. 29.99
100.00

Buttons

  • Disabled
  • Disabled

Form