From dragonruby
Guides 2D game development with DragonRuby Game Toolkit, covering tick loops, sprite rendering, input handling, collisions, animations, state management, and performance.
npx claudepluginhub hoblin/claude-ruby-marketplace --plugin dragonrubyThis skill uses the workspace's default tool permissions.
This skill provides comprehensive guidance for building 2D games with DragonRuby Game Toolkit (DRGTK). Use for game loop implementation, sprite rendering, input handling, collision detection, animation, and scene management.
examples/audio/audio_events.rbexamples/audio/background_music.rbexamples/audio/crossfade.rbexamples/audio/music_controls.rbexamples/audio/sound_effects.rbexamples/core/coordinate_system.rbexamples/core/hello_world.rbexamples/core/labels.rbexamples/core/sprites.rbexamples/core/state_management.rbexamples/distribution/background_pause.rbexamples/distribution/build_workflow.shexamples/distribution/cvars_production.txtexamples/distribution/game_metadata_hd.txtexamples/distribution/game_metadata_minimal.txtexamples/distribution/game_metadata_mobile.txtexamples/distribution/platform_detection.rbexamples/distribution/steam_metadata.txtexamples/entities/collision_detection.rbexamples/entities/entity_lifecycle.rbSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides MCP server integration in Claude Code plugins via .mcp.json or plugin.json configs for stdio, SSE, HTTP types, enabling external services as tools.
This skill provides comprehensive guidance for building 2D games with DragonRuby Game Toolkit (DRGTK). Use for game loop implementation, sprite rendering, input handling, collision detection, animation, and scene management.
def boot args
args.state = {}
end
def tick args
# Called 60 times per second
args.state.player ||= { x: 640, y: 360, w: 50, h: 50, path: 'player.png' }
# Handle input
args.state.player.x += 5 if args.inputs.right
args.state.player.x -= 5 if args.inputs.left
# Render
args.outputs.sprites << args.state.player
end
| Concept | Purpose |
|---|---|
def tick(args) | Main game loop (60 FPS) |
args.outputs | Render sprites, labels, primitives |
args.state | Persistent game data storage |
args.inputs | Keyboard, mouse, controller input |
args.grid | Screen dimensions (1280x720) |
Geometry | Collision detection helpers |
(0, 720) ─────────────── (1280, 720)
│ │
│ 1280 × 720 │
│ │
(0, 0) ─────────────── (1280, 0)
Use args.outputs.primitives for FIFO (first-in, first-out) render order control.
args.outputs.primitives << {
x: 100, y: 100, w: 64, h: 64,
path: 'sprites/player.png',
angle: 45,
anchor_x: 0.5, anchor_y: 0.5,
r: 255, g: 255, b: 255, a: 255,
flip_horizontally: false
}
args.outputs.primitives << {
x: 640, y: 360,
text: "Score: #{args.state.score}",
size_px: 22,
anchor_x: 0.5, anchor_y: 0.5,
r: 255, g: 255, b: 255
}
# Filled rectangle (use primitive_marker: :solid)
args.outputs.primitives << {
x: 0, y: 0, w: 100, h: 100,
r: 255, g: 0, b: 0,
primitive_marker: :solid
}
# For many rectangles, use path: :solid for better performance
args.outputs.primitives << { x: 0, y: 0, w: 100, h: 100, path: :solid, r: 255, g: 0, b: 0 }
# Outline rectangle
args.outputs.primitives << { x: 0, y: 0, w: 100, h: 100, r: 0, g: 0, b: 0, primitive_marker: :border }
Use args.state with ||= for lazy initialization:
def tick args
args.state.player ||= { x: 640, y: 360 }
args.state.enemies ||= []
args.state.score ||= 0
args.state.scene ||= :title
end
# Directional (arrows, WASD, gamepad)
args.inputs.up / down / left / right
# Magnitude values
args.inputs.left_right # -1, 0, or 1
args.inputs.up_down # -1, 0, or 1
args.inputs.keyboard.key_down.space # Pressed this frame
args.inputs.keyboard.key_held.space # Held down
args.inputs.keyboard.key_up.space # Released this frame
args.inputs.mouse.click # Any button clicked
args.inputs.mouse.x / .y # Position
args.inputs.mouse.inside_rect?(rect) # Collision check
if Geometry.intersect_rect?(player, enemy)
enemy.dead = true
args.state.score += 1
end
# Clean up dead entities
args.state.enemies.reject! { |e| e.dead }
# Frame-based animation
sprite_index = 0.frame_index(count: 6, hold_for: 8, repeat: true)
args.state.player.path = "sprites/player-#{sprite_index}.png"
def tick args
args.state.scene ||= :title
send("#{args.state.scene}_tick", args)
end
def title_tick args
args.outputs.labels << { x: 640, y: 400, text: "Press SPACE", anchor_x: 0.5 }
args.state.scene = :gameplay if args.inputs.keyboard.key_down.space
end
def gameplay_tick args
# Game logic here
end
||= for state initialization$gtk.reset during development to reset stateargs.outputs.primitives for FIFO render order controlprimitive_marker: :solid or :border for rectangle typesFPS = 60)For detailed API documentation and patterns:
references/core.md - Game loop, args object, rendering, coordinatesreferences/input.md - Keyboard, mouse, controller input patternsreferences/entities.md - Entity spawning, collision, lifecyclereferences/game-logic/state.md - Timers, scoring, scene transitionsreferences/game-logic/persistence.md - Save/load, file I/O patternsreferences/audio.md - Sound effects, music playback, audio controlsreferences/rendering/primitives.md - Sprites, labels, solids, borders, layeringreferences/rendering/animation.md - frame_index, spritesheets, easing functionsWorking code in examples/:
examples/core/ - Hello world, sprites, labels, state, coordinatesexamples/input/ - Directional, keyboard, mouse, movementexamples/entities/ - Storage, factories, collision, lifecycleexamples/game-logic/ - Timers, scoring, save/load, state transitionsexamples/audio/ - Sound effects, background music, pause/resumeexamples/rendering/ - Sprites, labels, animation, layeringdef tick args
# Game logic
end
$gtk.reset # Add at end during development
$gtk.reset # Immediate reset
$gtk.reset_next_tick # Reset before next tick (safer)
args.outputs.debug << "Frame: #{Kernel.tick_count}"
args.outputs.debug.watch args.state.player