Renderon Engine API

v2.1.0

Complete API Reference

Lua Scripting Engine with Advanced GTA-Style AI

Renderon Engine provides a powerful Lua scripting environment integrated with a sophisticated AI system inspired by GTA's living world mechanics. Create immersive open-world experiences with autonomous NPCs, dynamic traffic, police systems, daily schedules, and complex pathfinding — all without touching C++.

This documentation covers 100+ API functions across multiple systems including physics, input handling, NPC behavior, crime simulation, and advanced navigation.

🎮 Input & Controls

  • Complete keyboard/mouse detection
  • FPS camera locking & unlocking
  • Mouse delta tracking for smooth camera
  • Input axis mapping
  • Gamepad support ready

🔧 Core Engine

  • Transform manipulation (Position/Rotation/Scale)
  • Entity spawning & destruction
  • Distance and vector math utilities
  • Animation playback control
  • Material & color manipulation

🚗 Vehicle Systems

  • Full vehicle physics with suspension
  • Traffic AI with lane following
  • Vehicle entry/exit animations
  • Police pursuit vehicles
  • Damage and fire systems

đŸ”Ģ Combat & Weapons

  • Raycast weapon system
  • Accuracy and recoil simulation
  • NPC reaction to gunfire
  • Health and armor systems
  • Automatic weapon switching

Core API Reference

Essential Functions for Game Logic

âąī¸ Time & Delta

GetDeltaTime()
Returns the time in seconds since the last frame. Essential for frame-rate independent movement.
→ Returns: float (typically 0.016 for 60fps)
GetTime()
Returns the total elapsed time since the game started in seconds.
→ Returns: float
StartTimer(name)
Starts a named timer for measuring custom durations.
Parameters: name (string) - Timer identifier
GetTimer(name)
Gets the elapsed time for a named timer.
→ Returns: float (seconds elapsed)

đŸ•šī¸ Input System

IsKeyDown(key)
Checks if a keyboard key is currently pressed.
Parameters: key (string) - "W", "A", "S", "D", "SPACE", "SHIFT", "CTRL", "ALT", "ESC", "ENTER", "TAB", "0"-"9", "UP", "DOWN", "LEFT", "RIGHT"
→ Returns: boolean
IsMouseButton(button)
Checks if a mouse button is pressed.
Parameters: button (number) - 0 (Left), 1 (Right), 2 (Middle)
→ Returns: boolean
GetMousePos()
Gets the current mouse position in screen coordinates.
→ Returns: x (float), y (float)
GetMouseDelta()
Gets the mouse movement since last frame. Perfect for FPS cameras.
→ Returns: deltaX (float), deltaY (float)
LockMouse(locked)
Locks/unlocks the mouse cursor (GLFW_CURSOR_DISABLED mode).
Parameters: locked (boolean) - true to lock, false to show cursor
SetMousePos(x, y)
Manually sets the mouse cursor position.
Parameters: x (float), y (float) - Screen coordinates

📍 Transform System

SetPosition(x, y, z)
Instantly teleports the entity to a specific world position.
Parameters: x, y, z (float) - World coordinates
GetPosition()
Gets the current world position of the entity.
→ Returns: x, y, z (float)
Translate(x, y, z)
Moves the entity by the specified offset (relative movement).
Parameters: x, y, z (float) - Movement delta
SetRotation(x, y, z)
Sets the entity's rotation in Euler angles (degrees).
Parameters: x (pitch), y (yaw), z (roll) in degrees
GetRotation()
Gets the current rotation in Euler angles.
→ Returns: x, y, z (float) in degrees
Rotate(x, y, z)
Rotates the entity by the specified angles (relative rotation).
Parameters: x, y, z (float) - Rotation delta in degrees
LookAt(x, y, z)
Rotates the entity to face a target position. Calculates yaw and pitch automatically.
Parameters: x, y, z (float) - Target world position
SetScale(x, y, z)
Sets the entity's scale (size multiplier).
Parameters: x, y, z (float) - Scale factors (1.0 = normal size)
GetScale()
Gets the current scale values.
→ Returns: x, y, z (float)

⚡ Physics & RigidBody

