module Eagle

Overview

Eagle is a 2D and 3D game engine written in Crystal. This page is the API reference; each type explains what it's for and shows how to use it.

Where to start

By topic

A complete game

class Game < App
  @player = Sprite2D.new(Texture.new(Image.circle(24, Color::YELLOW)), Vec2.new(480, 270))
  @score = 0

  def load : Nil
    Input.map "left", Key::A, Key::Left
    Input.map "right", Key::D, Key::Right
    SceneTree.root.add(@player)
  end

  def update(dt : Float32) : Nil
    @player.x += Input.axis("left", "right") * 300 * dt
    @score += 1 if Input.pressed?(Key::Space)
  end

  def draw(g : Graphics) : Nil
    g.print("score #{@score}", 10, 10, scale: 2)
  end
end

Eagle.run(Game, title: "My Game", width: 960, height: 540)

Defined in:

eagle.cr
eagle/assets/assets.cr
eagle/assets/codecs/bmp.cr
eagle/assets/codecs/png.cr
eagle/assets/codecs/qoi.cr
eagle/assets/codecs/zlib.cr
eagle/assets/image.cr
eagle/audio/audio.cr
eagle/audio/vorbis.cr
eagle/audio/wav.cr
eagle/core/clock.cr
eagle/core/engine.cr
eagle/core/error.cr
eagle/core/events.cr
eagle/core/log.cr
eagle/core/node.cr
eagle/core/scene_tree.cr
eagle/core/script.cr
eagle/core/signal.cr
eagle/core/tween.cr
eagle/core/window.cr
eagle/gpu/device.cr
eagle/gpu/gl33.cr
eagle/graphics/canvas.cr
eagle/graphics/default_font_data.cr
eagle/graphics/font.cr
eagle/graphics/graphics.cr
eagle/graphics/shader.cr
eagle/graphics/texture.cr
eagle/graphics/truetype.cr
eagle/graphics3d/material.cr
eagle/graphics3d/mesh.cr
eagle/graphics3d/renderer3d.cr
eagle/input/input.cr
eagle/input/keys.cr
eagle/lib/gl.cr
eagle/math/color.cr
eagle/math/mat4.cr
eagle/math/math.cr
eagle/math/quat.cr
eagle/math/rect.cr
eagle/math/transform2d.cr
eagle/math/vec2.cr
eagle/math/vec3.cr
eagle/nodes/animated_sprite2d.cr
eagle/nodes/audio_player.cr
eagle/nodes/camera2d.cr
eagle/nodes/node2d.cr
eagle/nodes/node3d.cr
eagle/nodes/particles2d.cr
eagle/nodes/physics3d_nodes.cr
eagle/nodes/physics_nodes.cr
eagle/nodes/shapes2d.cr
eagle/nodes/sprite2d.cr
eagle/nodes/tilemap.cr
eagle/nodes/timer.cr
eagle/physics/body2d.cr
eagle/physics/collision2d.cr
eagle/physics/physics2d.cr
eagle/physics/physics3d.cr
eagle/physics/shapes2d.cr
eagle/physics/world2d.cr
eagle/platform/base.cr
eagle/platform/sdl.cr
eagle/ui/control.cr
eagle/ui/theme.cr
eagle/ui/widgets.cr
eagle/version.cr

Constant Summary

