About Projects Skills Experience Education Contact Resume ↓
Based in Toronto · Open to Montreal, Vancouver & Remote worldwide

Hi, I'm Dwip.
I build gameplay
systems.

Gameplay Programmer with a published mobile game, AR/XR solutions, and combat systems — specializing in Unity, Unreal Engine 5, and clean production-quality C#/C++.

Scroll

Code that feels
as good as it runs.

T-shaped developer — deep in gameplay mechanics and systems, broad across mobile, AR/XR, tools, and AI.

I'm a Gameplay Programmer based in Toronto. I've built and published a hyper-casual mobile game to Google Play with real analytics, monetization, and cloud save pipelines — not a demo, a live product with players.

I have professional experience at Liminal VR/AR (Unity + AWS AR asset pipeline, 200MB → 45MB app size) and Oneros Tech (Photon multiplayer, 45% latency reduction). Currently completing a Post-Graduate Certificate in Applied AI at George Brown College.

I like games with bluffing mechanics and real-time co-op. If something's broken, I dig until I find it — and I don't settle until it's right.

C# · Unity3DC++ · UE5 Gameplay SystemsMobile Optimization AR / XR / ARCoreFirebase + Crashlytics Unity IAP · AdMob SDKGoogle Play Games SDK Cinemachine · New Input System DOTS / Job SystemPhoton Networking Git / PerforceApplied AI

Quick Gaming Experience

Software Programmer
Liminal VR and AR
Aug 2022 – Aug 2023 · Mumbai
  • Cloud AR pipeline: app size 200 MB → 45 MB via Addressables + AWS S3
  • Asset load times ↓60% via LRU caching + progressive loading
  • Memory footprint ↓40% via runtime texture compression + dynamic LOD
Game Programmer
Oneros Tech Pvt. Ltd.
Jan 2021 – Jun 2021 · Mumbai
  • Photon multiplayer latency ↓45%, desync issues eliminated 80%
  • Stable 60fps on Adreno 506 GPU via Unity Profiler data-driven optimization
  • Modular MVC architecture → merge conflicts ↓70%

Projects that prove
the depth.

Selected work with real technical breakdowns — not just what it looks like, but how and why it was built.

🎮 Published · Google Play · Android + WebGL + PC

Crossy Railroad

A hyper-casual mobile game fully architected and published to Google Play. A live product with real players, analytics, monetization, cloud saves, and cross-platform builds — profiled from 28fps to stable 60fps on mid-range devices.

Unity 2022C# Curvy SplinesFirebase + Crashlytics IronSource MediationUnity IAP Google Play Games SDKURP GameAnalytics SDK
+32%
Day-7 Retention
60fps
Mid-range Devices
6
Themed Maps
3
Build Platforms
⚙ Technical Deep Dive

Vehicle queue handoff at spline position 48 → 54

The core challenge: queue multiple vehicles on a single road, let the player control only the front one, and keep everything else auto-driving without stutter. Each vehicle follows a Curvy Splines path with Mathf.Lerp acceleration — zero physics overhead.

// VehicleController.cs — smooth spline acceleration
if (isMoving || IsPassed)
    currentSpeed = Mathf.Lerp(currentSpeed, targetSpeed, accelerationRate * Time.deltaTime);
else
    currentSpeed = Mathf.Lerp(currentSpeed, 0.0f, decelerationRate * 10.0f * Time.deltaTime);

Control hands off at spline position 48. When the active vehicle crosses position 54, it cascades a push to every other vehicle — a data-driven queue with no hardcoded offsets.

// GameManager.cs — cascade queue update
public void UpdateVehiclesTargetPos(float addTargetPos, GameObject instigator) {
    for (int i = 0; i < CurrentVehiclesOnMap.Count; i++)
        if (CurrentVehiclesOnMap[i] != instigator)
            CurrentVehiclesOnMap[i].GetComponent<VehicleController>().targetPos += addTargetPos;
}