SetVelocity(x, y, z)
Directly sets the velocity of the RigidBody component. Overrides current motion.
Parameters: x, y, z (float) - Velocity in units/second
GetVelocity()
Gets the current velocity vector.
→ Returns: x, y, z (float)
AddForce(x, y, z)
Applies an impulse force to the entity (adds to existing velocity).
Parameters: x, y, z (float) - Force vector
SetGravity(enabled)
Enables or disables gravity for this RigidBody.
Parameters: enabled (boolean)
IsGrounded()
Checks if the entity's collider is touching the ground (y ≤ height/2 + 0.1).
→ Returns: boolean

🎨 Visual & Rendering

SetColor(r, g, b)
Changes the mesh tint color. Values should be between 0.0 and 1.0.
Parameters: r, g, b (float) - RGB values (0.0 to 1.0)
GetColor()
Gets the current mesh color.
→ Returns: r, g, b (float)
PlayAnim(name)
Plays an animation from the MeshComponent's animation list.
Parameters: name (string) - Animation name (e.g., "Walk", "Run", "Idle")
StopAnim()
Stops the currently playing animation.
SetAnimSpeed(speed)
Changes the animation playback speed multiplier.
Parameters: speed (float) - 1.0 = normal, 2.0 = double speed, 0.5 = half speed

🔊 Audio System

PlayAudio(filepath)
Plays a sound file once (fire-and-forget).
Parameters: filepath (string) - Path to .wav file
PlayAudioLoop(filepath)
Plays a sound file in a continuous loop.
Parameters: filepath (string) - Path to .wav file
StopAudio()
Stops all currently playing audio.

đŸŽ¯ Entity Management

Destroy()
Destroys the current entity and all its components. Entity becomes invalid after this call.
FindEntity(tag)
Searches for an entity by its tag name.
Parameters: tag (string) - Tag to search for (e.g., "Player", "Enemy")
→ Returns: entityID (number) or nil if not found
GetEntityPosition(entityID)
Gets the position of any entity by its ID.
Parameters: entityID (number) - Entity identifier
→ Returns: x, y, z (float)

📐 Math Utilities

GetDistance(x1, y1, z1, x2, y2, z2)
Calculates the 3D distance between two points.
Parameters: Two sets of x, y, z coordinates
→ Returns: distance (float)
Lerp(a, b, t)
Linear interpolation between two values.
Parameters: a, b (float) - Start and end values, t (float) - Interpolation factor (0-1)
→ Returns: interpolated value (float)
Clamp(value, min, max)
Restricts a value to a specified range.
Parameters: value, min, max (float)
→ Returns: clamped value (float)
Random() or Random(min, max)
Generates a random number. Without parameters returns 0-1, with parameters returns value in range.
→ Returns: random value (float)
Sin(angle) / Cos(angle)
Trigonometric functions (angle in radians).
→ Returns: float
Abs(value) / Sqrt(value)
Absolute value and square root functions.
→ Returns: float

📷 Camera

GetCameraPosition()
Gets the position of the primary camera.
→ Returns: x, y, z (float)
💡 Best Practice: Always multiply movement by GetDeltaTime() to ensure frame-rate independent gameplay. For example: Translate(speed * GetDeltaTime(), 0, 0)

NPC AI System

Personality-Driven Autonomous Characters

The NPC system provides complete AI behavior with perception, personality traits, state machines, and social interactions. NPCs can patrol, chase, flee, attack, talk, and react dynamically to their environment and other entities.

Available NPC Types

CIVILIAN_MALE CIVILIAN_FEMALE POLICE GANG_MEMBER SECURITY_GUARD SHOP_KEEPER BUSINESS_PERSON TAXI_DRIVER

🎭 NPC Configuration