DEFAULT_FONT_GLYPHS = ".....\n.....\n.....\n.....\n.....\n.....\n.....\n\n..#..\n..#..\n..#..\n..#..\n..#..\n.....\n..#..\n\n.#.#.\n.#.#.\n.#.#.\n.....\n.....\n.....\n.....\n\n.#.#.\n.#.#.\n#####\n.#.#.\n#####\n.#.#.\n.#.#.\n\n..#..\n.####\n#.#..\n.###.\n..#.#\n####.\n..#..\n\n##...\n##..#\n...#.\n..#..\n.#...\n#..##\n...##\n\n.##..\n#..#.\n#.#..\n.#...\n#.#.#\n#..#.\n.##.#\n\n.##..\n..#..\n.#...\n.....\n.....\n.....\n.....\n\n...#.\n..#..\n.#...\n.#...\n.#...\n..#..\n...#.\n\n.#...\n..#..\n...#.\n...#.\n...#.\n..#..\n.#...\n\n.....\n..#..\n#.#.#\n.###.\n#.#.#\n..#..\n.....\n\n.....\n..#..\n..#..\n#####\n..#..\n..#..\n.....\n\n.....\n.....\n.....\n.....\n.##..\n..#..\n.#...\n\n.....\n.....\n.....\n#####\n.....\n.....\n.....\n\n.....\n.....\n.....\n.....\n.....\n.##..\n.##..\n\n.....\n....#\n...#.\n..#..\n.#...\n#....\n.....\n\n.###.\n#...#\n#..##\n#.#.#\n##..#\n#...#\n.###.\n\n..#..\n.##..\n..#..\n..#..\n..#..\n..#..\n.###.\n\n.###.\n#...#\n....#\n...#.\n..#..\n.#...\n#####\n\n#####\n...#.\n..#..\n...#.\n....#\n#...#\n.###.\n\n...#.\n..##.\n.#.#.\n#..#.\n#####\n...#.\n...#.\n\n#####\n#....\n####.\n....#\n....#\n#...#\n.###.\n\n..##.\n.#...\n#....\n####.\n#...#\n#...#\n.###.\n\n#####\n....#\n...#.\n..#..\n.#...\n.#...\n.#...\n\n.###.\n#...#\n#...#\n.###.\n#...#\n#...#\n.###.\n\n.###.\n#...#\n#...#\n.####\n....#\n...#.\n.##..\n\n.....\n.##..\n.##..\n.....\n.##..\n.##..\n.....\n\n.....\n.##..\n.##..\n.....\n.##..\n..#..\n.#...\n\n...#.\n..#..\n.#...\n#....\n.#...\n..#..\n...#.\n\n.....\n.....\n#####\n.....\n#####\n.....\n.....\n\n.#...\n..#..\n...#.\n....#\n...#.\n..#..\n.#...\n\n.###.\n#...#\n....#\n...#.\n..#..\n.....\n..#..\n\n.###.\n#...#\n#.###\n#.#.#\n#.###\n#....\n.###.\n\n.###.\n#...#\n#...#\n#####\n#...#\n#...#\n#...#\n\n####.\n#...#\n#...#\n####.\n#...#\n#...#\n####.\n\n.###.\n#...#\n#....\n#....\n#....\n#...#\n.###.\n\n###..\n#..#.\n#...#\n#...#\n#...#\n#..#.\n###..\n\n#####\n#....\n#....\n####.\n#....\n#....\n#####\n\n#####\n#....\n#....\n####.\n#....\n#....\n#....\n\n.###.\n#...#\n#....\n#.###\n#...#\n#...#\n.####\n\n#...#\n#...#\n#...#\n#####\n#...#\n#...#\n#...#\n\n.###.\n..#..\n..#..\n..#..\n..#..\n..#..\n.###.\n\n..###\n...#.\n...#.\n...#.\n...#.\n#..#.\n.##..\n\n#...#\n#..#.\n#.#..\n##...\n#.#..\n#..#.\n#...#\n\n#....\n#....\n#....\n#....\n#....\n#....\n#####\n\n#...#\n##.##\n#.#.#\n#.#.#\n#...#\n#...#\n#...#\n\n#...#\n#...#\n##..#\n#.#.#\n#..##\n#...#\n#...#\n\n.###.\n#...#\n#...#\n#...#\n#...#\n#...#\n.###.\n\n####.\n#...#\n#...#\n####.\n#....\n#....\n#....\n\n.###.\n#...#\n#...#\n#...#\n#.#.#\n#..#.\n.##.#\n\n####.\n#...#\n#...#\n####.\n#.#..\n#..#.\n#...#\n\n.####\n#....\n#....\n.###.\n....#\n....#\n####.\n\n#####\n..#..\n..#..\n..#..\n..#..\n..#..\n..#..\n\n#...#\n#...#\n#...#\n#...#\n#...#\n#...#\n.###.\n\n#...#\n#...#\n#...#\n#...#\n#...#\n.#.#.\n..#..\n\n#...#\n#...#\n#...#\n#.#.#\n#.#.#\n#.#.#\n.#.#.\n\n#...#\n#...#\n.#.#.\n..#..\n.#.#.\n#...#\n#...#\n\n#...#\n#...#\n#...#\n.#.#.\n..#..\n..#..\n..#..\n\n#####\n....#\n...#.\n..#..\n.#...\n#....\n#####\n\n.###.\n.#...\n.#...\n.#...\n.#...\n.#...\n.###.\n\n.....\n#....\n.#...\n..#..\n...#.\n....#\n.....\n\n.###.\n...#.\n...#.\n...#.\n...#.\n...#.\n.###.\n\n..#..\n.#.#.\n#...#\n.....\n.....\n.....\n.....\n\n.....\n.....\n.....\n.....\n.....\n.....\n#####\n\n.#...\n..#..\n...#.\n.....\n.....\n.....\n.....\n\n.....\n.....\n.###.\n....#\n.####\n#...#\n.####\n\n#....\n#....\n#.##.\n##..#\n#...#\n#...#\n####.\n\n.....\n.....\n.###.\n#....\n#....\n#...#\n.###.\n\n....#\n....#\n.##.#\n#..##\n#...#\n#...#\n.####\n\n.....\n.....\n.###.\n#...#\n#####\n#....\n.###.\n\n..##.\n.#..#\n.#...\n###..\n.#...\n.#...\n.#...\n\n.....\n.....\n.####\n#...#\n.####\n....#\n.###.\n\n#....\n#....\n#.##.\n##..#\n#...#\n#...#\n#...#\n\n..#..\n.....\n.##..\n..#..\n..#..\n..#..\n.###.\n\n...#.\n.....\n..##.\n...#.\n...#.\n#..#.\n.##..\n\n#....\n#....\n#..#.\n#.#..\n##...\n#.#..\n#..#.\n\n.##..\n..#..\n..#..\n..#..\n..#..\n..#..\n.###.\n\n.....\n.....\n##.#.\n#.#.#\n#.#.#\n#...#\n#...#\n\n.....\n.....\n#.##.\n##..#\n#...#\n#...#\n#...#\n\n.....\n.....\n.###.\n#...#\n#...#\n#...#\n.###.\n\n.....\n.....\n####.\n#...#\n####.\n#....\n#....\n\n.....\n.....\n.####\n#...#\n.####\n....#\n....#\n\n.....\n.....\n#.##.\n##..#\n#....\n#....\n#....\n\n.....\n.....\n.####\n#....\n.###.\n....#\n####.\n\n.#...\n.#...\n###..\n.#...\n.#...\n.#..#\n..##.\n\n.....\n.....\n#...#\n#...#\n#...#\n#..##\n.##.#\n\n.....\n.....\n#...#\n#...#\n#...#\n.#.#.\n..#..\n\n.....\n.....\n#...#\n#...#\n#.#.#\n#.#.#\n.#.#.\n\n.....\n.....\n#...#\n.#.#.\n..#..\n.#.#.\n#...#\n\n.....\n.....\n#...#\n#...#\n.####\n....#\n.###.\n\n.....\n.....\n#####\n...#.\n..#..\n.#...\n#####\n\n..##.\n.#...\n.#...\n#....\n.#...\n.#...\n..##.\n\n..#..\n..#..\n..#..\n..#..\n..#..\n..#..\n..#..\n\n.##..\n...#.\n...#.\n....#\n...#.\n...#.\n.##..\n\n.....\n.....\n.#..#\n#.#.#\n#..#.\n.....\n....."