Every ad event logs to two analytics systems simultaneously — Firebase Analytics with structured Parameter[] arrays AND GameAnalytics SDK — giving cross-platform redundancy and independent reporting dashboards.

Firebase Analytics
Structured event logging + Crashlytics
IronSource
Mediated banner, interstitial, rewarded
Unity IAP
5-tier coin purchase + receipt validation
GPGS Cloud Save
Binary JSON + conflict resolution
GameAnalytics SDK
Progression + business events
YouTube Playables
WebGL + YT leaderboard API

Google Play Games cloud save uses ConflictResolutionStrategy.UseMostRecentlySaved with an internet connectivity check before any write — prevents corrupt saves on flaky connections.

Six fully themed maps (Carnival, City, Port, WildWest, SciFi, Plain) — each with their own light arrays, train models, and building window materials — all toggled via a single enum-switch call.

The day/night system reads actual system time via System.DateTime.Now.Hour — not a designer-set bool. The "Auto" theme makes the game world literally reflect the player's real-world time of day.

// GameManager.cs — real-world DateTime drives day/night
case "Auto":
    isDay = System.DateTime.Now.Hour >= 7 && System.DateTime.Now.Hour <= 18;
    break;

Framerate target is set dynamically at runtime by reading the device's actual hardware refresh rate — not hardcoded. Mobile gets 30fps to preserve battery, PC via Google Play Games gets 60fps, and high-refresh-rate devices get their full native rate.

// GameManager.cs — adaptive framerate from hardware
Application.targetFrameRate = useHigherFramerate
    ? Mathf.RoundToInt(Screen.currentResolution.refreshRateRatio.value)
    : isGPG_PC() ? 60 : 30;
⚔️ Combat Systems · Original Architecture · HDRP

God of War — Demo

One axe-grab mechanic came from a reference tutorial. Everything else — dual-system lock-on, attack magnetism, quadratic Bézier axe return, Physics.Linecast hit detection, animation hitstop, directional hit reactions, bone-attached blood decals, procedural compass HUD, Rage mode with HDRP screen tint — designed and built from scratch.

Unity 2021C# CinemachineHDRP New Input SystemDOTween Animator IKPhysics.Linecast AudioMixer
10+
Original Systems
6
AudioSources
2
Weapons + FX
0
Tutorial Lines Kept
⚔ Technical Deep Dive

Reticle snaps to nearest enemy by screen-center angle, not distance

Two separate systems run in parallel and neither knows the other exists. EnemyLockOn handles camera and reticle; PlayerAttackPush silently slides the player toward the target during attacks only.

Target selection uses Vector3.Angle(cam.forward, dir) — finds the enemy closest to screen center, not nearest by distance. A LOS raycast rejects enemies behind walls before confirming lock.

// EnemyLockOn.cs — screen-center angle selection
float _angle = Vector3.Angle(cam.forward, dir);
if (_angle < closestAngle) { closestTarget = nearbyTargets[i].transform; }
// Crosshair scales with distance
lockOnCanvas.localScale = Vector3.one * ((cam.position - pos).magnitude * crossHair_Scale);

// PlayerAttackPush.cs — weapon-range-aware magnetism
noticeZone = PlayerController.instance.isAxeEquipped ? 5 : 10;
if (noticeZone == 5 && dis >= 1.6f)
    transform.position = Vector3.Lerp(transform.position, currentTarget.position, Time.deltaTime * 5f);

Quadratic Bézier arc — the curve is entirely code, no animation

The return follows a hand-rolled quadratic Bézier curve through a designer-placed midpoint — not a straight lerp. Gives the arc its iconic curved flight path entirely in code.

// PlayerController.cs — quadratic Bézier formula
public Vector3 GetQuadraticCurvePoint(float t, Vector3 p0, Vector3 p1, Vector3 p2) {
    float u = 1 - t;
    return (u*u * p0) + (2 * u * t * p1) + (t*t * p2);
}
Axe.transform.position = GetQuadraticCurvePoint(returnTime,
    pullPos, CurvePoint.transform.position, AxeLoc.transform.position);
