yuka Game AI library

repository·master·Indexed 23 days ago

https://github.com/mugen87/yuka

A standalone, engine-agnostic JavaScript library for developing Game AI. It provides tools for autonomous agent design, steering behaviors, navigation (graph classes and navmeshes), perception, fuzzy logic, and state-driven behavior via a Finite State Machine (FSM). Includes utilities for JSON serialization of game states and simulation time management.

Tokens
7.8K
Snippets
1
Records
58
Agent score
80%

What's inside yuka

  1. Overview of Yuka Game AI library

    master

    Yuka is a standalone JavaScript library designed for developing Game AI. It is engine-agnostic and can be used with any 3D engine. The library provides several core capabilities for game development:

    • Autonomous Agent Design: Basic game entity concepts and classes for state-driven and goal-driven agent design.
    • Steering: Built-in vehicle models and steering behaviors for moving entities.
    • Navigation: Graph classes, search algorithms, and navigation mesh implementations for pathfinding.
    • Perception: Vision components and short-term memory for game entities.
    • Trigger: Systems to generate dynamic actions.
    • Fuzzy Logic: A fuzzy inference system for complex decision-making.
    • JSON Serialization: APIs to save and load game states using JSON.
  2. Run Yuka examples locally

    master

    To explore the library's capabilities, you can run the included examples on your local machine. After downloading the repository, use npm to install dependencies and start a local development server.

    1. Install dependencies: npm install
    2. Start the server: npm start

    Once the server is running, you can view the examples in your web browser.

    npm install && npm start
  3. What is a FuzzySet and how is it used?

    master

    A FuzzySet is a base class used in fuzzy inference systems to define a membership function. It represents a gradual transition from regions completely outside a set to regions completely within it, allowing a value to have a partial degree of membership.

    Because FuzzySet inherits from FuzzyTerm, it can be used directly in fuzzy rules. In the context of the composite design pattern, a FuzzySet is treated as an atomic fuzzy term.

    Note that FuzzySet is an abstract base class; concrete implementations (like triangular or trapezoidal sets) must implement the computeDegreeOfMembership(value) method to define the specific shape of the membership function.

  4. How BVH and BVHNode work together

    master

    The BVH class acts as the high-level manager for the spatial hierarchy, while BVHNode represents the individual elements of the tree.

    • BVH: Responsible for the top-level lifecycle, including configuration (branchingFactor, depth, etc.) and the initial construction via fromMeshGeometry. It holds a reference to the root node.
    • BVHNode: The building block of the tree. Each node contains:
      • boundingVolume: An AABB representing the node's spatial extent.
      • children: An array of child BVHNode instances (empty if the node is a leaf).
      • primitives: An array of vertex data (only populated in leaf nodes).
      • parent: A reference to the parent node.

    Node State

    • root(): Returns true if the node has no parent.
    • leaf(): Returns true if the node has no children.
    • getDepth(): Returns the current hierarchical depth of the node.

    This structure allows for efficient recursive traversal and spatial queries by pruning branches whose boundingVolume does not intersect the query object (like a ray).

  5. Manage short-term memory with MemorySystem

    master

    The MemorySystem class is used to manage, filter, and remember sensory input for a game entity. It maintains a collection of MemoryRecord objects representing recently sensed entities.

    Key properties:

    • owner: The GameEntity that owns this memory system.
    • memorySpan: The duration (in seconds) for which an entity remains in short-term memory. When querying valid records, only those sensed within this span are returned.
    • records: An array of all MemoryRecord instances.
    • recordsMap: A Map for fast access to records by GameEntity.
  6. Use the HalfEdge class for mesh manipulation

    master
    The HalfEdge class implements a half-edge data structure (also known as a Doubly Connected Edge List). It is used to represent edges in a mesh, where each edge is split into two directed 'half-edges' pointing in opposite directions. Each HalfEdge instance maintains references to its vertex, its next/previous half-edges in a loop, its twin (the opponent half-edge), and its associated polygon/face.
  7. Manage agent states with StateMachine

    master

    The StateMachine class is a Finite State Machine (FSM) used to implement state-driven agent design. It manages a collection of State objects and controls the transitions between them.

    Key behaviors:

    • Update Loop: When update() is called, the machine executes the logic for the globalState (if present) and then the currentState.
    • State Transitions: Changing states triggers the exit() method of the old state and the enter() method of the new state.
    • Message Handling: You can dispatch messages via handleMessage(telegram). The machine first attempts to let the currentState handle the message; if it returns false, it attempts to let the globalState handle it.
    • Ownership: A StateMachine is typically owned by a GameEntity.
  8. Extend the GameEntity class

    master

    The GameEntity class is the base class for all entities in the Yuka simulation. To create custom entities (like players, obstacles, or NPCs), you should extend this class and override the start, update, handleMessage, or lineOfSightTest methods.

    • start(): Called once when the entity is first updated by an EntityManager.
    • update(delta): Called every simulation step. Use this for frame-by-frame logic.
    • handleMessage(): Implement this to define how your entity responds to messages sent via sendMessage.
    • lineOfSightTest(ray, intersectionPoint): Implement this if your entity acts as an obstacle that can block vision/rays.
  9. Manage Goal status and lifecycle

    master

    Goals transition through several statuses defined in Goal.STATUS. You can check the current state using helper methods like .active(), .inactive(), .completed(), and .failed().

    Goal Statuses

    • Goal.STATUS.ACTIVE: The goal is activated and will be processed in each update step.
    • Goal.STATUS.INACTIVE: The goal is waiting to be activated.
    • Goal.STATUS.COMPLETED: The goal has completed and will be removed on the next update.
    • Goal.STATUS.FAILED: The goal has failed and will either be replanned or removed on the next update.

    Lifecycle Helpers

    • activateIfInactive(): If the goal is currently INACTIVE, it sets the status to ACTIVE and calls activate().
    • replanIfFailed(): If the goal has FAILED, it resets the status to INACTIVE to allow for replanning.
  10. Convert Vector3 to and from other formats

    master

    Methods for data conversion:

    • fromArray(array, offset): Sets components from an array starting at offset.
    • toArray(array, offset): Copies components into an array at offset.
    • fromSpherical(radius, phi, theta): Sets components using spherical coordinates (phi in radians, theta in radians).
    • clone(): Returns a new Vector3 instance with the same values.
    • copy(v): Copies values from vector v to this vector.
    • set(x, y, z): Sets the x, y, and z components directly.
  11. Create and manage MemoryRecords

    master

    You can manually manage the lifecycle of memory records for specific entities within a MemorySystem using the following methods:

    • createRecord(entity): Creates a new MemoryRecord for the specified GameEntity and adds it to the system. Returns the MemorySystem instance for chaining.
    • getRecord(entity): Returns the MemoryRecord associated with the given GameEntity.
    • hasRecord(entity): Returns true if the system currently has a record for the specified GameEntity.
    • deleteRecord(entity): Removes the memory record for the specified GameEntity.
    • clear(): Removes all memory records from the system.
  12. Perform vector arithmetic with Vector3

    master

    You can perform basic arithmetic on Vector3 instances using both in-place operations and static-style operations that take two vectors as arguments.

    In-place operations (modifies the instance):

    • add(v): Adds vector v to this vector.
    • sub(v): Subtracts vector v from this vector.
    • multiply(v): Multiplies components by vector v.
    • divide(v): Divides components by vector v.
    • addScalar(s): Adds scalar s to all components.
    • subScalar(s): Subtracts scalar s from all components.
    • multiplyScalar(s): Multiplies all components by scalar s.
    • divideScalar(s): Divides all components by scalar s.

    Two-vector operations (stores result in this instance):

    • addVectors(a, b): Sets this vector to the sum of a and b.
    • subVectors(a, b): Sets this vector to the difference of a and b.
    • multiplyVectors(a, b): Sets this vector to the component-wise product of a and b.
    • divideVectors(a, b): Sets this vector to the component-wise division of a by b.