Skip to content

Latest commit

 

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 

Repository files navigation

Court Smith

Contact

Table of Contents

Section Description
Experience Company Projects - No Source
Projects Personal and Contract + Source Available
Demonstrations Videos of Demonstrating Systems where code is not available

Experience

Game Design and Production Instructor

  • Creating course projects for Unreal Engine 5.

Looty Games - Avatar Air Bender Fighting Game (Lua)

  • Missions System
  • Emote System
  • Tutorial
  • Leaderboard
  • Sound System
  • Round System

VIDEO | GAME

Twin Atlas - MTV, Teen Wolf, West Elm (Lua)

  • House Editor
  • Voting System
  • Obstacle Course
  • Round System
  • Shop System

WEREWOLF ESCAPE PROMO | WEREWOLF ESCAPE GAME

WELD ELM PROMO | WEST ELM GAME

MTV PROMO

CUDO - CUDO World RPG (Unreleased) (Lua)

  • Chest Reward System
  • Shop System

Fishing Simulator (Lua, JavaScript)

  • Live Operations Data Management Tools

Video Demonstration

GAME

Projects

  • Fallen Star Horizon (Unreal Engine, C++)
  • Unreal VR Template Conversion to C++ (Unreal Engine, C++)
  • Necromancer's Tomb (Unreal Engine, Blueprint)
  • Clan Labs (Node.js, JavaScript, Web, API)
  • Area 24 (Roblox, Lua, Weapons, AI, RPG Systems)

Fallen Star Horizon - C++ - Current Work in Progress

About

A project for testing networking and top-down gameplay.

Excerpt - Interaction Component

SOURCE: https://github.com/TechProgramming/Fallen-Star-Horizon

// Fill out your copyright notice in the Description page of Project Settings.


#include "FSHInteractComponent.h"

#include "Components/SphereComponent.h"
#include "FallenStarHorizon/Character/FSHCharacter.h"
#include "FallenStarHorizon/UserInterface/HUD/FSHInteractOption.h"
#include "FallenStarHorizon/Weapon/FSHWeapon.h"


// Sets default values for this component's properties
UFSHInteractComponent::UFSHInteractComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;
	
}


// Called when the game starts
void UFSHInteractComponent::BeginPlay()
{
	Super::BeginPlay();

	AActor* Owner = this->GetOwner();
	SetWidgetVisible(false, nullptr);
	if (Owner && Owner->HasAuthority())
	{
		InteractionSphere->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
		InteractionSphere->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
		InteractionSphere->OnComponentBeginOverlap.AddDynamic(this, &UFSHInteractComponent::OnSphereBeginOverlap);
		InteractionSphere->OnComponentEndOverlap.AddDynamic(this, &UFSHInteractComponent::OnSphereEndOverlap);
		
	}
}

void UFSHInteractComponent::SetWidgetVisible(bool bIsVisible, AActor* Instigator)
{
	AActor* Owner = this->GetOwner();
	 if (Owner && InteractPromptWidget)
	 {
	 	InteractPromptWidget->SetVisibility(bIsVisible);
	 	if (auto* Character = Cast<AFSHCharacter>(Instigator))
	 	{
	 		switch (InteractObjectType)
	 		{
	 		case EInteractObjectType::EIOT_Weapon:
	 			{
	 				auto* Weapon = Cast<AFSHWeapon>(GetOwner());
	 				Character->PushReplicationOverlappingWeapon(Weapon);
	 				return;
	 			}
	 		case EInteractObjectType::EIOT_Custom:
	 			{
	 				return;
	 			}
	 		}
	 	}
	 }
}

void UFSHInteractComponent::SetCanInteract(bool bNewIsActive)
{
	bActive = bNewIsActive;
	//UFSHInteractComponent::SetWidgetVisible(bIsVisible, Instigator);
}

bool UFSHInteractComponent::GetCanInteract()
{
	return bActive;
}