returnTime += Time.deltaTime * 1.5f;
OnAim() ──→ ToggleFrostAxeParticle ──→ PSMeshRendererUpdater (mesh-conform FX) OnAttack() ──→ Rigidbody.AddForce(ReticleDir × throwPower) OnAxeRecall() ──→ Bézier arc each frame ──→ CatchAxe() coroutine

Hit detection uses Physics.Linecast between two blade-tip Transforms. Fires only while isDamage == true (animation events), with HitCount + RecoveryTime preventing multi-frame registrations.

// WeaponCollision.cs — animation hitstop (the juice)
IEnumerator SpeedRegain() {
    PlayerController.instance.ThirdPersonAnimator.speed = ContactSpeedTime.x; // freeze
    yield return new WaitForSeconds(ContactSpeedTime.y);
    PlayerController.instance.ThirdPersonAnimator.speed = initSpeed;           // restore
}
// Blades Heavy Attack — slow-mo cinematic chain
FXHandler.instance.BladeHeavyAttackCamera();
ToggleSlowMo(1);  // Time.timeScale = 0.2f
yield return new WaitForSeconds(.2f);
ToggleSlowMo(0); Blade1.transform.DOLocalMove(Vector3.zero, 0.1f);

On hit: animation hitstop, directional hit reaction (HitLeft/HitRight/HitGut), blood decal on nearest skeleton bone, and weapon-specific audio through independent AudioMixer groups — all fire simultaneously.

Entire input layer uses Unity's New Input System with InputActionAsset — zero KeyCode polling. OnControlsChanged() auto-detects keyboard vs. gamepad to switch HUD layouts at runtime.

// Stick combination input logic
if (isRightStickPressed && isLeftStickPressed && PlayerStats.instance.canRage)
    StartCoroutine(SpecialAbility());  // Both sticks = RAGE
else if (isRightStickPressed && !isLeftStickPressed)
    isEnemyLockOn = true;             // Right only = LOCK-ON

The compass HUD is fully procedural — 5 direction labels and 5 dividers repositioned every frame from Camera.main.eulerAngles.y. Quest waypoint clamps to ±400px with overflow arrows when offscreen. Audio uses 6 independent AudioSources each routed to their own AudioMixerGroup.

Purple — co-op puzzle game
🏆 LevelUp 2024 Competition · Technical Lead

Purple

Two-character co-op puzzle game in UE5. As technical head, designed and implemented the core C++ gameplay architecture — dual-player merge/split system, color-state machine, health pooling, and camera behavior using 3D math. Managed Git workflow for a 5-person team across a 10-week delivery cycle with 12 completed levels.

UE5.4C++ BlueprintsALSGit
12
Levels Delivered
↓70%
Merge Conflicts
10 wk
Full Cycle
5
Person Team
🏗 Technical Deep Dive

VectorInterpTo drives the physical merge into a shared position

Blue and Red players move independently until Merge — physically interpolating to a shared position via VectorInterpTo toward TargetMergePos. On merge, individual health pools collapse into a single Purple pool.

Event Tick ──→ Update Coloring System ──→ Update Border FX (Both Players) Merge Event ──→ Check Is Player Busy ──→ VectorInterpTo TargetMergePos Split Event ──→ VectorInterpTo TargetMergePosRed ──→ Restore Separate HP

Damage routing fires BPI_SetOverlayState (Blueprint Interface) to cleanly decouple health logic from the character BP. If health ≤ 0: DoRagdollAfterDeath → respawn via SetWorldLocationAndRotation to stored player start. No scene reload.

Merge conflicts reduced by 70% through a documented Git branching strategy — feature branches per team member, protected main, and weekly integration reviews. Blueprint Interfaces kept each developer's work isolated with no direct cross-BP dependencies.

Applied strong 3D math to movement, interaction, and camera behaviour, reducing rework on level scripting by 30%. Delivered clean C++ interfaces ready for future online services — the kind of forward-looking architecture that saves teams from expensive rewrites.

