Frostbite2D/AGENTS.md

5.8 KiB

Frostbite2D Agent Guide

This guide helps agentic coding agents work effectively with the Frostbite2D 2D game engine codebase.

Build Commands

Basic Build

xmake build

Clean Build

xmake clean
xmake build

Debug Build

xmake build -m debug

Release Build

xmake build -m release

Platform-Specific Build

xmake build -p windows
xmake build -p linux
xmake build -p switch

Configuration

xmake f -c          # Show current configuration
xmake f             # Interactive configuration

Testing

Currently no automated test framework is configured. Manual testing is performed by running the built binary.

Project Structure

Frostbite2D/
├── include/frostbite2D/    # Public headers
│   ├── core/               # Core engine classes
│   ├── types/              # Type definitions
│   ├── utils/              # Utility classes
│   └── platform/           # Platform-specific code
└── src/frostbite2D/        # Implementation files

Code Style Guidelines

Naming Conventions

  • Classes/Structs: PascalCase (Application, Window, Vec2)
  • Methods/Functions: camelCase (readTextFile, getFileName)
  • Member Variables: camelCase with trailing underscore (width_, height_, running_)
  • Constants: UPPER_CASE (PI_F, DEG_TO_RAD) or PascalCase static methods (Vec2::Zero())
  • Namespaces: lowercase (frostbite2D, math)
  • Template Parameters: PascalCase (T, Args, Sig)
  • Type Aliases: using keyword with PascalCase (using int8 = std::int8_t;)

Imports and Includes

  • Engine headers: Use path relative to frostbite2D root
    #include <frostbite2D/core/application.h>
    #include <frostbite2D/utils/asset.h>
    
  • Third-party libraries: Use vendor prefixes
    #include <SDL2/SDL.h>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glad/glad.h>
    
  • Standard library: Use angle brackets
    #include <string>
    #include <functional>
    #include <optional>
    

Formatting

  • Indentation: 2 spaces
  • Brace Style: K&R (opening brace on same line)
    void myFunction() {
      // body
    }
    
  • Pointer/Reference Style: Type on left, not centered
    void func(T* ptr);      // Good
    void func(T *ptr);      // Avoid
    void func(T& ref);      // Good
    
  • Const Placement: After type
    const std::string& str;  // Good
    std::string const& str;  // Avoid
    

Types

  • Use custom type aliases: int8, int32, uint8, uint64, Ptr<T>, SharedPtr<T>
  • Smart pointers: Prefer Ptr<T> alias over std::shared_ptr<T>
  • constexpr: Use for compile-time constants
  • Struct vs Class:
    • Use struct for POD types, configurations, and data-only types
    • Use class for objects with methods/encapsulation
  • Default member initialization: Initialize at declaration
    bool running_ = false;
    int width_ = 1280;
    

Error Handling

  • Return bool for success/failure operations (especially I/O)
  • Use SDL_Log/SDL_LogError for logging
  • Use std::optional for optional returns
  • Avoid exceptions (not observed in codebase)
  • Return early on failure: Check conditions and return false immediately

Singletons

  • Use static instance pattern with private constructor:
    static Application& get();
    private:
      Application() = default;
    

Const Correctness

  • Mark methods const if they don't modify state
  • Pass by const reference for large types: const std::string&
  • Return const references to member data when appropriate

Documentation

  • Doxygen-style comments with @brief tag
  • Use /// for single-line comments in headers
  • Section separators use // ---------------------------------------------------------------------------
  • Chinese comments are present and should be preserved/maintained
    /**
     * @brief 读取文本文件
     * @param path 文件路径
     * @param outContent 输出文件内容
     * @return 读取成功返回 true
     */
    bool readTextFile(const std::string& path, std::string& outContent);
    

Platform Handling

  • Use #ifdef guards for platform-specific code:
    #ifdef __SWITCH__
      switchInit();
    #endif
    
  • Supported platforms: Windows, Linux, macOS, Switch
  • Platform configs in platform/ directory

STL Usage

  • Prefer STL algorithms over manual loops
  • Use std::filesystem for file operations (already wrapped in Asset class)
  • Use std::optional for nullable returns
  • Use std::function for callbacks
  • Use std::vector for dynamic arrays
  • Use std::string for text

OpenGL/Graphics

  • GLM library for math operations
  • Glad for OpenGL function loading
  • Keep OpenGL-specific code minimal and well-encapsulated

Dependencies

  • SDL2: Windowing, input, platform abstraction
  • GLM: Math library (vectors, matrices)
  • Glad: OpenGL loader
  • STB: Image/text utilities (single-header libs)

Key Patterns

Module Pattern

void Application::use(Module& m) {
  modules_.push_back(&m);
}

Configuration Pattern

Use configuration structs with default values:

struct WindowConfig {
  uint32_t width = 640;
  uint32_t height = 480;
  std::string title = "Frostbite2D Game";
};

Path Handling

Always use the Asset singleton for file operations - it handles platform-specific path issues:

Asset& asset = Asset::get();
asset.setWorkingDirectory("path/to/assets");
std::string content;
if (asset.readTextFile("file.txt", content)) {
  // success
}

Common Issues

  • Path separators: Use Asset class, it handles platform differences
  • Encoding: Project uses UTF-8, Asset handles Windows UTF-8 paths
  • Memory leaks: Use smart pointers, ensure proper cleanup in destructors
  • OpenGL context: Initialize only after window creation