SetNPCType(type)
Sets the NPC archetype which determines default behaviors and reactions.
Parameters: type (string) - "CIVILIAN_MALE", "CIVILIAN_FEMALE", "POLICE", "GANG_MEMBER", "SECURITY_GUARD", "SHOP_KEEPER", "BUSINESS_PERSON", "TAXI_DRIVER"
SetNPCPersonality(aggression, fear, courage)
Defines the NPC's personality traits which influence decision-making.
Parameters: aggression (0-1) - Likelihood to attack, fear (0-1) - Likelihood to flee, courage (0-1) - Resistance to panic
SetNPCAnimations(idle, walk, run, attack, death)
Assigns animation names for different NPC states.
Parameters: All strings - Animation names from the model
SetNPCSpeed(walkSpeed, runSpeed)
Sets movement speeds for walking and running states.
Parameters: walkSpeed, runSpeed (float) - Units per second (typical: walk=1.5, run=5.0)
SetNPCStats(health, vision, hearing)
Configures NPC health and sensory capabilities.
Parameters: health (float) - Max HP, vision (float) - Vision range in units, hearing (float) - Audio detection range

🎮 State Control

SetNPCState(state)
Forces the NPC into a specific behavioral state.
Parameters: state (string) - "IDLE", "WALKING", "RUNNING", "ATTACKING", "FLEEING", "DRIVING", "TALKING", "SITTING", "DANCING", "WORKING"
GetNPCState()
Returns the current NPC state.
→ Returns: state (string)
SetNPCDestination(x, y, z)
Makes the NPC walk to a target position. Automatically switches to WALKING state.
Parameters: x, y, z (float) - Target world coordinates
SetNPCTarget(entityID)
Sets another entity as the NPC's target (for chasing, attacking, or following).
Parameters: entityID (number) - Target entity identifier
NPCDamage(amount)
Applies damage to the NPC and triggers appropriate reactions based on personality.
Parameters: amount (float) - Damage value
→ Returns: isDead (boolean)
GetNPCHealth()
Gets the NPC's current health value.
→ Returns: health (float)

🔍 Perception & Detection

FindNearestEntity(tag, range)
Finds the closest entity with a specific tag within range.
Parameters: tag (string) - Tag to search for, range (float) - Search radius
→ Returns: entityID (number), distance (float) or nil if not found
đŸŽ¯ NPC Design Tip: Combine personality traits creatively! A high-courage, low-fear Guard will chase threats, while a high-fear Civilian will flee at the first sign of danger. Aggression + Courage = dangerous enemy, Fear + Low Courage = coward who runs immediately.

GTA-Style Systems

Living World Mechanics & Advanced AI

The GTA Behavior System brings your world to life with autonomous daily routines, crime simulation, witness reactions, police response, gang territories, and complex social relationships. NPCs live their lives independently, reacting dynamically to crimes and player actions.

đŸ™ī¸ Daily Life & Schedules

AddDailyActivity(name, startHour, endHour, x, y, z)
Adds a scheduled activity to the NPC's daily routine. NPCs will automatically pathfind to the location at the specified times.
Parameters:
â€ĸ name (string) - Activity identifier (e.g., "Work", "Sleep", "Gym")
â€ĸ startHour, endHour (float) - Time range in 24-hour format (0.0 to 24.0)
â€ĸ x, y, z (float) - Activity location in world coordinates
âš ī¸ Important: Activities are processed in order of start time. Overlapping schedules will use the first matching activity. Ensure your time ranges don't conflict unless intentional.

🚨 Crime & Police System

ReportCrime(x, y, z, severity)
Reports a crime to the global police system. Nearby NPCs will react as witnesses, and police will be dispatched based on severity.
Parameters:
â€ĸ x, y, z (float) - Crime location
â€ĸ severity (float) - Crime severity level (1-5)
  1 = Minor (jaywalking, trespassing)
  2 = Moderate (assault, theft)
  3 = Serious (assault with weapon)
  4 = Severe (murder, cop assault)
  5 = Extreme (mass violence, terrorism)
HasSeenPolice()
Checks if the NPC has recently seen a police officer within their visual range.
→ Returns: boolean (true if police visible in last 10 seconds)

đŸ‘Ĩ Social Relationships

MakeFriend(entityID)
Adds an entity to the NPC's friends list. Friends won't attack each other and may provide backup in combat.
Parameters: entityID (number) - Entity to befriend

đŸ—ēī¸ Navigation & Pathfinding