Monument Valley — orthographic illusion
🏛 Level Design · Puzzle Mechanics · Built from Scratch

Monument Valley — Demo Level

Built entirely from scratch — no tutorial, just the original game as inspiration. Implemented the orthographic impossible geometry illusion, rotatable structure mechanics, and path-following navigation logic that create Monument Valley's signature feel using only Unity and C#.

UnityC# Orthographic CameraCustom Path LogicBFS Graph
0
Tutorial Lines Used
90°
Snap Increments
BFS
Path Validation
2D→3D
Illusion Logic
🔮 Technical Deep Dive

90° snap rotation recalculates all walkable path conditions in real-time

The illusion relies on an orthographic camera — parallel projection removes depth cues, making geometrically separate platforms appear connected when their 2D screen positions align. Rotatable pivots snap to 90° increments using DOTween with RotateMode.WorldAxisAdd and Ease.OutBack for a satisfying overshoot.

// GameManager.cs — 90° snap with DOTween
public void RotateMainPlatdform(int multiplier) {
    pivots[0].DOComplete();
    pivots[0].DORotate(new Vector3(0, 90 * multiplier, 0), .6f, RotateMode.WorldAxisAdd)
             .SetEase(Ease.OutBack);
}

After every rotation, PathCondition structs are re-evaluated each Update() tick. Each condition checks if a pivot's eulerAngles matches a target angle — only then marking those tile connections active = true. Platforms that look connected only become walkable when their angles satisfy the condition.

// GameManager.cs — condition-gated path activation (runs every frame)
foreach (PathCondition pc in pathConditions) {
    int count = 0;
    for (int i = 0; i < pc.conditions.Count; i++)
        if (pc.conditions[i].conditionObject.eulerAngles == pc.conditions[i].eulerAngle)
            count++;
    foreach (SinglePath sp in pc.paths)
        sp.block.possiblePaths[sp.index].active = (count == pc.conditions.Count);
}

Movement uses a custom BFS traversal over the tile graph. On click, FindPath() explores outward from the player's tile — only following edges marked active = true. Because rotation changes active edges in real-time, the walkable graph updates every frame before the player commits to a move.

// PlayerController.cs — BFS graph traversal
void ExploreCube(List<Transform> nextCubes, List<Transform> visited) {
    Transform current = nextCubes.First();
    nextCubes.Remove(current);
    if (current == clickedCube) return;
    foreach (WalkPath path in current.GetComponent<Walkable>().possiblePaths) {
        if (!visited.Contains(path.target) && path.active) {
            nextCubes.Add(path.target);
            path.target.GetComponent<Walkable>().previousBlock = current;
        }
    }
    visited.Add(current);
    if (nextCubes.Any()) ExploreCube(nextCubes, visited);
}

BuildPath() traces back through previousBlock references to reconstruct the route. FollowPath() chains DOTween DOMove + DOLookAt per tile — stair tiles get 1.5× travel time. The player parents to moving ground tiles so it rides platform rotations naturally.

// PlayerController.cs — sequenced path follow
for (int i = finalPath.Count - 1; i > 0; i--) {
    float time = finalPath[i].GetComponent<Walkable>().isStair ? 1.5f : 1;
    s.Append(transform.DOMove(finalPath[i].GetComponent<Walkable>().GetWalkPoint(), .2f * time).SetEase(Ease.Linear));
    if (!finalPath[i].GetComponent<Walkable>().dontRotate)
        s.Join(transform.DOLookAt(finalPath[i].position, .1f, AxisConstraint.Y, Vector3.up));
}

Camera dolly + orthographic zoom driven entirely in code — no Timeline, no Animator

Level completion is a fully code-driven cinematic. A DOTween Sequence with chained SetDelay fades UI layers in staggered order, while both orthographic cameras simultaneously dolly back and zoom out via DOVirtual.Float driving orthographicSize directly.

