Going Up! – Game Jam Project

Going Up! – Game Jam Project

A first-person 3D platformer about escaping a perfect apartment and climbing your way through dangerous heights. Built in 7 days with one 3D artist, focusing on tight movement, clean architecture, and responsive physics.

A first-person 3D platformer about escaping a perfect apartment and climbing your way through dangerous heights. Built in 7 days with one 3D artist, focusing on tight movement, clean architecture, and responsive physics.

Category

Category

Unity · C# · GitHub

Unity · C# · GitHub

Role

Role

Game Developer

Game Developer

Studio

Studio

2 Person Team

2 Person Team

Duration

Duration

1 Week

1 Week

The Challenge

Build a responsive and rewarding first-person climbing game in just one week. Gameplay had to feel fast, tight, and fun, with real tension between the safety of home and the chaos of vertical platforming. I focused on feel-first programming and system polish over content scale.

What I Built

  • Programmed a custom physics-based movement system using Rigidbody with air control, drag, and jump buffering

  • Built precision first-person camera controls with vertical clamping and decoupled movement orientation

  • Implemented accurate ground detection using raycasts and layer masks for stable jumping

  • Developed a unified UI interaction framework using interfaces and raycasts

  • Optimized performance by caching references, minimizing physics calls, and separating concerns in system logic

My Technical Contributions

1. Physics-Based Movement System

Problem: Create responsive first-person platforming controls that feel tight enough for precision jumping while maintaining realistic physics behavior.

Solution: Implemented a comprehensive movement controller using Unity's Rigidbody system with custom ground detection and air control.

public class PlayerMovement : MonoBehaviour {
    // Movement configuration
    public float moveSpeed;
    public float groundDrag;
    public float jumpForce;
    public float jumpCooldown;
    public float airMultiplier;
    private bool readyToJump;
    
    // Jump input configuration
    public KeyCode jumpKey = KeyCode.Space;
    
    // Ground detection variables
    public float playerHeight;
    public LayerMask whatIsGround;
    private bool grounded;
    
    // Transform references for movement calculation
    public Transform orientation;
    private float horizontalInput;
    private float verticalInput;
    Vector3 moveDirection;
    
    // Physics component
    Rigidbody rb;
    
    private void Start() {
        rb = GetComponent<Rigidbody>();
        rb.freezeRotation = true; // Prevent physics from rotating the player
        readyToJump = true;
    }
    
    private void FixedUpdate() {
        MovePlayer(); // Handle movement in FixedUpdate for consistent physics
    }
    
    private void Update() {
        // Check if player is touching ground using raycast
        grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.2f, whatIsGround);
        
        MyInput(); // Process input every frame
        SpeedControl(); // Limit player speed to prevent infinite acceleration
        