Built-in 5x7 pixel font, ASCII 32..126. Each glyph is 7 rows of 5 columns. Authored for Eagle; public domain.

VERSION = "0.1.0"

Eagle's version, following semantic versioning.

Class Method Summary

Macro Summary

Class Method Detail

def self.app : App #

The running app. Raises if nothing is running.


def self.config : Config #

The active configuration.


def self.g : Graphics #

Short alias for .graphics.


def self.graphics : Graphics #

The 2D drawing context, the same object passed to App#draw.


def self.handle_event(ev : Event) : Nil #

Routes one event through Input, the app and the scene tree right away. Most code should use .inject.


def self.init(app_class : App.class, **opts) : Nil #

Opens the window and GPU and constructs app_class, without entering the loop. Drive frames with .step and finish with .shutdown.


def self.init(app : App = App.new, **opts, &factory : -> App) : Nil #

Opens everything with a placeholder, then builds the real app with factory.


def self.init(app : App = App.new, **opts) : Nil #

Opens the window and GPU and calls App#load, without entering the loop. Use it in tests and tools, then call .step to advance frames and .shutdown when done.

Eagle.init(title: "test", hidden: true)
3.times { Eagle.step }
image = Eagle.screenshot
Eagle.shutdown

def self.initialized? : Bool #

True after the window and GPU are open.


def self.inject(*events : Event) : Nil #

Queues synthetic events for the next frame. They go through the same path as real input, so Input, App#input and nodes all see them. Use it for tests, demos and replays.

Eagle.inject(KeyEvent.new(Key::Space, pressed: true))

def self.log : Log #

Eagle's logger, a standard Crystal Log named "eagle". Set EAGLE_LOG=debug for more output.

Eagle.log.info { "level loaded" }
Eagle.log.debug { "spawned enemy" }

def self.platform : Platform::Base #

The platform backend (SDL on desktop, the browser on the web). Raises if Eagle isn't running. You rarely need it; Window, Input and Audio wrap it.


def self.platform? : Platform::Base | Nil #

The platform backend, or nil before Eagle.run.


def self.quit : Nil #

Asks the loop to stop after the current frame. App#unload runs during shutdown.


def self.run(app : App = App.new, **opts) : Nil #

Opens the window, calls App#load, runs the main loop until quit, then shuts down. Named arguments set Config fields.

class Game < App
end

Eagle.run(Game.new, title: "Hi", width: 800, height: 600)

On the web the browser drives frames, so this returns right away.


def self.run(**opts, &block : App -> ) : Nil #

Creates a plain App, lets the block attach hooks with App#on_draw and friends, then runs it.


def self.run(app_class : App.class, **opts) : Nil #

Runs a game given its class. The app is constructed after the window and GPU exist, so instance-variable initializers can create textures, fonts and sounds. This is the recommended form.

class Game < App
  @logo = Texture.new(Image.circle(32, Color::WHITE)) # safe: the GPU is ready
end

Eagle.run(Game, title: "Hi")

def self.running? : Bool #

True while the main loop is running.


def self.screenshot(path : String | Nil = nil) : Image #

Reads the current frame back from the GPU and returns it as an Image. Saves a PNG if you give a path.

Eagle.screenshot("shot.png") if Input.pressed?(Key::F12)

def self.setup_logging : Nil #

Sets the log level from the EAGLE_LOG environment variable (debug, info, warn, error or off). The default is info. Eagle.run calls this for you.


def self.shutdown : Nil #

Closes the window and frees GPU, audio and asset resources. .run calls it for you.


def self.step : Nil #

Runs exactly one frame: input, fixed updates, update, tweens, audio and drawing. .run calls this in a loop. Call it yourself after .init to drive the engine from tests.


Macro Detail

macro embed_assets(dir = "assets") #

Bakes every file under dir into the executable at compile time, so the game runs with no files beside it. Web builds need this, because the browser can't read your disk. Put it at the top level of your main file:

Eagle.embed_assets("assets")
Texture.load("res://player.png") # served from memory

Paths inside dir become res:// paths.