MoveTo(x, y, z)
Advanced pathfinding to target position. Uses A* algorithm with obstacle avoidance, traffic rules, and sidewalk preference.
Parameters: x, y, z (float) - Destination coordinates
🧭 Pathfinding Details: The system automatically avoids obstacles, prefers sidewalks over roads, respects traffic lights, and uses crowd avoidance. NPCs will wait at crosswalks if a traffic light is red (unless they're criminals with low rule-following).

Crime Severity Reference

Severity Crime Type Police Response Witness Reaction
1 - Minor Jaywalking, Trespassing, Speeding 1 patrol car (delayed) Ignore or mild concern
2 - Moderate Assault, Vehicle Theft, Vandalism 2 patrol cars Move away, call police
3 - Serious Armed Assault, Weapon Discharge 3-4 units, armed response Flee, panic, hide
4 - Severe Murder, Cop Killing 6+ units, SWAT dispatched Mass panic, stampede
5 - Extreme Mass Shooting, Terrorism Full lockdown, helicopters City-wide alert, evacuation

Code Examples

Real-World Implementation Patterns

đŸĸ Example 1: Business Person with Daily Routine

Office Worker - Complete Daily Schedule
-- Creates a realistic NPC with work-life balance

function OnStart()
    -- Configure as business professional
    SetNPCType("BUSINESS_PERSON")
    SetNPCPersonality(0.1, 0.7, 0.3)
    -- Low aggression, high fear (avoids conflict)
    
    -- Set appropriate speeds
    SetNPCSpeed(1.8, 5.5) -- Slightly faster walk
    
    -- Configure animations
    SetNPCAnimations("Idle_Office", "Walk_Business", 
                      "Run", "Punch", "Death")
    
    -- 🕐 Define Complete Daily Schedule
    
    -- 6:00 AM - Wake up at home
    AddDailyActivity("Wake", 6.0, 7.0, 10, 0, 10)
    
    -- 7:00 AM - Coffee shop (morning routine)
    AddDailyActivity("Coffee", 7.0, 7.5, 45, 0, -15)
    
    -- 8:00 AM - 5:00 PM - Work at office downtown
    AddDailyActivity("Work", 8.0, 17.0, 150, 0, -40)
    
    -- 5:00 PM - 6:00 PM - Gym after work
    AddDailyActivity("Gym", 17.0, 18.0, -20, 0, 50)
    
    -- 6:30 PM - 7:30 PM - Dinner at restaurant
    AddDailyActivity("Dinner", 18.5, 19.5, 80, 0, 25)
    
    -- 8:00 PM - 6:00 AM - Home (sleep)
    AddDailyActivity("Sleep", 20.0, 6.0, 10, 0, 10)
    
    print("Business NPC initialized with daily schedule")
end

function OnUpdate(dt)
    -- React to danger (high fear personality)
    local playerID = FindNearestEntity("Player", 15.0)
    
    if playerID ~= nil then
        local px, py, pz = GetEntityPosition(playerID)
        local mx, my, mz = GetPosition()
        local distance = GetDistance(mx, my, mz, px, py, pz)
        
        -- If player is shooting nearby, flee immediately
        if IsKeyDown("F") and distance < 20.0 then
            SetNPCState("FLEEING")
            
            -- Run away from danger
            local fleeDir = {
                x = mx - px,
                z = mz - pz
            }
            local length = Sqrt(fleeDir.x * fleeDir.x + fleeDir.z * fleeDir.z)
            fleeDir.x = fleeDir.x / length
            fleeDir.z = fleeDir.z / length
            
            local fleeDist = 30.0
            SetNPCDestination(
                mx + fleeDir.x * fleeDist,
                my,
                mz + fleeDir.z * fleeDist
            )
            
            PlayAnim("Run")
        end
    end
    
    -- Health check
    if GetNPCHealth() < 20 then
        SetNPCState("FLEEING")
    end
end

🚨 Example 2: Crime Witness System

Civilian Witness - Reports Crimes to Police
-- Civilian who witnesses crimes and calls police

local crimeReported = false
local witnessedCrime = false
local panicMode = false

function OnStart()
    SetNPCType("CIVILIAN_MALE")
    SetNPCPersonality(0.05, 0.85, 0.2) -- Very afraid, won't fight
    SetNPCSpeed(1.5, 6.0)
    SetNPCStats(80, 25.0, 30.0) -- Good hearing range
    
    StartTimer("witness_check")
end

function OnUpdate(dt)
    -- Look for nearby player
    local playerID = FindNearestEntity("Player", 25.0)
    
    if playerID ~= nil and not crimeReported then
        local px, py, pz = GetEntityPosition(playerID)
        local mx, my, mz = GetPosition()
        local distance = GetDistance(mx, my, mz, px, py, pz)
        
        -- Witness shooting (serious crime)
        if IsKeyDown("F") and distance < 20.0 then
            witnessedCrime = true
            panicMode = true
            
            -- Immediately report to police system
            ReportCrime(px, py, pz, 3.0) -- Severity 3: Armed assault
            crimeReported = true
            
            print("[WITNESS] Crime reported to police!")
            
            -- Play panic animation
            PlayAnim("Panic")
            SetNPCState("FLEEING")
            
            -- Run to safe distance
            local safeX = mx + (mx - px) * 2.0
            local safeZ = mz + (mz - pz) * 2.0
            SetNPCDestination(safeX, my, safeZ)
        end
        
        -- Witness assault (moderate crime)
        local nearbyNPC = FindNearestEntity("NPC", 5.0)
        if nearbyNPC ~= nil and distance < 8.0 then
            local npcState = GetNPCState()
            if npcState == "ATTACKING" then
                ReportCrime(px, py, pz, 2.0) -- Severity 2: Assault
                crimeReported = true
                print("[WITNESS] Assault reported!")
            end
        end
    end
    
    -- If crime reported, stay in panic mode for a while
    if panicMode then
        local panicTime = GetTimer("witness_check")
        if panicTime > 10.0 then
            panicMode = false
            SetNPCState("IDLE")
            PlayAnim("Idle")
        end
    end
    
    -- Check if police arrived (witness feels safer)
    if HasSeenPolice() and panicMode then
        print("[WITNESS] Police have arrived, feeling safer")
        panicMode = false
        SetNPCState("IDLE")
    end
end

💀 Example 3: Gang Member AI

Aggressive Gang Member - Territory Defense
-- Gang member who defends territory and attacks police on sight

local territoryCenter = {x = 50, y = 0, z = -30}
local territoryRadius = 40.0
local gangMates = {}
local inCombat = false

function OnStart()
    SetNPCType("GANG_MEMBER")
    SetNPCPersonality(0.95, 0.15, 0.9) -- High aggression, fearless
    SetNPCSpeed(2.0, 7.0) -- Fast runner
    SetNPCStats(150, 30.0, 35.0) -- Tough, alert
    
    -- Find and befriend other gang members
    local gang1 = FindEntity("GangMember2")
    local gang2 = FindEntity("GangMember3")
    
    if gang1 ~= nil then 
        MakeFriend(gang1)
        table.insert(gangMates, gang1)
    end
    if gang2 ~= nil then 
        MakeFriend(gang2)
        table.insert(gangMates, gang2)
    end
    
    print("[GANG] Territory patrol initialized")
end

function OnUpdate(dt)
    local mx, my, mz = GetPosition()
    
    -- Check if in territory
    local distFromCenter = GetDistance(
        mx, my, mz,
        territoryCenter.x, territoryCenter.y, territoryCenter.z
    )
    local inTerritory = distFromCenter < territoryRadius
    
    -- PRIORITY 1: Attack police on sight (gang vs cops)
    local copID, copDist = FindNearestEntity("Police", 40.0)
    if copID ~= nil then
        print("[GANG] Cop spotted! Engaging!")
        SetNPCTarget(copID)
        SetNPCState("ATTACKING")
        inCombat = true
        
        -- Report crime (gang attacking cop = high severity)
        local cx, cy, cz = GetEntityPosition(copID)
        ReportCrime(cx, cy, cz, 4.0) -- Cop assault = severity 4
        
        return -- Focus on combat
    end
    
    -- PRIORITY 2: Defend territory from intruders
    if inTerritory then
        local playerID, playerDist = FindNearestEntity("Player", territoryRadius)
        
        if playerID ~= nil and playerDist < 20.0 then
            -- Warn player first time
            if not inCombat then
                print("[GANG] You're in our territory!")
                SetNPCState("TALKING")
                LookAt(GetEntityPosition(playerID))
                
                -- If player comes closer, attack
                if playerDist < 8.0 then
                    SetNPCTarget(playerID)
                    SetNPCState("ATTACKING")
                    inCombat = true
                end
            end
        end
    else
        -- Outside territory: return to patrol
        if GetNPCState() == "IDLE" then
            SetNPCDestination(
                territoryCenter.x + Random(-20, 20),
                territoryCenter.y,
                territoryCenter.z + Random(-20, 20)
            )
        end
    end
    
    -- Health management
    local health = GetNPCHealth()
    if health < 40 and inCombat then
        -- Even tough gang members retreat when badly injured
        print("[GANG] Retreating to cover!")
        SetNPCState("FLEEING")
        
        -- Run back to territory center
        SetNPCDestination(territoryCenter.x, territoryCenter.y, territoryCenter.z)
        inCombat = false
    end
end

🚔 Example 4: Advanced Police AI

Police Officer - Dynamic Crime Response
-- Police officer who patrols, investigates crimes, and pursues suspects

local patrolPoints = {
    {x = 0, y = 0, z = 0},
    {x = 50, y = 0, z = 0},
    {x = 50, y = 0, z = 50},
    {x = 0, y = 0, z = 50}
}
local currentPatrolIndex = 1
local investigating = false
local pursuitMode = false

function OnStart()
    SetNPCType("POLICE")
    SetNPCPersonality(0.65, 0.25, 0.85) -- Aggressive but controlled
    SetNPCSpeed(2.0, 6.5) -- Fast response
    SetNPCStats(180, 40.0, 45.0) -- High awareness
    
    SetNPCAnimations("Idle_Cop", "Walk_Patrol", 
                      "Run_Chase", "Arrest", "Death")
    
    -- Start patrol route
    StartPatrolRoute()
end

function StartPatrolRoute()
    local nextPoint = patrolPoints[currentPatrolIndex]
    MoveTo(nextPoint.x, nextPoint.y, nextPoint.z) -- Uses advanced pathfinding
    SetNPCState("WALKING")
end

function OnUpdate(dt)
    local mx, my, mz = GetPosition()
    
    -- PRIORITY 1: Respond to active crimes
    local criminalID, crimeDist = FindNearestEntity("Criminal", 50.0)
    
    if criminalID ~= nil and crimeDist < 30.0 then
        investigating = true
        pursuitMode = true
        
        local cx, cy, cz = GetEntityPosition(criminalID)
        local distance = GetDistance(mx, my, mz, cx, cy, cz)
        
        -- If close enough, attempt arrest
        if distance < 2.5 then
            SetNPCState("ATTACKING") -- Arrest animation
            PlayAnim("Arrest")
            print("[POLICE] Attempting arrest!")
            
            -- Apply arrest (in real game, this would remove wanted level)
            local arrested = NPCDamage(criminalID, 0) -- Just check without damage
        elseif distance < 15.0 then
            -- Chase suspect
            SetNPCTarget(criminalID)
            SetNPCState("RUNNING")
            PlayAnim("Run_Chase")
            
            -- Use pathfinding for smart chase
            MoveTo(cx, cy, cz)
        else
            -- Move to last known position
            SetNPCState("RUNNING")
            MoveTo(cx, cy, cz)
        end
        
        return -- Focus on pursuit
    end
    
    -- PRIORITY 2: Investigate suspicious activity
    local suspectID = FindNearestEntity("NPC", 20.0)
    if suspectID ~= nil and not investigating then
        local suspectState = GetNPCState(suspectID)
        
        -- If NPC is fleeing or fighting, investigate
        if suspectState == "FLEEING" or suspectState == "ATTACKING" then
            investigating = true
            local sx, sy, sz = GetEntityPosition(suspectID)
            MoveTo(sx, sy, sz)
            SetNPCState("RUNNING")
            print("[POLICE] Investigating suspicious activity")
        end
    end
    
    -- PRIORITY 3: Normal patrol
    if not investigating and not pursuitMode then
        local currentPoint = patrolPoints[currentPatrolIndex]
        local distToPoint = GetDistance(
            mx, my, mz,
            currentPoint.x, currentPoint.y, currentPoint.z
        )
        
        -- Reached patrol point, move to next
        if distToPoint < 2.0 then
            currentPatrolIndex = currentPatrolIndex + 1
            if currentPatrolIndex > #patrolPoints then
                currentPatrolIndex = 1
            end
            StartPatrolRoute()
        end
    end
    
    -- Give up chase if suspect escapes
    if pursuitMode and crimeDist > 60.0 then
        print("[POLICE] Suspect escaped")
        pursuitMode = false
        investigating = false
        SetNPCState("IDLE")
        StartPatrolRoute()
    end
end

🎮 Example 5: FPS Player Controller

Complete FPS Movement with Mouse Look
-- Full FPS controller with WASD movement, jumping, and mouse camera

local moveSpeed = 8.0
local sprintSpeed = 12.0
local jumpForce = 8.0
local mouseSensitivity = 0.1

local cameraYaw = 0.0
local cameraPitch = 0.0
local isJumping = false

function OnStart()
    -- Lock mouse for FPS controls
    LockMouse(true)
    
    -- Setup player
    SetGravity(true)
    
    print("[PLAYER] FPS Controller initialized")
    print("Controls: WASD = Move, SHIFT = Sprint, SPACE = Jump, ESC = Exit")
end

function OnUpdate(dt)
    -- ESC to unlock mouse
    if IsKeyDown("ESC") then
        LockMouse(false)
    end
    
    -- === MOUSE LOOK ===
    local deltaX, deltaY = GetMouseDelta()
    cameraYaw = cameraYaw + deltaX * mouseSensitivity
    cameraPitch = cameraPitch + deltaY * mouseSensitivity
    
    -- Clamp pitch to prevent camera flipping
    cameraPitch = Clamp(cameraPitch, -89.0, 89.0)
    
    SetRotation(cameraPitch, cameraYaw, 0)
    
    -- === MOVEMENT ===
    local currentSpeed = moveSpeed
    if IsKeyDown("SHIFT") then
        currentSpeed = sprintSpeed
    end
    
    -- Get current position and rotation
    local px, py, pz = GetPosition()
    local rotX, rotY, rotZ = GetRotation()
    
    -- Calculate forward and right vectors
    local yawRad = rotY * 3.14159 / 180.0
    local forward = {
        x = Sin(yawRad),
        z = Cos(yawRad)
    }
    local right = {
        x = Cos(yawRad),
        z = -Sin(yawRad)
    }
    
    -- WASD movement
    local moveX = 0
    local moveZ = 0
    
    if IsKeyDown("W") then
        moveX = moveX + forward.x
        moveZ = moveZ + forward.z
    end
    if IsKeyDown("S") then
        moveX = moveX - forward.x
        moveZ = moveZ - forward.z
    end
    if IsKeyDown("A") then
        moveX = moveX - right.x
        moveZ = moveZ - right.z
    end
    if IsKeyDown("D") then
        moveX = moveX + right.x
        moveZ = moveZ + right.z
    end
    
    -- Normalize diagonal movement
    local moveLength = Sqrt(moveX * moveX + moveZ * moveZ)
    if moveLength > 0 then
        moveX = moveX / moveLength
        moveZ = moveZ / moveLength
    end
    
    -- Apply movement
    Translate(
        moveX * currentSpeed * dt,
        0,
        moveZ * currentSpeed * dt
    )
    
    -- === JUMPING ===
    if IsKeyDown("SPACE") and IsGrounded() and not isJumping then
        AddForce(0, jumpForce, 0)
        isJumping = true
    end
    
    -- Reset jump when grounded
    if IsGrounded() then
        isJumping = false
    end
    
    -- === INTERACTION ===
    if IsKeyDown("E") then
        -- Check for nearby interactable NPCs
        local npcID, distance = FindNearestEntity("NPC", 3.0)
        if npcID ~= nil then
            print("[PLAYER] Interacting with NPC")
            -- Trigger NPC dialogue or interaction
        end
    end
end
🎓 Pro Tips:
  • Always multiply speeds by GetDeltaTime() for frame-independent movement
  • Use FindNearestEntity() with appropriate ranges to optimize performance
  • Combine personality traits to create unique NPC behaviors
  • Use daily schedules to make your world feel alive and realistic
  • Test crime reporting in different scenarios to balance police response
↑