// GameManager.cs — camera dolly + orthographic zoom
cameras[0].DOMove(new Vector3(16, 35f, -20), 10f).SetEase(Ease.OutBack);
DOVirtual.Float(13, 6, 10, v => cameras[0].GetComponent<Camera>().orthographicSize = v);
// Staggered UI reveal with 3s delay
DOTween.Sequence().SetDelay(3)
    .Append(UIManager.Instance.infoText.GetComponent<Image>().DOColor(new Color(1,1,1,1), 1))
    .Append(UIManager.Instance.infoText.transform.GetChild(0).GetComponent<Image>().DOColor(Color.white, 1));

Buttons fade to alpha 0 via DOColor and become non-interactable simultaneously. Player movement locks via gamecomplete = true. Zero animation assets — the entire closing cinematic is one C# method.

The toolkit.

Proficiency earned through production code, competition projects, and real optimisation work.

Languages

C#95%
C / C++80%
Python75%
Java65%
JavaScript / TypeScript60%

Engines & Tools

Unity3D (URP / HDRP)95%
Unreal Engine 580%
Visual Studio / VS Code90%
Git / GitHub / Perforce88%
Android Studio70%

Backend & APIs

Firebase Analytics + Crashlytics88%
Unity IAP / AdMob SDK85%
REST APIs82%
AWS SDK72%
Backend Service Integration80%

Systems

Unity Profiler92%
DOTS / Job System70%
GitLab-style CI/CD65%
Photon Networking78%

Where I've
worked.

Professional roles with measurable impact on live products.

Field AgentBest BuySep 2025 – Present · Toronto
  • Client recommendations, home theater installations, network upgrades, and camera setups
Project Intern — AI ToolsKinectricsMay 2025 – Aug 2025 · Toronto
  • Designed AI-enabled tools for high-stakes safety and compliance industries
  • Led database team for MVP delivery and defined the release cycle roadmap
Programming Peer Tutor + Student ResearcherGeorge Brown CollegeSep 2023 – Apr 2025 · Toronto
  • Tutored students in C#, C++, and Math for Development
  • Integrated ArcGIS SDK in Unity for geospatial world generation (lat/lng/altitude)
  • Established persistent WebSocket connection for real-time AR data updates
Software ProgrammerLiminal VR and ARAug 2022 – Aug 2023 · Mumbai
  • Cloud AR asset pipeline: app size 200 MB → 45 MB via Addressables + LRU caching + AWS S3
  • Asset load times ↓60%; memory footprint ↓40% via dynamic LOD management for 500+ models
  • Framework bugs ↓40% via Unity Profiler; onboarding time ↓25% via documented APIs
Game ProgrammerOneros Tech Pvt. Ltd.Jan 2021 – Jun 2021 · Mumbai
  • Photon multiplayer: latency ↓45%, desync issues eliminated 80%
  • Consistent 60fps on Adreno 506 GPU via data-driven Unity Profiler optimization
  • Modular MVC architecture: merge conflicts ↓70%, post-release bugs ↓30%

Always learning,
always building.

🤖
PG Certificate — Applied AI Solutions Development
George Brown College
Aug 2024 – Aug 2025 · Toronto
🎮
PG Certificate — Digital Design: Game Design
George Brown College
Aug 2023 – Aug 2024 · Toronto
💻
B.Sc. Information Technology
University of Mumbai
Aug 2019 – May 2021 · Mumbai
⚙️
Diploma — Information Technology
SVKM Bhagubhai Mafatlal Polytechnic
2017 – 2019 · Mumbai

Certifications & Publications

Security in Gaming — IJRASET Publication EA Software Engineering Simulation (Forage) Unreal GAS Top-Down RPG (Udemy) C++ Multiplayer Shooter UE5 (Udemy) ARCore Augmented Reality Unity (Udemy) AI A-Z™ — Build an AI Google Fundamentals of Digital Marketing

Ready to build
something great?

Actively looking for Gameplay Programmer and Tools Developer roles in Toronto, Montreal, Vancouver, or remote worldwide. If you're building something exciting, I'd love to hear about it.