void UFSHInteractComponent::Trigger(AActor* Instigator)
{
	OnTriggered.Broadcast(Instigator);
	Triggered(Instigator);
}

void UFSHInteractComponent::Triggered_Implementation(AActor* Instigator)
{
	
}


void UFSHInteractComponent::OnSphereBeginOverlap(UPrimitiveComponent* OverlapComponent, AActor* OtherActor,
                                                 UPrimitiveComponent* OtherComp, int32 OtherBoxIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	AActor* Owner = this->GetOwner();
	AFSHCharacter* FSHCharacter = Cast<AFSHCharacter>(OtherActor);
	if (Owner && FSHCharacter)
	{
		if(UFSHInteractOption* InteractionOption = Cast<UFSHInteractOption>(InteractPromptWidget->GetUserWidgetObject()))
		{
			InteractionOption->ActionTextBlock->SetText(FText::FromString(DisplayText));
			// Push
			FSHCharacter->InteractableComponentsNearby.Emplace(this);
		}
	}
}

void UFSHInteractComponent::OnSphereEndOverlap(UPrimitiveComponent* OverlapComponent, AActor* OtherActor,
											UPrimitiveComponent* OtherComp, int32 OtherBoxIndex)
{
	AActor* Owner = this->GetOwner();
	AFSHCharacter* FSHCharacter = Cast<AFSHCharacter>(OtherActor);
	if (Owner && FSHCharacter)
	{
		//if(GEngine) { 
		//	GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, TEXT("END 1"));
		//}
		if(UFSHInteractOption* InteractionOption = Cast<UFSHInteractOption>(InteractPromptWidget->GetUserWidgetObject()))
		{
			//if(GEngine) { 
			//	GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, TEXT("END 2"));
			//}
			const int32 ItemIndex = FSHCharacter->InteractableComponentsNearby.IndexOfByKey(this);
			FSHCharacter->InteractableComponentsNearby.RemoveAt(ItemIndex);
			SetWidgetVisible(false, nullptr);
		}
	}
}

// Called every frame
void UFSHInteractComponent::TickComponent(float DeltaTime, ELevelTick TickType,
                                          FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
 
}

Demonstration

Features

  • Interact Prompt
  • Crouch
  • Environment Obstacles
  • Wandering AI
  • Equip Weapon
  • Aim Weapon
  • Lobby Networking

Unreal VR Template C++ Conversion (WIP) - C++

SOURCE: https://github.com/TechProgramming/VRProjectExample

Video

Changes

  • Converted Grab Component to C++
  • Made a new Pistol that supports the C++ Grab Component
  • Added Locomotion and Smooth Turn
  • Added Pullable Lever

Excerpt - Lever

Source: https://github.com/TechProgramming/VRProjectExample/blob/master/Source/VRProjectExample/VRPLever.cpp

#include "VRPLever.h"
#include <Kismet/KismetMathLibrary.h>

// Sets default values
AVRPLever::AVRPLever()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	Scene = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
	Lever = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Lever"));
	GrabComponent = CreateDefaultSubobject<UVRPGrabComponent>(TEXT("GrabComponent"));

	RootComponent = Scene;
	Lever->SetupAttachment(Scene);
	GrabComponent->SetupAttachment(Lever);
}

// Called when the game starts or when spawned
void AVRPLever::BeginPlay()
{
	Super::BeginPlay();

	GrabComponent->OnGrabbedDelegate.AddDynamic(this, &ThisClass::OnGrabbed);
	GrabComponent->OnDroppedDelegate.AddDynamic(this, &ThisClass::OnDropped);
}