        // Apply drag based on ground state
        if (grounded == true) {
            rb.linearDamping = groundDrag; // High drag on ground for responsive stopping
        } else {
            rb.linearDamping = 0; // No drag in air for natural physics
        }
    }
    
    private void MyInput() {
        // Get raw input for immediate response
        horizontalInput = Input.GetAxisRaw("Horizontal");
        verticalInput = Input.GetAxisRaw("Vertical");
        
        // Jump logic with cooldown and ground check
        if (Input.GetKey(jumpKey) && readyToJump && grounded == true) {
            readyToJump = false;
            Jump();
            Invoke(nameof(ResetJump), jumpCooldown); // Reset jump availability after cooldown
        }
    }
    
    private void MovePlayer() {
        // Calculate movement direction relative to camera orientation
        moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;
        
        // Apply different force based on ground state
        if (grounded == true) {
            // Full force on ground
            rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force);
        } else if (!grounded) {
            // Reduced force in air for limited air control
            rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force);
        }
    }
    
    private void SpeedControl() {
        // Get horizontal velocity only (ignore vertical for jumping)
        Vector3 flatVelocity = new Vector3(rb.linearVelocity.x, 0f, rb.linearVelocity.z);
        
        // Limit speed if moving too fast
        if (flatVelocity.magnitude > moveSpeed) {
            Vector3 limitedVelocity = flatVelocity.normalized * moveSpeed;
            // Apply limited velocity while preserving vertical movement
            rb.linearVelocity = new Vector3(limitedVelocity.x, rb.linearVelocity.y, limitedVelocity.z);
        }
    }
    
    private void Jump() {
        // Reset vertical velocity for consistent jump height
        rb.linearVelocity = new Vector3(rb.linearVelocity.x, 0f, rb.linearVelocity.z);
        // Apply upward impulse for jump
        rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
    }
    
    private void ResetJump() {
        readyToJump = true; // Allow jumping again

Result: Smooth, responsive movement that allows for precise platforming while maintaining realistic physics momentum and air control.

2. Precision Camera Control System

Problem: Implement smooth first-person camera controls that provide precise aiming for platforming while preventing disorientation during fast movements.

Solution: Built a mouse-look system with proper rotation clamping and separate orientation handling for movement direction.

public class PlayerCamera : MonoBehaviour {
    // Mouse sensitivity settings
    public float camSensX;
    public float camSensY;
    
    // Reference to player orientation for movement direction
    public Transform orientation;
    
    // Rotation tracking variables
    public float xRotation;
    public float yRotation;
    
    private void Start() {
        // Lock cursor to center of screen for FPS controls
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false; // Hide cursor during gameplay
    }
    
    private void Update() {
        // Get mouse input and apply sensitivity and frame rate independence
        float mouseX = Input.GetAxisRaw("Mouse X") * Time.deltaTime * camSensX;
        float mouseY = Input.GetAxisRaw("Mouse Y") * Time.deltaTime * camSensY;
        
        // Apply horizontal rotation (left/right look)
        yRotation += mouseX;
        
        // Apply vertical rotation (up/down look) with inverted controls
        xRotation -= mouseY;
        
        // Clamp vertical rotation to prevent over-rotation
        xRotation = Mathf.Clamp(xRotation, -90f, 90f);
        
        // Apply rotation to camera (full 3D rotation)
        transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
        
        // Apply only horizontal rotation to orientation for movement direction
        orientation.rotation = Quaternion.Euler(0, yRotation, 0

Result: Smooth, responsive camera controls that enhance the platforming experience without causing motion sickness or disorientation.

3. Advanced Ground Detection System

Problem: Ensure accurate ground detection for jumping mechanics while handling complex geometry and preventing edge cases that could break platforming.

Solution: Implemented robust raycast-based ground detection with proper offset calculations and layer masking.

private void Update() {
    // Precise ground detection with offset for player height
    grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.2f, whatIsGround);
    
    // Dynamic drag system based on ground state
    if (grounded == true) {
        rb.linearDamping = groundDrag;  // High drag on ground for responsive stops
    } else {
        rb.linearDamping = 0;  // No drag in air for natural physics
    }
}

private void Jump() {
    // Reset vertical velocity for consistent jump height
    rb.linearVelocity = new Vector3(rb.linearVelocity.x, 0f, rb.linearVelocity.z);
    rb.AddForce(transform.up * jumpForce, ForceMode.Impulse

Result: Reliable ground detection that works consistently across all platform types and prevents double-jumping exploits.

Results & Impact

  • Built a feature-complete 3D platformer prototype in one week

  • Delivered responsive and polished controls for a first person platformer

  • All systems were cleanly architected for easy testing, debugging, and reuse

  • Maintained 144 FPS with no physics hitches or collision bugs across the full vertical level

Lessons Learned

  • Feel > Realism: Balancing real-world physics with game feel taught me how to tweak systems like jump buffering, drag, and input timing for fun

  • Modular Thinking: Building small, reusable systems helped me iterate fast without rewriting code

  • First-Person Movement: Precision platforming from a first-person perspective requires deep coordination between camera, physics, and input

  • Team Communication: Even with a small 2-person team, early clarity on roles helped us hit the deadline with a playable result

Key Technologies & Patterns Demonstrated

  • Physics Systems: Custom Rigidbody movement with air control, drag physics, jump buffering

  • First-Person Controls: Camera/movement, vertical clamping, mouse-look implementation

  • Detection Systems: Raycast-based ground detection, layer masking, offset calculations

  • Performance Optimization: Reference caching, minimized physics calls, separation of concerns

  • Interface Design: Unified UI interaction framework, component-based architecture

Create a free website with Framer, the website builder loved by startups, designers and agencies.