
Zombies+
Game Mod
Project Overview
This was a mod designed for Minecraft. It was originally created for a custom zombie modpack, enabling new types of AI for zombies. It was also my first attempt at maintaining the mod across multiple Minecraft versions, programming the mod to work on two different modloaders (Forge and Fabric), and combining the two separate modloader files into one using library mods such as Architectury. I created a multitude of different zombies, each with unique traits. I created my own textures for each AI and even modeled some of them. Because this was originally designed for a zombie modpack, I created special textures and animations meant to synergize with Tissou's Zombies. My most proud creation was the Crawler Zombie, as I had to model it using parts from the base Zombie and animate it from scratch.
After posting the mod to Modrinth and CurseForge, I updated it continuously with new mobs and bug fixes. It slowly started to gain traction, and over time it reached more than 140k downloads. It was featured in modpacks made by other users and was even included in a YouTube video. This mod gained so much popularity that I landed a partnership with Kinetic Hosting, a Minecraft server hosting platform.
Skills & Learning Outcomes
- •Refined Java programming skills and AI behavior programming
- •Proficiency with IntelliJ IDEA Community Edition development environment
- •Minecraft Forge/Fabric API and modding framework expertise
- •Gained user feedback
- •Large-scale community and downloads (140k+ downloads)
Project Gallery

Runner Zombie

Realistic Brute Zombie

Realistic Zombie Variant

Realistic Cave Zombie

Brute Zombie

Crossbow Zombie

Weak Zombie

Axe Zombie

Shrieker Zombie

Realistic Crawler Zombie

Cave Zombie

Slow Zombie

Crawler Zombie

Bow Zombie

Vile Zombie

Sword Zombie