// Called every frame
void AVRPLever::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void AVRPLever::UpdateRotation()
{
    if (!MotionControllerRef || !bIsGrabbed) {
        return;
    }


    FVector ControllerWorldPos = MotionControllerRef->GetComponentLocation();
    FVector LeverPivotPos = Scene->GetComponentLocation();
    FVector ControllerLocalPos = Scene->GetComponentTransform().InverseTransformPosition(ControllerWorldPos);
    FVector MovementDelta = ControllerLocalPos - InitialGrabOffset;
    float RotationDelta = -MovementDelta.X * RotationSensitivity;

    float NewPitch = FMath::Clamp(
        InitialLeverRotation.Pitch + RotationDelta,
        -70.0f,
        70.0f
    );

    FRotator NewRotation = FRotator(
        NewPitch,
        InitialLeverRotation.Yaw,
        InitialLeverRotation.Roll
    );

    Lever->SetRelativeRotation(NewRotation);
}

void AVRPLever::OnGrabbed(UMotionControllerComponent* MotionController)
{
	MotionControllerRef = MotionController;
	GetWorldTimerManager().SetTimer(UpdateRotationTimerHandle, this, &ThisClass::UpdateRotation, 0.01f, true);

	bIsGrabbed = true;
	InitialLeverRotation = Lever->GetRelativeRotation();
	FVector ControllerWorldPos = MotionController->GetComponentLocation();
	InitialGrabOffset = Scene->GetComponentTransform().InverseTransformPosition(ControllerWorldPos);
}

void AVRPLever::OnDropped()
{
	GetWorldTimerManager().ClearTimer(UpdateRotationTimerHandle);
	MotionControllerRef = nullptr;
	bIsGrabbed = false;
}

Necromancer's Tomb - Blueprint

SOURCE: https://github.com/TechProgramming/NecromancersTomb

WEBSITE: https://clanlabs.co/

About

  • A project to test AI, Obstacles, Hiding Mechanic, and Unlocking Doors

Features

  • Patrolling AI
  • Stealth Hide in Corners
  • Floor Trap with Delay
  • Collectible
  • Unlockable Door
  • Objective UI

Code Snapshots

Shadow Cover

GRAPH: https://blueprintue.com/blueprint/njj2tnol/

Trap

GRAPH: https://blueprintue.com/blueprint/ruoybuci/

Clan Labs - Private Snapshot (Request Only) - JavaScript

SOURCE CODE: https://github.com/TechProgramming/Clan-Labs-Snapshot

About

  • This is a older snapshot of a commercial project called "Clan Labs"
  • The web API for customers to talk to the database.
  • A discord bot is used to manage users and data within customer "groups"
  • Created in 2018
  • 3000+ Groups
  • $5/mo

Technology Stack

  • MongoDB
  • Express.js
  • Discord.js
  • Mongoose.js
  • Node.js

Features

  • User Profiles
  • User XP
  • Quota Tracking
  • Blacklist
  • Automated Background Check
  • Warnings
  • Permission System
  • Customization
  • Subscription System
  • Developer Web API

Architecture

Tutorial

Excerpt - User API

SOURCE: https://github.com/TechProgramming/Clan-Labs-Snapshot/blob/main/ClanLabs-API/src/services/user.service.js

const setUserExperience = async (group, userId, amount) => {

    // Get User

    let userData = await getUserById(group, userId);
    if(!userData) {
        userData = await createUserById(group, userId);
        if(userData == "User doesn't exist on Roblox") return userData;
    }

    // XP Magic? - Thanks Doge
    
    if(amount < userData.experience) {
        amount = userData.experience - amount;
        amount = -amount;
    } else if(amount > userData.experience) amount - amount - userData.experience;

    // Clamp to Settings

    let maxChangeAmount = group.settings.experienceAPIAwardLimit;
    if(amount >= 0) amount = require('../utils/clamp.js')(amount, 0, maxChangeAmount)
    else amount = require('../utils/clamp.js')(amount, -maxChangeAmount, 0);

    // Increment XP

    let newUserData = await userDB.incrementXP(group, userId, amount);

    // Create Audit Log

    auditService.createAudit(group, {
        targetId: newUserData.userid,
        targetName: newUserData.username,
        auditString: `(**API**): Changed **${newUserData.username}**'s XP from **${userData ? userData.experience : "0"}** to **${newUserData.experience + amount}**!`,
    });

    // Auto Rank Member
    
    await (require('../utils/autoRank.js')(group, newUserData));

    // Get Updated User

    newUserData = await getUserById(group, userId);
    return newUserData;

}

