Basic Game AI Logic for NPCs

 

Build Smarter Characters in Unity, Godot, or Python (Pygame)

NPCs (Non-Player Characters) are essential in any game. Whether they're enemies, shopkeepers, or just background characters, adding basic AI logic gives life to your game world.





🧠 What is Game AI?

Game AI is about making game characters appear intelligent using logic and rules. You don't need machine learning or neural networks — just smart behavior like:

  • Patrolling areas

  • Chasing or avoiding the player

  • Talking or trading

  • Reacting to environment or actions


🧩 Core AI Concepts

1. Finite State Machine (FSM)

NPCs often follow a state pattern:

sql

Idle → Patrol → Chase → Attack → Return

Each “state” is like a mode with its own logic:

  • Idle: Wait or play animation.

  • Patrol: Move between waypoints.

  • Chase: Follow the player.

  • Attack: When close to player.

  • Return: Go back to original position.

FSMs help organize code and make behavior modular.


👣 Behavior #1: Patrol and Chase

Let’s implement a patrolling guard that chases the player when nearby.

🔧 Unity (C#)

csharp

using UnityEngine; public class EnemyAI : MonoBehaviour { public Transform[] patrolPoints; public Transform player; public float speed = 2f; public float chaseRange = 5f; private int patrolIndex = 0; private enum State { Patrol, Chase } private State state = State.Patrol; void Update() { float distance = Vector3.Distance(transform.position, player.position); if (distance < chaseRange) { state = State.Chase; } else { state = State.Patrol; } if (state == State.Patrol) { Patrol(); } else if (state == State.Chase) { Chase(); } } void Patrol() { Transform target = patrolPoints[patrolIndex]; transform.position = Vector3.MoveTowards(transform.position, target.position, speed * Time.deltaTime); if (Vector3.Distance(transform.position, target.position) < 0.2f) { patrolIndex = (patrolIndex + 1) % patrolPoints.Length; } } void Chase() { transform.position = Vector3.MoveTowards(transform.position, player.position, speed * 1.5f * Time.deltaTime); } }

🕹️ Godot (GDScript)

gdscript

extends KinematicBody2D enum { PATROL, CHASE } var state = PATROL var patrol_points = [Vector2(100, 100), Vector2(300, 100)] var patrol_index = 0 var speed = 100 onready var player = get_node("/root/Player") func _physics_process(delta): var dir = Vector2.ZERO var distance = global_position.distance_to(player.global_position) if distance < 150: state = CHASE elif state == CHASE and distance > 200: state = PATROL match state: PATROL: var target = patrol_points[patrol_index] dir = (target - global_position).normalized() move_and_slide(dir * speed) if global_position.distance_to(target) < 10: patrol_index = (patrol_index + 1) % patrol_points.size() CHASE: dir = (player.global_position - global_position).normalized() move_and_slide(dir * speed * 1.5)

🐍 Pygame (Python)

python

import pygame import math enemy_pos = [100, 100] player_pos = [300, 300] patrol_points = [(100, 100), (200, 100)] patrol_index = 0 enemy_speed = 2 chase_range = 100 def update_enemy(): global patrol_index dx = player_pos[0] - enemy_pos[0] dy = player_pos[1] - enemy_pos[1] distance = math.hypot(dx, dy) if distance < chase_range: # Chase enemy_pos[0] += dx / distance * enemy_speed enemy_pos[1] += dy / distance * enemy_speed else: # Patrol target = patrol_points[patrol_index] pdx = target[0] - enemy_pos[0] pdy = target[1] - enemy_pos[1] pdist = math.hypot(pdx, pdy) if pdist > 1: enemy_pos[0] += pdx / pdist * enemy_speed enemy_pos[1] += pdy / pdist * enemy_speed else: patrol_index = (patrol_index + 1) % len(patrol_points)

👀 Behavior #2: Line of Sight

Make NPCs “see” the player before reacting.

Unity Example:

csharp

Ray ray = new Ray(transform.position, (player.position - transform.position)); if (Physics.Raycast(ray, out RaycastHit hit, 10f)) { if (hit.transform == player) { // Player visible } }

🗣️ Behavior #3: NPC Dialogue & Interaction

NPCs can talk or react when the player is near.

Unity (Trigger):

csharp

void OnTriggerEnter(Collider other) { if (other.CompareTag("Player")) { // Start dialogue UI } }

Godot:

gdscript

func _on_Area2D_body_entered(body): if body.name == "Player": show_dialogue()

🧠 Tips for Smarter AI

  1. Timers – Add delays or cooldowns for realistic behavior.

  2. Random Patrol – Randomize patrol points for variety.

  3. Memory – NPCs "remember" player for a few seconds after chase.

  4. Animations – Sync states with animations for realism.

  5. Pathfinding – Use Unity NavMesh or Godot AStar for smarter movement.


🛠 Recommended Tools

ToolBest ForLanguage
Unity2D/3D games, cross-platformC#
GodotLightweight indie gamesGDScript / C#
PygameRetro 2D games, learningPython

Post a Comment

0 Comments