Leaper Zombie
The abstract base class that all zombie variants extend from. This class handles core zombie behavior, animations, and spawn conditions:
package net.trial.zombies_plus.entity.custom;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.Difficulty;
import net.minecraft.world.entity.*;
public abstract class abstractZombieEntity extends Zombie {
public final AnimationState idleAnimationState = new AnimationState();
private int idleAnimationTimeout = 0;
private boolean hasSetupAnim = false;
private boolean leftArmVisible = true;
private boolean rightArmVisible = true;
private static boolean isAggro = false;
public abstractZombieEntity(EntityType<? extends Zombie> pEntityType, Level pLevel) {
super(pEntityType, pLevel);
this.refreshDimensions();
}
public ResourceLocation getTexture(){
return new ResourceLocation("minecraft", "textures/entity/zombie/zombie.png");
}
public static boolean getAggressiveState(){
return isAggro;
}
@Override
public boolean isAggressive() {
isAggro = super.isAggressive();
return isAggro;
}
@Override
protected boolean convertsInWater() {
return false;
}
public float rotlerpRad(float pAngle, float pMaxAngle, float pMul) {
float f = (pMul - pMaxAngle) % ((float)Math.PI * 2F);
if (f < -({float)Math.PI) {
f += ((float)Math.PI * 2F);
}
if (f >= (float)Math.PI) {
f -= ((float)Math.PI * 2F);
}
return pMaxAngle + pAngle * f;
}
@Override
public void tick() {
super.tick();
if(this.level().isClientSide()) {
setupAnimationStates();
}
}
protected void setupAnimationStates() {
if(this.idleAnimationTimeout <= 0) {
this.idleAnimationTimeout = this.random.nextInt(40) + 80;
this.idleAnimationState.start(this.tickCount);
} else {
--this.idleAnimationTimeout--;
}
}
@Override
public void setBaby(boolean pChildZombie) {
// Prevents baby zombies
}
@Override
protected void updateWalkAnimation(float pPartialTick) {
float f;
if(this.getPose() == Pose.STANDING) {
f = Math.min(pPartialTick * 6F, 1f);
} else {
f = 0f;
}
this.walkAnimation.update(f, 0.2f);
}
public static boolean canSpawnDuringDay(ServerLevelAccessor pLevel, BlockPos pPos, RandomSource pRandom) {
DimensionType dimensiontype = pLevel.dimensionType();
int i = dimensiontype.monsterSpawnBlockLightLimit();
if (i < 15 && pLevel.getBrightness(LightLayer.BLOCK, pPos) > i) {
return false;
}
int j = pLevel.getLevel().isThundering() ? pLevel.getMaxLocalRawBrightness(pPos, 10) : pLevel.getMaxLocalRawBrightness(pPos);
return j <= dimensiontype.monsterSpawnLightTest().sample(pRandom);
}
@Override
public EntityDimensions getDimensions(Pose pPose) {
return EntityDimensions.scalable(DEFAULT_BB_WIDTH, 2f);
}
}Click to expand and view the full code implementation.

Junk Food Additions
Game Mod
Project Overview
This mod was created to spice up the stale food economy with more fun foods in the base game of Minecraft. This project adds a multitude of junk-food items to the game, each with its own behavior. It also adds blocks and other food utilities. Most textures were created by me, with the fries' textures created by Alexander Allred (a friend). This project helped build confidence in Java programming and improved my understanding of more complex development environments inside an IDE.
Skills & Learning Outcomes
- •Java programming and Minecraft Forge/Fabric API implementation
- •Texture creation and pixel art design
- •Item behavior programming and crafting recipe design
- •Texture file management
- •Gained public traction (3k+ downloads)
Code Example
package net.trial.junk_food_additions.item.custom;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.SwordItem;
import net.minecraft.world.item.Tier;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import java.util.Map;
public class DIAMOND_KITCHEN_KNIFE extends SwordItem {
public DIAMOND_KITCHEN_KNIFE(Tier pTier, int pAttackDamageModifier,
float pAttackSpeedModifier,
Properties pProperties) {
super(pTier, pAttackDamageModifier, pAttackSpeedModifier,
pProperties.durability(1561));
}
@Override
public boolean isEnchantable(ItemStack pStack) {
return true;
}
@Override
public boolean hasCraftingRemainingItem(ItemStack stack) {
return true;
}
@Override
public ItemStack getCraftingRemainingItem(ItemStack itemStack) {
ItemStack remainingItem = itemStack.copy();
if (remainingItem.hurt(1, RandomSource.create(), null)) {
remainingItem.shrink(1); // remove if broken
}
return remainingItem;
}
@Override
public boolean isBookEnchantable(ItemStack stack, ItemStack book) {
Map<Enchantment, Integer> enchantments =
EnchantmentHelper.getEnchantments(book);
for (Enchantment enchantment : enchantments.keySet()) {
if (!enchantment.canEnchant(
new ItemStack(Items.DIAMOND_SWORD))) {
return false;
}
}
return true;
}
}This is the custom item class for the Diamond Kitchen Knife, a custom item in my mod. This code displays the Minecraft item behavior, including durability management, enchantment, and crafting mechanics. The diamond kitchen knife is a reusable tool that loses durability when used in crafting recipes.
Gallery

In-game inventory showing all custom junk food items

Custom 3D model for the dino nugget creature mob

JSON recipe configuration for diamond kitchen knife crafting

Cardboard Momoa
Game Mod
Project Overview
Cardboard Momoa is a Lethal Company mod that introduces a custom AI entity with pathfinding capabilities. The model of Jason Momoa was provided to me and modeled onto a flat surface by Alexander Allred (a friend of mine). This project represents a significant achievement in my C# programming journey, reaching over 40,000 downloads on Thunderstore. The mod features enemy behavior that challenges players and effectively keeps players uneasy.
Through developing this mod, I refined my skills in AI pathfinding, C# programming, and the Unity engine. This mod was also featured in other modpacks and even in some Youtube clips.
Skills & Learning Outcomes
- •AI pathfinding and navigation systems
- •Built confidence with C# programming and Unity engine
- •Refined skills with VS 2022
- •Game AI behavior design implementation
- •40k+ downloads
Here's the setup for configuring the Jason Momoa AI entity:
jasonBehaviour.yellSound= scream;
jasonBehaviour.scrapeSound= scrape;
jasonBehaviour.eye= momoaBody.transform.Find("Eye");
jasonBehaviour.scrapeSound= scrape;
jasonBehaviour.eye= momoaBody.transform.Find("Eye");
jasonBehaviour.animStopPoints= momoaBody.transform.Find("AnimContainer").GetComponent<AnimationStopPoints>();
momoaBody.GetComponent<EnemyAICollisionDetect>().mainScript= jasonBehaviour;
jasonBehaviour.mainCollider= momoaBody.GetComponent<BoxCollider>();
LethalLib.Modules.NetworkPrefabs.RegisterNetworkPrefab(jasonMomoa.enemyPrefab);
Utilities.FixMixerGroups(jasonMomoa.enemyPrefab);
Enemies.RegisterEnemy(jasonMomoa, Configuration.configSpawnWeight.Value, Levels.LevelTypes.All, null, null);Click to expand and view the full code implementation.
Gallery


Scraptopia
Game Mod
Project Overview
This was a mod designed for a horror game called Lethal Company. Around a year ago, Lethal Company overtook the gaming market, and a growing modding community formed around the game using C#. I decided to join that community and introduced myself to C# programming. Within just a couple of days, I programmed many items into the game, all with their own models, textures, and behaviors that I created.
I quickly adapted to the syntax of C# despite not having prior experience with the language. I also learned how to work with Unity, a game engine I was unfamiliar with. I switched to Visual Studio 2022 for my development environment, so I had to get familiar with the new IDE as I had never used it before.
Skills & Learning Outcomes
- •Introduction to C# programming language, Unity game engine, and VS 2022
- •Proficiency with VS 2022
- •3D modeling and texture painting
- •Package handling and file handling (.dll)
- •8k+ downloads
Gallery

Squibble Character

Golden Donut in-game

Strawberry Donut in-game

Golden Donut 3D model
Here's the method used to register custom scrap items in the mod: We set the item's rarity, spawn types, model, stats, and where it can spawn
void setupScrapItem(Item item, int rarity)
{
if (item != null && rarity > 0)
{
NetworkPrefabs.RegisterNetworkPrefab(item.spawnPrefab);
Utilities.FixMixerGroups(item.spawnPrefab);
Items.RegisterScrap(item, rarity, Levels.LevelTypes.All);
Logger.LogInfo(`{item} has been loaded!`);
}
}Click to expand and view the full code implementation.

UncannyJackBlack
Game Mod
Project Overview
UncannyJackBlack is a Lethal Company mod that introduces a custom AI entity with animations and pathfinding systems. This project served as my introduction to animation states and more complex behavior systems. The mod features a world-renowned celebrity Jack Black as an enemy with animations and player-seeking navigation that creates tense gameplay moments.
Through this project, I learned the fundamentals of animation states in AI behavior. After publishing the mod, it received 12000+ downloads.
Skills & Learning Outcomes
- •Introduction to AI animation states
- •AI pathfinding algorithms
- •C# programming and Unity animation controller setup
- •Behavior flow and AI line of sight programming
- •Fostered community engagement and featured in modpacks (12k+ downloads)
This code implements the chase behavior. He first finds a player nearby to chase. If it has been more than 20 seconds since his last kill, he switches into a wandering state. Else, he continues to chase them.
PlayerControllerB closestPlayer = GetClosestPlayer();
SetMovingTowardsTargetPlayer(closestPlayer);
ModMain.LOGGER.LogInfo(sinceLastKill);
if ((Time.time - sinceLastKill) >= 20f)
{
ModMain.LOGGER.LogInfo("Switching back to wandering!");
this.creatureAnimator.SetTrigger("stopChase");
SwitchToBehaviourState((int)behaviourStates.wanderingState);
StartSearch(base.transform.position, this.searchRoutine);
break;
}
audioSource.PlayOneShot(screamAudio);
StopSearch(this.searchRoutine);
this.agent.speed= chaseSpeed;
ModMain.LOGGER.LogInfo("Chasing closest player");
break;Click to expand and view the full code implementation.
Gallery

Jack Black - in-game enemy

Escape Jason
Video Game
Key Highlights
Project Overview
This project was a Roblox horror game made collaboratively with other developers. I was the lead and primary programmer on the team. This game demonstrated my skill in Lua programming and team collaboration. Our custom AI used a separate pathfinding module called SimplePath, which was made by other creators. After publishing the game to Roblox, we achieved around 1,000 visits, and about 100 players joined our community group.
Skills & Learning Outcomes
- •LUA programming and AI pathfinding programming
- •Collaboration with other team members and working together
- •Game design and horror game mechanics
- •Map design and atmospheric environment creation
- •Community building and player engagement (1,000+ visits, ~100 community members on group)
local jason = script.Parent
local Enemy = jason:WaitForChild("Enemy")
local jasonisStuck = false
-- set the bounds of the model
local AgentParameters = {
["AgentRadius"] = 7,
["AgentHeight"] = 5,
["AgentCanJump"] = true
}
-- grab the walkpoints that the AI will move to
local Waypoints = jason:WaitForChild("Waypoints").Value:GetChildren()
-- SimplePath is a Roblox pathfinding module developed by other creators
-- The link to SimplePath: https://grayzcale.github.io/simplepath/
local SimplePath = require(game.ServerStorage:WaitForChild("SimplePath"))
-- Function that checks to see if we can see a player to chase
local function CanSeeTarget(Target)
-- Roblox raycasts can be used to check line of sight between two positions
local Origin = jason.HumanoidRootPart.Position
local Direction = (Target.HumanoidRootPart.Position - Origin).unit * MaxDistance.Value
local RayParams = RaycastParams.new()
RayParams.FilterType = Enum.RaycastFilterType.Blacklist
local RaycastResult = game.Workspace:Raycast(Origin, Direction, RayParams)
if RaycastResult then
if RaycastResult.Instance:IsDescendantOf(Target) then
return true
end
end
return false
end
-- Main loop that does the patrolling
while wait() do
for _, waypoint in pairs(Waypoints) do
WalkToGoal(waypoint)
end
endClick to expand and view the full code implementation.
Project Gallery

Military Camp Area

Map Voting Lobby

Farm Environment

Nighttime Forest

OpenCV Computer Vision Bot
Computer Vision Project
Key Highlights
Project Overview
This program was designed to be an automated bot that used the Python AutoHotKey library to simulate input. This bot would play a specific Roblox game and "farm" in-game currency for multiple hours while I worked on other tasks. To achieve this, I used computer vision to detect images or objects on screen, and upon detecting them, the program simulated certain input. To detect certain objects more clearly, I applied an HSV color filter to make the target object's colors stand out more. I then fed an image of this color-filtered object into the program and applied the same HSV filter to my screen. After doing so, the program could see the target object more clearly and used the OpenCV Python library to detect it based on its colors. Once detected, it returned the object's screen coordinates. In a perfect environment (with no connectivity issues), this program could run indefinitely.
Skills & Learning Outcomes
- •Python programming with OpenCV library integration
- •Profiency with PyCharm Community Edition IDE
- •Template matching and object detection algorithms
- •HSV color space filtering and image segmentation
- •AutoHotKey python library integration
- •Ran for multiple hours without supervision
This Python code shows the computer vision system using OpenCV for image/object matching and image processing.
import cv2 as cv
import numpy as np
from hsvfilter import HsvFilter
class Vision:
# constants
TRACKBAR_WINDOW = "Trackbars"
# properties
needle_img = None
needle_w = 0
needle_h = 0
method = None
# constructor
def __init__(self, needle_img_path, method=cv.TM_CCOEFF_NORMED):
# load the image we're trying to match
self.needle_img = cv.imread(needle_img_path, cv.IMREAD_UNCHANGED)
# save the dimensions of needle image
self.needle_w = self.needle_img.shape[1]
self.needle_h = self.needle_img.shape[0]
self.method = method
def find(self, haystack_img, threshold=0.5, max_results=10):
# run OpenCV
result = cv.matchTemplate(haystack_img, self.needle_img, self.method)
# get positions from match result that exceed our threshold
locations = np.where(result >= threshold)
locations = list(zip(*locations[::-1]))
if not locations:
return np.array([], dtype=np.int32).reshape(0, 4)
rectangles = []
for loc in locations:
rect = [int(loc[0]), int(loc[1]), self.needle_w, self.needle_h]
rectangles.append(rect)
rectangles.append(rect)
rectangles, weights = cv.groupRectangles(rectangles, groupThreshold=1, eps=0.5)
if len(rectangles) > max_results:
print('Warning: too many results, raise the threshold.')
rectangles = rectangles[:max_results]
return rectangles
def draw_rectangles(self, haystack_img, rectangles):
line_color = (0, 255, 0)
line_type = cv.LINE_4
for (x, y, w, h) in rectangles:
top_left = (x, y)
bottom_right = (x + w, y + h)
cv.rectangle(haystack_img, top_left, bottom_right, line_color, lineType=line_type)
return haystack_imgClick to expand and view the full code implementation.
Project Gallery

HSV color filtering demonstration showing before and after results

Object/image detection example visualization

Discord bot integration showing automated status updates