Area 24 - Lua

SOURCE CODE: https://github.com/TechProgramming/Area-24

GAME: https://www.roblox.com/games/7027296354/SCP-Area-24

About

This is a project that was developed as a fan game for an SCP community where you could roleplay different teams and SCP creatures.

Features

  • Weapons
  • Teams
  • Camera System
  • Area Detection
  • Lighting Management
  • Time Management
  • Items and Interaction
  • Enemy AI
  • Vehicles
  • Currency
  • Shop
  • Monetization
  • Character Customization
  • Daily Login Award
  • Jobs
  • Data Saving

Demonstration

Excerpt - SCP 042 AI

SOURCE: https://github.com/TechProgramming/Area-24/blob/master/src/Server/Server/Services/Core/SCP/Entities/035.luau

function SCP:BreachWander()
	
	if script:GetAttribute("Debug_Print") then
		print("035 Breach Wandering");
	end;
	local scpHumanoidRootPart = self.Agent.Character.HumanoidRootPart;
	local scpPosition = scpHumanoidRootPart.Position;
	
	if not self.Agent.Directive then
		if script:GetAttribute("Debug_Print") then
			print("035 No Directive is Available, requesting new Directive");
		end;
		math.randomseed(tick());
		local nodeTarget = SCPNodemap:GetChildren()[math.random(1, #SCPNodemap:GetChildren())]:GetAttribute("NodePosition");
		local success = AgentService:CreateDirective(self.Agent, nodeTarget, SCPNodemap);
		self:BreachWander();
	else
		if script:GetAttribute("Debug_Print") then
			print("035 Directive Available, continuing");
		end;
		SCP:DebugDirective();
		if self.Agent.WaypointType ~= "Breach" then
			local nodeTarget = self.Agent.Directive[1];
			local success = AgentService:CreateWaypoints(self.Agent,
				Vector3.new(math.random(scpPosition.X - PATH_START_BIAS, scpPosition.X + PATH_START_BIAS), scpPosition.Y,math.random(scpPosition.Z - PATH_START_BIAS, scpPosition.Z + PATH_START_BIAS)),
				Vector3.new(math.random(nodeTarget.X - PATH_END_BIAS, nodeTarget.X + PATH_END_BIAS), nodeTarget.Y, math.random(nodeTarget.Z - PATH_END_BIAS, nodeTarget.Z + PATH_END_BIAS)),
				"Breach");
			if success then
				self:BreachWander();
			else
				self:RemoveWaypoint();
				if not self.Agent.Directed then
					self.Agent.Directed = 0;
				end;
				self.Agent.Directed += 1;
				if self.Agent.Directed >= DIRECT_TIMEOUT then
					AgentService:ClearDirective(self.Agent);
				end;
			end;
		else
			
			self:DoWaypoint();
			
			if (Normalize(self.Agent.Directive[1]) - Normalize(scpHumanoidRootPart.Position)).magnitude <= DIRECTIVE_REACH_RADIUS then
				
				if math.random(1, 100) <= SPEECH_CHANCE then
					SCP:Speak();
				end;
				table.remove(self.Agent.Directive, 1);
				self:RemoveWaypoint();
				if #self.Agent.Directive <= 0 then
					AgentService:ClearDirective(self.Agent);
				else
					self:BreachWander();
				end;
			end;
		end;
	end;
end

Demonstrations (UE)

Unreal Engine Networking

Cutscene Test + Dialogue

Interaction System + Dialogue

Architecture Camera and Floor Change + Control Time

Pickup Object + Lean + Camera Bob + Camera Zoon + Sprint and Stamina + Breathing Change with Stamina + Hold Breath and Hear Heartbeat + Flashlight

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors