Class: RGame::Core::SpriteSheet
- Inherits:
-
Object
- Object
- RGame::Core::SpriteSheet
- Defined in:
- lib/rgame/core/sprite_sheet.rb
Overview
A texture atlas — one image plus a JSON descriptor — sliced into frames and drawn one at a time.
sheet = RGame::Core::SpriteSheet.load(app, 'media/hero.json')
sheet.draw(renderer, row, col, x, y, flip_x: facing_left, z: 10)
The descriptor
{
"image": "hero.png",
"frame_width": 16, "frame_height": 24,
"cell_width": 32, "cell_height": 32,
"origin_x": 8, "origin_y": 4,
"animations": { "walk_left": { "row": 1, "frames": 4, "fps": 8 } }
}
image is resolved next to the descriptor. The rest describes the grid.
A frame can be smaller than its cell. Cells are laid out on a fixed
cell_width x cell_height grid, but what is drawn is a
frame_width x frame_height rectangle offset by origin_x/origin_y
inside the cell. That is what lets a sheet whose cells are sized for the
widest pose — an attack, a swing — still expose a tight, centred box for
walking, so a character does not appear to change size between animations.
Leave the cell and origin keys out and frame == cell, which is what a
simple sheet wants.
animations is handed back untouched by #animations. This class knows
nothing about time; the scene layer builds its own animation table from
that hash, which is why the raw form is what gets exposed.
Slicing costs nothing
Every frame is cut once, at construction, as a view onto the one upload —
so a sheet of two hundred frames is two hundred small objects and a single
texture, and #draw is an array index plus one call.
Instance Attribute Summary collapse
-
#animations ⇒ Object
readonly
Returns the value of attribute animations.
-
#frame_height ⇒ Object
readonly
Returns the value of attribute frame_height.
-
#frame_width ⇒ Object
readonly
Returns the value of attribute frame_width.
Class Method Summary collapse
-
.load(app, atlas_path) ⇒ Object
Loads a descriptor and the image beside it.
Instance Method Summary collapse
-
#draw(renderer, row, col, x, y, flip_x: false, z: 0) ⇒ Object
Draws one frame with its top-left at (x, y).
-
#grid ⇒ Object
How many frames the sheet was cut into, as [rows, columns].
-
#initialize(image, atlas) ⇒ SpriteSheet
constructor
atlasis the parsed descriptor;imagean already-loaded sheet image.
Constructor Details
#initialize(image, atlas) ⇒ SpriteSheet
atlas is the parsed descriptor; image an already-loaded sheet image.
61 62 63 64 65 66 67 |
# File 'lib/rgame/core/sprite_sheet.rb', line 61 def initialize(image, atlas) @frame_width = atlas.fetch(:frame_width) { missing(:frame_width) } @frame_height = atlas.fetch(:frame_height) { missing(:frame_height) } @animations = atlas[:animations] || {} @frames = slice(image, atlas) end |
Instance Attribute Details
#animations ⇒ Object (readonly)
Returns the value of attribute animations.
46 47 48 |
# File 'lib/rgame/core/sprite_sheet.rb', line 46 def animations @animations end |
#frame_height ⇒ Object (readonly)
Returns the value of attribute frame_height.
46 47 48 |
# File 'lib/rgame/core/sprite_sheet.rb', line 46 def frame_height @frame_height end |
#frame_width ⇒ Object (readonly)
Returns the value of attribute frame_width.
46 47 48 |
# File 'lib/rgame/core/sprite_sheet.rb', line 46 def frame_width @frame_width end |
Class Method Details
.load(app, atlas_path) ⇒ Object
Loads a descriptor and the image beside it.
The AssetManager does not use this — it calls .new with an image it
has already cached, so a sheet's PNG is shared with a standalone load of
the same file. This is the standalone path, for a game with one sheet
and no asset manager.
54 55 56 57 58 |
# File 'lib/rgame/core/sprite_sheet.rb', line 54 def self.load(app, atlas_path) atlas = JSON.parse(File.read(atlas_path), symbolize_names: true) directory = File.dirname(File.(atlas_path)) new(Image.new(app, File.join(directory, atlas[:image])), atlas) end |
Instance Method Details
#draw(renderer, row, col, x, y, flip_x: false, z: 0) ⇒ Object
Draws one frame with its top-left at (x, y).
flip_x mirrors the frame within that same rectangle, so a character
occupies the same pixels whichever way it faces — see
RGame::Core::Renderer#image_at.
74 75 76 |
# File 'lib/rgame/core/sprite_sheet.rb', line 74 def draw(renderer, row, col, x, y, flip_x: false, z: 0) renderer.image_at(@frames[row][col], x, y, scale_x: flip_x ? -1 : 1, z: z) end |
#grid ⇒ Object
How many frames the sheet was cut into, as [rows, columns].
79 |
# File 'lib/rgame/core/sprite_sheet.rb', line 79 def grid = [@frames.length, @frames.empty? ? 0 : @frames[0].length] |