|
This document is under active development and discussion!
If you find errors or omissions in this document, please don’t hesitate to submit an issue or open a pull request with a fix. We also encourage you to ask questions and discuss any aspects of the project on IRC. New contributors are always welcome! |
1. What is Fifengine?
Flexible Isometric Free Engine (FIFE) is a multi-platform isometric game engine written in C++. It comes with Python bindings allowing users to create games using Python as well as C++. The engine is extendable and enables you to add any feature you can imagine to your project.
It’s a very flexible game creation framework and not tied to any genre, but geared towards an RTS or RPG using an isometric or top-down view style.
This manual describes how to use FIFE to power your game.
Features
This chapter describes all the features the engine currently supports in the master branch. Features are organized into categories for easy reference.
As we continue to add features to FIFE, we will update this list to keep it up to date.
| Just because a feature is listed here does not mean that feature is 100% bug free. You may from time to time stumble upon a bug. Please file any bugs you find using our Issue Tracker on Github. |
-
Supported Formats
-
Large file streaming
-
Looping
-
Logger
-
Module specific logging functionality
-
Logging according to priority levels
-
Logging output to file and stdout
-
-
Map Editor
-
Multi Map Interface (edit multiple maps at the same time)
-
Object Selector
-
Deleting instances from map layer
-
Loading existing maps
-
Placing instances on map layer
-
Saving maps
-
Undo/Redo support for instances
-
Object Editor plugin
-
Light Editor plugin
-
Camera Editor plugin
-
-
Image Atlas Creator
-
Create/Edit image atlases
-
cross-platform
-
written in C++ using the Qt framework
-
The following event types are supported and can be bound to scripting functionality:
-
Mouse events
-
Keyboard events
-
Widget events
-
Custom commands
Support for following font formats:
-
True type SDL_ttf
-
Bitmap fonts
-
General
-
Support for all formats implemented by SDL_image:
-
BMP, GIF, JPEG, LBM, PCX, PNG, PNM, TGA, TIFF, WEBP, XCF, XPM, XV
-
-
Color key support
-
Take ingame screenshots via hotkey
-
Pooling of image resources, resulting enhanced performance and reduced memory consumption
-
Image atlases (many images contained in one file)
-
-
Animations
-
Multiple definable key frame animations per object
-
-
Effects
-
Lighting (OpenGL renderer only)
-
Fog of War (OpenGL renderer only)
-
-
Maps
-
3D geometry definition (defined by tilt, rotation and scale)
-
Support for different tile and object grids with independent geometries
-
Multiple layers per map
-
All variations of square and hex shape geometries
-
Multiple cameras / views per map
-
Custom XML-based map file format
-
-
Pathfinding
-
Exchangable pathfinding backends:
-
Route path finder
-
-
Python based scripting system (out of the box)
-
Scripts be can executed from the console
-
Support for different renderers (RendererBackends):
-
SDL
-
OpenGL
-
-
Various resolutions
-
Bit-depth (16, 24, 32bit)
-
Window mode (fullscreen & windowed)
-
Colorkey for fast transparency effects
-
Transparency for tiles & objects
-
Colorkey for fast transparency effects
-
Lighting effects
-
Fog of War
-
Custom Isometric views defined by angle and tilt of camera
-
Top down/side views
-
Correct z-order sorting of map instances
-
Support for different renderers:
-
Blocking renderer
-
Cell selection renderer
-
Coordinate renderer
-
Floating text renderer
-
Grid renderer
-
Instance renderer
-
Quadtree renderer
-
Light renderer (OpenGL only)
-
-
Static layer support which renders an entire layer as one texture
-
Support for reading files on platforms with different byte orders
-
Read support for ZIP archives
-
Lazy loading of files for decreased load times
Games using Fifengine
The following projects are using Fife as their engine.
We work closely with both Unknown Horizons to continue to improve fife.
| Unknown Horizons |
A realtime strategy game with economy simulation. This project is in very active development. |
| Zero-Projekt |
A turn-based post apocalyptic RPG. Check out some videos from Zero-Project here (development ceased). |
| PARPG |
A post-apocalyptic roleplaying game inspired by Fallout, Planescape: Torment & Arcanum (development ceased). PAPRG Blog |
| FIFE RPG |
Rewrite of PARPG. Build with the intention to create an RPG framework, which helps create new RPG games. |
| Jagged Alliance 2 - Fife Demo |
A small game demo for using the Jagged Alliance 2 assets in FIFE engine. |
| SteamFolkTales |
- |
| Fife Tactics |
- |
If you are developing a game with Fifengine and want it posted here, please let us know!
Media
You’ll find various media items in this section, including screenshots and videos.
Screenshots
There is a media page that can be found here: http://www.fifengine.net/media.html
Also check out some screenshots on our archived wiki here: http://archivewiki.fifengine.net/Screenshots
1.1. License
The source code (*.cpp, *.h & *.py) of Fifengine is licensed under the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1.
See GNU Lesser General Public License v2.1 (LGPL-2.1) Explained for more info.
Can I use FIFE to make a commercial product?
You can create commercial games with FIFE without needing to pay us any fee.
The following basic rules apply concerning the used LGPL:
Third-Party Content Licenses
Third-party content, such as assets, images, and sounds might come from different sources.
Therefore each client directory comes with a separate LICENSE file that states the origin of the content, the author and the actual license it was published under.
2. Getting started
2.1. Installation
This chapter explains how to install fifengine.
3. Core Concepts
This chapter provides an overview of FIFE’s architecture and how the major subsystems connect. Understanding the core architecture helps when working with maps, rendering, input, and other engine features.
3.1. Engine
The Engine class is the central entry point to all engine subsystems.
It initializes, manages, and provides access to all major components.
3.1.1. Initialization
Before using any engine features, the Engine must be initialized:
engine = fife.Engine()
engine.init()
During initialization, the engine creates and connects the following subsystems:
| SoundManager |
Handles audio playback |
| EventManager |
Manages input and game events |
| TimeManager |
Controls timing and frame rate |
| Model |
Contains the game world (maps, layers, objects) |
| VFS |
Virtual file system for loading assets |
| RenderBackend |
Graphics rendering (SDL or OpenGL) |
| IGUIManager |
GUI system integration |
3.1.2. Game Loop
FIFE uses a pump-based game loop. Call pump() repeatedly in your main loop:
# Initialize engine pumping
engine.initializePumping()
# Main game loop
running = True
while running:
engine.pump() # Process one frame
# Update game logic here
# Clean up
engine.finalizePumping()
engine.destroy()
The pump() method processes all pending events, updates the model, and renders the frame.
3.1.3. Accessing Subsystems
The Engine class provides getter methods for each subsystem:
sound_manager = engine.getSoundManager()
event_manager = engine.getEventManager()
time_manager = engine.getTimeManager()
model = engine.getModel()
vfs = engine.getVFS()
render_backend = engine.getRenderBackend()
gui_manager = engine.getGuiManager()
3.2. Engine Settings
The EngineSettings class controls initialization parameters before calling engine.init().
3.2.1. Display Settings
settings = engine.getSettings()
# Screen dimensions
settings.setScreenWidth(1024)
settings.setScreenHeight(768)
# Display mode
settings.setFullScreen(True)
settings.setBitsPerPixel(32)
settings.setVSync(True)
settings.setRefreshRate(60)
# Render backend
settings.setRenderBackend("OpenGL") # or "SDL"
3.2.2. Window Settings
settings.setWindowTitle("My Game")
settings.setWindowIcon("icon.png")
3.2.3. Audio Settings
settings.setInitialVolume(0.8) # 80% volume
3.2.4. OpenGL-Specific Settings
# Texture filtering
settings.setGLTextureFiltering("nearest") # or "linear"
# Texture compression
settings.setGLCompressImages(True)
# Mipmapping
settings.setGLUseMipmapping(True)
# Framebuffer effects
settings.setGLUseFramebuffer(True)
3.3. Subsystem Overview
FIFE’s architecture consists of several interconnected subsystems:
| Model |
The game world containing maps, layers, and instances. See Model and Instances. |
| View |
Rendering pipeline including cameras and renderers. See Rendering. |
| Video |
Low-level graphics backend (SDL/OpenGL). |
| Audio |
Sound management and playback. See Audio. |
| EventChannel |
Input handling and event distribution. See Input and Events. |
| GUI |
Graphical user interface integration. See GUI. |
| Pathfinder |
Pathfinding and movement. See Pathfinding. |
| VFS |
Virtual file system for asset loading. See Virtual Filesystem. |
3.4. Resource Managers
FIFE uses resource managers to cache and manage loaded assets:
| ImageManager |
Caches loaded images |
| AnimationManager |
Caches animations |
| SoundClipManager |
Caches sound clips |
These managers implement lazy loading, so resources are loaded only when first accessed.
image_manager = engine.getImageManager()
animation_manager = engine.getAnimationManager()
sound_clip_manager = engine.getSoundClipManager()
3.5. Time Management
The TimeManager provides timing information for frame-rate independent updates:
time_manager = engine.getTimeManager()
dt = time_manager.getTimeDelta() # Time since last frame in seconds
Use dt to scale movement and animation speeds for consistent behavior regardless of frame rate.
3.6. Engine Change Listener
Monitor engine-level changes such as screen mode switches:
class MyEngineChangeListener(fife.IEngineChangeListener):
def onScreenModeChanged(self, newmode):
print("Screen mode changed")
listener = MyEngineChangeListener()
engine.addChangeListener(listener)
# Later, remove it
engine.removeChangeListener(listener)
3.7. Changing Screen Mode at Runtime
Change the display mode without re-initializing the engine:
# Get available screen modes from device capabilities
device_caps = engine.getDeviceCaps()
modes = device_caps.getNearestScreenMode(width, height, bpp, fullscreen)
# Apply the new mode
engine.changeScreenMode(modes)
The changeScreenMode() method handles re-creation of internal objects that depend on the display.
3.8. Device Capabilities
Query supported display configurations:
device_caps = engine.getDeviceCaps()
# Get available screen modes
modes = device_caps.getAvailableScreenModes()
# Get available render drivers
drivers = device_caps.getAvailableRenderDrivers()
3.9. Additional Engine Accessors
The Engine provides access to additional subsystems:
# Logging subsystem
log_manager = engine.getLogManager()
# Special renderers (owned by engine, do not delete)
off_renderer = engine.getOffRenderer()
target_renderer = engine.getTargetRenderer()
# Cursor control
cursor = engine.getCursor()
3.10. Engine Settings Reference
3.10.1. Display Index
For multi-monitor setups, select which display to use:
settings.setDisplay(0) # Primary display (default)
settings.setDisplay(1) # Secondary display
3.10.2. SDL Render Driver
Select a specific SDL render driver:
settings.setSDLDriver("software") # Platform-dependent values
3.10.3. Video Driver
Set the video driver (platform-dependent):
settings.setVideoDriver("x11") # Linux X11
3.10.4. Color Key Transparency
Enable global colorkey-based transparency:
settings.setColorKeyEnabled(True)
settings.setColorKey(255, 0, 255) # Magenta as transparent color
3.10.6. Alpha Test Value
Set the alpha threshold for depth buffer discarding (OpenGL only):
settings.setGLUseDepthBuffer(True)
settings.setGLAlphaTestValue(0.1) # Discard fragments with alpha < 0.1
3.10.7. SDL Fake Alpha Removal
Remove fake alpha in SDL backend:
settings.setSDLRemoveFakeAlpha(True)
3.10.8. Joystick Support
Enable or disable joystick and gamepad input:
settings.setJoystickSupport(True) # Enable gamepad support
3.10.9. Frame Limit
Limit the frame rate at the settings level. Also documented in Rendering.
settings.setFrameLimitEnabled(True)
settings.setFrameLimit(60) # 60 FPS max
if settings.isFrameLimitEnabled():
print("Frame limit:", settings.getFrameLimit())
3.10.10. Mouse Sensitivity
Configure mouse input sensitivity and acceleration via settings (also configurable at runtime through EventManager):
settings.setMouseSensitivity(1.5) # Speed factor (1.0 = default)
settings.setMouseAccelerationEnabled(True) # Enable mouse acceleration
3.10.11. Native Image Cursor
Use a native OS cursor backed by an image file:
settings.setNativeImageCursorEnabled(True)
if settings.isNativeImageCursorEnabled():
print("Using native cursor")
3.11. Log Modules
FIFE uses a hierarchical logging system. Each subsystem is a log module:
-
LM_AUDIO- Audio subsystem -
LM_MODEL- Game model -
LM_VIDEO- Video/rendering -
LM_VIEW- View system -
LM_CAMERA- Camera -
LM_PATHFINDER- Pathfinding -
LM_GUI- GUI system -
LM_VFS- Virtual file system
Configure logging levels to filter debug output during development.
4. Coordinate Systems
FIFE uses several different coordinate systems to handle positions across the game world, layers, and screen display. Understanding these coordinate systems is essential for positioning objects, handling input, and working with the camera.
This chapter explains each coordinate system, how they relate to each other, and provides examples for converting between them.
4.1. Overview
FIFE has four main coordinate systems:
| Model Coordinates |
Integer-based 3D coordinates representing discrete grid positions (cells) |
| Exact Model Coordinates |
Floating-point 3D coordinates for precise positioning |
| Layer Coordinates |
Model coordinates mapped to a specific layer |
| Screen Coordinates |
2D pixel coordinates on the screen after camera transformation |
The base types are defined in model/metamodel/modelcoords.h:
typedef DoublePoint3D ExactModelCoordinate; // Double precision (x, y, z)
typedef Point3D ModelCoordinate; // Integer precision (x, y, z)
typedef DoublePoint3D AudioSpaceCoordinate; // Audio positioning
4.2. Model Coordinates
Model coordinates represent positions on the game grid using integers. They correspond to discrete cell positions and are useful when you need to reference specific tiles or cells on a layer.
4.2.1. Creating Model Coordinates
# Create a model coordinate at cell (5, 3, 0)
coord = fife.ModelCoordinate(5, 3, 0)
# Access components
print(coord.x) # 5
print(coord.y) # 3
print(coord.z) # 0
4.2.2. Use Cases
-
Referencing specific cells on a grid
-
Placing objects at exact tile boundaries
-
Grid-based pathfinding
-
Layer grid calculations
4.3. Exact Model Coordinates
Exact model coordinates use double-precision floating-point values for smooth, continuous positioning. They allow objects to be placed between grid cells, enabling smooth movement and animations.
4.3.1. Creating Exact Model Coordinates
# Create an exact coordinate at (5.5, 3.7, 0.0)
coord = fife.ExactModelCoordinate(5.5, 3.7, 0.0)
# Access components
print(coord.x) # 5.5
print(coord.y) # 3.7
print(coord.z) # 0.0
4.3.2. Use Cases
-
Smooth object movement between cells
-
Precise positioning for animations
-
Camera positioning
-
Map coordinate calculations
4.4. Layer Coordinates
Layer coordinates are model coordinates that are associated with a specific layer.
The Location class ties coordinates to a layer, providing the bridge between coordinate systems.
4.4.1. The Location Class
The Location class represents a position on a specific layer:
# Create a location on a layer
location = fife.Location(layer)
# Set position using layer coordinates (cell precision)
location.setLayerCoordinates(fife.ModelCoordinate(5, 3, 0))
# Set position using exact layer coordinates (precise)
location.setExactLayerCoordinates(fife.ExactModelCoordinate(5.5, 3.7, 0.0))
4.4.2. Getting Coordinates from a Location
# Get the layer this location is on
layer = location.getLayer()
# Get exact layer coordinates
exact_coords = location.getExactLayerCoordinates()
print(f"Exact: ({exact_coords.x}, {exact_coords.y}, {exact_coords.z})")
# Get cell precision coordinates
cell_coords = location.getLayerCoordinates()
print(f"Cell: ({cell_coords.x}, {cell_coords.y}, {cell_coords.z})")
# Get map coordinates
map_coords = location.getMapCoordinates()
print(f"Map: ({map_coords.x}, {map_coords.y}, {map_coords.z})")
4.4.3. Coordinate Mapping Between Layers
Convert coordinates to a different layer:
# Get exact coordinates mapped to a specific layer
other_exact = location.getExactLayerCoordinates(target_layer)
# Get cell coordinates mapped to a specific layer
other_cell = location.getLayerCoordinates(target_layer)
4.4.4. Cell Offset Distance
Get the offset from the nearest cell center:
offset = location.getCellOffsetDistance()
# Returns distance between exact position and cell center
4.4.5. Checking Location Validity
A location is valid if: - A layer is set - The layer has a cell grid assigned
if location.isValid():
# Location is ready to use
pass
4.4.6. Calculating Distances
The Location class provides methods for calculating distances:
# Distance in map coordinates
map_distance = location.getMapDistanceTo(other_location)
# Distance in layer coordinates
layer_distance = location.getLayerDistanceTo(other_location)
4.5. Screen Coordinates
Screen coordinates represent positions on the game window in pixels. The camera transforms model coordinates to screen coordinates for rendering.
4.5.1. The Camera and ScreenPoint
The Camera class handles screen coordinate transformations.
Screen coordinates use ScreenPoint, which is a Point3D where z represents depth.
4.5.2. Converting Between Map and Screen Coordinates
# Convert map coordinates to screen coordinates
screen_point = camera.toScreenCoordinates(exact_map_coords)
# Convert screen coordinates back to map coordinates
map_point = camera.toMapCoordinates(screen_point)
# Convert map to virtual screen coordinates (sub-pixel precision)
virtual_screen = camera.toVirtualScreenCoordinates(exact_map_coords)
4.5.3. Virtual Screen Coordinates
Virtual screen coordinates provide sub-pixel precision before final screen conversion:
# Map to virtual screen
virtual = camera.toVirtualScreenCoordinates(map_coords)
# Virtual screen to screen
screen = camera.virtualScreenToScreen(virtual)
# Screen to virtual screen
virtual = camera.screenToVirtualScreen(screen)
4.5.4. Mouse Click Example
When handling mouse clicks, you typically convert screen coordinates to map coordinates:
def onMousePress(self, event):
# Get screen coordinates from mouse event
screen_point = fife.ScreenPoint(event.getX(), event.getY(), 0)
# Convert to map coordinates
map_point = camera.toMapCoordinates(screen_point)
# Convert to layer coordinates for a specific layer
# (map coordinates are layer-independent)
4.6. Coordinate Conversion Summary
This table shows how to convert between coordinate systems:
| Model to Exact |
|
| Exact to Model |
|
| Layer to Screen |
|
| Screen to Map |
|
| Map to Layer |
Use cell grid’s |
| Layer to Map |
Use cell grid’s |
4.7. Practical Examples
4.7.1. Moving an Instance
def move_instance(instance, target_x, target_y):
# Get current location
current = instance.getLocation()
# Create target coordinates
target = fife.ExactModelCoordinate(target_x, target_y, 0)
# Create new location on same layer
new_location = fife.Location(current.getLayer())
new_location.setExactLayerCoordinates(target)
# Move the instance
instance.setLocation(new_location)
4.7.2. Finding Instance at Mouse Position
def get_instance_at(screen_x, screen_y, camera, layer):
# Convert screen coordinates to screen point
screen_point = fife.ScreenPoint(screen_x, screen_y, 0)
# Get matching instances
instances = []
camera.getMatchingInstances(screen_point, layer, instances)
return instances[0] if instances else None
4.7.3. Placing an Object on a Grid
def place_object_at(object_id, layer, cell_x, cell_y):
# Create location at specific cell
location = fife.Location(layer)
location.setLayerCoordinates(fife.ModelCoordinate(cell_x, cell_y, 0))
# Create instance
instance = layer.createInstance(object_id, location)
return instance
4.8. Camera Properties Affecting Coordinate Transformations
The camera’s properties affect how coordinates are transformed:
| Rotation |
Rotates the view around the target point |
| Tilt |
Adjusts the viewing angle (0 = top-down, 45 = isometric) |
| Zoom |
Scales the view |
| zToY |
Affects the z-axis to y-axis transformation ratio |
These properties can be set via the camera:
camera.setRotation(45) # Rotate 45 degrees
camera.setTilt(60) # 60 degree tilt angle
camera.setZoom(1.5) # Zoom to 1.5x
camera.setZToY(32) # 1 z-unit = 32 y-pixels
Understanding these coordinate systems is key to working with FIFE’s rendering and input systems effectively.
4.9. Point Utilities
The Point and Point3D classes provide vector math utilities.
4.9.1. Point2D Operations
p = fife.Point(3, 4)
# Vector operations
p2 = p + fife.Point(1, 2) # (4, 6)
p3 = p - fife.Point(1, 1) # (2, 3)
p4 = p * 2 # (6, 8)
p5 = p / 2 # (1, 2)
# Length (magnitude)
length = p.length() # 5.0
# Normalize to unit vector
p.normalize()
# Rotate around origin (degrees)
p.rotate(90)
# Rotate around a specific point
origin = fife.Point(0, 0)
p.rotate(origin, 45)
# Set coordinates
p.set(10, 20)
4.9.2. Point3D Operations
p = fife.Point3D(1, 2, 3)
# Same operations as Point2D, plus z-component
length = p.length()
p.normalize()
p.set(10, 20, 30)
4.9.3. Type Conversions
Convert between integer and double point types:
# Double to int (rounds)
int_point = fife.doublePt2intPt(double_point)
# Int to double
double_point = fife.intPt2doublePt(int_point)
4.9.4. Typedefs
| Point |
|
| DoublePoint |
|
| Point3D |
|
| DoublePoint3D |
|
4.10. Rect Utilities
The Rect class provides rectangle operations for screen areas:
rect = fife.Rect(x, y, width, height)
# Edge coordinates
right = rect.right() # x + width
bottom = rect.bottom() # y + height
# Point containment
if rect.contains(fife.Point(px, py)):
print("Point is inside rect")
# Rectangle intersection
if rect.intersects(other_rect):
print("Rectangles overlap")
# In-place intersection (modifies rect)
rect.intersectInplace(other_rect)
4.10.1. Typed Rectangles
| Rect |
|
| FloatRect |
|
| DoubleRect |
|
5. Working with Maps
This chapter explains how maps work in Fife, including the XML file format and lighting system.
5.1. Map Format
Fife uses a custom XML-based map format. Maps are structured hierarchically with layers, cells, and instances.
5.1.1. Map Structure Overview
A map consists of the following components:
| Map |
The top-level container that holds all layers, cameras, and settings. |
| Layer |
Contains a grid of cells with instances. Multiple layers can exist per map. |
| Cell |
A single tile or position on the grid. |
| Instance |
A game object placed on the map at a specific location. |
5.1.2. XML File Structure
The basic map XML structure looks like this:
<?xml version="1.0" encoding="utf-8"?>
<fife version="0.4.0">
<map id="mymap">
<name>My Map</name>
<grid type="square">
<cell_scale>1.0</cell_scale>
<x_scale>1.0</x_scale>
<y_scale>1.0</y_scale>
<rot>0</rot>
<tilt>0</tilt>
<x_offset>0</x_offset>
<y_offset>0</y_offset>
</grid>
<elevation id="el1">
<name>Ground Floor</name>
<layer id="layer1">
<name>Ground Layer</name>
<grid type="square">
<cell_scale>1.0</cell_scale>
<x_scale>1.0</x_scale>
<y_scale>1.0</y_scale>
<rot>0</rot>
<tilt>30</tilt>
</grid>
<instances>
<instance object="myobject" x="0" y="0" id="inst1"/>
</instances>
</layer>
</elevation>
</map>
</fife>
5.1.3. Grid Types
Fife supports different tile and object grids with independent geometries:
-
Square - Standard square tile grid
-
Hexagonal - Hexagonal grid for more natural movement
Grids are defined by:
-
cell_scale- Size of each cell -
x_scale/y_scale- Scaling factors -
rot- Rotation angle -
tilt- Camera tilt angle for 3D-like view
5.1.4. Layers
Each map can have multiple layers. Layers are useful for separating different types of content:
-
Ground layer for terrain
-
Object layer for buildings and decorations
-
Agent layer for game characters
-
Static layer for performance (renders entire layer as one texture)
5.1.5. Instances
Instances are game objects placed on the map. Each instance references an object (archetype) that defines its properties.
<instance object="tree" x="5" y="3" id="tree1"/>
<instance object="building" x="10" y="7" id="building1" rotation="90"/>
5.1.6. File Loaders
Fife provides multiple loaders for map files:
-
MapLoader - Main loader that orchestrates map loading from XML
-
ObjectLoader - Loads object and instance data from XML
-
AnimationLoader - Loads animation definitions from XML
-
AtlasLoader - Loads image atlas definitions
Maps are typically saved in the same XML format using MapSaver.
5.2. Lighting System
Fife includes a lighting system for creating atmospheric lighting effects in your game.
| The lighting system is only available when using the OpenGL renderer. The SDL renderer does not support lighting effects. |
5.2.1. Light Sources
Fife supports three types of light sources:
5.2.1.1. Image-Based Lights
Use images as light sources. This allows for complex, custom lighting effects.
lightrenderer = map.getLightRenderer()
lightrenderer.addImageLightInfo(
layer=my_layer,
image="my_light.png",
x=5, y=5
)
5.2.1.2. Animation-Based Lights
Use animations as light sources. Useful for flickering or animated lighting effects.
lightrenderer.addAnimationLightInfo(
layer=my_layer,
animation="my_light_animation",
x=5, y=5
)
5.2.1.3. Simple Procedural Lights
Create simple lights programmatically with full control over properties.
lightrenderer.addSimpleLightInfo(
layer=my_layer,
x=5, y=5,
color=[255, 255, 128], # Warm yellow light
intensity=200,
radius=5.0,
subdivisions=32,
xstretch=1.0,
ystretch=1.0
)
5.2.2. Light Parameters
The simple light type supports these parameters:
| x, y |
Position of the light on the map |
| color |
RGB color value (0-255 per channel) |
| intensity |
Brightness of the light (0-255) |
| radius |
How far the light reaches |
| subdivisions |
Quality of the light circle (more = smoother) |
| xstretch |
Horizontal stretch factor |
| ystretch |
Vertical stretch factor |
5.2.3. Blending Modes
Light sources use additive blending by default. You can configure the blend modes for custom effects:
lightrenderer.setBlendMode(
src_factor="src_alpha",
dst_factor="one" # Additive blending
)
5.2.4. Fog of War
Fife supports fog of war effects in the OpenGL renderer. This creates areas of the map that are hidden from the player until they explore them.
| Fog of war is only available when using the OpenGL renderer. |
5.2.5. Light Groups
You can group lights together for easier management and organization. This is useful when you have many lights in a scene and want to control them as a group.
lightrenderer.setGroupIndex(my_group_index)
lightrenderer.addSimpleLightInfo(...)
5.2.6. Editor Support
The Fife Map Editor includes a Light Editor plugin for visual creation and editing of light sources. This provides a WYSIWYG interface for placing and configuring lights on your map.
6. Rendering
This chapter covers the camera, renderers, and graphics pipeline.
FIFE’s rendering system consists of three main components: the render backend, cameras, and renderers. The render backend handles low-level graphics operations, cameras define what to display, and renderers draw specific aspects of the view.
6.1. Render Backend
The RenderBackend is the foundation of FIFE’s graphics system.
It provides hardware-acstraction for all drawing operations.
6.1.1. Available Backends
FIFE supports two render backends:
| SDL |
Software rendering, widely compatible |
| OpenGL |
Hardware-accelerated, supports advanced effects |
Set the backend before initializing the engine:
settings = engine.getSettings()
settings.setRenderBackend("OpenGL") # or "SDL"
6.1.2. Screen Mode
Configure the display before initializing the engine:
settings = engine.getSettings()
settings.setScreenWidth(1024)
settings.setScreenHeight(768)
settings.setBitsPerPixel(32)
settings.setFullScreen(True)
settings.setVSync(True)
6.1.3. OpenGL-Specific Settings
The OpenGL backend supports additional features:
# Texture filtering (improves image quality)
settings.setGLTextureFiltering("linear") # none, linear, bilinear, trilinear, anisotropic
# Mipmapping (reduces aliasing at distance)
settings.setGLUseMipmapping(True)
# Texture compression (reduces memory usage)
settings.setGLCompressImages(True)
# Framebuffer effects (for post-processing)
settings.setGLUseFramebuffer(True)
# NPOT textures (non-power-of-two sizes)
settings.setGLUseNPOT(True)
# Depth buffer (for 3D effects)
settings.setGLUseDepthBuffer(True)
6.2. Camera
The Camera defines what portion of the game world is visible on screen.
Each camera can have different settings for tilt, rotation, and zoom.
6.2.1. Creating a Camera
import fifengine
# Get the map
map = model.getMap("mymap")
# Define viewport (area of screen to render to)
viewport = fifengine.Rect(0, 0, 800, 600)
# Create camera
camera = fifengine.Camera("mycam", map, viewport, engine.getRenderBackend())
6.2.2. Camera Properties
6.2.2.1. Tilt
Controls the viewing angle. 0 is top-down, 45 is classic isometric:
camera.setTilt(45) # Isometric view
camera.setTilt(60) # Steeper angle
6.2.2.2. Rotation
Rotates the view around the camera target:
camera.setRotation(0) # Default
camera.setRotation(90) # Quarter turn
camera.setRotation(45) # Diagonal view
6.2.2.3. Zoom
Scales the view (1.0 is default):
camera.setZoom(1.0) # Normal zoom
camera.setZoom(2.0) # Zoomed in
camera.setZoom(0.5) # Zoomed out
6.2.2.4. zToY
Controls the z-axis transformation ratio:
camera.setZToY(32) # 1 z-unit = 32 pixels vertically
6.2.3. Setting Camera Location
Position the camera in the game world:
# Create a location
location = fifife.Location(layer)
location.setLayerCoordinates(fife.ModelCoordinate(10, 10, 0))
# Move camera to location
camera.setLocation(location)
6.2.4. Camera Attachment
Attach the camera to follow an instance:
# Attach to instance
camera.attach(instance)
# Detach
camera.detach()
6.2.5. Coordinate Transformations
The camera transforms between map coordinates and screen coordinates:
# Map to screen
screen_point = camera.toScreenCoordinates(map_coords)
# Screen to map
map_point = camera.toMapCoordinates(screen_point)
# Virtual screen coordinates (sub-pixel precision)
virtual = camera.toVirtualScreenCoordinates(map_coords)
# Convert between virtual and screen
screen = camera.virtualScreenToScreen(virtual)
virtual = camera.screenToVirtualScreen(screen_point)
See Coordinate Systems for details on coordinate transformations.
6.2.6. Camera Position
Set camera position directly without a Location object:
camera.setPosition(fife.ExactModelCoordinate(10.5, 20.3))
pos = camera.getPosition()
6.2.7. Camera Enabled State
Enable or disable a camera (disabled cameras are not rendered):
camera.setEnabled(False) # Disable rendering
camera.setEnabled(True) # Enable rendering
6.2.8. Z-to-Y Transformation
Control the z-axis transformation. Enable or disable the custom zToY factor:
camera.setZToY(32) # 1 z-unit = 32 pixels vertically
camera.setZToYEnabled(True) # Enable custom z-to-y
camera.setZToYEnabled(False) # Use original matrix value
is_enabled = camera.isZToYEnabled()
original = camera.getOriginalZToY() # Original value from matrix
6.2.9. Cell Image Dimensions
Set the screen size of cell images and retrieve reference scale:
camera.setCellImageDimensions(64, 32)
dims = camera.getCellImageDimensions() # For current layer
dims = camera.getCellImageDimensions(layer) # For specific layer
# Reference scale factors
scale_x = camera.getReferenceScaleX()
scale_y = camera.getReferenceScaleY()
6.2.10. Camera Hit Testing
Find instances at screen coordinates:
# Single point hit test
instances = []
camera.getMatchingInstances(
fife.ScreenPoint(x, y, 0), layer, instances, alpha=0
)
# Rectangle selection
rect = fife.Rect(x, y, width, height)
instances = []
camera.getMatchingInstances(rect, layer, instances, alpha=128)
# Location-based matching (sorted by camera view)
location = fife.Location(layer)
location.setLayerCoordinates(fife.ModelCoordinate(5, 3))
instances = []
camera.getMatchingInstances(location, instances)
6.2.11. Camera Lighting
Apply per-camera lighting color:
# Set lighting color (RGB floats 0.0-1.0)
camera.setLightingColor(0.5, 0.5, 1.0) # Blue tint
# Get current lighting
color = camera.getLightingColor() # Returns [r, g, b]
# Reset to default
camera.resetLightingColor()
6.2.12. Camera Overlays
Apply color, image, or animation overlays to the entire camera view:
# Color overlay (RGBA)
camera.setOverlayColor(255, 0, 0, 128) # Semi-transparent red
color = camera.getOverlayColor()
camera.resetOverlayColor()
# Image overlay
camera.setOverlayImage(image_id, fill=True) # Fill viewport
img_id = camera.getOverlayImage()
camera.resetOverlayImage()
# Animation overlay
camera.setOverlayAnimation(anim_ptr, fill=True)
anim = camera.getOverlayAnimation()
camera.resetOverlayAnimation()
6.2.13. Reset Renderers
Reset the active layer information on all renderers. Call this after changing layers or when renderers need to re-evaluate their context:
camera.resetRenderers()
6.2.14. Viewport
The viewport defines the screen area for rendering:
# Set viewport
camera.setViewPort(fife.Rect(100, 50, 600, 400))
# Get viewport
viewport = camera.getViewPort()
Multiple cameras can render to different screen areas.
6.3. Renderers
Renderers draw specific aspects of the view. Each renderer operates in a pipeline, executed in order per frame.
6.3.1. Available Renderers
FIFE includes the following built-in renderers:
| InstanceRenderer |
Renders game objects and instances |
| GridRenderer |
Renders the tile grid overlay |
| CellRenderer |
Renders individual cells |
| CellSelectionRenderer |
Renders selected cells |
| CoordinateRenderer |
Renders coordinate labels |
| BlockingInfoRenderer |
Renders blocking information |
| FloatingTextRenderer |
Renders floating text above instances |
| LightRenderer |
Renders lighting effects (OpenGL only) |
| QuadtreeRenderer |
Renders spatial partitioning info (debugging) |
| OffRenderer |
Renders off-screen objects |
| TargetRenderer |
Renders to target surfaces |
| GenericRenderer |
Custom rendering with generic shapes |
6.3.2. Accessing Renderers
Get renderers from the camera:
instance_renderer = camera.getRenderer("InstanceRenderer")
light_renderer = camera.getRenderer("LightRenderer")
grid_renderer = camera.getRenderer("GridRenderer")
6.3.3. Enabling/Disabling Renderers
Control which renderers are active:
renderer = camera.getRenderer("GridRenderer")
renderer.setEnabled(True) # Enable
renderer.setEnabled(False) # Disable
6.3.4. Pipeline Position
Renderers execute in pipeline order. Adjust position to change render order:
renderer.setPipelinePosition(5) # Render 5th in pipeline
Lower numbers render first (background), higher numbers render later (foreground).
6.3.5. Layer Activation
Renderers can be limited to specific layers:
renderer.addActiveLayer(my_layer) # Add one layer
renderer.clearActiveLayers() # Clear all
renderer.activateAllLayers(my_map) # Activate all from map
6.3.6. InstanceRenderer
Renders game objects on screen:
renderer = camera.getRenderer("InstanceRenderer")
6.3.7. GridRenderer
Renders the tile grid for debugging:
renderer = camera.getRenderer("GridRenderer")
renderer.setEnabled(True)
6.3.8. LightRenderer
Renders dynamic lighting effects (OpenGL only):
lightrenderer = camera.getRenderer("LightRenderer")
# Add simple light
lightrenderer.addSimpleLightInfo(
layer=layer,
x=5, y=5,
color=[255, 255, 128],
intensity=200,
radius=5.0
)
# Add image-based light
lightrenderer.addImageLightInfo(
layer=layer,
image="light.png",
x=5, y=5
)
# Add animated light
lightrenderer.addAnimationLightInfo(
layer=layer,
animation="flicker.anim",
x=5, y=5
)
See Working with Maps for lighting system details.
6.3.9. GenericRenderer
For custom drawing, use the GenericRenderer:
renderer = camera.getRenderer("GenericRenderer")
The GenericRenderer allows drawing lines, points, and other shapes directly.
6.4. Screenshots
Capture the current frame:
render_backend = engine.getRenderBackend()
render_backend.captureScreen("screenshot.png")
render_backend.captureScreen("small.png", 320, 240)
6.5. Frame Rate Control
Limit the frame rate to reduce CPU usage:
settings = engine.getSettings()
settings.setFrameLimitEnabled(True)
settings.setFrameLimit(60) # 60 FPS
Enable VSync to synchronize with monitor refresh rate:
settings.setVSync(True)
6.6. RenderBackend Enums
6.6.1. GLConstants
Stencil buffer constants used with changeRenderInfos() (OpenGL only):
| KEEP |
Keep current stencil value |
| ZERO |
Set stencil to 0 |
| REPLACE |
Replace stencil with reference value |
| INCR |
Increment stencil value |
| DECR |
Decrement stencil value |
| INVERT |
Bitwise invert stencil value |
| NEVER |
Never pass stencil test |
| LESS |
Pass if reference < stencil |
| LEQUAL |
Pass if reference ⇐ stencil |
| GREATER |
Pass if reference > stencil |
| GEQUAL |
Pass if reference >= stencil |
| EQUAL |
Pass if reference == stencil |
| NOTEQUAL |
Pass if reference != stencil |
| ALWAYS |
Always pass stencil test |
6.6.2. OverlayType
Controls how texture overlays are applied (OpenGL only):
| OVERLAY_TYPE_NONE |
(0) No overlay |
| OVERLAY_TYPE_COLOR |
(1) Single color overlay |
| OVERLAY_TYPE_COLOR_AND_TEXTURE |
(2) Color and texture combined |
| OVERLAY_TYPE_TEXTURES_AND_FACTOR |
(3) Multiple textures with blend factor |
6.6.3. TextureFiltering
Texture filtering modes (OpenGL only):
| TEXTURE_FILTER_NONE |
(0) No filtering |
| TEXTURE_FILTER_BILINEAR |
(1) Bilinear filtering |
| TEXTURE_FILTER_TRILINEAR |
(2) Trilinear filtering |
| TEXTURE_FILTER_ANISOTROPIC |
(3) Anisotropic filtering |
6.6.4. RenderDataType
Controls the rendering data type for batched drawing (OpenGL only):
| RENDER_DATA_WITHOUT_Z |
(0) No z-buffer data |
| RENDER_DATA_TEXTURE_Z |
(1) Texture with z-buffer |
| RENDER_DATA_TEXCOLOR_Z |
(2) Texture color with z-buffer |
| RENDER_DATA_MULTITEXTURE_Z |
(3) Multiple textures with z-buffer |
6.7. Drawing Primitives
The RenderBackend provides 2D drawing functions for overlays, debug visuals, and UI elements.
6.7.1. Basic Shapes
rb = engine.getRenderBackend()
# Draw a pixel
rb.putPixel(x, y, r, g, b, a=255)
# Draw a line
rb.drawLine(fife.Point(x1, y1), fife.Point(x2, y2), r, g, b, a=255)
# Draw a thick line
rb.drawThickLine(fife.Point(x1, y1), fife.Point(x2, y2), width, r, g, b, a=255)
# Draw connected lines
points = [fife.Point(0, 0), fife.Point(10, 10), fife.Point(20, 0)]
rb.drawPolyLine(points, width, r, g, b, a=255)
# Draw bezier curve
rb.drawBezier(points, steps, width, r, g, b, a=255)
6.7.2. Rectangles
# Draw rectangle outline
rb.drawRectangle(fife.Point(x, y), width, height, r, g, b, a=255)
# Draw filled rectangle
rb.fillRectangle(fife.Point(x, y), width, height, r, g, b, a=255)
6.7.3. Circles
# Draw circle outline
rb.drawCircle(fife.Point(cx, cy), radius, r, g, b, a=255)
# Draw filled circle
rb.drawFillCircle(fife.Point(cx, cy), radius, r, g, b, a=255)
# Draw circle segment (0 angle is right side)
rb.drawCircleSegment(fife.Point(cx, cy), radius, start_angle, end_angle, r, g, b, a=255)
# Draw filled circle segment
rb.drawFillCircleSegment(fife.Point(cx, cy), radius, start_angle, end_angle, r, g, b, a=255)
6.7.4. Triangles and Quads
# Draw triangle
rb.drawTriangle(fife.Point(x1,y1), fife.Point(x2,y2), fife.Point(x3,y3), r, g, b, a=255)
# Draw quad
rb.drawQuad(p1, p2, p3, p4, r, g, b, a=255)
# Draw vertex point
rb.drawVertex(fife.Point(x, y), size, r, g, b, a=255)
6.7.5. Scissor Test
Clip rendering to a specific region:
rb.enableScissorTest()
# ... draw clipped content ...
rb.disableScissorTest()
6.8. Color Class
The Color class represents RGBA colors:
# Create a color (default: black, fully opaque)
color = fife.Color(r=255, g=128, b=0, alpha=255)
# Get channel values
r = color.getR()
g = color.getG()
b = color.getB()
a = color.getAlpha()
# Set channel values
color.setR(100)
color.setG(200)
color.setB(50)
color.setAlpha(128)
# Set all at once
color.set(255, 255, 255, 255)
# Compare colors
if color1 == color2:
print("Same color")
6.9. Animation
The Animation class manages sequences of images with timing.
6.9.1. Creating Animations
Animations are typically loaded from XML files, but can be created programmatically:
anim = fife.Animation()
# Add frames with durations (in milliseconds)
anim.addFrame(image_ptr_1, 100) # Show for 100ms
anim.addFrame(image_ptr_2, 100)
anim.addFrame(image_ptr_3, 150)
6.9.2. Querying Frames
# Get frame index by timestamp
index = anim.getFrameIndex(timestamp)
# Get frame image by index
frame = anim.getFrame(index)
# Get frame by timestamp
frame = anim.getFrameByTimestamp(timestamp)
# Get all frames
frames = anim.getFrames()
# Get frame duration
duration = anim.getFrameDuration(index) # milliseconds
# Total frame count
count = anim.getFrameCount()
# Total animation duration
total = anim.getDuration() # milliseconds
6.9.3. Action Frame
The action frame is when the associated action takes effect (e.g., a punch hitting):
anim.setActionFrame(2) # Action happens on frame 2
action_frame = anim.getActionFrame()
6.9.4. Animation Direction
Direction associates an animation with movement direction:
anim.setDirection(0) # Default direction
direction = anim.getDirection()
6.10. Image
The Image class wraps SDL surfaces and GPU textures.
6.10.1. Image Constructors
Images are created by the RenderBackend or loaded via ResourceLoader. You can also create them directly:
# From SDL_Surface (takes ownership)
image = fife.Image(surface)
# From raw RGBA pixel data
image = fife.Image(pixel_data, width, height)
# From a resource loader
image = fife.Image("name", loader)
6.10.2. Image Rendering
Render an image to the current target:
# Basic render with optional alpha
image.render(rect, alpha=255)
# Render with color overlay (RGB bytes)
image.render(rect, alpha=255, rgb=[r, g, b])
# Render with z-depth (OpenGL only)
image.renderZ(rect, vertexZ, alpha=255)
# Render with overlay image and z-depth
image.renderZ(rect, vertexZ, overlay_image, alpha=255)
6.10.3. Detaching Surface
Remove ownership of the SDL_Surface from the Image so it is not freed on destruction:
surface = image.detachSurface()
# Now caller is responsible for freeing the surface
6.10.6. Image Properties
width = image.getWidth()
height = image.getHeight()
area = image.getArea() # Returns Rect(0, 0, width, height)
6.10.7. Pixel Access
r, g, b, a = image.getPixelRGBA(x, y)
6.10.8. Image Shifts
Offset the rendering position of an image:
image.setXShift(10)
image.setYShift(-5)
shift_x = image.getXShift()
shift_y = image.getYShift()
6.10.9. Saving Images
image.saveImage("output.png")
6.10.10. Shared Images
Use texture atlasing by sharing image data:
image.useSharedImage(shared_image_ptr, region_rect)
if image.isSharedImage():
rect = image.getSubImageRect()
6.10.11. Copying Sub-Images
target_image.copySubimage(xoffset, yoffset, source_image_ptr)
6.11. Background Color
Set the render backend background color:
rb = engine.getRenderBackend()
rb.setBackgroundColor(0, 0, 128) # Dark blue background
rb.resetBackgroundColor() # Reset to black
6.12. Render-to-Texture
Attach an Image as the render target instead of the main screen. All subsequent rendering commands draw to the image:
# Attach render target (discard = clear the image first)
rb.attachRenderTarget(target_image, discard=True)
# ... render commands draw into target_image ...
# Detach and resume rendering to main screen
rb.detachRenderTarget()
| Render-to-texture is only available with the OpenGL backend. |
6.13. GUI Geometry
The render backend provides a method to render geometry required by the GUI subsystem:
# This is an internal method used by FifechanManager
rb.renderGuiGeometry(vertices, indices, translation, texture)
6.14. Rendering Pipeline
The rendering pipeline processes each frame in this order:
-
RenderBackend.startFrame()- Begin frame -
For each layer (back to front):
-
Camera updates render lists
-
Each renderer in pipeline order calls
render()
-
-
RenderBackend.endFrame()- Present frame
Renderers are called once per visible layer, allowing per-layer customization.
7. Model and Instances
This chapter explains objects, instances, layers, and maps. The model system is the core data structure that represents the game world.
7.1. Overview
The model system follows a hierarchy:
| Model |
Top-level container managing all maps |
| Map |
Contains layers and cameras |
| Layer |
Contains instances arranged in a grid |
| Instance |
A placed object in the game world |
7.2. Map
A Map is the top-level container for game world data.
Maps contain layers, which in turn contain instances.
7.2.1. Creating a Map
model = engine.getModel()
my_map = model.createMap("mymap")
7.2.2. Managing Layers
# Create a cell grid (square or hex)
grid = fife.SquareGrid() # or fife.HexGrid()
# Add a layer to the map
layer = my_map.createLayer("ground_layer", grid)
# Get existing layers
layers = my_map.getLayers()
ground = my_map.getLayer("ground_layer")
7.2.3. Map Cameras
Maps manage their own cameras:
# Add camera to map
camera = my_map.addCamera("main_camera", viewport)
# Get camera
camera = my_map.getCamera("main_camera")
# Get all cameras
cameras = my_map.getCameras()
7.2.4. Map Updates
Maps update their state each frame:
# Check if map changed
if my_map.isChanged():
changed_layers = my_map.getChangedLayers()
7.2.5. Map Speed
Control time progression on a map:
my_map.setTimeMultiplier(1.0) # Normal speed
my_map.setTimeMultiplier(2.0) # Double speed
my_map.setTimeMultiplier(0.5) # Half speed
7.2.6. Map TimeProvider
Access the map’s time provider for scaled game time:
time_provider = my_map.getTimeProvider()
game_time = time_provider.getGameTime()
7.2.7. Map Layers
Delete layers and get layer count:
count = my_map.getLayerCount()
my_map.deleteLayers() # Remove all layers
7.2.8. Map Bounding Box
Get the min/max coordinates of all instances across all layers:
min_coord, max_coord = my_map.getMinMaxCoordinates()
7.2.9. Map Filename
Get or set the filename for the map:
my_map.setFilename("saves/mymap.sav")
filename = my_map.getFilename()
7.2.10. Map Camera Count
Get the number of active cameras on this map:
count = my_map.getActiveCameraCount()
7.2.11. Instance Transfer
Transfer instances between layers (used internally by the pathfinder):
# Register instance for transfer
my_map.addInstanceForTransfer(instance)
# Unregister
my_map.removeInstanceForTransfer(instance)
# Initialize cell caches after all transfers
my_map.initializeCellCaches()
# Clean up cell caches
my_map.finalizeCellCaches()
7.2.12. Trigger Controller
Access the map’s trigger system:
trigger_ctrl = my_map.getTriggerController()
7.3. Layer
A Layer is a grid of cells containing game instances.
Layers allow organizing game objects by type (ground, objects, units).
7.3.1. Creating Instances
# Create instance at exact position
instance = layer.createInstance(my_object, fife.ModelCoordinate(5, 3), "my_instance")
# Create instance at precise position
instance = layer.createInstance(my_object, fife.ExactModelCoordinate(5.5, 3.2), "precise")
7.3.2. Querying Instances
# Get all instances
instances = layer.getInstances()
# Get instance by ID
instance = layer.getInstance("my_instance")
# Get instances by type
instances = layer.getInstances("tree")
# Get instances at location
location = fife.Location(layer)
location.setLayerCoordinates(fife.ModelCoordinate(5, 3))
instances_at = layer.getInstancesAt(location)
# Get instances in rectangle
rect = fife.Rect(0, 0, 10, 10)
instances_in = layer.getInstancesIn(rect)
# Get instances in circle
instances = layer.getInstancesInCircle(fife.ModelCoordinate(5, 5), 3)
# Get instances in line
instances = layer.getInstancesInLine(
fife.ModelCoordinate(0, 0),
fife.ModelCoordinate(10, 10)
)
7.3.3. Removing Instances
layer.removeInstance(instance) # Remove without deleting
layer.deleteInstance(instance) # Remove and delete
7.3.4. Layer Properties
7.3.4.1. Visibility
layer.setInstancesVisible(True)
layer.setInstancesVisible(False)
layer.toggleInstancesVisible()
7.3.4.2. Transparency
layer.setLayerTransparency(128) # Semi-transparent (0-255)
7.3.4.3. Static Layers
Static layers render as a single texture for performance:
layer.setStatic(True) # Enable static rendering
layer.isStatic() # Check if static
| Static layers only work correctly with the OpenGL backend. Do not use static layers for instances with animations. |
7.3.4.4. Walkable Layers
Only walkable layers can have pathfinding:
layer.setWalkable(True)
if layer.isWalkable():
# Can create CellCache for pathfinding
pass
7.3.4.5. Pathing Strategy
Configure how pathfinding works on this layer:
# Edges only (4-direction movement)
layer.setPathingStrategy(fife.CELL_EDGES_ONLY)
# Edges and diagonals (8-direction movement)
layer.setPathingStrategy(fife.CELL_EDGES_AND_DIAGONALS)
7.3.4.6. Sorting Strategy
Control how instances are sorted for rendering:
layer.setSortingStrategy(fife.SORTING_CAMERA) # By camera view
layer.setSortingStrategy(fife.SORTING_LOCATION) # By location
layer.setSortingStrategy(fife.SORTING_CAMERA_AND_LOCATION) # Combined
7.3.4.7. Instance Queries
Get instances within a circle segment (angle range):
# center, radius, starting angle, ending angle, use_exact_coordinates
instances = layer.getInstancesInCircleSegment(
center_location, radius, start_angle, end_angle, True
)
Get bounding coordinates of all instances on the layer:
min_coord, max_coord = layer.getMinMaxCoordinates()
7.3.4.9. Blocking Queries
Check if a cell contains a blocking instance:
if layer.cellContainsBlockingInstance(cell_coord):
print("Cell is blocked")
# Get all blocking instances
blockers = layer.getBlockingInstances()
7.3.4.11. Instance Activity
Activate or deactivate instances on a layer to skip updates:
layer.setInstanceActivityStatus(False) # Pause all instances
layer.setInstanceActivityStatus(True) # Resume updates
7.3.4.12. Interact Layers
Interact layers merge pathfinding data from multiple layers. Useful for buildings with floors:
# Mark this as an interact layer
layer.setInteract(True)
if layer.isInteract():
walkable_id = layer.getWalkableId()
# Add another layer's interact data to this layer
layer.addInteractLayer(other_layer)
interact_layers = layer.getInteractLayers()
# Remove an interact layer
layer.removeInteractLayer(other_layer)
7.3.4.13. CellCache
The CellCache stores pathfinding data. Create it before using the pathfinder:
layer.createCellCache()
cache = layer.getCellCache()
# When done (rarely needed)
layer.destroyCellCache()
7.4. Instance Change Tracking
FIFE tracks changes to instances using a bitmask system.
The InstanceChangeType enum defines possible changes:
| ICHANGE_NO_CHANGES |
(0x0000) No changes |
| ICHANGE_LOC |
(0x0001) Location changed |
| ICHANGE_ROTATION |
(0x0002) Rotation changed |
| ICHANGE_SPEED |
(0x0004) Speed changed |
| ICHANGE_ACTION |
(0x0008) Action changed |
| ICHANGE_TIME_MULTIPLIER |
(0x0010) Time multiplier changed |
| ICHANGE_SAYTEXT |
(0x0020) Say text changed |
| ICHANGE_BLOCK |
(0x0040) Blocking state changed |
| ICHANGE_CELL |
(0x0080) Cell changed |
| ICHANGE_TRANSPARENCY |
(0x0100) Transparency changed |
| ICHANGE_VISIBLE |
(0x0200) Visibility changed |
| ICHANGE_STACKPOS |
(0x0400) Stack position changed |
| ICHANGE_VISUAL |
(0x0800) Visual changed |
Use getChangeInfo() to retrieve the change bitmask from the last update:
changes = instance.getChangeInfo()
if changes & fife.ICHANGE_LOC:
print("Location changed")
7.5. Instance Change Listener
Listen for any instance property changes:
class MyChangeListener(fife.InstanceChangeListener):
def onInstanceChanged(self, instance, info):
if info & fife.ICHANGE_LOC:
print("Instance moved:", instance.getId())
listener = MyChangeListener()
instance.addChangeListener(listener)
7.6. Instance Delete Listener
Be notified when an instance is deleted:
class MyDeleteListener(fife.InstanceDeleteListener):
def onInstanceDeleted(self, instance):
print("Instance deleted:", instance.getId())
listener = MyDeleteListener()
instance.addDeleteListener(listener)
7.7. Instance
An Instance is a placed object in the game world.
Instances are created from object archetypes and can perform actions.
7.7.1. TimeProvider
The TimeProvider class manages hierarchical time scaling.
Each level (model, map, instance) has its own time provider that multiplies with its parent.
7.7.2. Creating a TimeProvider
# Create with a master provider (or None for root)
provider = fife.TimeProvider(master_provider)
7.7.3. Time Multiplier
# Set local multiplier (0.5 = half speed, 2.0 = double speed)
provider.setMultiplier(2.0)
# Get local multiplier
local = provider.getMultiplier()
# Get total multiplier including all parents
total = provider.getTotalMultiplier() # E.g., master=2.0, local=0.5 -> 1.0
7.7.4. Game Time
# Get current scaled game time in milliseconds
game_time = provider.getGameTime()
7.8. Object
Objects define the template properties that instances inherit.
# Get or create an object archetype
object = model.getObject("tree")
7.8.1. Object Namespace
Objects can be organized into namespaces:
namespace = object.getNamespace() # e.g., "vegetation"
object.setId("oak_tree") # Set object identifier
7.8.2. Object Properties
7.8.2.1. Blocking and Static
object.setBlocking(True) # Instances block movement
object.setStatic(True) # Object does not move
7.8.2.2. Cell Stack Position
Set default stack position for instances:
object.setCellStackPosition(3) # Default stack order
pos = object.getCellStackPosition()
7.8.2.3. Pather Assignment
Assign a pather algorithm to instances of this object:
object.setPather(my_pather) # Set custom pather
pather = object.getPather() # Get current pather
7.8.2.4. Cost and Speed
Set pathfinding cost properties on the object:
object.setCostId("terrain") # Cost category
object.setCost(2.5) # Cost multiplier
object.setSpeed(0.8) # Speed modifier
# Query properties
if object.isSpecialCost():
print("Cost:", object.getCost(), "ID:", object.getCostId())
if object.isSpecialSpeed():
print("Speed modifier:", object.getSpeed())
7.8.2.5. Z-Step Range
Limit how many z-levels an object can climb:
object.setZStepRange(1) # Can climb 1 z-level
range = object.getZStepRange() # -1 if unlimited
7.8.2.6. Walkable Areas
Restrict which areas an object can walk on:
object.addWalkableArea("main_path")
object.addWalkableArea("forest_trail")
areas = object.getWalkableAreas()
object.removeWalkableArea("forest_trail")
# Set the area this object contributes to
object.setArea("building_zone")
7.8.3. Multi-Part Objects
Objects can consist of multiple parts for large buildings or structures:
# Mark object as a multi-part component
object.setMultiPart(True)
# Add part identifiers
object.addMultiPartId("tower_base")
object.addMultiPartId("tower_top")
# Get all part IDs
part_ids = object.getMultiPartIds()
# Set rotation anchor for the multi object
object.setRotationAnchor(fife.ExactModelCoordinate(0.5, 0.5))
# Enable restricted rotation (only use predefined angles)
object.setRestrictedRotation(True)
# Get obvious rotation from any angle
snapped = object.getRestrictedRotation(47) # Returns nearest valid angle
Add rotation-dependent coordinates for parts:
# Add coordinates for specific rotations
object.addMultiPartCoordinate(0, fife.ModelCoordinate(0, 0))
object.addMultiPartCoordinate(90, fife.ModelCoordinate(1, 0))
# Get coordinates for a rotation
coords = object.getMultiPartCoordinates(90)
all_coords = object.getMultiPartCoordinates() # All rotations
7.8.4. Instance Location
# Set location
location = fife.Location(layer)
location.setLayerCoordinates(fife.ModelCoordinate(5, 3))
instance.setLocation(location)
# Get location
current_location = instance.getLocation()
# Set facing direction
instance.setFacingLocation(target_location)
# Get facing location
facing = instance.getFacingLocation()
# Get reference to previous location (before last move)
old_loc = instance.getOldLocationRef()
7.8.5. Instance State
Check if an instance needs active updates:
if instance.isActive():
print("Instance requires updates each frame")
7.8.6. Instance Say Text
Get the current say text pointer (None if not speaking):
text = instance.getSayText()
if text:
print("Saying:", text)
7.8.7. Instance Actions
Instances can perform actions defined by their object:
# Play action once
instance.actOnce("idle")
# Play action repeatedly
instance.actRepeat("idle")
# Play action with specific direction
instance.actOnce("walk", direction_location)
instance.actRepeat("idle", 90) # 90 degree rotation
7.8.8. Instance Movement
Move instances between locations:
# Move with action animation
instance.move("walk", target_location, speed=5.0)
# Movement speed: units = distance per second in layer coordinates
instance.move("run", target_location, speed=10.0)
# Follow another instance
instance.follow("walk", leader_instance, speed=5.0)
# Follow a route
instance.follow("walk", route, speed=5.0)
7.8.9. Instance Properties
7.8.9.1. Blocking
Blocking instances prevent movement through them:
instance.setBlocking(True)
instance.isBlocking()
7.8.9.2. Rotation
instance.setRotation(90) # Set rotation offset
instance.getRotation() # Get current rotation
instance.getOldRotation() # Get previous frame's rotation
7.8.9.3. Override Blocking
Allow instances to pass through blocking objects:
instance.setOverrideBlocking(True) # Can pass through blockers
if instance.isOverrideBlocking():
print("Can override blocking")
7.8.9.4. Speed Control
instance.setTimeMultiplier(2.0) # Double speed
instance.getMovementSpeed() # Current speed
Get total time multiplier including map and model speeds:
total = instance.getTotalTimeMultiplier() # Includes all parent multipliers
7.8.9.5. Instance Runtime
Get scaled runtime in milliseconds:
runtime = instance.getRuntime() # Time scaled by time multiplier
7.8.9.6. Action Runtime
Save and restore action animation state:
# Get current action time offset
offset = instance.getActionRuntime()
# Restore action state later
instance.setActionRuntime(offset)
7.8.9.7. Instance Refresh
After directly modifying an instance’s location (bypassing setLocation()),
call refresh() to update internal state:
instance.refresh() # Update time provider and other internals
7.8.9.8. Transparency
instance.setTransparency(128) # Semi-transparent (0-255)
7.8.10. Instance Say Text
Display text above an instance:
# Show text for 3 seconds (3000ms)
instance.say("Hello!", 3000)
# Show text indefinitely
instance.say("Important message!")
# Clear text
instance.say("")
7.8.11. Instance Listeners
Listen for instance events:
class MyActionListener(fife.InstanceActionListener):
def onInstanceActionFinished(self, instance, action):
print("Action finished:", action.getId())
def onInstanceActionCancelled(self, instance, action):
print("Action cancelled")
def onInstanceActionFrame(self, instance, action, frame):
pass
listener = MyActionListener()
instance.addActionListener(listener)
7.8.12. Cell Stack Position
Control rendering order within a cell (higher values render on top):
instance.setCellStackPosition(5) # Render above stack position 0
pos = instance.getCellStackPosition()
7.8.13. Cost and Speed Overrides
Override pathfinding cost and movement speed per instance:
# Set custom pathfinding cost
instance.setCost("movement", 2.0) # Costs 2x normal
instance.resetCost() # Use object default
# Check if instance has custom cost
if instance.isSpecialCost():
cost = instance.getCost()
cost_id = instance.getCostId()
# Get movement speed modifier
speed = instance.getSpeed()
if instance.isSpecialSpeed():
print("Has custom speed:", speed)
7.8.14. Multi-Cell Instances
Instances can occupy multiple cells:
if instance.isMultiCell():
instances = instance.getMultiInstances()
for inst in instances:
print(inst.getLocation())
7.8.15. Overlays
Add visual overlays to instances:
# Static color overlay (applies regardless of action)
colors = fife.OverlayColors()
instance.addStaticColorOverlay(0, colors)
# Query static color overlay
if instance.isStaticColorOverlay(0):
overlay = instance.getStaticColorOverlay(0)
instance.removeStaticColorOverlay(0)
# Action-specific color overlay
instance.addColorOverlay("walk", 0, colors)
# Query color overlay
if instance.isColorOverlay("walk"):
pass
# Animation overlay (action, order, animation)
instance.addAnimationOverlay("walk", 0, 0, animation_ptr)
# Query animation overlay
if instance.isAnimationOverlay("walk"):
anim = instance.getAnimationOverlay("walk", 0)
instance.removeAnimationOverlay("walk", 0)
# Convert action visual to overlays (e.g., for tinting)
instance.convertToOverlays("walk")
7.9. CellGrid
CellGrids define the coordinate system for layers.
7.9.1. Square Grid
Standard square tiles:
grid = fife.SquareGrid()
grid.setScale(32, 32) # Cell size in pixels
layer = my_map.createLayer("ground", grid)
7.9.2. Hexagonal Grid
Hex-based tiles for natural movement:
grid = fife.HexGrid()
grid.setScale(32, 32)
layer = my_map.createLayer("ground", grid)
7.9.3. Grid Queries
# Get cell coordinates from exact position
cell = grid.getCellCoordinates(exact_position)
# Get exact position from cell
exact = grid.getExactLayerCoordinates(cell)
# Get cell dimensions
dims = grid.getCellDimensions()
7.10. Map Change Listeners
Monitor changes across the entire map:
class MyMapListener(fife.MapChangeListener):
def onMapChanged(self, map, changed_layers):
for layer in changed_layers:
print("Layer changed:", layer.getId())
def onLayerCreate(self, map, layer):
print("Layer created:", layer.getId())
def onLayerDelete(self, map, layer):
print("Layer deleted:", layer.getId())
listener = MyMapListener()
my_map.addChangeListener(listener)
7.11. Layer Change Listeners
Monitor changes on a specific layer:
class MyLayerListener(fife.LayerChangeListener):
def onLayerChanged(self, layer, changed_instances):
for instance in changed_instances:
print("Instance changed:", instance.getId())
def onInstanceCreate(self, layer, instance):
print("Instance created:", instance.getId())
def onInstanceDelete(self, layer, instance):
print("Instance deleted:", instance.getId())
listener = MyLayerListener()
layer.addChangeListener(listener)
7.12. Saving and Loading Maps
Maps are typically saved in FIFE’s XML format using loaders and savers:
# Load a map
model = engine.getModel()
map_loader = fife.MapLoader(model, vfs, image_manager)
my_map = map_loader.load("mymap.xml")
# Save a map
map_saver = fife.MapSaver(model)
map_saver.save(my_map, "mymap.xml")
See Working with Maps for details on the map file format.
8. Input and Events
This chapter covers the event system, mouse and keyboard input, and command handling.
FIFE uses an event-driven architecture where user input and game events are distributed through listeners.
8.1. Event Manager
The EventManager is the central hub for all input handling.
It processes SDL events and dispatches them to registered listeners.
8.1.1. Getting the Event Manager
event_manager = engine.getEventManager()
8.2. Event Listeners
FIFE provides several listener interfaces for different event types:
| IKeyListener |
Keyboard input |
| IMouseListener |
Mouse input |
| ITextListener |
Text input (for text fields) |
| IDropListener |
File drop events |
| ICommandListener |
Custom command events |
| ISdlEventListener |
Raw SDL events |
8.3. Mouse Events
8.3.1. Mouse Listener Interface
Implement IMouseListener to handle mouse events:
class MyMouseListener(fife.IMouseListener):
def mousePressed(self, event):
print(f"Mouse pressed at ({event.getX()}, {event.getY()})")
def mouseReleased(self, event):
print(f"Mouse released at ({event.getX()}, {event.getY()})")
def mouseMoved(self, event):
print(f"Mouse moved to ({event.getX()}, {event.getY()})")
def mouseDragged(self, event):
print(f"Mouse dragged to ({event.getX()}, {event.getY()})")
def mouseEntered(self, event):
print("Mouse entered window")
def mouseExited(self, event):
print("Mouse exited window")
def mouseWheelMovedUp(self, event):
print("Wheel moved up")
def mouseWheelMovedDown(self, event):
print("Wheel moved down")
Register the listener:
listener = MyMouseListener()
event_manager.addMouseListener(listener)
event_manager.addMouseListener(listener) # Add to front of queue
# Later, remove it
event_manager.removeMouseListener(listener)
8.3.2. Mouse Event Types
| MOVED |
Mouse cursor moved without button press |
| PRESSED |
Mouse button pressed |
| RELEASED |
Mouse button released |
| CLICKED |
Mouse button clicked (press and release) |
| DRAGGED |
Mouse moved while button is held |
| WHEEL_MOVED_UP |
Scroll wheel up |
| WHEEL_MOVED_DOWN |
Scroll wheel down |
| WHEEL_MOVED_RIGHT |
Scroll wheel right |
| WHEEL_MOVED_LEFT |
Scroll wheel left |
| ENTERED |
Mouse entered window |
| EXITED |
Mouse exited window |
| UNKNOWN_EVENT |
Unknown mouse event type |
8.3.3. Mouse Button Types
| LEFT |
Left mouse button |
| RIGHT |
Right mouse button |
| MIDDLE |
Middle mouse button (wheel) |
| X1 |
Extra button 1 |
| X2 |
Extra button 2 |
| EMPTY |
No button |
| UNKNOWN_BUTTON |
Unknown button type |
8.3.4. MouseEvent Properties
def mousePressed(self, event):
x = event.getX()
y = event.getY()
button = event.getButton()
timestamp = event.getTimeStamp()
# Check modifier keys
shift = event.isShiftPressed()
ctrl = event.isControlPressed()
alt = event.isAltPressed()
meta = event.isMetaPressed()
# Check button type
if button == fife.MouseEvent.LEFT:
print("Left button pressed")
elif button == fife.MouseEvent.RIGHT:
print("Right button pressed")
8.3.5. Widget Consumption
Check if a mouse event was consumed by a GUI widget:
def mousePressed(self, event):
if event.isConsumedByWidgets():
return # Don't process if GUI handled it
8.3.6. Event Name and Debugging
Get event metadata for debugging:
name = event.getName() # Returns "MouseEvent"
debug = event.getDebugString() # Human-readable description
attr = event.getAttrStr() # Detailed attribute string
8.3.7. Example: Click to Move Instance
class ClickToMoveListener(fife.IMouseListener):
def __init__(self, camera, instance):
self.camera = camera
self.instance = instance
def mousePressed(self, event):
if event.getButton() == fife.MouseEvent.LEFT:
# Convert screen coordinates to map coordinates
screen_point = fife.ScreenPoint(event.getX(), event.getY(), 0)
map_point = self.camera.toMapCoordinates(screen_point)
# Move instance
location = fife.Location(self.instance.getLocation().getLayer())
location.setExactLayerCoordinates(map_point)
self.instance.move("walk", location, 5.0)
8.4. Keyboard Events
8.4.1. Key Listener Interface
Implement IKeyListener to handle keyboard events:
class MyKeyListener(fife.IKeyListener):
def keyPressed(self, event):
key = event.getKey()
print(f"Key pressed: {key.getAsString()}")
def keyReleased(self, event):
key = event.getKey()
print(f"Key released: {key.getAsString()}")
Register the listener:
listener = MyKeyListener()
event_manager.addKeyListener(listener)
# Later, remove it
event_manager.removeKeyListener(listener)
8.4.2. Key Event Types
| PRESSED |
Key was pressed down |
| RELEASED |
Key was released |
| UNKNOWN |
Unknown key event type |
8.4.3. Key Properties
def keyPressed(self, event):
key = event.getKey()
# Get key code
code = key.getValue()
# Get string representation
name = key.getAsString()
# Check if numpad
is_numpad = event.isNumericPad()
# Check modifier keys
shift = event.isShiftPressed()
ctrl = event.isControlPressed()
alt = event.isAltPressed()
# Check specific keys
if key.getValue() == fife.Key.ESCAPE:
print("Escape pressed")
elif key.getValue() == fife.Key.ENTER:
print("Enter pressed")
8.4.4. Key Constants
Common key constants:
| Key.ENTER |
Enter/Return |
| Key.ESCAPE |
Escape |
| Key.SPACE |
Spacebar |
| Key.TAB |
Tab |
| Key.UP |
Arrow up |
| Key.DOWN |
Arrow down |
| Key.LEFT |
Arrow left |
| Key.RIGHT |
Arrow right |
| Key.LSHIFT |
Left Shift |
| Key.RSHIFT |
Right Shift |
| Key.LCTRL |
Left Control |
| Key.RCTRL |
Right Control |
| Key.LALT |
Left Alt |
| Key.RALT |
Right Alt |
| Key.F1-F12 |
Function keys |
8.5. Text Events
For text input fields, use the text listener:
class MyTextListener(fife.ITextListener):
def textInput(self, event):
text = event.getText()
print(f"Text entered: {text}")
listener = MyTextListener()
event_manager.addTextListener(listener)
8.6. Command Events
Custom commands can be dispatched through the event system:
class MyCommandListener(fife.ICommandListener):
def onCommand(self, command):
command_code = command.getCode()
if command_code == 1:
print("Custom command received")
listener = MyCommandListener()
event_manager.addCommandListener(listener)
# Dispatch a command
command = fife.Command()
command.setCode(1)
event_manager.dispatchCommand(command)
8.7. Key Filters
Filter specific keys to be processed by the engine or your application:
class MyKeyFilter(fife.IKeyFilter):
def isFiltered(self, key):
# Filter out specific keys
return key.getValue() == fife.Key.F12
filter = MyKeyFilter()
event_manager.setKeyFilter(filter)
8.8. Drop Events
Handle file drag-and-drop:
class MyDropListener(fife.IDropListener):
def fileDropped(self, event):
path = event.getPath()
print(f"File dropped: {path}")
listener = MyDropListener()
event_manager.addDropListener(listener)
8.9. Mouse Sensitivity
Adjust mouse behavior:
# Set mouse sensitivity (0.0 = default, positive = faster, negative = slower)
event_manager.setMouseSensitivity(1.5)
# Enable mouse acceleration
event_manager.setMouseAccelerationEnabled(True)
8.10. Clipboard Support
Access system clipboard:
# Check if clipboard has text
if event_manager.isClipboardText():
# Get clipboard text
text = event_manager.getClipboardText()
# Set clipboard text
event_manager.setClipboardText("Hello, clipboard!")
8.11. Event Consumption
Events can be consumed to prevent further processing:
def mousePressed(self, event):
if is_handled:
event.consume() # Prevent other listeners from receiving this event
8.12. SDL Events
For low-level access to SDL events:
class MySdlListener(fife.ISdlEventListener):
def onSdlEvent(self, event):
# Raw SDL event
event_type = event.type
print(f"SDL event type: {event_type}")
listener = MySdlListener()
event_manager.addSdlEventListener(listener)
8.13. Event Queue
The event manager processes events automatically during engine.pump().
You should register your listeners before the game loop starts.
Listeners are called in the order they were registered.
Use addListenerFront() to add listeners to the front of the queue.
|
8.14. Adding Listeners to Front of Queue
Add listeners that receive events before previously registered ones:
event_manager.addKeyListenerFront(listener)
event_manager.addMouseListenerFront(listener)
event_manager.addCommandListenerFront(listener)
event_manager.addTextListenerFront(listener)
event_manager.addDropListenerFront(listener)
event_manager.addSdlEventListenerFront(listener)
8.15. Joystick and Gamepad Support
FIFE supports joystick and gamepad input through SDL.
8.15.1. Enabling Joystick Support
settings = engine.getSettings()
settings.setJoystickSupport(True) # Enable before engine.init()
8.15.2. Joystick Manager Methods
event_manager = engine.getEventManager()
# Get number of connected joysticks
count = event_manager.getJoystickCount()
# Get a specific joystick by instance ID
joystick = event_manager.getJoystick(instance_id)
8.15.3. Gamepad Mappings
Load and save SDL gamepad controller mappings:
# Load mappings from file
event_manager.loadGamepadMapping("gamecontrollerdb.txt")
# Save mapping for a specific GUID
event_manager.saveGamepadMapping(guid, "mymapping.txt")
# Save all mappings used this session
event_manager.saveGamepadMappings("all_mappings.txt")
# Get/Set mapping as string
mapping = event_manager.getGamepadStringMapping(guid)
event_manager.setGamepadStringMapping(mapping)
8.15.4. Joystick Listener
class MyJoystickListener(fife.IJoystickListener):
# Implement joystick event callbacks
pass
event_manager.addJoystickListener(listener)
event_manager.addJoystickListenerFront(listener) # Front of queue
event_manager.removeJoystickListener(listener)
9. Audio
This chapter explains the sound engine, sound emitters, and audio playback.
FIFE’s audio system is built on OpenAL and supports positional 3D audio.
9.1. Sound Manager
The SoundManager is the central audio controller.
It manages emitters, sound effects, and the listener position.
9.1.1. Getting the Sound Manager
sound_manager = engine.getSoundManager()
9.1.2. Volume Control
# Set master volume (0.0 = silence, 1.0 = normal)
sound_manager.setVolume(0.8)
volume = sound_manager.getVolume()
# Mute/unmute
sound_manager.mute()
sound_manager.unmute()
9.1.3. Global Playback Control
sound_manager.play() # Play all emitters
sound_manager.pause() # Pause all emitters
sound_manager.stop() # Stop all emitters
sound_manager.rewind() # Rewind all emitters
9.2. Listener Position
The listener represents the player’s "ears" in the 3D audio space.
9.2.1. Setting Listener Position
# Set listener position (follows the camera)
listener_pos = fife.AudioSpaceCoordinate(10.0, 10.0, 0.0)
sound_manager.setListenerPosition(listener_pos)
# Set listener orientation
orientation = fife.AudioSpaceCoordinate(0.0, 1.0, 0.0)
sound_manager.setListenerOrientation(orientation)
# Set listener velocity (for Doppler effect)
velocity = fife.AudioSpaceCoordinate(0.0, 0.0, 0.0)
sound_manager.setListenerVelocity(velocity)
9.2.2. Distance Model
Configure how sound attenuates with distance:
# Distance models
sound_manager.setDistanceModel(fife.SD_DISTANCE_NONE)
sound_manager.setDistanceModel(fife.SD_DISTANCE_INVERSE)
sound_manager.setDistanceModel(fife.SD_DISTANCE_INVERSE_CLAMPED)
sound_manager.setDistanceModel(fife.SD_DISTANCE_LINEAR)
sound_manager.setDistanceModel(fife.SD_DISTANCE_LINEAR_CLAMPED)
sound_manager.setDistanceModel(fife.SD_DISTANCE_EXPONENT)
sound_manager.setDistanceModel(fife.SD_DISTANCE_EXPONENT_CLAMPED)
9.2.3. Doppler Effect
Configure the Doppler effect for moving sources:
sound_manager.setDopplerFactor(1.0)
9.3. Sound Emitters
Sound emitters are individual sound sources that can play audio clips.
9.3.1. Creating Emitters
# Create an empty emitter
emitter = sound_manager.createEmitter()
# Create emitter with a sound clip
emitter = sound_manager.createEmitter("mysound.ogg")
9.3.2. Emitter Listener
Listen for sound completion events:
class MySoundListener(fife.SoundEmitterListener):
def onSoundFinished(self, emitterId, soundClipId):
print("Sound finished:", emitterId)
listener = MySoundListener()
emitter.addListener(listener)
emitter.removeListener(listener)
9.3.3. Loading Sound Clips
# Load a sound clip
emitter.setSoundClip("sounds/mysound.ogg")
9.3.4. Playing Sounds
# Play once
emitter.play()
# Play with fade in/out (time in seconds)
emitter.play(0.5, 0.5) # 0.5s fade in, 0.5s fade out
# Play in a loop
emitter.setLooping(True)
emitter.play()
# Stop playback
emitter.stop()
# Stop with fade out
emitter.stop(0.5) # 0.5s fade out
# Pause/resume
emitter.pause()
emitter.play()
emitter.rewind()
9.3.5. Volume Control
# Set gain (0.0 = silence, 1.0 = normal)
emitter.setGain(0.8)
gain = emitter.getGain()
# Set max/min gain limits
emitter.setMaxGain(1.0)
emitter.setMinGain(0.0)
9.3.6. Pitch Control
emitter.setPitch(1.0) # Normal speed
emitter.setPitch(2.0) # Double speed (higher pitch)
emitter.setPitch(0.5) # Half speed (lower pitch)
9.3.7. Positional Audio
Place emitters in 3D space for positional audio:
# Set position
pos = fife.AudioSpaceCoordinate(5.0, 3.0, 0.0)
emitter.setPosition(pos)
# Set direction (for directional sounds)
direction = fife.AudioSpaceCoordinate(1.0, 0.0, 0.0)
emitter.setDirection(direction)
# Set velocity (for Doppler effect)
velocity = fife.AudioSpaceCoordinate(0.0, 0.0, 0.0)
emitter.setVelocity(velocity)
9.3.8. Sound Cone
Configure directional sound cones:
emitter.setConeInnerAngle(90) # Full volume within 90 degrees
emitter.setConeOuterAngle(180) # Reduced volume outside 90 degrees
emitter.setConeOuterGain(0.5) # Volume outside cone (0-1)
9.3.9. Distance Attenuation
Configure how sound fades with distance:
emitter.setReferenceDistance(1.0) # Distance for half volume
emitter.setMaxDistance(100.0) # Maximum audible distance
emitter.setRolloff(1.0) # Attenuation factor
9.3.10. Relative Positioning
Use relative positioning for ambient sounds:
emitter.setRelativePositioning(True) # Position relative to listener
9.3.11. Emitter State
Check emitter status:
state = emitter.getState()
if state == fife.SD_PLAYING_STATE:
print("Playing")
elif state == fife.SD_PAUSED_STATE:
print("Paused")
elif state == fife.SD_STOPPED_STATE:
print("Stopped")
elif state == fife.SD_INITIAL_STATE:
print("Initial (not yet played)")
if emitter.isFinished():
print("Sound finished playing")
9.3.12. Emitter Activity
Check if emitter has an active OpenAL source:
if emitter.isActive():
print("Emitter has an OpenAL source")
9.3.13. Cursor Position
Get and set playback cursor position:
# Set cursor by sample offset
emitter.setCursor(fife.SD_SAMPLE_POS, 44100.0)
# Set cursor by time (seconds)
emitter.setCursor(fife.SD_TIME_POS, 1.5)
# Set cursor by byte offset
emitter.setCursor(fife.SD_BYTE_POS, 1024.0)
# Get cursor position
pos = emitter.getCursor(fife.SD_TIME_POS)
The SoundPositionType enum values:
| SD_SAMPLE_POS |
Position by sample offset |
| SD_TIME_POS |
Position in seconds |
| SD_BYTE_POS |
Position by byte offset |
9.3.14. Emitter Reset
Reset emitter to default state:
emitter.reset(defaultall=True) # Reset position, velocity, gain, etc.
emitter.reset(defaultall=False) # Reset only internal buffers
9.3.15. Sound Information
Get details about the loaded sound:
is_stereo = emitter.isStereo()
bit_depth = emitter.getBitResolution()
sample_rate = emitter.getSampleRate()
decoded_length = emitter.getDecodedLength() # In bytes
duration = emitter.getDuration() # In milliseconds
play_time = emitter.getPlayTimestamp() # Last play start in ms
9.3.16. Relative Positioning
Use relative positioning for ambient sounds:
emitter.setRelativePositioning(True) # Position relative to listener
is_rel = emitter.isRelativePositioning()
9.3.17. Emitter ID and SoundClip
Get the emitter’s unique ID and current sound clip:
emitter_id = emitter.getId()
sound_clip = emitter.getSoundClip() # Returns SoundClipPtr
9.3.18. Emitter Reset
Reset emitter to default state:
emitter.reset(defaultall=True) # Reset position, velocity, gain, etc.
emitter.reset(defaultall=False) # Reset only internal buffers
9.4. Sound Groups
Group emitters for batch operations:
# Create a group
emitter.setGroup("music")
# Play/pause/stop entire group
sound_manager.play("music")
sound_manager.pause("music")
sound_manager.stop("music")
sound_manager.rewind("music")
# Set volume for entire group
sound_manager.setGain("music", 0.7)
# Remove group
sound_manager.removeGroup("music")
9.5. Sound Effects
Add effects like reverb to sounds:
# Create an effect by type
effect = sound_manager.createSoundEffect(fife.SF_EAXREVERB)
# Create effect with preset
effect = sound_manager.createSoundEffectPreset(fife.SEP_GENERIC)
# Add emitter to effect
sound_manager.addEmitterToSoundEffect(effect, emitter)
# Enable effect
sound_manager.enableSoundEffect(effect)
# Later, disable effect
sound_manager.disableSoundEffect(effect)
# Remove emitter from effect
sound_manager.removeEmitterFromSoundEffect(effect, emitter)
# Delete effect
sound_manager.deleteSoundEffect(effect)
9.6. Sound Filters
Apply direct filters to individual emitters:
# Create a filter
sound_filter = sound_manager.createSoundFilter(fife.SFT_LOWPASS)
# Add emitter to direct filter
sound_manager.addEmitterToDirectSoundFilter(sound_filter, emitter)
# Enable/disable direct filter
sound_manager.enableDirectSoundFilter(sound_filter)
sound_manager.disableDirectSoundFilter(sound_filter)
# Remove emitter from filter
sound_manager.removeEmitterFromDirectSoundFilter(sound_filter, emitter)
# Delete filter
sound_manager.deleteSoundFilter(sound_filter)
9.7. Listener Max Distance
Set maximum distance for emitter activation. Emitters beyond this distance are automatically deactivated:
sound_manager.setListenerMaxDistance(500.0)
max_dist = sound_manager.getListenerMaxDistance()
9.8. Sound Manager Initialization
Explicitly initialize the audio system (called automatically by Engine):
sound_manager.init()
if sound_manager.isActive():
print("Audio system is active")
# Access the OpenAL context (advanced usage)
context = sound_manager.getContext()
9.9. Group Management Extended
Additional group operations:
# Set gain limits for a group
sound_manager.setMaxGain("music", 0.9)
sound_manager.setMinGain("music", 0.1)
# Remove all groups
sound_manager.removeAllGroups()
9.10. SoundClip
SoundClip manages audio data buffers and supports streaming for large files.
9.10.1. Streaming Check
Determine if the clip requires streaming:
sound_clip = emitter.getSoundClip()
if sound_clip.isStream():
print("Uses streaming (large file)")
9.10.2. Buffer Management
For non-streaming clips:
count = sound_clip.countBuffers() # Number of OpenAL buffers
buffers = sound_clip.getBuffers() # Buffer IDs for queuing
9.10.3. Streaming Control
For streaming audio, manage the stream lifecycle:
stream_id = sound_clip.beginStreaming()
sound_clip.acquireStream(stream_id) # Fill initial buffers
# Set/get stream position
sound_clip.setStreamPos(stream_id, fife.SD_TIME_POS, 5.0) # Seek to 5s
pos = sound_clip.getStreamPos(stream_id, fife.SD_TIME_POS)
# Refill buffer (returns True at EOF)
eof = sound_clip.getStream(stream_id, buffer_id)
sound_clip.quitStreaming(stream_id)
sound_clip.endStreaming(stream_id)
9.10.4. Decoder
Attach a custom sound decoder:
sound_clip.setDecoder(decoder)
decoder = sound_clip.getDecoder()
9.11. Cleanup
Release emitters when no longer needed:
emitter.release() # Release the emitter
sound_manager.deleteEmitter(emitter) # Delete the emitter
# Or release by ID
sound_manager.releaseEmitter(emitter_id)
# Release OpenAL source handle (advanced)
sound_manager.releaseSource(emitter)
9.12. Attaching to Instances
Attach sounds to game instances for automatic position tracking:
# Create emitter and attach to instance
emitter = sound_manager.createEmitter("walk.ogg")
emitter.setLooping(True)
emitter.play()
# Update position each frame
def update():
location = instance.getLocation()
coords = location.getExactLayerCoordinates()
emitter.setPosition(fife.AudioSpaceCoordinate(coords.x, coords.y, coords.z))
9.13. Example: Ambient Music
# Create background music
music = sound_manager.createEmitter()
music.setSoundClip("music/theme.ogg")
music.setGain(0.6)
music.setLooping(True)
music.setRelativePositioning(True)
music.play()
# Create ambient sound effect
ambient = sound_manager.createEmitter()
ambient.setSoundClip("sounds/wind.ogg")
ambient.setGain(0.3)
ambient.setLooping(True)
ambient.setRelativePositioning(True)
ambient.play()
10. GUI
This chapter covers FifeChan integration, widgets, and GUI management.
FIFE supports multiple GUI backends. The primary backend is FifeChan (a fork of Guichan).
10.1. GUI Manager
The IGUIManager interface provides access to the GUI system.
The FifechanManager implements this interface for FifeChan.
10.1.1. Getting the GUI Manager
gui_manager = engine.getGuiManager()
10.2. FifeChan
FifeChan is the recommended GUI library for FIFE games. It provides a widget-based UI with Python bindings.
10.2.1. Available Backends
FIFE supports two GUI backends:
| FifeChan |
Default, lightweight, Python bindings via PyChan |
| CEGUI |
Full-featured, requires PyCEGUI |
10.2.2. Adding Widgets
# Get the FifechanManager
fifechan_manager = gui_manager # if using FifechanManager
# Add a widget
fifechan_manager.add(my_widget)
# Remove a widget
fifechan_manager.remove(my_widget)
# Get the top container
top_container = fifechan_manager.getTopContainer()
10.2.3. Initializing FifechanManager
The FifechanManager is initialized by the engine. You can also initialize manually:
fifechan_manager.init("SDL2", screen_width, screen_height)
10.2.4. Tabbing
Enable or disable tab key focus cycling:
fifechan_manager.setTabbingEnabled(True)
if fifechan_manager.isTabbingEnabled():
print("Tab navigation enabled")
10.2.6. Frame Update
The turn() method is called each frame to process GUI logic and rendering.
This is handled automatically by the engine.
10.2.7. Resizing
Resize the top container (e.g., after window resize):
gui_manager.resizeTopContainer(x, y, width, height)
10.3. Widgets
FifeChan provides several built-in widgets:
| Window |
Container window |
| Button |
Clickable button |
| Label |
Text label |
| TextField |
Single-line text input |
| TextBox |
Multi-line text area |
| Slider |
Horizontal/vertical slider |
| CheckBox |
Checkbox control |
| RadioButton |
Radio button |
| ListBox |
List of items |
| DropDown |
Dropdown selector |
| TabbedArea |
Tabbed container |
| ScrollArea |
Scrollable container |
| Icon |
Image display |
10.3.1. Creating Widgets
import fife
# Create a button
button = fife.fifechan.Button("Click Me")
button.setWidth(100)
button.setHeight(30)
button.setPosition(10, 10)
# Create a label
label = fife.fifechan.Label("Hello World")
label.setPosition(10, 50)
# Create a text field
textfield = fife.fifechan.TextField()
textfield.setWidth(200)
textfield.setHeight(25)
textfield.setPosition(10, 80)
# Create a checkbox
checkbox = fife.fifechan.CheckBox("Enable feature")
checkbox.setPosition(10, 115)
# Create a window
window = fife.fifechan.Window("My Window")
window.setWidth(300)
window.setHeight(200)
window.setPosition(50, 50)
10.3.2. Widget Properties
# Position
widget.setPosition(x, y)
# Size
widget.setWidth(width)
widget.setHeight(height)
# Visibility
widget.setVisible(True)
widget.setVisible(False)
# Enabled/disabled
widget.setEnabled(True)
widget.setEnabled(False)
# Focus
widget.setFocusable(True)
10.4. Text Input
10.4.1. Default Font
Set the default font before initializing the GUI:
settings = engine.getSettings()
settings.setDefaultFontPath("fonts/FreeSans.ttf")
settings.setDefaultFontSize(12)
settings.setDefaultFontGlyphs("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
10.4.2. Font Creation
Create custom fonts for specific widgets:
font = gui_manager.createFont("fonts/FreeSans.ttf", 14, glyphs)
widget.setFont(font)
10.5. Widget Events
Listen for widget events:
class MyWidgetListener:
def __init__(self, button):
self.button = button
def handleAction(self, event):
if event.getSource() == self.button:
print("Button clicked!")
# In Python, you typically subclass widgets or use callbacks
10.6. Console
The built-in console allows executing Python code in-game.
10.6.1. Enabling the Console
gui_manager.setConsoleEnabled(True)
10.6.2. Using the Console
Press the default hotkey (typically backtick or tilde) to open the console. Type Python expressions and press Enter to execute them.
10.7. Cursor
Configure the mouse cursor:
cursor = engine.getCursor()
# Set cursor image
cursor.setImage(cursor_image)
# Set cursor animation
cursor.setAnimation(cursor_animation)
# Enable native image cursor (system cursor)
cursor.setNativeImageCursorEnabled(True)
10.8. Layout Example
def create_main_menu():
# Create main window
window = fife.fifechan.Window("Main Menu")
window.setWidth(300)
window.setHeight(250)
window.setPosition(100, 100)
# Create buttons
start_btn = fife.fifechan.Button("Start Game")
start_btn.setWidth(200)
start_btn.setHeight(40)
start_btn.setPosition(50, 30)
options_btn = fife.fifechan.Button("Options")
options_btn.setWidth(200)
options_btn.setHeight(40)
options_btn.setPosition(50, 80)
quit_btn = fife.fifechan.Button("Quit")
quit_btn.setWidth(200)
quit_btn.setHeight(40)
quit_btn.setPosition(50, 130)
# Add buttons to window
window.add(start_btn)
window.add(options_btn)
window.add(quit_btn)
# Add window to GUI
gui_manager.add(window)
return window
10.9. Tabbing
Control keyboard navigation between widgets:
# Enable/disable tab navigation
gui_manager.setTabbingEnabled(True)
10.10. GUI Rendering
The GUI is rendered automatically each frame by gui_manager.turn().
No manual rendering is required.
10.11. Top Container
Access the top-level container for layout:
container = gui_manager.getTopContainer()
container.setWidth(screen_width)
container.setHeight(screen_height)
| The top container is resized automatically when the screen mode changes. |
11. Pathfinding
This chapter explains pathfinding, routes, and instance movement.
FIFE includes a pathfinding system that allows game entities to navigate the map automatically.
11.1. Overview
The pathfinding system consists of:
| Route |
Holds the calculated path between two locations |
| Pather |
Algorithms that compute routes (A* based) |
Pathfinding integrates with the model system through the Layer and Location classes.
11.2. Pathfinding Prerequisites
For pathfinding to work, the layer must be marked as walkable:
layer.setWalkable(True)
Blocking instances will prevent paths from going through them:
instance.setBlocking(True)
11.3. Route
A Route represents a path from a start location to a destination.
11.3.1. Creating Routes
Routes are typically created when calling instance.move():
# The move method internally creates a route
instance.move("walk", target_location, 5.0)
You can also create routes manually:
route = fife.Route(start_location, end_location)
11.3.2. Route Status
Routes have a status indicating their current state:
| ROUTE_CREATED |
(0) Route created but not yet calculated |
| ROUTE_SEARCHING |
(1) Path calculation in progress |
| ROUTE_SEARCHED |
(2) Search complete, ready to solve |
| ROUTE_SOLVED |
(3) Path found successfully |
| ROUTE_FAILED |
(4) No path could be found |
Query the status:
status = route.getRouteStatus()
route.setRouteStatus(fife.ROUTE_SOLVED)
11.3.3. Route Nodes
# Get start and end locations
start = route.getStartNode()
end = route.getEndNode()
# Set new start/end
route.setStartNode(new_start)
route.setEndNode(new_end)
# Get current position on path
current = route.getCurrentNode()
# Get next/previous positions
next_node = route.getNextNode()
prev_node = route.getPreviousNode()
11.3.4. Route Properties
route = instance.getRoute()
if route:
status = route.getRouteStatus()
path_length = route.getPathLength()
walked = route.getWalkedLength()
if route.getRouteStatus() == fife.ROUTE_SOLVED:
path = route.getPath()
for node in path:
print(node.getLayerCoordinates())
11.3.5. Path Manipulation
# Set path manually
route.setPath(path_list)
# Cut path after certain length
route.cutPath(3) # Keep only first 3 steps
# Check if at end of path
if route.reachedEnd():
print("Destination reached")
# Walk to next node
if route.walkToNextNode(step=1):
print("Moved forward")
11.3.6. Route Replanning
Routes can be marked for replanning if the environment changes:
route.setReplanned(True)
if route.isReplanned():
print("Route will be recalculated")
11.3.7. Session and Rotation
# Set search session ID
route.setSessionId(42)
session = route.getSessionId()
# Set current rotation for multi-cell pathfinding
route.setRotation(90)
rotation = route.getRotation()
11.3.8. Cost Configuration
# Set cost identifier for pathfinding
route.setCostId("movement")
cost_id = route.getCostId()
11.3.9. Multi-Cell Pathfinding
For objects that occupy multiple cells:
# Set occupied area on the route
route.setOccupiedArea([fife.ModelCoordinate(0, 0), fife.ModelCoordinate(1, 0)])
# Get occupied cells based on rotation
cells = route.getOccupiedCells(rotation)
# Check if multi-cell route
if route.isMultiCell():
area = route.getOccupiedArea()
11.3.10. Object Association
Associate route with an object for z-step range and multi-cell info:
route.setObject(my_object)
obj = route.getObject()
z_range = route.getZStepRange()
11.3.11. Area Limitations
if route.isAreaLimited():
areas = route.getLimitedAreas()
11.3.12. Cost Modifiers
Configure how pathfinding works on a layer:
# 4-direction movement (edges only)
layer.setPathingStrategy(fife.CELL_EDGES_ONLY)
# 8-direction movement (edges and diagonals)
layer.setPathingStrategy(fife.CELL_EDGES_AND_DIAGONALS)
11.4. Instance Movement
The Instance.move() method handles pathfinding automatically:
11.4.1. Basic Movement
# Move with action animation at speed 5
instance.move("walk", target_location, 5.0)
The parameters are:
| actionName |
Action to play during movement (e.g., "walk") |
| target |
Destination location |
| speed |
Movement speed (layer units per second) |
| costId |
Optional cost identifier for pathfinding |
11.4.2. Movement Speed
Speed is measured in layer coordinate units per second:
# Walk at 5 units/second
instance.move("walk", target, 5.0)
# Run at 10 units/second
instance.move("run", target, 10.0)
# Slow walk at 2 units/second
instance.move("walk", target, 2.0)
11.4.3. Canceling Movement
Stop an instance mid-movement:
# Cancel movement (stops at next cell)
instance.cancelMovement()
# Cancel after a certain number of cells
instance.cancelMovement(2) # Stop after 2 more cells
11.5. Following
Instances can follow other instances or routes:
11.5.1. Following an Instance
# Follow another instance
instance.follow("walk", leader_instance, 5.0)
11.5.2. Following a Route
# Follow a pre-calculated route
instance.follow("walk", route, 5.0)
11.6. Multi-Cell Pathfinding
For objects that occupy multiple cells:
# Set occupied area on the route
route.setOccupiedArea([fife.ModelCoordinate(0, 0), fife.ModelCoordinate(1, 0)])
# Get occupied cells based on rotation
cells = route.getOccupiedCells(rotation)
11.7. Cost Modifiers
Pathfinding can use custom costs for different terrain or obstacles:
11.7.1. Instance Costs
# Set custom cost on instance
instance.setCost("movement", 2.0) # Costs 2x normal
instance.setCost("movement", 0.5) # Costs 0.5x normal
11.7.2. Route Cost ID
Specify which cost type to use:
# Create movement with cost identifier
instance.move("walk", target, 5.0, "movement")
11.8. Blocking Behavior
11.8.1. Blocking Instances
Blocking instances prevent paths from going through them:
# Set instance as blocking
instance.setBlocking(True)
# Override blocking (instance can pass through)
instance.setOverrideBlocking(True)
11.8.2. Ignoring Blockers
Routes can optionally ignore dynamic blockers:
route.setDynamicBlockerIgnored(True)
# Get locations where blockers are ignored
blocking_locations = route.getBlockingPathLocations()
11.9. Pathfinding Algorithms
FIFE uses A* (A-star) for pathfinding. The algorithm considers:
-
Distance heuristic (Manhattan or Euclidean)
-
Cell costs (terrain modifiers)
-
Blocking instances
-
Multi-cell object sizes
11.10. Route Replanning
Routes can be marked for replanning if the environment changes:
route.setReplanned(True)
11.11. Movement Actions
Instance actions are played automatically during movement:
# The "walk" action animation plays while moving
instance.move("walk", target, 5.0)
# Different actions for different speeds
instance.move("run", target, 10.0)
instance.move("sneak", target, 2.0)
11.12. Path Navigation
Navigate through a path manually:
route = instance.getRoute()
# Get current position on path
current = route.getCurrentNode()
# Get next position
next_node = route.getNextNode()
# Get previous position
prev_node = route.getPreviousNode()
# Move to next node
if route.walkToNextNode():
print("Moved to next node")
# Check if at end
if route.reachedEnd():
print("Destination reached")
11.13. Distance Calculations
Calculate distances between locations:
location1 = fife.Location(layer)
location1.setLayerCoordinates(fife.ModelCoordinate(0, 0))
location2 = fife.Location(layer)
location2.setLayerCoordinates(fife.ModelCoordinate(10, 10))
# Map coordinate distance
map_dist = location1.getMapDistanceTo(location2)
# Layer coordinate distance
layer_dist = location1.getLayerDistanceTo(location2)
11.14. Example: Move to Click Location
class ClickToMove(fife.IMouseListener):
def __init__(self, camera, instance):
self.camera = camera
self.instance = instance
def mousePressed(self, event):
if event.getButton() == fife.MouseEvent.LEFT:
screen = fife.ScreenPoint(event.getX(), event.getY(), 0)
map_point = self.camera.toMapCoordinates(screen)
target = fife.Location(self.instance.getLocation().getLayer())
target.setExactLayerCoordinates(map_point)
self.instance.move("walk", target, 5.0)
11.15. Layer Configuration for Pathfinding
Configure layer behavior for pathfinding:
# Set pathing strategy
layer.setPathingStrategy(fife.CELL_EDGES_AND_DIAGONALS)
# Make layer walkable
layer.setWalkable(True)
# Create interact layer for additional blocking info
interact_layer.setInteract(True, "ground_layer")
layer.addInteractLayer(interact_layer)
12. Virtual Filesystem
This chapter covers the virtual file system (VFS), file loading, and archive support.
FIFE’s VFS provides transparent access to files regardless of their location (filesystem, ZIP archives, etc.).
12.1. Overview
The Virtual File System (VFS) abstracts file access from the actual storage. Files can come from:
-
Local filesystem directories
-
ZIP archives
-
Custom sources
12.1.1. Getting the VFS
vfs = engine.getVFS()
12.2. File Operations
12.2.1. Checking File Existence
if vfs.exists("maps/mymap.xml"):
print("File exists")
12.2.2. Checking Directories
if vfs.isDirectory("maps/"):
print("Is a directory")
12.2.3. Opening Files
# Open a file
raw_data = vfs.open("maps/mymap.xml")
# Read from the file
content = raw_data.read()
# Close when done
raw_data.close()
12.4. Custom VFS Providers
Register custom file source providers:
# Add a custom provider (C++ level)
vfs.addProvider(my_provider)
# Create a source from a file (tries all providers)
source = vfs.createSource("custom_archive.dat")
# Add a pre-created source
vfs.addSource(source)
12.5. Removing Sources
# Remove by path
vfs.removeSource("assets.zip")
# Remove by source object
vfs.removeSource(source_object)
12.6. Directory Listing
12.6.1. List Files
# List all files in a directory
files = vfs.listFiles("sprites/")
# List files matching a regex pattern
xml_files = vfs.listFiles("maps/", ".*\.xml")
12.6.2. List Directories
# List subdirectories
dirs = vfs.listDirectories("assets/")
# List directories matching pattern
dirs = vfs.listDirectories("assets/", "level_.*")
12.7. Checking Sources
if vfs.hasSource("assets.zip"):
print("ZIP archive is mounted")
12.8. Archive Support
FIFE supports reading files from ZIP archives.
12.8.1. Adding ZIP Sources
# Add a ZIP file as a source
vfs.addNewSource("assets.zip")
# Files in the archive are now accessible
# e.g., vfs.open("assets.zip/sprites/hero.png")
12.8.2. Removing Sources
vfs.removeSource("assets.zip")
12.8.3. Checking Sources
if vfs.hasSource("assets.zip"):
print("ZIP archive is mounted")
12.9. File Source Order
VFS searches sources in the order they were added. The filesystem provider is typically added first, meaning local files override archived files.
| All filenames must be lowercase. The VFS converts them automatically and warns if uppercase is used. |
12.10. Lazy Loading
FIFE implements lazy loading for resources. Files are loaded only when first accessed, improving startup time.
12.10.1. Resource Managers
Resource managers handle lazy loading for different file types:
# Image manager - lazy loads images
image_manager = engine.getImageManager()
# Animation manager - lazy loads animations
animation_manager = engine.getAnimationManager()
# Sound clip manager - lazy loads audio
sound_clip_manager = engine.getSoundClipManager()
12.11. Loading Maps
Maps are loaded through the model using the VFS:
# Create a map loader
map_loader = fife.MapLoader(model, vfs, image_manager)
# Load a map file
my_map = map_loader.load("maps/mymap.xml")
12.12. Loading Objects
Object definitions can be loaded from XML:
# Object loader loads objects from XML
object_loader = fife.ObjectLoader(model, vfs, image_manager)
# Load objects
object_loader.load("objects/trees.xml")
12.13. Loading Animations
Animation definitions are loaded from XML:
# Animation loader
animation_loader = fife.AnimationLoader(vfs, image_manager)
# Load animations from XML
animation_loader.load("animations/hero_walk.xml")
12.14. VFS Providers
FIFE supports different VFS source providers:
| HostFileSystem |
Local filesystem (added automatically) |
| ZipProvider |
ZIP archive support |
12.15. Adding Custom Providers
Custom providers can be added for alternative file sources:
# Custom providers are added at the C++ level
# The VFS handles provider registration internally
12.16. Best Practices
12.16.1. File Path Conventions
-
Use forward slashes for paths:
sprites/hero.png -
All paths must be lowercase
-
Use relative paths from game root
12.16.2. Archive Organization
Organize ZIP archives by type:
assets/ ├── sprites.zip # Contains sprites/ ├── maps.zip # Contains maps/ ├── sounds.zip # Contains sounds/ └── fonts.zip # Contains fonts/
12.16.3. Loading Order
-
Initialize engine
-
Add archive sources
-
Load maps (which loads dependencies)
12.16.4. Memory Management
The VFS and resource managers handle memory automatically:
-
Resources are cached after first load
-
Unused resources can be released
-
Lazy loading prevents loading unnecessary files
12.17. Example: Complete Asset Setup
def setup_assets(engine):
vfs = engine.getVFS()
# Add ZIP archives as sources
vfs.addNewSource("assets/sprites.zip")
vfs.addNewSource("assets/maps.zip")
vfs.addNewSource("assets/sounds.zip")
# Load the map
model = engine.getModel()
image_manager = engine.getImageManager()
map_loader = fife.MapLoader(model, vfs, image_manager)
return map_loader.load("maps/level1.xml")
12.18. Troubleshooting
12.18.1. File Not Found
Check:
-
File exists in filesystem or archive
-
Path is lowercase
-
Source is added before file is accessed
-
Correct relative path from game root
12.18.2. Case Sensitivity
FIFE requires lowercase paths:
# Correct
vfs.open("sprites/hero.png")
# Will warn and convert to lowercase
vfs.open("Sprites/Hero.png")
12.18.3. Source Priority
If files exist in both filesystem and archive:
-
Local filesystem files take priority (loaded first)
-
Archive files are fallbacks
-
Check source order if unexpected files are loaded