summaryrefslogtreecommitdiffhomepage
path: root/docs/docs.html
diff options
context:
space:
mode:
authorAmir Rajan <[email protected]>2021-08-07 00:14:16 -0500
committerAmir Rajan <[email protected]>2021-08-07 00:14:16 -0500
commit17d6f2a45d07932fb2ac354d4f8996c420eddc27 (patch)
tree7b1ba6b28448d4e4d13d215d86e0e611a42b9d37 /docs/docs.html
parenta503afe87619ff82201c0a43818fa1c3f070a548 (diff)
downloaddragonruby-game-toolkit-contrib-17d6f2a45d07932fb2ac354d4f8996c420eddc27.tar.gz
dragonruby-game-toolkit-contrib-17d6f2a45d07932fb2ac354d4f8996c420eddc27.zip
Docs synced.
Diffstat (limited to 'docs/docs.html')
-rw-r--r--docs/docs.html5670
1 files changed, 3978 insertions, 1692 deletions
diff --git a/docs/docs.html b/docs/docs.html
index 39d0086..5ad5d6c 100644
--- a/docs/docs.html
+++ b/docs/docs.html
@@ -1,7 +1,8 @@
-<html>
+<html lang="en">
<head>
+ <meta charset="utf-8">
<title>DragonRuby Game Toolkit Documentation</title>
- <link href="docs.css?ver=1617643886" rel="stylesheet" type="text/css" media="all">
+ <link href="docs.css?ver=1628311142" rel="stylesheet" type="text/css" media="all">
</head>
<body>
<div id='toc'>
@@ -10,16 +11,16 @@
<li><a class='header-1' href='#--dragonruby-game-toolkit-live-docs'>DragonRuby Game Toolkit Live Docs</a></li>
<li><a class='header-1' href='#--hello-world'>Hello World</a></li>
<li><a class='header-1' href='#--join-the-discord-and-subscribe-to-the-news-letter'>Join the Discord and Subscribe to the News Letter</a></li>
-<li><a class='header-1' href='#--watch-some-intro-videos'>Watch Some Intro Videos</a></li>
-<li><a class='header-1' href='#--getting-started-tutorial'>Getting Started Tutorial</a></li>
-<ul><li><a class='header-2' href='#---introduction'>Introduction</a></li></ul><ul><li><a class='header-2' href='#---prerequisites'>Prerequisites</a></li></ul><ul><li><a class='header-2' href='#---the-game-loop'>The Game Loop</a></li></ul><ul><li><a class='header-2' href='#---breakdown-of-the--tick--method'>Breakdown Of The <code>tick</code> Method</a></li></ul><ul><li><a class='header-2' href='#---rendering-a-sprite'>Rendering A Sprite</a></li></ul><ul><li><a class='header-2' href='#---coordinate-system-and-virtual-canvas'>Coordinate System and Virtual Canvas</a></li></ul><ul><li><a class='header-2' href='#---game-state'>Game State</a></li></ul><ul><li><a class='header-2' href='#---there-is-no-delta-time'>There Is No Delta Time</a></li></ul><ul><li><a class='header-2' href='#---handling-user-input'>Handling User Input</a></li></ul><ul><li><a class='header-2' href='#---coding-on-a-raspberry-pi'>Coding On A Raspberry Pi</a></li></ul><ul><li><a class='header-2' href='#---conclusion'>Conclusion</a></li></ul><li><a class='header-1' href='#--deploying-to-itch.io'>Deploying To Itch.io</a></li>
+<li><a class='header-1' href='#--intro-videos'>Intro Videos</a></li>
+<ul><li><a class='header-2' href='#---quick-api-tour'>Quick Api Tour</a></li></ul><ul><li><a class='header-2' href='#---if-you-are-completely-new-to-ruby-and-programming'>If You Are Completely New to Ruby and Programming</a></li></ul><ul><li><a class='header-2' href='#---if-you-have-game-dev-experience'>If You Have Game Dev Experience</a></li></ul><li><a class='header-1' href='#--getting-started-tutorial'>Getting Started Tutorial</a></li>
+<ul><li><a class='header-2' href='#---introduction'>Introduction</a></li></ul><ul><li><a class='header-2' href='#---prerequisites'>Prerequisites</a></li></ul><ul><li><a class='header-2' href='#---the-game-loop'>The Game Loop</a></li></ul><ul><li><a class='header-2' href='#---breakdown-of-the--tick--method'>Breakdown Of The <code>tick</code> Method</a></li></ul><ul><li><a class='header-2' href='#---rendering-a-sprite'>Rendering A Sprite</a></li></ul><ul><li><a class='header-2' href='#---coordinate-system-and-virtual-canvas'>Coordinate System and Virtual Canvas</a></li></ul><ul><li><a class='header-2' href='#---game-state'>Game State</a></li></ul><ul><li><a class='header-2' href='#---there-is-no-delta-time'>There Is No Delta Time</a></li></ul><ul><li><a class='header-2' href='#---handling-user-input'>Handling User Input</a></li></ul><ul><li><a class='header-2' href='#---coding-on-a-raspberry-pi'>Coding On A Raspberry Pi</a></li></ul><ul><li><a class='header-2' href='#---conclusion'>Conclusion</a></li></ul><li><a class='header-1' href='#--deploying-to-itch-io'>Deploying To Itch.io</a></li>
<ul><li><a class='header-2' href='#---creating-your-game-landing-page'>Creating Your Game Landing Page</a></li></ul><ul><li><a class='header-2' href='#---update-your-game's-metadata'>Update Your Game's Metadata</a></li></ul><ul><li><a class='header-2' href='#---building-your-game-for-distribution'>Building Your Game For Distribution</a></li></ul><li><a class='header-1' href='#--deploying-to-mobile-devices'>Deploying To Mobile Devices</a></li>
<li><a class='header-1' href='#--dragonruby's-philosophy'>DragonRuby's Philosophy</a></li>
-<ul><li><a class='header-2' href='#---challenge-the-status-quo'>Challenge The Status Quo</a></li></ul><ul><li><a class='header-2' href='#---continuity-of-design'>Continuity of Design</a></li></ul><ul><li><a class='header-2' href='#---release-early-and-often'>Release Early and Often</a></li></ul><ul><li><a class='header-2' href='#---sustainable-and-ethical-monetization'>Sustainable And Ethical Monetization</a></li></ul><ul><li><a class='header-2' href='#---sustainable-and-ethical-open-source'>Sustainable And Ethical Open Source</a></li></ul><ul><li><a class='header-2' href='#---people-over-entities'>People Over Entities</a></li></ul><ul><li><a class='header-2' href='#---building-a-game-should-be-fun-and-bring-happiness'>Building A Game Should Be Fun And Bring Happiness</a></li></ul><ul><li><a class='header-2' href='#---real-world-application-drives-features'>Real World Application Drives Features</a></li></ul><li><a class='header-1' href='#--frequently-asked-questions,-comments,-and-concerns'>Frequently Asked Questions, Comments, and Concerns</a></li>
-<ul><li><a class='header-2' href='#---frequently-asked-questions'>Frequently Asked Questions</a></li></ul><ul><ul><li><a class='header-3' href='#----what-is-dragonruby-llp?'>What is DragonRuby LLP?</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----what-is-dragonruby?'>What is DragonRuby?</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----how-is-dragonruby-different-than-mri?'>How is DragonRuby different than MRI?</a></li></ul></ul><ul><li><a class='header-2' href='#---frequent-comments-about-ruby-as-a-language-choice'>Frequent Comments About Ruby as a Language Choice</a></li></ul><ul><ul><li><a class='header-3' href='#----but-ruby-is-dead.'>But Ruby is dead.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----but-ruby-is-slow.'>But Ruby is slow.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dynamic-languages-are-slow.'>Dynamic languages are slow.</a></li></ul></ul><ul><li><a class='header-2' href='#---frequent-concerns'>Frequent Concerns</a></li></ul><ul><ul><li><a class='header-3' href='#----dragonruby-is-not-open-source.-that's-not-right.'>DragonRuby is not open source. That's not right.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dragonruby-is-for-pay.-you-should-offer-a-free-version.'>DragonRuby is for pay. You should offer a free version.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----but-still,-you-should-offer-a-free-version.-so-i-can-try-it-out-and-see-if-i-like-it.'>But still, you should offer a free version. So I can try it out and see if I like it.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----i-still-think-you-should-do-a-free-version.-think-of-all-people-who-would-give-it-a-shot.'>I still think you should do a free version. Think of all people who would give it a shot.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----what-if-i-build-something-with-dragonruby,-but-dragonruby-llp-becomes-insolvent.'>What if I build something with DragonRuby, but DragonRuby LLP becomes insolvent.</a></li></ul></ul><li><a class='header-1' href='#--recipies-'>RECIPIES:</a></li>
-<ul><li><a class='header-2' href='#---how-to-determine-what-frame-you-are-on'>How To Determine What Frame You Are On</a></li></ul><ul><li><a class='header-2' href='#---how-to-get-current-framerate'>How To Get Current Framerate</a></li></ul><ul><li><a class='header-2' href='#---how-to-render-a-sprite-using-an-array'>How To Render A Sprite Using An Array</a></li></ul><ul><li><a class='header-2' href='#---more-sprite-properties-as-an-array'>More Sprite Properties As An Array</a></li></ul><ul><li><a class='header-2' href='#---different-sprite-representations'>Different Sprite Representations</a></li></ul><ul><li><a class='header-2' href='#---how-to-render-a-label'>How To Render A Label</a></li></ul><ul><li><a class='header-2' href='#---a-colored-label'>A Colored Label</a></li></ul><ul><li><a class='header-2' href='#---extended-label-properties'>Extended Label Properties</a></li></ul><ul><li><a class='header-2' href='#---rendering-a-label-as-a--hash-'>Rendering A Label As A <code>Hash</code></a></li></ul><ul><li><a class='header-2' href='#---getting-the-size-of-a-piece-of-text'>Getting The Size Of A Piece Of Text</a></li></ul><ul><li><a class='header-2' href='#---how-to-play-a-sound'>How To Play A Sound</a></li></ul><ul><li><a class='header-2' href='#---using--args.state--to-store-your-game-state'>Using <code>args.state</code> To Store Your Game State</a></li></ul><ul><li><a class='header-2' href='#---troubleshoot-performance'>Troubleshoot Performance</a></li></ul><li><a class='header-1' href='#--docs---gtk--runtime-'>DOCS: <code>GTK::Runtime</code></a></li>
+<ul><li><a class='header-2' href='#---challenge-the-status-quo'>Challenge The Status Quo</a></li></ul><ul><li><a class='header-2' href='#---continuity-of-design'>Continuity of Design</a></li></ul><ul><li><a class='header-2' href='#---release-early-and-often'>Release Early and Often</a></li></ul><ul><li><a class='header-2' href='#---sustainable-and-ethical-monetization'>Sustainable And Ethical Monetization</a></li></ul><ul><li><a class='header-2' href='#---sustainable-and-ethical-open-source'>Sustainable And Ethical Open Source</a></li></ul><ul><li><a class='header-2' href='#---people-over-entities'>People Over Entities</a></li></ul><ul><li><a class='header-2' href='#---building-a-game-should-be-fun-and-bring-happiness'>Building A Game Should Be Fun And Bring Happiness</a></li></ul><ul><li><a class='header-2' href='#---real-world-application-drives-features'>Real World Application Drives Features</a></li></ul><li><a class='header-1' href='#--frequently-asked-questions--comments--and-concerns'>Frequently Asked Questions, Comments, and Concerns</a></li>
+<ul><li><a class='header-2' href='#---frequently-asked-questions'>Frequently Asked Questions</a></li></ul><ul><ul><li><a class='header-3' href='#----what-is-dragonruby-llp-'>What is DragonRuby LLP?</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----what-is-dragonruby-'>What is DragonRuby?</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----how-is-dragonruby-different-than-mri-'>How is DragonRuby different than MRI?</a></li></ul></ul><ul><li><a class='header-2' href='#---frequent-comments-about-ruby-as-a-language-choice'>Frequent Comments About Ruby as a Language Choice</a></li></ul><ul><ul><li><a class='header-3' href='#----but-ruby-is-dead-'>But Ruby is dead.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----but-ruby-is-slow-'>But Ruby is slow.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dynamic-languages-are-slow-'>Dynamic languages are slow.</a></li></ul></ul><ul><li><a class='header-2' href='#---frequent-concerns'>Frequent Concerns</a></li></ul><ul><ul><li><a class='header-3' href='#----dragonruby-is-not-open-source--that's-not-right-'>DragonRuby is not open source. That's not right.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dragonruby-is-for-pay--you-should-offer-a-free-version-'>DragonRuby is for pay. You should offer a free version.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----but-still--you-should-offer-a-free-version--so-i-can-try-it-out-and-see-if-i-like-it-'>But still, you should offer a free version. So I can try it out and see if I like it.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----i-still-think-you-should-do-a-free-version--think-of-all-people-who-would-give-it-a-shot-'>I still think you should do a free version. Think of all people who would give it a shot.</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----what-if-i-build-something-with-dragonruby--but-dragonruby-llp-becomes-insolvent-'>What if I build something with DragonRuby, but DragonRuby LLP becomes insolvent.</a></li></ul></ul><li><a class='header-1' href='#--recipies-'>RECIPIES:</a></li>
+<ul><li><a class='header-2' href='#---how-to-determine-what-frame-you-are-on'>How To Determine What Frame You Are On</a></li></ul><ul><li><a class='header-2' href='#---how-to-get-current-framerate'>How To Get Current Framerate</a></li></ul><ul><li><a class='header-2' href='#---how-to-render-a-sprite-using-an-array'>How To Render A Sprite Using An Array</a></li></ul><ul><li><a class='header-2' href='#---more-sprite-properties-as-an-array'>More Sprite Properties As An Array</a></li></ul><ul><li><a class='header-2' href='#---different-sprite-representations'>Different Sprite Representations</a></li></ul><ul><li><a class='header-2' href='#---how-to-render-a-label'>How To Render A Label</a></li></ul><ul><li><a class='header-2' href='#---a-colored-label'>A Colored Label</a></li></ul><ul><li><a class='header-2' href='#---extended-label-properties'>Extended Label Properties</a></li></ul><ul><li><a class='header-2' href='#---rendering-a-label-as-a--hash-'>Rendering A Label As A <code>Hash</code></a></li></ul><ul><li><a class='header-2' href='#---getting-the-size-of-a-piece-of-text'>Getting The Size Of A Piece Of Text</a></li></ul><ul><li><a class='header-2' href='#---rendering-labels-with-new-line-characters-and-wrapping'>Rendering Labels With New Line Characters And Wrapping</a></li></ul><ul><li><a class='header-2' href='#---how-to-play-a-sound'>How To Play A Sound</a></li></ul><ul><li><a class='header-2' href='#---using--args-state--to-store-your-game-state'>Using <code>args.state</code> To Store Your Game State</a></li></ul><ul><li><a class='header-2' href='#---troubleshoot-performance'>Troubleshoot Performance</a></li></ul><li><a class='header-1' href='#--docs---gtk--runtime-'>DOCS: <code>GTK::Runtime</code></a></li>
<li><a class='header-1' href='#--summary---def-tick-args;-end;-'>SUMMARY: <code>def tick args; end;</code></a></li>
-<ul><li><a class='header-2' href='#----args.state-'><code>args.state</code></a></li></ul><ul><ul><li><a class='header-3' href='#-----.-.entity_id-'><code>.*.entity_id</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.-.entity_type-'><code>.*.entity_type</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.-.created_at-'><code>.*.created_at</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.-.created_at_elapsed-'><code>.*.created_at_elapsed</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.-.global_created_at-'><code>.*.global_created_at</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.-.global_created_at_elapsed-'><code>.*.global_created_at_elapsed</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.-.as_hash-'><code>.*.as_hash</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.new_entity-'><code>.new_entity</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.new_entity_strict-'><code>.new_entity_strict</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.tick_count-'><code>.tick_count</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args.inputs-'><code>args.inputs</code></a></li></ul><ul><ul><li><a class='header-3' href='#-----.up-'><code>.up</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.down-'><code>.down</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.left-'><code>.left</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.right-'><code>.right</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.left_right-'><code>.left_right</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.up_down-'><code>.up_down</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.text--or--.history-'><code>.text</code> OR <code>.history</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.mouse-'><code>.mouse</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.controller_one-,--.controller_two-'><code>.controller_one</code>, <code>.controller_two</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.keyboard-'><code>.keyboard</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args.outputs-'><code>args.outputs</code></a></li></ul><ul><ul><li><a class='header-3' href='#-----.background_color-'><code>.background_color</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.sounds-'><code>.sounds</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.solids-'><code>.solids</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.static_solids-'><code>.static_solids</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.sprites-,--.static_sprites-'><code>.sprites</code>, <code>.static_sprites</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.primitives-,--.static_primitives-'><code>.primitives</code>, <code>.static_primitives</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.labels-,--.static_labels-'><code>.labels</code>, <code>.static_labels</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.lines-,--.static_lines-'><code>.lines</code>, <code>.static_lines</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.borders-,--.static_borders-'><code>.borders</code>, <code>.static_borders</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.debug-,--.static_debug-'><code>.debug</code>, <code>.static_debug</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args.geometry-'><code>args.geometry</code></a></li></ul><ul><ul><li><a class='header-3' href='#-----.inside_rect?-rect_1,-rect_2-'><code>.inside_rect? rect_1, rect_2</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.intersect_rect?-rect_2,-rect_2-'><code>.intersect_rect? rect_2, rect_2</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.scale_rect-rect,-x_percentage,-y_percentage-'><code>.scale_rect rect, x_percentage, y_percentage</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.angle_to-start_point,-end_point-'><code>.angle_to start_point, end_point</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.angle_from-start_point,-end_point-'><code>.angle_from start_point, end_point</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.point_inside_circle?-point,-circle_center_point,-radius-'><code>.point_inside_circle? point, circle_center_point, radius</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.center_inside_rect-rect,-other_rect-'><code>.center_inside_rect rect, other_rect</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.center_inside_rect_x-rect,-other_rect-'><code>.center_inside_rect_x rect, other_rect</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.center_inside_rect_y-rect,-other_rect-'><code>.center_inside_rect_y rect, other_rect</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.anchor_rect-rect,-anchor_x,-anchor_y-'><code>.anchor_rect rect, anchor_x, anchor_y</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.shift_line-line,-x,-y-'><code>.shift_line line, x, y</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.line_y_intercept-line-'><code>.line_y_intercept line</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.angle_between_lines-line_one,-line_two,-replace_infinity--'><code>.angle_between_lines line_one, line_two, replace_infinity:</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.line_slope-line,-replace_infinity--'><code>.line_slope line, replace_infinity:</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.line_rise_run-'><code>.line_rise_run</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.ray_test-point,-line-'><code>.ray_test point, line</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.line_rect-line-'><code>.line_rect line</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.line_intersect-line_one,-line_two-'><code>.line_intersect line_one, line_two</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.distance-point_one,-point_two-'><code>.distance point_one, point_two</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.cubic_bezier-t,-a,-b,-c,-d-'><code>.cubic_bezier t, a, b, c, d</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args.easing-'><code>args.easing</code></a></li></ul><ul><ul><li><a class='header-3' href='#-----.ease-start_tick,-current_tick,-duration,-easing_functions-'><code>.ease start_tick, current_tick, duration, easing_functions</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.ease_spline-start_tick,-current_tick,-duration,-spline-'><code>.ease_spline start_tick, current_tick, duration, spline</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args.string-'><code>args.string</code></a></li></ul><ul><ul><li><a class='header-3' href='#-----.wrapped_lines-string,-max_character_length-'><code>.wrapped_lines string, max_character_length</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args.grid-'><code>args.grid</code></a></li></ul><ul><ul><li><a class='header-3' href='#-----.name-'><code>.name</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.bottom-'><code>.bottom</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.top-'><code>.top</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.left-'><code>.left</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.right-'><code>.right</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.rect-'><code>.rect</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.origin_bottom_left!-'><code>.origin_bottom_left!</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.origin_center!-'><code>.origin_center!</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.w-'><code>.w</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.h-'><code>.h</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args.gtk-'><code>args.gtk</code></a></li></ul><ul><ul><li><a class='header-3' href='#-----.argv-'><code>.argv</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.platform-'><code>.platform</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.request_quit-'><code>.request_quit</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.write_file-path,-contents-'><code>.write_file path, contents</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.write_file_root-'><code>.write_file_root</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.append_file-path,-contents-'><code>.append_file path, contents</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.append_file_root-path,-contents-'><code>.append_file_root path, contents</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.read_file-path-'><code>.read_file path</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.parse_xml-string,-parse_xml_file-path-'><code>.parse_xml string, parse_xml_file path</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.parse_json-string,-parse_json_file-path-'><code>.parse_json string, parse_json_file path</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.http_get-url,-extra_headers-=-{}-'><code>.http_get url, extra_headers = {}</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.http_post-url,-form_fields-=-{},-extra_headers-=-{}-'><code>.http_post url, form_fields = {}, extra_headers = {}</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.reset-'><code>.reset</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.stop_music-'><code>.stop_music</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.calcstringbox-str,-size_enum,-font-'><code>.calcstringbox str, size_enum, font</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.slowmo!-factor-'><code>.slowmo! factor</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.notify!-string-'><code>.notify! string</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.system-'><code>.system</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.exec-'><code>.exec</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.save_state-'><code>.save_state</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.load_state-'><code>.load_state</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.serialize_state-file,-state-'><code>.serialize_state file, state</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.deserialize_state-file-'><code>.deserialize_state file</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.reset_sprite-path-'><code>.reset_sprite path</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.show_cursor-'><code>.show_cursor</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.hide_cursor-'><code>.hide_cursor</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.cursor_shown?-'><code>.cursor_shown?</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.set_window_fullscreen-enabled-'><code>.set_window_fullscreen enabled</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.openurl-url-'><code>.openurl url</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.get_base_dir-'><code>.get_base_dir</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#-----.get_game_dir-'><code>.get_game_dir</code></a></li></ul></ul><li><a class='header-1' href='#--docs---gtk--runtime#reset-'>DOCS: <code>GTK::Runtime#reset</code></a></li>
+<ul><li><a class='header-2' href='#----args-state-'><code>args.state</code></a></li></ul><ul><ul><li><a class='header-3' href='#--------entity_id-'><code>.*.entity_id</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#--------entity_type-'><code>.*.entity_type</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#--------created_at-'><code>.*.created_at</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#--------created_at_elapsed-'><code>.*.created_at_elapsed</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#--------global_created_at-'><code>.*.global_created_at</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#--------global_created_at_elapsed-'><code>.*.global_created_at_elapsed</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#--------as_hash-'><code>.*.as_hash</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------new_entity-'><code>.new_entity</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------new_entity_strict-'><code>.new_entity_strict</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------tick_count-'><code>.tick_count</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args-inputs-'><code>args.inputs</code></a></li></ul><ul><ul><li><a class='header-3' href='#------up-'><code>.up</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------down-'><code>.down</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------left-'><code>.left</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------right-'><code>.right</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------left_right-'><code>.left_right</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------up_down-'><code>.up_down</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------text--or---history-'><code>.text</code> OR <code>.history</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------mouse-'><code>.mouse</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------controller_one-----controller_two-'><code>.controller_one</code>, <code>.controller_two</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------keyboard-'><code>.keyboard</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args-outputs-'><code>args.outputs</code></a></li></ul><ul><ul><li><a class='header-3' href='#------background_color-'><code>.background_color</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------sounds-'><code>.sounds</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------solids-'><code>.solids</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------static_solids-'><code>.static_solids</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------sprites-----static_sprites-'><code>.sprites</code>, <code>.static_sprites</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------primitives-----static_primitives-'><code>.primitives</code>, <code>.static_primitives</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------labels-----static_labels-'><code>.labels</code>, <code>.static_labels</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------lines-----static_lines-'><code>.lines</code>, <code>.static_lines</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------borders-----static_borders-'><code>.borders</code>, <code>.static_borders</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------debug-----static_debug-'><code>.debug</code>, <code>.static_debug</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args-geometry-'><code>args.geometry</code></a></li></ul><ul><ul><li><a class='header-3' href='#------inside_rect--rect_1--rect_2-'><code>.inside_rect? rect_1, rect_2</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------intersect_rect--rect_2--rect_2-'><code>.intersect_rect? rect_2, rect_2</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------scale_rect-rect--x_percentage--y_percentage-'><code>.scale_rect rect, x_percentage, y_percentage</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------angle_to-start_point--end_point-'><code>.angle_to start_point, end_point</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------angle_from-start_point--end_point-'><code>.angle_from start_point, end_point</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------point_inside_circle--point--circle_center_point--radius-'><code>.point_inside_circle? point, circle_center_point, radius</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------center_inside_rect-rect--other_rect-'><code>.center_inside_rect rect, other_rect</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------center_inside_rect_x-rect--other_rect-'><code>.center_inside_rect_x rect, other_rect</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------center_inside_rect_y-rect--other_rect-'><code>.center_inside_rect_y rect, other_rect</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------anchor_rect-rect--anchor_x--anchor_y-'><code>.anchor_rect rect, anchor_x, anchor_y</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------shift_line-line--x--y-'><code>.shift_line line, x, y</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------line_y_intercept-line-'><code>.line_y_intercept line</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------angle_between_lines-line_one--line_two--replace_infinity--'><code>.angle_between_lines line_one, line_two, replace_infinity:</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------line_slope-line--replace_infinity--'><code>.line_slope line, replace_infinity:</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------line_rise_run-'><code>.line_rise_run</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------ray_test-point--line-'><code>.ray_test point, line</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------line_rect-line-'><code>.line_rect line</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------line_intersect-line_one--line_two-'><code>.line_intersect line_one, line_two</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------distance-point_one--point_two-'><code>.distance point_one, point_two</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------cubic_bezier-t--a--b--c--d-'><code>.cubic_bezier t, a, b, c, d</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args-easing-'><code>args.easing</code></a></li></ul><ul><ul><li><a class='header-3' href='#------ease-start_tick--current_tick--duration--easing_functions-'><code>.ease start_tick, current_tick, duration, easing_functions</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------ease_spline-start_tick--current_tick--duration--spline-'><code>.ease_spline start_tick, current_tick, duration, spline</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args-string-'><code>args.string</code></a></li></ul><ul><ul><li><a class='header-3' href='#------wrapped_lines-string--max_character_length-'><code>.wrapped_lines string, max_character_length</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args-grid-'><code>args.grid</code></a></li></ul><ul><ul><li><a class='header-3' href='#------name-'><code>.name</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------bottom-'><code>.bottom</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------top-'><code>.top</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------left-'><code>.left</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------right-'><code>.right</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------rect-'><code>.rect</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------origin_bottom_left!-'><code>.origin_bottom_left!</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------origin_center!-'><code>.origin_center!</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------w-'><code>.w</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------h-'><code>.h</code></a></li></ul></ul><ul><li><a class='header-2' href='#----args-gtk-'><code>args.gtk</code></a></li></ul><ul><ul><li><a class='header-3' href='#------argv-'><code>.argv</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------platform-'><code>.platform</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------request_quit-'><code>.request_quit</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------write_file-path--contents-'><code>.write_file path, contents</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------write_file_root-'><code>.write_file_root</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------append_file-path--contents-'><code>.append_file path, contents</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------append_file_root-path--contents-'><code>.append_file_root path, contents</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------read_file-path-'><code>.read_file path</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------parse_xml-string--parse_xml_file-path-'><code>.parse_xml string, parse_xml_file path</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------parse_json-string--parse_json_file-path-'><code>.parse_json string, parse_json_file path</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------http_get-url--extra_headers-=-{}-'><code>.http_get url, extra_headers = {}</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------http_post-url--form_fields-=-{}--extra_headers-=-{}-'><code>.http_post url, form_fields = {}, extra_headers = {}</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------reset-'><code>.reset</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------stop_music-'><code>.stop_music</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------calcstringbox-str--size_enum--font-'><code>.calcstringbox str, size_enum, font</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------slowmo!-factor-'><code>.slowmo! factor</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------notify!-string-'><code>.notify! string</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------system-'><code>.system</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------exec-'><code>.exec</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------save_state-'><code>.save_state</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------load_state-'><code>.load_state</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------serialize_state-file--state-'><code>.serialize_state file, state</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------deserialize_state-file-'><code>.deserialize_state file</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------reset_sprite-path-'><code>.reset_sprite path</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------show_cursor-'><code>.show_cursor</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------hide_cursor-'><code>.hide_cursor</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------cursor_shown--'><code>.cursor_shown?</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------set_window_fullscreen-enabled-'><code>.set_window_fullscreen enabled</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------openurl-url-'><code>.openurl url</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------get_base_dir-'><code>.get_base_dir</code></a></li></ul></ul><ul><ul><li><a class='header-3' href='#------get_game_dir-'><code>.get_game_dir</code></a></li></ul></ul><li><a class='header-1' href='#--docs---gtk--runtime#reset-'>DOCS: <code>GTK::Runtime#reset</code></a></li>
<li><a class='header-1' href='#--docs---gtk--runtime#calcstringbox-'>DOCS: <code>GTK::Runtime#calcstringbox</code></a></li>
<li><a class='header-1' href='#--docs---gtk--runtime#write_file-'>DOCS: <code>GTK::Runtime#write_file</code></a></li>
<li><a class='header-1' href='#--docs---array-'>DOCS: <code>Array</code></a></li>
@@ -29,28 +30,29 @@
<li><a class='header-1' href='#--docs---array#reject_false-'>DOCS: <code>Array#reject_false</code></a></li>
<li><a class='header-1' href='#--docs---array#product-'>DOCS: <code>Array#product</code></a></li>
<li><a class='header-1' href='#--docs---array#map_2d-'>DOCS: <code>Array#map_2d</code></a></li>
-<li><a class='header-1' href='#--docs---array#include_any?-'>DOCS: <code>Array#include_any?</code></a></li>
-<li><a class='header-1' href='#--docs---array#any_intersect_rect?-'>DOCS: <code>Array#any_intersect_rect?</code></a></li>
+<li><a class='header-1' href='#--docs---array#include_any--'>DOCS: <code>Array#include_any?</code></a></li>
+<li><a class='header-1' href='#--docs---array#any_intersect_rect--'>DOCS: <code>Array#any_intersect_rect?</code></a></li>
<li><a class='header-1' href='#--docs---gtk--args#audio-'>DOCS: <code>GTK::Args#audio</code></a></li>
<ul><li><a class='header-2' href='#---audio-synthesis-(pro-only)'>Audio synthesis (Pro only)</a></li></ul><ul><ul><li><a class='header-3' href='#----sound-source'>Sound source</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----example-'>Example:</a></li></ul></ul><li><a class='header-1' href='#--docs---gtk--outputs-'>DOCS: <code>GTK::Outputs</code></a></li>
<li><a class='header-1' href='#--docs---gtk--outputs#solids-'>DOCS: <code>GTK::Outputs#solids</code></a></li>
<ul><li><a class='header-2' href='#---rendering-a-solid-using-an-array'>Rendering a solid using an Array</a></li></ul><ul><li><a class='header-2' href='#---rendering-a-solid-using-an-array-with-colors-and-alpha'>Rendering a solid using an Array with colors and alpha</a></li></ul><ul><li><a class='header-2' href='#---rendering-a-solid-using-a-hash'>Rendering a solid using a Hash</a></li></ul><ul><li><a class='header-2' href='#---rendering-a-solid-using-a-class'>Rendering a solid using a Class</a></li></ul><li><a class='header-1' href='#--docs---gtk--outputs#borders-'>DOCS: <code>GTK::Outputs#borders</code></a></li>
-<li><a class='header-1' href='#--docs---gtk--outputs#screenshots-'>DOCS: <code>GTK::Outputs#screenshots</code></a></li>
+<li><a class='header-1' href='#--docs---gtk--outputs#sprites-'>DOCS: <code>GTK::Outputs#sprites</code></a></li>
+<ul><li><a class='header-2' href='#---rendering-a-sprite-using-an-array'>Rendering a sprite using an Array</a></li></ul><ul><li><a class='header-2' href='#---rendering-a-sprite-using-an-array-with-colors-and-alpha'>Rendering a sprite using an Array with colors and alpha</a></li></ul><ul><li><a class='header-2' href='#---rendering-a-sprite-using-a-hash'>Rendering a sprite using a Hash</a></li></ul><ul><li><a class='header-2' href='#---rendering-a-solid-using-a-class'>Rendering a solid using a Class</a></li></ul><li><a class='header-1' href='#--docs---gtk--outputs#screenshots-'>DOCS: <code>GTK::Outputs#screenshots</code></a></li>
<ul><li><a class='header-2' href='#---chroma-key-(making-a-color-transparent)'>Chroma key (Making a color transparent)</a></li></ul><li><a class='header-1' href='#--docs---gtk--mouse-'>DOCS: <code>GTK::Mouse</code></a></li>
<li><a class='header-1' href='#--docs---gtk--mousepoint-'>DOCS: <code>GTK::MousePoint</code></a></li>
<li><a class='header-1' href='#--docs---gtk--openentity-'>DOCS: <code>GTK::OpenEntity</code></a></li>
<li><a class='header-1' href='#--docs---gtk--openentity#as_hash-'>DOCS: <code>GTK::OpenEntity#as_hash</code></a></li>
<li><a class='header-1' href='#--docs---numeric#frame_index-'>DOCS: <code>Numeric#frame_index</code></a></li>
<li><a class='header-1' href='#--docs---numeric#elapsed_time-'>DOCS: <code>Numeric#elapsed_time</code></a></li>
-<li><a class='header-1' href='#--docs---numeric#elapsed?-'>DOCS: <code>Numeric#elapsed?</code></a></li>
-<li><a class='header-1' href='#--docs---numeric#created?-'>DOCS: <code>Numeric#created?</code></a></li>
+<li><a class='header-1' href='#--docs---numeric#elapsed--'>DOCS: <code>Numeric#elapsed?</code></a></li>
+<li><a class='header-1' href='#--docs---numeric#created--'>DOCS: <code>Numeric#created?</code></a></li>
<li><a class='header-1' href='#--docs---kernel-'>DOCS: <code>Kernel</code></a></li>
<li><a class='header-1' href='#--docs---kernel--tick_count-'>DOCS: <code>Kernel::tick_count</code></a></li>
<li><a class='header-1' href='#--docs---kernel--global_tick_count-'>DOCS: <code>Kernel::global_tick_count</code></a></li>
<li><a class='header-1' href='#--docs---geometry-'>DOCS: <code>Geometry</code></a></li>
<li><a class='header-1' href='#--docs---gtk--geometry#scale_rect-'>DOCS: <code>GTK::Geometry#scale_rect</code></a></li>
<li><a class='header-1' href='#--source-code'>Source Code</a></li>
-<ul><li><a class='header-2' href='#---samples'>Samples</a></li></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---beginner-ruby-primer---automation.rb'>Learn Ruby Optional - Beginner Ruby Primer - automation.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---beginner-ruby-primer---main.rb'>Learn Ruby Optional - Beginner Ruby Primer - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---printing.txt'>Learn Ruby Optional - Intermediate Ruby Primer - printing.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---strings.txt'>Learn Ruby Optional - Intermediate Ruby Primer - strings.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---numbers.txt'>Learn Ruby Optional - Intermediate Ruby Primer - numbers.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---booleans.txt'>Learn Ruby Optional - Intermediate Ruby Primer - booleans.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---conditionals.txt'>Learn Ruby Optional - Intermediate Ruby Primer - conditionals.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---looping.txt'>Learn Ruby Optional - Intermediate Ruby Primer - looping.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---functions.txt'>Learn Ruby Optional - Intermediate Ruby Primer - functions.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---arrays.txt'>Learn Ruby Optional - Intermediate Ruby Primer - arrays.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---main.rb'>Learn Ruby Optional - Intermediate Ruby Primer - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---labels---main.rb'>Rendering Basics - Labels - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---lines---main.rb'>Rendering Basics - Lines - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---solids-borders---main.rb'>Rendering Basics - Solids Borders - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---sprites---main.rb'>Rendering Basics - Sprites - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---sounds---main.rb'>Rendering Basics - Sounds - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---audio-mixer---main.rb'>Rendering Basics - Audio Mixer - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---sound-synthesis---main.rb'>Rendering Basics - Sound Synthesis - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---keyboard---main.rb'>Input Basics - Keyboard - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---mouse---main.rb'>Input Basics - Mouse - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---mouse-point-to-rect---main.rb'>Input Basics - Mouse Point To Rect - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---mouse-rect-to-rect---main.rb'>Input Basics - Mouse Rect To Rect - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---controller---main.rb'>Input Basics - Controller - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---touch---main.rb'>Input Basics - Touch - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-sprites---animation-using-separate-pngs---main.rb'>Rendering Sprites - Animation Using Separate Pngs - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-sprites---animation-using-sprite-sheet---main.rb'>Rendering Sprites - Animation Using Sprite Sheet - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-sprites---animation-states---main.rb'>Rendering Sprites - Animation States - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-sprites---color-and-rotation---main.rb'>Rendering Sprites - Color And Rotation - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---simple---main.rb'>Physics And Collisions - Simple - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---moving-objects---main.rb'>Physics And Collisions - Moving Objects - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---entities---main.rb'>Physics And Collisions - Entities - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---box-collision---main.rb'>Physics And Collisions - Box Collision - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---box-collision-2---main.rb'>Physics And Collisions - Box Collision 2 - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---box-collision-3---main.rb'>Physics And Collisions - Box Collision 3 - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---jump-physics---main.rb'>Physics And Collisions - Jump Physics - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---ball.rb'>Physics And Collisions - Bouncing On Collision - ball.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---block.rb'>Physics And Collisions - Bouncing On Collision - block.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---cannon.rb'>Physics And Collisions - Bouncing On Collision - cannon.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---main.rb'>Physics And Collisions - Bouncing On Collision - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---peg.rb'>Physics And Collisions - Bouncing On Collision - peg.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---vector2d.rb'>Physics And Collisions - Bouncing On Collision - vector2d.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---ball.rb'>Physics And Collisions - Arbitrary Collision - ball.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---blocks.rb'>Physics And Collisions - Arbitrary Collision - blocks.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---linear_collider.rb'>Physics And Collisions - Arbitrary Collision - linear_collider.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---main.rb'>Physics And Collisions - Arbitrary Collision - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---paddle.rb'>Physics And Collisions - Arbitrary Collision - paddle.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---rectangle.rb'>Physics And Collisions - Arbitrary Collision - rectangle.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---square_collider.rb'>Physics And Collisions - Arbitrary Collision - square_collider.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---vector2d.rb'>Physics And Collisions - Arbitrary Collision - vector2d.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---ball.rb'>Physics And Collisions - Collision With Object Removal - ball.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---linear_collider.rb'>Physics And Collisions - Collision With Object Removal - linear_collider.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---main.rb'>Physics And Collisions - Collision With Object Removal - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---paddle.rb'>Physics And Collisions - Collision With Object Removal - paddle.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---tests.rb'>Physics And Collisions - Collision With Object Removal - tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---vector2d.rb'>Physics And Collisions - Collision With Object Removal - vector2d.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----mouse---mouse-click---main.rb'>Mouse - Mouse Click - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----mouse---mouse-move---main.rb'>Mouse - Mouse Move - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----mouse---mouse-move-paint-app---main.rb'>Mouse - Mouse Move Paint App - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----mouse---coordinate-systems---main.rb'>Mouse - Coordinate Systems - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----save-load---save-load-game---main.rb'>Save Load - Save Load Game - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---simple-render-targets---main.rb'>Advanced Rendering - Simple Render Targets - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---render-targets-with-tile-manipulation---main.rb'>Advanced Rendering - Render Targets With Tile Manipulation - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---render-target-viewports---main.rb'>Advanced Rendering - Render Target Viewports - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---render-primitive-hierarchies---main.rb'>Advanced Rendering - Render Primitive Hierarchies - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---render-primitives-as-hash---main.rb'>Advanced Rendering - Render Primitives As Hash - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---pixel-arrays---main.rb'>Advanced Rendering - Pixel Arrays - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---splitscreen-camera---main.rb'>Advanced Rendering - Splitscreen Camera - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---z-targeting-camera---main.rb'>Advanced Rendering - Z Targeting Camera - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----tweening-lerping-easing-functions---easing-functions---main.rb'>Tweening Lerping Easing Functions - Easing Functions - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----tweening-lerping-easing-functions---cubic-bezier---main.rb'>Tweening Lerping Easing Functions - Cubic Bezier - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----tweening-lerping-easing-functions---easing-using-spline---main.rb'>Tweening Lerping Easing Functions - Easing Using Spline - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----tweening-lerping-easing-functions---parametric-enemy-movement---main.rb'>Tweening Lerping Easing Functions - Parametric Enemy Movement - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---sprites-as-hash---main.rb'>Performance - Sprites As Hash - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---sprites-as-entities---main.rb'>Performance - Sprites As Entities - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---sprites-as-strict-entities---main.rb'>Performance - Sprites As Strict Entities - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---sprites-as-classes---main.rb'>Performance - Sprites As Classes - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---static-sprites-as-classes---main.rb'>Performance - Static Sprites As Classes - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---static-sprites-as-classes-with-custom-drawing---main.rb'>Performance - Static Sprites As Classes With Custom Drawing - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---collision-limits---main.rb'>Performance - Collision Limits - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---trace-debugging---main.rb'>Advanced Debugging - Trace Debugging - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---trace-debugging-classes---main.rb'>Advanced Debugging - Trace Debugging Classes - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---exception_raising_tests.rb'>Advanced Debugging - Unit Tests - exception_raising_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---fn_tests.rb'>Advanced Debugging - Unit Tests - fn_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---gen_docs.rb'>Advanced Debugging - Unit Tests - gen_docs.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---geometry_tests.rb'>Advanced Debugging - Unit Tests - geometry_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---http_tests.rb'>Advanced Debugging - Unit Tests - http_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---nil_coercion_tests.rb'>Advanced Debugging - Unit Tests - nil_coercion_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---object_to_primitive_tests.rb'>Advanced Debugging - Unit Tests - object_to_primitive_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---parsing_tests.rb'>Advanced Debugging - Unit Tests - parsing_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---require_tests.rb'>Advanced Debugging - Unit Tests - require_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---serialize_deserialize_tests.rb'>Advanced Debugging - Unit Tests - serialize_deserialize_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---state_serialization_experimental_tests.rb'>Advanced Debugging - Unit Tests - state_serialization_experimental_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---suggest_autocompletion_tests.rb'>Advanced Debugging - Unit Tests - suggest_autocompletion_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----http---retrieve-images---main.rb'>Http - Retrieve Images - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----http---web-server---main.rb'>Http - Web Server - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----c-extensions---basics---main.rb'>C Extensions - Basics - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----c-extensions---intermediate---main.rb'>C Extensions - Intermediate - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----c-extensions---native-pixel-arrays---main.rb'>C Extensions - Native Pixel Arrays - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---breadth-first-search---main.rb'>Path Finding Algorithms - Breadth First Search - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---detailed-breadth-first-search---main.rb'>Path Finding Algorithms - Detailed Breadth First Search - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---breadcrumbs---main.rb'>Path Finding Algorithms - Breadcrumbs - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---early-exit---main.rb'>Path Finding Algorithms - Early Exit - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---dijkstra---main.rb'>Path Finding Algorithms - Dijkstra - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---heuristic---main.rb'>Path Finding Algorithms - Heuristic - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---heuristic-with-walls---main.rb'>Path Finding Algorithms - Heuristic With Walls - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---a-star---main.rb'>Path Finding Algorithms - A Star - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---tower-defense---main.rb'>Path Finding Algorithms - Tower Defense - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----3d---3d-cube---main.rb'>3d - 3d Cube - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----3d---wireframe---main.rb'>3d - Wireframe - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----3d---wireframe---data---what-is-this.txt'>3d - Wireframe - Data - what-is-this.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---bullet-hell---main.rb'>Arcade - Bullet Hell - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---dueling-starships---main.rb'>Arcade - Dueling Starships - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade/flappy-dragon/credits.txt'>arcade/flappy dragon/credits.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade/flappy-dragon/main.rb'>arcade/flappy dragon/main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---pong---main.rb'>Arcade - Pong - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---snakemoji---main.rb'>Arcade - Snakemoji - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---solar-system---main.rb'>Arcade - Solar System - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---sound-golf---main.rb'>Arcade - Sound Golf - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---twinstick---main.rb'>Arcade - Twinstick - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----crafting---craft-game-starting-point---main.rb'>Crafting - Craft Game Starting Point - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dev-tools---add-buttons-to-console---main.rb'>Dev Tools - Add Buttons To Console - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dev-tools---animation-creator-starting-point---main.rb'>Dev Tools - Animation Creator Starting Point - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dev-tools---tile-editor-starting-point---main.rb'>Dev Tools - Tile Editor Starting Point - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----lowrez---nokia-3310---main.rb'>Lowrez - Nokia 3310 - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----lowrez---nokia-3310---nokia.rb'>Lowrez - Nokia 3310 - nokia.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----lowrez---resolution-64x64---lowrez.rb'>Lowrez - Resolution 64x64 - lowrez.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----lowrez---resolution-64x64---main.rb'>Lowrez - Resolution 64x64 - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---clepto-frog---main.rb'>Platformer - Clepto Frog - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---clepto-frog---map.rb'>Platformer - Clepto Frog - map.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---gorillas-basic---credits.txt'>Platformer - Gorillas Basic - credits.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---gorillas-basic---main.rb'>Platformer - Gorillas Basic - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---gorillas-basic---tests.rb'>Platformer - Gorillas Basic - tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---gorillas-basic---tests---building_generation_tests.rb'>Platformer - Gorillas Basic - Tests - building_generation_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---the-little-probe---main.rb'>Platformer - The Little Probe - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---the-little-probe---data---level.txt'>Platformer - The Little Probe - Data - level.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---the-little-probe---data---level_lava.txt'>Platformer - The Little Probe - Data - level_lava.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---choose-your-own-adventure---decision.rb'>Rpg Narrative - Choose Your Own Adventure - decision.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---choose-your-own-adventure---main.rb'>Rpg Narrative - Choose Your Own Adventure - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---lowrez_simulator.rb'>Rpg Narrative - Return Of Serenity - lowrez_simulator.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---main.rb'>Rpg Narrative - Return Of Serenity - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---require.rb'>Rpg Narrative - Return Of Serenity - require.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline.rb'>Rpg Narrative - Return Of Serenity - storyline.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_anka.rb'>Rpg Narrative - Return Of Serenity - storyline_anka.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_blinking_light.rb'>Rpg Narrative - Return Of Serenity - storyline_blinking_light.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_day_one.rb'>Rpg Narrative - Return Of Serenity - storyline_day_one.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_final_decision.rb'>Rpg Narrative - Return Of Serenity - storyline_final_decision.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_final_message.rb'>Rpg Narrative - Return Of Serenity - storyline_final_message.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_serenity_alive.rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_alive.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_serenity_bio.rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_bio.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_serenity_introduction.rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_introduction.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_speed_of_light.rb'>Rpg Narrative - Return Of Serenity - storyline_speed_of_light.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-roguelike---roguelike-starting-point---constants.rb'>Rpg Roguelike - Roguelike Starting Point - constants.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-roguelike---roguelike-starting-point---legend.rb'>Rpg Roguelike - Roguelike Starting Point - legend.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-roguelike---roguelike-starting-point---main.rb'>Rpg Roguelike - Roguelike Starting Point - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-roguelike---roguelike-starting-point---sprite_lookup.rb'>Rpg Roguelike - Roguelike Starting Point - sprite_lookup.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-roguelike---roguelike-line-of-sight---main.rb'>Rpg Roguelike - Roguelike Line Of Sight - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-tactical---hexagonal-grid---main.rb'>Rpg Tactical - Hexagonal Grid - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-tactical---isometric-grid---main.rb'>Rpg Tactical - Isometric Grid - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-topdown---topdown-starting-point---main.rb'>Rpg Topdown - Topdown Starting Point - main.rb</a></li></ul></ul><ul><li><a class='header-2' href='#---oss'>OSS</a></li></ul><ul><ul><li><a class='header-3' href='#----args.rb'>args.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----assert.rb'>assert.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----attr_gtk.rb'>attr_gtk.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----attr_sprite.rb'>attr_sprite.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----console.rb'>console.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----console_color.rb'>console_color.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----console_font_style.rb'>console_font_style.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----console_menu.rb'>console_menu.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----console_prompt.rb'>console_prompt.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----controller.rb'>controller.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----controller/config.rb'>controller/config.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----controller/keys.rb'>controller/keys.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----directional_input_helper_methods.rb'>directional_input_helper_methods.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----easing.rb'>easing.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----entity.rb'>entity.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----geometry.rb'>geometry.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----grid.rb'>grid.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----inputs.rb'>inputs.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----ios_wizard.rb'>ios_wizard.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----itch_wizard.rb'>itch_wizard.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----layout.rb'>layout.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----log.rb'>log.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----numeric.rb'>numeric.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----remote_hotload_client.rb'>remote_hotload_client.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/autocomplete.rb'>runtime/autocomplete.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/draw.rb'>runtime/draw.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/framerate.rb'>runtime/framerate.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/framerate_diagnostics.rb'>runtime/framerate_diagnostics.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/hotload.rb'>runtime/hotload.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----string.rb'>string.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----tests.rb'>tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----trace.rb'>trace.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----wizards.rb'>wizards.rb</a></li></ul></ul></ul> </div>
+<ul><li><a class='header-2' href='#---samples'>Samples</a></li></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---beginner-ruby-primer---automation-rb'>Learn Ruby Optional - Beginner Ruby Primer - automation.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---beginner-ruby-primer---main-rb'>Learn Ruby Optional - Beginner Ruby Primer - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---printing-txt'>Learn Ruby Optional - Intermediate Ruby Primer - printing.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---strings-txt'>Learn Ruby Optional - Intermediate Ruby Primer - strings.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---numbers-txt'>Learn Ruby Optional - Intermediate Ruby Primer - numbers.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---booleans-txt'>Learn Ruby Optional - Intermediate Ruby Primer - booleans.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---conditionals-txt'>Learn Ruby Optional - Intermediate Ruby Primer - conditionals.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---looping-txt'>Learn Ruby Optional - Intermediate Ruby Primer - looping.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---functions-txt'>Learn Ruby Optional - Intermediate Ruby Primer - functions.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---arrays-txt'>Learn Ruby Optional - Intermediate Ruby Primer - arrays.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----learn-ruby-optional---intermediate-ruby-primer---main-rb'>Learn Ruby Optional - Intermediate Ruby Primer - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---labels---main-rb'>Rendering Basics - Labels - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---lines---main-rb'>Rendering Basics - Lines - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---solids-borders---main-rb'>Rendering Basics - Solids Borders - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---sprites---main-rb'>Rendering Basics - Sprites - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-basics---sounds---main-rb'>Rendering Basics - Sounds - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---keyboard---main-rb'>Input Basics - Keyboard - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---moving-a-sprite---main-rb'>Input Basics - Moving A Sprite - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---mouse---main-rb'>Input Basics - Mouse - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---mouse-point-to-rect---main-rb'>Input Basics - Mouse Point To Rect - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---mouse-rect-to-rect---main-rb'>Input Basics - Mouse Rect To Rect - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---controller---main-rb'>Input Basics - Controller - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----input-basics---touch---main-rb'>Input Basics - Touch - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-sprites---animation-using-separate-pngs---main-rb'>Rendering Sprites - Animation Using Separate Pngs - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-sprites---animation-using-sprite-sheet---main-rb'>Rendering Sprites - Animation Using Sprite Sheet - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-sprites---animation-states---main-rb'>Rendering Sprites - Animation States - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rendering-sprites---color-and-rotation---main-rb'>Rendering Sprites - Color And Rotation - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---simple---main-rb'>Physics And Collisions - Simple - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---moving-objects---main-rb'>Physics And Collisions - Moving Objects - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---entities---main-rb'>Physics And Collisions - Entities - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---box-collision---main-rb'>Physics And Collisions - Box Collision - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---box-collision-2---main-rb'>Physics And Collisions - Box Collision 2 - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---box-collision-3---main-rb'>Physics And Collisions - Box Collision 3 - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---jump-physics---main-rb'>Physics And Collisions - Jump Physics - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---ball-rb'>Physics And Collisions - Bouncing On Collision - ball.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---block-rb'>Physics And Collisions - Bouncing On Collision - block.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---cannon-rb'>Physics And Collisions - Bouncing On Collision - cannon.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---main-rb'>Physics And Collisions - Bouncing On Collision - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---peg-rb'>Physics And Collisions - Bouncing On Collision - peg.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---bouncing-on-collision---vector2d-rb'>Physics And Collisions - Bouncing On Collision - vector2d.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---ball-rb'>Physics And Collisions - Arbitrary Collision - ball.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---blocks-rb'>Physics And Collisions - Arbitrary Collision - blocks.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---linear_collider-rb'>Physics And Collisions - Arbitrary Collision - linear_collider.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---main-rb'>Physics And Collisions - Arbitrary Collision - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---paddle-rb'>Physics And Collisions - Arbitrary Collision - paddle.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---rectangle-rb'>Physics And Collisions - Arbitrary Collision - rectangle.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---square_collider-rb'>Physics And Collisions - Arbitrary Collision - square_collider.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---arbitrary-collision---vector2d-rb'>Physics And Collisions - Arbitrary Collision - vector2d.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---ball-rb'>Physics And Collisions - Collision With Object Removal - ball.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---linear_collider-rb'>Physics And Collisions - Collision With Object Removal - linear_collider.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---main-rb'>Physics And Collisions - Collision With Object Removal - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---paddle-rb'>Physics And Collisions - Collision With Object Removal - paddle.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---tests-rb'>Physics And Collisions - Collision With Object Removal - tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----physics-and-collisions---collision-with-object-removal---vector2d-rb'>Physics And Collisions - Collision With Object Removal - vector2d.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----mouse---mouse-click---main-rb'>Mouse - Mouse Click - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----mouse---mouse-move---main-rb'>Mouse - Mouse Move - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----mouse---mouse-move-paint-app---main-rb'>Mouse - Mouse Move Paint App - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----mouse---coordinate-systems---main-rb'>Mouse - Coordinate Systems - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----save-load---save-load-game---main-rb'>Save Load - Save Load Game - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-audio---audio-mixer---main-rb'>Advanced Audio - Audio Mixer - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-audio---audio-mixer---server_ip_address-txt'>Advanced Audio - Audio Mixer - server_ip_address.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-audio---audio-mixer---metadata---ios_metadata-txt'>Advanced Audio - Audio Mixer - Metadata - ios_metadata.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-audio---sound-synthesis---main-rb'>Advanced Audio - Sound Synthesis - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---simple-render-targets---main-rb'>Advanced Rendering - Simple Render Targets - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---render-targets-with-tile-manipulation---main-rb'>Advanced Rendering - Render Targets With Tile Manipulation - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---render-target-viewports---main-rb'>Advanced Rendering - Render Target Viewports - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---render-primitive-hierarchies---main-rb'>Advanced Rendering - Render Primitive Hierarchies - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---render-primitives-as-hash---main-rb'>Advanced Rendering - Render Primitives As Hash - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---pixel-arrays---main-rb'>Advanced Rendering - Pixel Arrays - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---simple-camera---main-rb'>Advanced Rendering - Simple Camera - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---splitscreen-camera---main-rb'>Advanced Rendering - Splitscreen Camera - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---z-targeting-camera---main-rb'>Advanced Rendering - Z Targeting Camera - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-rendering---blend-modes---main-rb'>Advanced Rendering - Blend Modes - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----tweening-lerping-easing-functions---easing-functions---main-rb'>Tweening Lerping Easing Functions - Easing Functions - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----tweening-lerping-easing-functions---cubic-bezier---main-rb'>Tweening Lerping Easing Functions - Cubic Bezier - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----tweening-lerping-easing-functions---easing-using-spline---main-rb'>Tweening Lerping Easing Functions - Easing Using Spline - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----tweening-lerping-easing-functions---parametric-enemy-movement---main-rb'>Tweening Lerping Easing Functions - Parametric Enemy Movement - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---sprites-as-hash---main-rb'>Performance - Sprites As Hash - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---sprites-as-entities---main-rb'>Performance - Sprites As Entities - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---sprites-as-strict-entities---main-rb'>Performance - Sprites As Strict Entities - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---sprites-as-classes---main-rb'>Performance - Sprites As Classes - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---static-sprites-as-classes---main-rb'>Performance - Static Sprites As Classes - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---static-sprites-as-classes-with-custom-drawing---main-rb'>Performance - Static Sprites As Classes With Custom Drawing - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----performance---collision-limits---main-rb'>Performance - Collision Limits - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---trace-debugging---main-rb'>Advanced Debugging - Trace Debugging - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---trace-debugging-classes---main-rb'>Advanced Debugging - Trace Debugging Classes - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---benchmark_api_tests-rb'>Advanced Debugging - Unit Tests - benchmark_api_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---exception_raising_tests-rb'>Advanced Debugging - Unit Tests - exception_raising_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---fn_tests-rb'>Advanced Debugging - Unit Tests - fn_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---gen_docs-rb'>Advanced Debugging - Unit Tests - gen_docs.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---geometry_tests-rb'>Advanced Debugging - Unit Tests - geometry_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---http_tests-rb'>Advanced Debugging - Unit Tests - http_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---nil_coercion_tests-rb'>Advanced Debugging - Unit Tests - nil_coercion_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---object_to_primitive_tests-rb'>Advanced Debugging - Unit Tests - object_to_primitive_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---parsing_tests-rb'>Advanced Debugging - Unit Tests - parsing_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---pretty_format_tests-rb'>Advanced Debugging - Unit Tests - pretty_format_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---require_tests-rb'>Advanced Debugging - Unit Tests - require_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---serialize_deserialize_tests-rb'>Advanced Debugging - Unit Tests - serialize_deserialize_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---state_serialization_experimental_tests-rb'>Advanced Debugging - Unit Tests - state_serialization_experimental_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----advanced-debugging---unit-tests---suggest_autocompletion_tests-rb'>Advanced Debugging - Unit Tests - suggest_autocompletion_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----http---retrieve-images---main-rb'>Http - Retrieve Images - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----http---web-server---main-rb'>Http - Web Server - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----c-extensions---basics---main-rb'>C Extensions - Basics - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----c-extensions---intermediate---main-rb'>C Extensions - Intermediate - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----c-extensions---native-pixel-arrays---main-rb'>C Extensions - Native Pixel Arrays - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---breadth-first-search---main-rb'>Path Finding Algorithms - Breadth First Search - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---detailed-breadth-first-search---main-rb'>Path Finding Algorithms - Detailed Breadth First Search - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---breadcrumbs---main-rb'>Path Finding Algorithms - Breadcrumbs - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---early-exit---main-rb'>Path Finding Algorithms - Early Exit - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---dijkstra---main-rb'>Path Finding Algorithms - Dijkstra - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---heuristic---main-rb'>Path Finding Algorithms - Heuristic - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---heuristic-with-walls---main-rb'>Path Finding Algorithms - Heuristic With Walls - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---a-star---main-rb'>Path Finding Algorithms - A Star - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----path-finding-algorithms---tower-defense---main-rb'>Path Finding Algorithms - Tower Defense - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----3d---3d-cube---main-rb'>3d - 3d Cube - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----3d---wireframe---main-rb'>3d - Wireframe - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----3d---wireframe---data---what-is-this-txt'>3d - Wireframe - Data - what-is-this.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---bullet-hell---main-rb'>Arcade - Bullet Hell - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---dueling-starships---main-rb'>Arcade - Dueling Starships - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade/flappy-dragon/credits-txt'>arcade/flappy dragon/credits.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade/flappy-dragon/main-rb'>arcade/flappy dragon/main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---pong---main-rb'>Arcade - Pong - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---snakemoji---main-rb'>Arcade - Snakemoji - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---solar-system---main-rb'>Arcade - Solar System - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---sound-golf---main-rb'>Arcade - Sound Golf - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----arcade---twinstick---main-rb'>Arcade - Twinstick - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----crafting---craft-game-starting-point---main-rb'>Crafting - Craft Game Starting Point - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----crafting---farming-game-starting-point---main-rb'>Crafting - Farming Game Starting Point - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----crafting---farming-game-starting-point---repl-rb'>Crafting - Farming Game Starting Point - repl.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----crafting---farming-game-starting-point---tests-rb'>Crafting - Farming Game Starting Point - tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dev-tools---add-buttons-to-console---main-rb'>Dev Tools - Add Buttons To Console - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dev-tools---animation-creator-starting-point---main-rb'>Dev Tools - Animation Creator Starting Point - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dev-tools---tile-editor-starting-point---main-rb'>Dev Tools - Tile Editor Starting Point - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----dungeon-crawl---classics-jam---main-rb'>Dungeon Crawl - Classics Jam - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----fighting---special-move-inputs---main-rb'>Fighting - Special Move Inputs - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----lowrez---nokia-3310---main-rb'>Lowrez - Nokia 3310 - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----lowrez---nokia-3310---nokia-rb'>Lowrez - Nokia 3310 - nokia.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----lowrez---resolution-64x64---lowrez-rb'>Lowrez - Resolution 64x64 - lowrez.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----lowrez---resolution-64x64---main-rb'>Lowrez - Resolution 64x64 - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---clepto-frog---main-rb'>Platformer - Clepto Frog - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---clepto-frog---map-rb'>Platformer - Clepto Frog - map.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---gorillas-basic---credits-txt'>Platformer - Gorillas Basic - credits.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---gorillas-basic---main-rb'>Platformer - Gorillas Basic - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---gorillas-basic---tests-rb'>Platformer - Gorillas Basic - tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---gorillas-basic---tests---building_generation_tests-rb'>Platformer - Gorillas Basic - Tests - building_generation_tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---the-little-probe---main-rb'>Platformer - The Little Probe - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---the-little-probe---data---level-txt'>Platformer - The Little Probe - Data - level.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----platformer---the-little-probe---data---level_lava-txt'>Platformer - The Little Probe - Data - level_lava.txt</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---choose-your-own-adventure---decision-rb'>Rpg Narrative - Choose Your Own Adventure - decision.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---choose-your-own-adventure---main-rb'>Rpg Narrative - Choose Your Own Adventure - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---lowrez_simulator-rb'>Rpg Narrative - Return Of Serenity - lowrez_simulator.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---main-rb'>Rpg Narrative - Return Of Serenity - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---require-rb'>Rpg Narrative - Return Of Serenity - require.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline-rb'>Rpg Narrative - Return Of Serenity - storyline.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_anka-rb'>Rpg Narrative - Return Of Serenity - storyline_anka.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_blinking_light-rb'>Rpg Narrative - Return Of Serenity - storyline_blinking_light.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_day_one-rb'>Rpg Narrative - Return Of Serenity - storyline_day_one.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_final_decision-rb'>Rpg Narrative - Return Of Serenity - storyline_final_decision.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_final_message-rb'>Rpg Narrative - Return Of Serenity - storyline_final_message.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_serenity_alive-rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_alive.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_serenity_bio-rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_bio.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_serenity_introduction-rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_introduction.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-narrative---return-of-serenity---storyline_speed_of_light-rb'>Rpg Narrative - Return Of Serenity - storyline_speed_of_light.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-roguelike---roguelike-starting-point---constants-rb'>Rpg Roguelike - Roguelike Starting Point - constants.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-roguelike---roguelike-starting-point---legend-rb'>Rpg Roguelike - Roguelike Starting Point - legend.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-roguelike---roguelike-starting-point---main-rb'>Rpg Roguelike - Roguelike Starting Point - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-roguelike---roguelike-starting-point---sprite_lookup-rb'>Rpg Roguelike - Roguelike Starting Point - sprite_lookup.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-roguelike---roguelike-line-of-sight---main-rb'>Rpg Roguelike - Roguelike Line Of Sight - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-tactical---hexagonal-grid---main-rb'>Rpg Tactical - Hexagonal Grid - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-tactical---isometric-grid---main-rb'>Rpg Tactical - Isometric Grid - main.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----rpg-topdown---topdown-starting-point---main-rb'>Rpg Topdown - Topdown Starting Point - main.rb</a></li></ul></ul><ul><li><a class='header-2' href='#---oss'>OSS</a></li></ul><ul><ul><li><a class='header-3' href='#----args-rb'>args.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----assert-rb'>assert.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----attr_gtk-rb'>attr_gtk.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----attr_sprite-rb'>attr_sprite.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----console-rb'>console.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----console_color-rb'>console_color.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----console_font_style-rb'>console_font_style.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----console_menu-rb'>console_menu.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----console_prompt-rb'>console_prompt.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----controller-rb'>controller.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----controller/config-rb'>controller/config.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----controller/keys-rb'>controller/keys.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----directional_input_helper_methods-rb'>directional_input_helper_methods.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----easing-rb'>easing.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----entity-rb'>entity.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----geometry-rb'>geometry.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----grid-rb'>grid.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----inputs-rb'>inputs.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----ios_wizard-rb'>ios_wizard.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----itch_wizard-rb'>itch_wizard.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----layout-rb'>layout.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----log-rb'>log.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----metadata-rb'>metadata.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----numeric-rb'>numeric.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----remote_hotload_client-rb'>remote_hotload_client.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/autocomplete-rb'>runtime/autocomplete.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/benchmark-rb'>runtime/benchmark.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/draw-rb'>runtime/draw.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/framerate-rb'>runtime/framerate.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/framerate_diagnostics-rb'>runtime/framerate_diagnostics.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----runtime/hotload-rb'>runtime/hotload.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----string-rb'>string.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----tests-rb'>tests.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----trace-rb'>trace.rb</a></li></ul></ul><ul><ul><li><a class='header-3' href='#----wizards-rb'>wizards.rb</a></li></ul></ul></ul> </div>
<div id='content'>
<h1 id='--dragonruby-game-toolkit-live-docs'>DragonRuby Game Toolkit Live Docs</h1>
<p>
@@ -61,9 +63,6 @@ To search docs you can type <code>docs_search "SEARCH TERM"</code> or if you wan
</p>
<pre><code class="language-ruby">docs_search { |entry| (entry.include? "Array") && (!entry.include? "Enumerable") }
</code></pre>
-<p>
-<img src='docs_search.gif'></img>
-</p>
<h1 id='--hello-world'>Hello World</h1>
<p>
Welcome to DragonRuby Game Toolkit. Take the steps below to get started.
@@ -91,21 +90,26 @@ Reply with:
I am a Dragon Rider.
</p>
</blockquote>
-<h1 id='--watch-some-intro-videos'>Watch Some Intro Videos</h1>
+<h1 id='--intro-videos'>Intro Videos</h1>
<p>
-Each video is only 20 minutes and all of them will fit into a lunch break. So please watch them:
+Here are some videos to help you get the lay of the land.
</p>
+<h2 id='---quick-api-tour'>Quick Api Tour</h2>
<ol>
<li> Beginner Introduction to DragonRuby Game Toolkit: <a href='https://youtu.be/ixw7TJhU08E'>https://youtu.be/ixw7TJhU08E</a></li>
+</ol>
+<h2 id='---if-you-are-completely-new-to-ruby-and-programming'>If You Are Completely New to Ruby and Programming</h2>
+<ol>
<li> Intermediate Introduction to Ruby Syntax: <a href='https://youtu.be/HG-XRZ5Ppgc'>https://youtu.be/HG-XRZ5Ppgc</a></li>
<li> Intermediate Introduction to Arrays in Ruby: <a href='https://youtu.be/N72sEYFRqfo'>https://youtu.be/N72sEYFRqfo</a></li>
+<li> You may also want to try this free course provided at <a href='http://dragonruby.school'>http://dragonruby.school</a>.</li>
+</ol>
+<h2 id='---if-you-have-game-dev-experience'>If You Have Game Dev Experience</h2>
+<ol>
+<li> Building Tetris - Part 1: <a href='https://youtu.be/xZMwRSbC4rY'>https://youtu.be/xZMwRSbC4rY</a></li>
+<li> Building Tetris - Part 2: <a href='https://youtu.be/C3LLzDUDgz4'>https://youtu.be/C3LLzDUDgz4</a></li>
+<li> Low Res Game Jam Tutorial: <a href='https://youtu.be/pCI90ukKCME'>https://youtu.be/pCI90ukKCME</a></li>
</ol>
-<p>
-The second and third videos are not required if you are proficient with Ruby, but *definitely* watch the first one.
-</p>
-<p>
-You may also want to try this free course provided at <a href='http://dragonruby.school'>http://dragonruby.school</a>.
-</p>
<h1 id='--getting-started-tutorial'>Getting Started Tutorial</h1>
<p>
This is a tutorial written by Ryan C Gordon (a Juggernaut in the industry who has contracted to Valve, Epic, Activision, and EA... check out his Wikipedia page: <a href='https://en.wikipedia.org/wiki/Ryan_C._Gordon'>https://en.wikipedia.org/wiki/Ryan_C._Gordon</a>).
@@ -291,7 +295,7 @@ Note that you can also run DragonRuby without X11 at all: if you run it from a v
<p>
There is a lot more you can do with DragonRuby, but now you've already got just about everything you need to make a simple game. After all, even the most fancy games are just creating objects and moving them around. Experiment a little. Add a few more things and have them interact in small ways. Want something to go away? Just don't add it to <code>args.output</code> anymore.
</p>
-<h1 id='--deploying-to-itch.io'>Deploying To Itch.io</h1>
+<h1 id='--deploying-to-itch-io'>Deploying To Itch.io</h1>
<p>
Once you've built your game, you're all set to deploy! Good luck in your game dev journey and if you get stuck, come to the Discord channel!
</p>
@@ -360,7 +364,7 @@ If you have a Pro subscription, you also have the capability to deploy to mobile
To deploy to iOS, you need to have a Mac running MacOS Catalina, an iOS device, and an active/paid Developer Account with Apple. From the Console type: <code>$wizards.ios.start</code> and you will be guided through the deployment process.
</p>
<p>
-To deploy to Android, you need to have an Android emulator/device, and a environment that is able to run Android SDK. <code>dragonruby-publish</code> will create an APK for you. From there, you can sign the APK and install it to your device. The signing and installation procedure varies from OS to OS. Here's an example of what the command might look like:
+To deploy to Android, you need to have an Android emulator/device, and an environment that is able to run Android SDK. <code>dragonruby-publish</code> will create an APK for you. From there, you can sign the APK and install it to your device. The signing and installation procedure varies from OS to OS. Here's an example of what the command might look like:
</p>
<pre><code class="language-ruby">> adb logcat -e mygame # you'll want to run this in a separate terminal
> keytool -genkey -v -keystore mygame.keystore -alias mygame -keyalg RSA -keysize 2048 -validity 10000
@@ -369,7 +373,7 @@ To deploy to Android, you need to have an Android emulator/device, and a environ
</code></pre>
<h1 id='--dragonruby's-philosophy'>DragonRuby's Philosophy</h1>
<p>
-The following tenants of DragonRuby are what set us apart from other game engines. Given that Game Toolkit is a relatively new engine, there are definitely features that are missing. So having a big check list of "all the cool things" is not this engine's forte. This is compensated with a strong commitment to the following principals.
+The following tenants of DragonRuby are what set us apart from other game engines. Given that Game Toolkit is a relatively new engine, there are definitely features that are missing. So having a big check list of "all the cool things" is not this engine's forte. This is compensated with a strong commitment to the following principles.
</p>
<h2 id='---challenge-the-status-quo'>Challenge The Status Quo</h2>
<p>
@@ -388,7 +392,7 @@ It's a hard pill to swallow, but forget blindly accepted best practices and try
There is a programming idiom in software called "The Pit of Success". The term normalizes upfront pain as a necessity/requirement in the hopes that the investment will yield dividends "when you become successful" or "when the code becomes more complicated". This approach to development is strongly discouraged by us. It leads to over-architected and unnecessary code; creates barriers to rapid prototyping and shipping a game; and overwhelms beginners who are new to the engine or programming in general.
</p>
<p>
-DragonRuby's philosophy is to provide multiple options across the "make it fast" vs "make it right" spectrum, with incremental/intuitive transitions between the options provided. A concrete example of this philosophy would be render primitives: the spectrum of options allows renderable constructs take the form of tuples/arrays (easy to pickup, simple, and fast to code/prototype with), hashes (a little more work, but gives you the ability to add additional properties), open and string entities (more work than hashes, but yields cleaner apis), and finally - if you really need full power/flexibility in rendering - classes (which take the most amount of code and programming knowledge to create).
+DragonRuby's philosophy is to provide multiple options across the "make it fast" vs "make it right" spectrum, with incremental/intuitive transitions between the options provided. A concrete example of this philosophy would be render primitives: the spectrum of options allows renderable constructs that take the form of tuples/arrays (easy to pickup, simple, and fast to code/prototype with), hashes (a little more work, but gives you the ability to add additional properties), open and strict entities (more work than hashes, but yields cleaner apis), and finally - if you really need full power/flexibility in rendering - classes (which take the most amount of code and programming knowledge to create).
</p>
<h2 id='---release-early-and-often'>Release Early and Often</h2>
<p>
@@ -432,12 +436,12 @@ We are bombarded by marketing speak day in and day out. We don't do that here. T
<p>
We want DragonRuby to *actually* help you build the game you want to build (as opposed to sell you something piece of demoware that doesn't work).
</p>
-<h1 id='--frequently-asked-questions,-comments,-and-concerns'>Frequently Asked Questions, Comments, and Concerns</h1>
+<h1 id='--frequently-asked-questions--comments--and-concerns'>Frequently Asked Questions, Comments, and Concerns</h1>
<p>
Here are questions, comments, and concerns that frequently come up.
</p>
<h2 id='---frequently-asked-questions'>Frequently Asked Questions</h2>
-<h3 id='----what-is-dragonruby-llp?'>What is DragonRuby LLP?</h3>
+<h3 id='----what-is-dragonruby-llp-'>What is DragonRuby LLP?</h3>
<p>
DragonRuby LLP is a partnership of four devs who came together with the goal of bringing the aesthetics and joy of Ruby, everywhere possible.
</p>
@@ -462,7 +466,7 @@ NOTE: We leave the "A DragonRuby LLP Product" off of this one because that just
<p>
NOTE: Devs who use DragonRuby are "Dragon Riders/Riders of Dragons". That's a bad ass identifier huh?
</p>
-<h3 id='----what-is-dragonruby?'>What is DragonRuby?</h3>
+<h3 id='----what-is-dragonruby-'>What is DragonRuby?</h3>
<p>
The response to this question requires a few subparts. First we need to clarify some terms. Specifically _language specification_ vs _runtime_.
</p>
@@ -482,7 +486,7 @@ DragonRuby's goal is to be compliant with the ISO/IEC 30170:2012 standard. It's
The elevator pitch is:
</p>
<p>
-DragonRuby is a Multilevel Cross-platform Runtime. The "multiple levels" within the runtime allows us to target platforms no other Ruby can target: PC, Mac, Linux, Raspberry Pi, WASM, iOS, Android, Nintendo Switch, PS4, Xbox, and Scadia.
+DragonRuby is a Multilevel Cross-platform Runtime. The "multiple levels" within the runtime allows us to target platforms no other Ruby can target: PC, Mac, Linux, Raspberry Pi, WASM, iOS, Android, Nintendo Switch, PS4, Xbox, and Stadia.
</p>
<h4>What does Multilevel Cross-platform mean?</h4>
<p>
@@ -513,7 +517,7 @@ These levels allow us to stay up to date with open source implementations of Rub
<p>
DragonRuby is a Ruby runtime implementation that takes all the lessons we've learned from MRI/CRuby, and merges it with the latest and greatest compiler and OSS technologies.
</p>
-<h3 id='----how-is-dragonruby-different-than-mri?'>How is DragonRuby different than MRI?</h3>
+<h3 id='----how-is-dragonruby-different-than-mri-'>How is DragonRuby different than MRI?</h3>
<p>
DragonRuby supports a subset of MRI apis. Our target is to support all of mRuby's standard lib. There are challenges to this given the number of platforms we are trying to support (specifically console).
</p>
@@ -535,7 +539,7 @@ end
</code></pre>
<ul>
<li>If you use the `repl` method, the code will be executed and the DragonRuby Console will automatically open so you can see the results (on Mac and Linux, the results will also be printed to the terminal).</li>
-<li>All <code>puts</code> statements will also be saved to <code>logs/log.txt</code>. So if you want to stay in your editor and not look at the terminal, or the DragonRuby Console, you can <code>tail</code> this file.</li>
+<li>All <code>puts</code> statements will also be saved to <code>logs/puts.txt</code>. So if you want to stay in your editor and not look at the terminal, or the DragonRuby Console, you can <code>tail</code> this file.</li>
</ul>
<p>
4. To ignore code in <code>repl.rb</code>, instead of commenting it out, prefix <code>repl</code> with the letter <code>x</code> and it'll be ignored.
@@ -568,18 +572,18 @@ You can use DragonRuby's replay capabilities to troubleshoot:
</p>
<ol>
<li> DragonRuby is hot loaded which gives you a very fast feedback loop (if the game throws an exception, it's because of the code you just added).</li>
-<li> Use <code>./dragonruby mygame --record</code> to create a game play recording that you can use to find the exception (you can replay a recoding by executing <code>./dragonruby mygame --replay last_replay.txt</code> or through the DragonRuby Console using <code>$gtk.recording.start_replay "last_replay.txt"</code>.</li>
+<li> Use <code>./dragonruby mygame --record</code> to create a game play recording that you can use to find the exception (you can replay a recording by executing <code>./dragonruby mygame --replay last_replay.txt</code> or through the DragonRuby Console using <code>$gtk.recording.start_replay "last_replay.txt"</code>.</li>
<li> DragonRuby also ships with a unit testing facility. You can invoke the following command to run a test: <code>./dragonruby . --eval some_ruby_file.rb --no-tick</code>.</li>
<li> Get into the habit of adding debugging facilities within the game itself. You can add drawing primitives to <code>args.outputs.debug</code> that will render on top of your game but will be ignored in a production release.</li>
<li> Debugging something that runs at 60fps is (imo) not that helpful. The exception you are seeing could have been because of a change that occurred many frames ago.</li>
</ol>
<h2 id='---frequent-comments-about-ruby-as-a-language-choice'>Frequent Comments About Ruby as a Language Choice</h2>
-<h3 id='----but-ruby-is-dead.'>But Ruby is dead.</h3>
+<h3 id='----but-ruby-is-dead-'>But Ruby is dead.</h3>
<p>
Let's check the official source for the answer to this question: isrubydead.com: <a href='https://isrubydead.com/'>https://isrubydead.com/</a>.
</p>
<p>
-On a more serious note, Ruby's _quantity_ levels aren't what they used to be. And that's totally fine. Every one chases the new and shiny.
+On a more serious note, Ruby's _quantity_ levels aren't what they used to be. And that's totally fine. Everyone chases the new and shiny.
</p>
<p>
What really matters is _quality/maturity_. Here is the latest (StackOverflow Survey sorted by highest paid developers)[https://insights.stackoverflow.com/survey/2019#top-paying-technologies].
@@ -587,11 +591,11 @@ What really matters is _quality/maturity_. Here is the latest (StackOverflow Sur
<p>
Let's stop making this comment shall we?
</p>
-<h3 id='----but-ruby-is-slow.'>But Ruby is slow.</h3>
+<h3 id='----but-ruby-is-slow-'>But Ruby is slow.</h3>
<p>
That doesn't make any sense. A language specification can't be slow... it's a language spec. Sure, an _implementation/runtime_ can be slow though, but then we'd have to talk about which runtime.
</p>
-<h3 id='----dynamic-languages-are-slow.'>Dynamic languages are slow.</h3>
+<h3 id='----dynamic-languages-are-slow-'>Dynamic languages are slow.</h3>
<p>
They are certainly slower than statically compiled languages. With the processing power and compiler optimizations we have today, dynamic languages like Ruby are _fast enough_.
</p>
@@ -602,7 +606,7 @@ Unless you are writing in some form of intermediate representation by hand, your
NOTE: If you _are_ hand writing LLVM IR, we are always open to bringing on new partners with such a skill set. Email us ^_^.
</p>
<h2 id='---frequent-concerns'>Frequent Concerns</h2>
-<h3 id='----dragonruby-is-not-open-source.-that's-not-right.'>DragonRuby is not open source. That's not right.</h3>
+<h3 id='----dragonruby-is-not-open-source--that's-not-right-'>DragonRuby is not open source. That's not right.</h3>
<p>
The current state of open source is unsustainable. Contributors work for free, most all open source repositories are severely under-staffed, and burnout from core members is rampant.
</p>
@@ -618,7 +622,7 @@ If the reason above isn't sufficient, then definitely use something else.
<p>
All this being said, we do have parts of the engine open sourced on GitHub: <a href='https://github.com/dragonruby/dragonruby-game-toolkit-contrib/'>https://github.com/dragonruby/dragonruby-game-toolkit-contrib/</a>
</p>
-<h3 id='----dragonruby-is-for-pay.-you-should-offer-a-free-version.'>DragonRuby is for pay. You should offer a free version.</h3>
+<h3 id='----dragonruby-is-for-pay--you-should-offer-a-free-version-'>DragonRuby is for pay. You should offer a free version.</h3>
<p>
If you can afford to pay for DragonRuby, you should (and will). We don't go around telling writers that they should give us their books for free, and only require payment if we read the entire thing. It's time we stop asking that of software products.
</p>
@@ -640,21 +644,21 @@ You qualify for a free, unrestricted license to DragonRuby products if any of th
<p>
Just contact Amir at [email protected] with a short explanation of your current situation and he'll set you up. No questions asked.
</p>
-<h3 id='----but-still,-you-should-offer-a-free-version.-so-i-can-try-it-out-and-see-if-i-like-it.'>But still, you should offer a free version. So I can try it out and see if I like it.</h3>
+<h3 id='----but-still--you-should-offer-a-free-version--so-i-can-try-it-out-and-see-if-i-like-it-'>But still, you should offer a free version. So I can try it out and see if I like it.</h3>
<p>
-You can try our [web-based sandbox environment](). But it won't do the runtime justice. Or just come to our [Slack]() or [Discord]() channel and ask questions. We'd be happy to have a one on one video chat with you and show off all the cool stuff we're doing.
+You can try our web-based sandbox environment at <a href='http://fiddle.dragonruby.org'>http://fiddle.dragonruby.org</a>. But it won't do the runtime justice. Or just come to our Discord Channel at <a href='http://discord.dragonruby.org'>http://discord.dragonruby.org</a> and ask questions. We'd be happy to have a one on one video chat with you and show off all the cool stuff we're doing.
</p>
<p>
Seriously just buy it. Get a refund if you don't like it. We make it stupid easy to do so.
</p>
-<h3 id='----i-still-think-you-should-do-a-free-version.-think-of-all-people-who-would-give-it-a-shot.'>I still think you should do a free version. Think of all people who would give it a shot.</h3>
+<h3 id='----i-still-think-you-should-do-a-free-version--think-of-all-people-who-would-give-it-a-shot-'>I still think you should do a free version. Think of all people who would give it a shot.</h3>
<p>
Free isn't a sustainable financial model. We don't want to spam your email. We don't want to collect usage data off of you either. We just want to provide quality toolchains to quality developers (as opposed to a large quantity of developers).
</p>
<p>
The people that pay for DragonRuby and make an effort to understand it are the ones we want to build a community around, partner with, and collaborate with. So having that small monetary wall deters entitled individuals that don't value the same things we do.
</p>
-<h3 id='----what-if-i-build-something-with-dragonruby,-but-dragonruby-llp-becomes-insolvent.'>What if I build something with DragonRuby, but DragonRuby LLP becomes insolvent.</h3>
+<h3 id='----what-if-i-build-something-with-dragonruby--but-dragonruby-llp-becomes-insolvent-'>What if I build something with DragonRuby, but DragonRuby LLP becomes insolvent.</h3>
<p>
That won't happen if the development world stop asking for free stuff and non-trivially compensate open source developers. Look, we want to be able to work on the stuff we love, every day of our lives. And we'll go to great lengths to make that happen.
</p>
@@ -743,11 +747,15 @@ You can represent a sprite as a <code>Hash</code>:
flip_vertically: false,
flip_horizontally: false,
angle_anchor_x: 0.5,
- angle_anchor_y: 1.0
+ angle_anchor_y: 1.0,
+ blendmode_enum: 1
}
end
</code></pre>
<p>
+The <code>blendmode_enum</code> value can be set to <code>0</code> (no blending), <code>1</code> (alpha blending), <code>2</code> (additive blending), <code>3</code> (modulo blending), <code>4</code> (multiply blending).
+</p>
+<p>
You can represent a sprite as an <code>object</code>:
</p>
<pre><code class="language-ruby"># Create type with ALL sprite properties AND primitive_marker
@@ -756,7 +764,7 @@ class Sprite
:source_x, :source_y, :source_w, :source_h,
:tile_x, :tile_y, :tile_w, :tile_h,
:flip_horizontally, :flip_vertically,
- :angle_anchor_x, :angle_anchor_y
+ :angle_anchor_x, :angle_anchor_y, :blendmode_enum
def primitive_marker
:sprite
@@ -832,16 +840,17 @@ You can add additional metadata about your game within a label, which requires y
</p>
<pre><code class="language-ruby">def tick args
args.outputs.labels << {
- x: 200,
- y: 550,
- text: "dragonruby",
- size_enum: 2,
- alignment_enum: 1,
- r: 155,
- g: 50,
- b: 50,
- a: 255,
- font: "fonts/manaspc.ttf",
+ x: 200,
+ y: 550,
+ text: "dragonruby",
+ size_enum: 2,
+ alignment_enum: 1,
+ r: 155,
+ g: 50,
+ b: 50,
+ a: 255,
+ font: "fonts/manaspc.ttf",
+ vertical_alignment_enum: 0, # 0 is bottom, 1 is middle, 2 is top
# You can add any properties you like (this will be ignored/won't cause errors)
game_data_one: "Something",
game_data_two: {
@@ -871,6 +880,19 @@ You can get the render size of any string using <code>args.gtk.calcstringbox</co
]
end
</code></pre>
+<h2 id='---rendering-labels-with-new-line-characters-and-wrapping'>Rendering Labels With New Line Characters And Wrapping</h2>
+<p>
+You can use a strategy like the following to create multiple labels from a String.
+</p>
+<pre><code class="language-ruby">def tick args
+ long_string = "Lorem ipsum dolor sit amet, consectetur adipiscing elitteger dolor velit, ultricies vitae libero vel, aliquam imperdiet enim."
+ max_character_length = 30
+ long_strings_split = args.string.wrapped_lines long_string, max_character_length
+ args.outputs.labels << long_strings_split.map_with_index do |s, i|
+ { x: 10, y: 600 - (i * 20), text: s }
+ end
+end
+</code></pre>
<h2 id='---how-to-play-a-sound'>How To Play A Sound</h2>
<p>
Sounds that end <code>.wav</code> will play once:
@@ -902,7 +924,7 @@ If you want to play a <code>.ogg</code> once as if it were a sound effect, you c
end
end
</code></pre>
-<h2 id='---using--args.state--to-store-your-game-state'>Using <code>args.state</code> To Store Your Game State</h2>
+<h2 id='---using--args-state--to-store-your-game-state'>Using <code>args.state</code> To Store Your Game State</h2>
<p>
<code>args.state</code> is a open data structure that allows you to define properties that are arbitrarily nested. You don't need to define any kind of <code>class</code>.
</p>
@@ -975,7 +997,7 @@ All the properties below hang off of <code>args</code> and can be accessed in th
args.PROPERTY
end
</code></pre>
-<h2 id='----args.state-'><code>args.state</code></h2>
+<h2 id='----args-state-'><code>args.state</code></h2>
<p>
Store your game state inside of this <code>state</code>. Properties with arbitrary nesting is allowed and a backing Entity will be created on your behalf.
</p>
@@ -984,35 +1006,35 @@ Store your game state inside of this <code>state</code>. Properties with arbitra
args.state.player.y ||= 0
end
</code></pre>
-<h3 id='-----.-.entity_id-'><code>.*.entity_id</code></h3>
+<h3 id='--------entity_id-'><code>.*.entity_id</code></h3>
<p>
Entities automatically receive an <code>entity_id</code> of type <code>Fixnum</code>.
</p>
-<h3 id='-----.-.entity_type-'><code>.*.entity_type</code></h3>
+<h3 id='--------entity_type-'><code>.*.entity_type</code></h3>
<p>
Entities can have an <code>entity_type</code> which is represented as a <code>Symbol</code>.
</p>
-<h3 id='-----.-.created_at-'><code>.*.created_at</code></h3>
+<h3 id='--------created_at-'><code>.*.created_at</code></h3>
<p>
Entities have <code>created_at</code> set to <code>args.state.tick_count</code> when they are created.
</p>
-<h3 id='-----.-.created_at_elapsed-'><code>.*.created_at_elapsed</code></h3>
+<h3 id='--------created_at_elapsed-'><code>.*.created_at_elapsed</code></h3>
<p>
Returns the elapsed number of ticks since creation.
</p>
-<h3 id='-----.-.global_created_at-'><code>.*.global_created_at</code></h3>
+<h3 id='--------global_created_at-'><code>.*.global_created_at</code></h3>
<p>
Entities have <code>global_created_at</code> set to <code>Kernel.global_tick_count</code> when they are created.
</p>
-<h3 id='-----.-.global_created_at_elapsed-'><code>.*.global_created_at_elapsed</code></h3>
+<h3 id='--------global_created_at_elapsed-'><code>.*.global_created_at_elapsed</code></h3>
<p>
Returns the elapsed number of global ticks since creation.
</p>
-<h3 id='-----.-.as_hash-'><code>.*.as_hash</code></h3>
+<h3 id='--------as_hash-'><code>.*.as_hash</code></h3>
<p>
Entity cast to a <code>Hash</code> so you can update values as if you were updating a <code>Hash</code>.
</p>
-<h3 id='-----.new_entity-'><code>.new_entity</code></h3>
+<h3 id='------new_entity-'><code>.new_entity</code></h3>
<p>
Creates a new Entity with a <code>type</code>, and initial properties. An option block can be passed to change the newly created entity:
</p>
@@ -1023,47 +1045,47 @@ Creates a new Entity with a <code>type</code>, and initial properties. An option
end
end
</code></pre>
-<h3 id='-----.new_entity_strict-'><code>.new_entity_strict</code></h3>
+<h3 id='------new_entity_strict-'><code>.new_entity_strict</code></h3>
<p>
Creates a new Strict Entity. While Entities created via <code>args.state.new_entity</code> can have new properties added later on, Entities created using <code>args.state.new_entity</code> must define all properties that are allowed during its initialization. Attempting to add new properties after initialization will result in an exception.
</p>
-<h3 id='-----.tick_count-'><code>.tick_count</code></h3>
+<h3 id='------tick_count-'><code>.tick_count</code></h3>
<p>
Returns the current tick of the game. <code>args.state.tick_count</code> is <code>0</code> when the game is first started or if the game is reset via <code>$gtk.reset</code>.
</p>
-<h2 id='----args.inputs-'><code>args.inputs</code></h2>
+<h2 id='----args-inputs-'><code>args.inputs</code></h2>
<p>
Access using input using <code>args.inputs</code>.
</p>
-<h3 id='-----.up-'><code>.up</code></h3>
+<h3 id='------up-'><code>.up</code></h3>
<p>
Returns <code>true</code> if: the <code>up</code> arrow or <code>w</code> key is pressed or held on the <code>keyboard</code>; or if <code>up</code> is pressed or held on <code>controller_one</code>; or if the <code>left_analog</code> on <code>controller_one</code> is tilted upwards.
</p>
-<h3 id='-----.down-'><code>.down</code></h3>
+<h3 id='------down-'><code>.down</code></h3>
<p>
Returns <code>true</code> if: the <code>down</code> arrow or <code>s</code> key is pressed or held on the <code>keyboard</code>; or if <code>down</code> is pressed or held on <code>controller_one</code>; or if the <code>left_analog</code> on <code>controller_one</code> is tilted downwards.
</p>
-<h3 id='-----.left-'><code>.left</code></h3>
+<h3 id='------left-'><code>.left</code></h3>
<p>
Returns <code>true</code> if: the <code>left</code> arrow or <code>a</code> key is pressed or held on the <code>keyboard</code>; or if <code>left</code> is pressed or held on <code>controller_one</code>; or if the <code>left_analog</code> on <code>controller_one</code> is tilted to the left.
</p>
-<h3 id='-----.right-'><code>.right</code></h3>
+<h3 id='------right-'><code>.right</code></h3>
<p>
Returns <code>true</code> if: the <code>right</code> arrow or <code>d</code> key is pressed or held on the <code>keyboard</code>; or if <code>right</code> is pressed or held on <code>controller_one</code>; or if the <code>left_analog</code> on <code>controller_one</code> is tilted to the right.
</p>
-<h3 id='-----.left_right-'><code>.left_right</code></h3>
+<h3 id='------left_right-'><code>.left_right</code></h3>
<p>
Returns <code>-1</code> (left), <code>0</code> (neutral), or <code>+1</code> (right) depending on results of <code>args.inputs.left</code> and <code>args.inputs.right</code>.
</p>
-<h3 id='-----.up_down-'><code>.up_down</code></h3>
+<h3 id='------up_down-'><code>.up_down</code></h3>
<p>
-Returns <code>-1</code> (down), <code>0</code> (neutral), or <code>+1</code> (right) depending on results of <code>args.inputs.up</code> and <code>args.inputs.down</code>.
+Returns <code>-1</code> (down), <code>0</code> (neutral), or <code>+1</code> (up) depending on results of <code>args.inputs.down</code> and <code>args.inputs.up</code>.
</p>
-<h3 id='-----.text--or--.history-'><code>.text</code> OR <code>.history</code></h3>
+<h3 id='------text--or---history-'><code>.text</code> OR <code>.history</code></h3>
<p>
Returns a string that represents the last key that was pressed on the keyboard.
</p>
-<h3 id='-----.mouse-'><code>.mouse</code></h3>
+<h3 id='------mouse-'><code>.mouse</code></h3>
<p>
Represents the user's
</p>
@@ -1105,37 +1127,49 @@ Returns a bitmask for all buttons on the mouse: <code>1</code> for a button in t
</p>
<h4><code>mouse.wheel</code></h4>
<p>
-Represents the mouse wheel. Returns <code>nil</code> if no mouse wheel actions occurred. ***** <code>.x</code> Returns the negative or positive number if the mouse wheel has changed in the <code>x</code> axis. ***** <code>.y</code> Returns the negative or positive number if the mouse wheel has changed in the <code>y</code> axis.
+Represents the mouse wheel. Returns <code>nil</code> if no mouse wheel actions occurred.
+</p>
+<p>
+***** <code>.x</code>
+</p>
+<p>
+Returns the negative or positive number if the mouse wheel has changed in the <code>x</code> axis.
+</p>
+<p>
+***** <code>.y</code>
+</p>
+<p>
+Returns the negative or positive number if the mouse wheel has changed in the <code>y</code> axis.
</p>
<h4><code>.click</code> OR <code>.down</code>, <code>.previous_click</code>, <code>.up</code></h4>
<p>
The properties <code>args.inputs.mouse.(click|down|previous_click|up)</code> each return <code>nil</code> if the mouse button event didn't occur. And return an Entity that has an <code>x</code>, <code>y</code> properties along with helper functions to determine collision: <code>inside_rect?</code>, <code>inside_circle</code>.
</p>
-<h3 id='-----.controller_one-,--.controller_two-'><code>.controller_one</code>, <code>.controller_two</code></h3>
+<h3 id='------controller_one-----controller_two-'><code>.controller_one</code>, <code>.controller_two</code></h3>
<p>
Represents controllers connected to the usb ports.
</p>
-<h4>~.up</h4>
+<h4><code>.up</code></h4>
<p>
Returns <code>true</code> if <code>up</code> is pressed or held on the directional or left analog.
</p>
-<h4>~.down</h4>
+<h4><code>.down</code></h4>
<p>
Returns <code>true</code> if <code>down</code> is pressed or held on the directional or left analog.
</p>
-<h4>~.left</h4>
+<h4><code>.left</code></h4>
<p>
Returns <code>true</code> if <code>left</code> is pressed or held on the directional or left analog.
</p>
-<h4>~.right</h4>
+<h4><code>.right</code></h4>
<p>
Returns <code>true</code> if <code>right</code> is pressed or held on the directional or left analog.
</p>
-<h4>~.left_right</h4>
+<h4><code>.left_right</code></h4>
<p>
Returns <code>-1</code> (left), <code>0</code> (neutral), or <code>+1</code> (right) depending on results of <code>args.inputs.controller_(one|two).left</code> and <code>args.inputs.controller_(one|two).right</code>.
</p>
-<h4>~.up_down</h4>
+<h4><code>.up_down</code></h4>
<p>
Returns <code>-1</code> (down), <code>0</code> (neutral), or <code>+1</code> (up) depending on results of <code>args.inputs.controller_(one|two).up</code> and <code>args.inputs.controller_(one|two).down</code>.
</p>
@@ -1155,19 +1189,19 @@ Returns a number between <code>-1</code> and <code>1</code> which represents the
<p>
Returns a number between <code>-1</code> and <code>1</code> which represents the percentage the analog is moved vertically as a ratio of the maximum vertical movement.
</p>
-<h4><code>.directional_up)</code></h4>
+<h4><code>.directional_up</code></h4>
<p>
Returns <code>true</code> if <code>up</code> is pressed or held on the directional.
</p>
-<h4><code>.directional_down)</code></h4>
+<h4><code>.directional_down</code></h4>
<p>
Returns <code>true</code> if <code>down</code> is pressed or held on the directional.
</p>
-<h4><code>.directional_left)</code></h4>
+<h4><code>.directional_left</code></h4>
<p>
Returns <code>true</code> if <code>left</code> is pressed or held on the directional.
</p>
-<h4><code>.directional_right)</code></h4>
+<h4><code>.directional_right</code></h4>
<p>
Returns <code>true</code> if <code>right</code> is pressed or held on the directional.
</p>
@@ -1191,7 +1225,7 @@ Returns <code>true</code> if the specific button is being held. <code>args.input
<p>
Returns <code>true</code> if the specific button was released. <code>args.inputs.controller_(one|two).key_up.BUTTON</code> will be true only on the frame the button was released.
</p>
-<h3 id='-----.keyboard-'><code>.keyboard</code></h3>
+<h3 id='------keyboard-'><code>.keyboard</code></h3>
<p>
Represents the user's keyboard
</p>
@@ -1333,139 +1367,148 @@ Returns a <code>Hash</code> with all keys on the keyboard in their respective st
<li><code>:down_or_held</code></li>
<li><code>:up</code></li>
</ul>
-<h2 id='----args.outputs-'><code>args.outputs</code></h2>
+<h2 id='----args-outputs-'><code>args.outputs</code></h2>
<p>
<code>args.outputs.PROPERTY</code> is how you render to the screen.
</p>
-<h3 id='-----.background_color-'><code>.background_color</code></h3>
+<h3 id='------background_color-'><code>.background_color</code></h3>
<p>
Set <code>args.outputs.background_color</code> to an <code>Array</code> with <code>RGB</code> values (eg. <code>[255, 255, 255]</code> for the color white).
</p>
-<h3 id='-----.sounds-'><code>.sounds</code></h3>
+<h3 id='------sounds-'><code>.sounds</code></h3>
<p>
Send a file path to this collection to play a sound. The sound file must be under the <code>mygame</code> directory. Example: <code>args.outputs.sounds << "sounds/jump.wav"</code>.
</p>
-<h3 id='-----.solids-'><code>.solids</code></h3>
+<h3 id='------solids-'><code>.solids</code></h3>
<p>
Send a Primitive to this collection to render a filled in rectangle to the screen. This collection is cleared at the end of every frame.
</p>
-<h3 id='-----.static_solids-'><code>.static_solids</code></h3>
+<h3 id='------static_solids-'><code>.static_solids</code></h3>
<p>
Send a Primitive to this collection to render a filled in rectangle to the screen. This collection is not cleared at the end of every frame. And objects can be mutated by reference.
</p>
-<h3 id='-----.sprites-,--.static_sprites-'><code>.sprites</code>, <code>.static_sprites</code></h3>
+<h3 id='------sprites-----static_sprites-'><code>.sprites</code>, <code>.static_sprites</code></h3>
<p>
Send a Primitive to this collection to render a sprite to the screen.
</p>
-<h3 id='-----.primitives-,--.static_primitives-'><code>.primitives</code>, <code>.static_primitives</code></h3>
+<h3 id='------primitives-----static_primitives-'><code>.primitives</code>, <code>.static_primitives</code></h3>
<p>
Send a Primitive of any type and it'll be rendered. The Primitive must have a <code>primitive_marker</code> that returns <code>:solid</code>, <code>:sprite</code>, <code>:label</code>, <code>:line</code>, <code>:border</code>.
</p>
-<h3 id='-----.labels-,--.static_labels-'><code>.labels</code>, <code>.static_labels</code></h3>
+<h3 id='------labels-----static_labels-'><code>.labels</code>, <code>.static_labels</code></h3>
<p>
Send a Primitive to this collection to render text to the screen.
</p>
-<h3 id='-----.lines-,--.static_lines-'><code>.lines</code>, <code>.static_lines</code></h3>
+<h3 id='------lines-----static_lines-'><code>.lines</code>, <code>.static_lines</code></h3>
<p>
Send a Primitive to this collection to render a line to the screen.
</p>
-<h3 id='-----.borders-,--.static_borders-'><code>.borders</code>, <code>.static_borders</code></h3>
+<h3 id='------borders-----static_borders-'><code>.borders</code>, <code>.static_borders</code></h3>
<p>
Send a Primitive to this collection to render an unfilled rectangle to the screen.
</p>
-<h3 id='-----.debug-,--.static_debug-'><code>.debug</code>, <code>.static_debug</code></h3>
+<h3 id='------debug-----static_debug-'><code>.debug</code>, <code>.static_debug</code></h3>
<p>
Send any Primitive to this collection which represents things you render to the screen for debugging purposes. Primitives in this collection will not be rendered in a production release of your game.
</p>
-<h2 id='----args.geometry-'><code>args.geometry</code></h2>
+<h2 id='----args-geometry-'><code>args.geometry</code></h2>
<p>
This property contains geometric functions. Functions can be invoked via <code>args.geometry.FUNCTION</code>.
</p>
-<h3 id='-----.inside_rect?-rect_1,-rect_2-'><code>.inside_rect? rect_1, rect_2</code></h3>
+<p>
+Here are some general notes with regards to the arguments these geometric functions accept.
+</p>
+<ol>
+<li> <code>Rectangles</code> can be represented as an <code>Array</code> with four (or more) values <code>[x, y, w, h]</code>, as a <code>Hash</code> <code>{ x:, y:, w:, h: }</code> or an object that responds to <code>x</code>, <code>y</code>, <code>w</code>, and <code>h</code>.</li>
+<li> <code>Points</code> can be represent as an <code>Array</code> with two (or more) values <code>[x, y]</code>, as a <code>Hash</code> <code>{ x:, y:}</code> or an object that responds to <code>x</code>, and <code>y</code>.</li>
+<li> <code>Lines</code> can be represented as an <code>Array</code> with four (or more) values <code>[x, y, x2, y2]</code>, as a <code>Hash</code> <code>{ x:, y:, x2:, y2: }</code> or an object that responds to <code>x</code>, <code>y</code>, <code>x2</code>, and <code>y2</code>.</li>
+<li> <code>Angles</code> are represented as degrees (not radians).</li>
+</ol>
+<h3 id='------inside_rect--rect_1--rect_2-'><code>.inside_rect? rect_1, rect_2</code></h3>
<p>
Returns <code>true</code> if <code>rect_1</code> is inside <code>rect_2</code>.
</p>
-<h3 id='-----.intersect_rect?-rect_2,-rect_2-'><code>.intersect_rect? rect_2, rect_2</code></h3>
+<h3 id='------intersect_rect--rect_2--rect_2-'><code>.intersect_rect? rect_2, rect_2</code></h3>
<p>
Returns <code>true</code> if <code>rect_1</code> intersects <code>rect_2</code>.
</p>
-<h3 id='-----.scale_rect-rect,-x_percentage,-y_percentage-'><code>.scale_rect rect, x_percentage, y_percentage</code></h3>
+<h3 id='------scale_rect-rect--x_percentage--y_percentage-'><code>.scale_rect rect, x_percentage, y_percentage</code></h3>
<p>
Returns a new rectangle that is scaled by the percentages provided.
</p>
-<h3 id='-----.angle_to-start_point,-end_point-'><code>.angle_to start_point, end_point</code></h3>
+<h3 id='------angle_to-start_point--end_point-'><code>.angle_to start_point, end_point</code></h3>
<p>
Returns the angle in degrees between two points <code>start_point</code> to <code>end_point</code>.
</p>
-<h3 id='-----.angle_from-start_point,-end_point-'><code>.angle_from start_point, end_point</code></h3>
+<h3 id='------angle_from-start_point--end_point-'><code>.angle_from start_point, end_point</code></h3>
<p>
Returns the angle in degrees between two points <code>start_point</code> from <code>end_point</code>.
</p>
-<h3 id='-----.point_inside_circle?-point,-circle_center_point,-radius-'><code>.point_inside_circle? point, circle_center_point, radius</code></h3>
+<h3 id='------point_inside_circle--point--circle_center_point--radius-'><code>.point_inside_circle? point, circle_center_point, radius</code></h3>
<p>
Returns <code>true</code> if a point is inside a circle defined by its center and radius.
</p>
-<h3 id='-----.center_inside_rect-rect,-other_rect-'><code>.center_inside_rect rect, other_rect</code></h3>
+<h3 id='------center_inside_rect-rect--other_rect-'><code>.center_inside_rect rect, other_rect</code></h3>
<p>
Returns a new rectangle based of off <code>rect</code> that is centered inside of <code>other_rect</code>.
</p>
-<h3 id='-----.center_inside_rect_x-rect,-other_rect-'><code>.center_inside_rect_x rect, other_rect</code></h3>
+<h3 id='------center_inside_rect_x-rect--other_rect-'><code>.center_inside_rect_x rect, other_rect</code></h3>
<p>
Returns a new rectangle based of off <code>rect</code> that is centered horizontally inside of <code>other_rect</code>.
</p>
-<h3 id='-----.center_inside_rect_y-rect,-other_rect-'><code>.center_inside_rect_y rect, other_rect</code></h3>
+<h3 id='------center_inside_rect_y-rect--other_rect-'><code>.center_inside_rect_y rect, other_rect</code></h3>
<p>
Returns a new rectangle based of off <code>rect</code> that is centered vertically inside of <code>other_rect</code>.
</p>
-<h3 id='-----.anchor_rect-rect,-anchor_x,-anchor_y-'><code>.anchor_rect rect, anchor_x, anchor_y</code></h3>
+<h3 id='------anchor_rect-rect--anchor_x--anchor_y-'><code>.anchor_rect rect, anchor_x, anchor_y</code></h3>
<p>
Returns a new rectangle based of off <code>rect</code> that has been repositioned based on the percentages passed into anchor_x, and anchor_y.
</p>
-<h3 id='-----.shift_line-line,-x,-y-'><code>.shift_line line, x, y</code></h3>
+<h3 id='------shift_line-line--x--y-'><code>.shift_line line, x, y</code></h3>
<p>
Returns a line that is offset by <code>x</code>, and <code>y</code>.
</p>
-<h3 id='-----.line_y_intercept-line-'><code>.line_y_intercept line</code></h3>
+<h3 id='------line_y_intercept-line-'><code>.line_y_intercept line</code></h3>
<p>
Given a line, the <code>b</code> value is determined for the point slope form equation: <code>y = mx + b</code>.
</p>
-<h3 id='-----.angle_between_lines-line_one,-line_two,-replace_infinity--'><code>.angle_between_lines line_one, line_two, replace_infinity:</code></h3>
+<h3 id='------angle_between_lines-line_one--line_two--replace_infinity--'><code>.angle_between_lines line_one, line_two, replace_infinity:</code></h3>
<p>
Returns the angle between two lines as if they were infinitely long. A numeric value can be passed in for the last parameter which would represent lines that do not intersect.
</p>
-<h3 id='-----.line_slope-line,-replace_infinity--'><code>.line_slope line, replace_infinity:</code></h3>
+<h3 id='------line_slope-line--replace_infinity--'><code>.line_slope line, replace_infinity:</code></h3>
<p>
Given a line, the <code>m</code> value is determined for the point slope form equation: <code>y = mx + b</code>.
</p>
-<h3 id='-----.line_rise_run-'><code>.line_rise_run</code></h3>
+<h3 id='------line_rise_run-'><code>.line_rise_run</code></h3>
<p>
Given a line, a <code>Hash</code> is returned that returns the slope as <code>x</code> and <code>y</code> properties with normalized values (the number is between -1 and 1).
</p>
-<h3 id='-----.ray_test-point,-line-'><code>.ray_test point, line</code></h3>
+<h3 id='------ray_test-point--line-'><code>.ray_test point, line</code></h3>
<p>
Given a point and a line, <code>:on</code>, <code>:left</code>, or <code>:right</code> which represents the location of the point relative to the line.
</p>
-<h3 id='-----.line_rect-line-'><code>.line_rect line</code></h3>
+<h3 id='------line_rect-line-'><code>.line_rect line</code></h3>
<p>
Returns the bounding rectangle for a line.
</p>
-<h3 id='-----.line_intersect-line_one,-line_two-'><code>.line_intersect line_one, line_two</code></h3>
+<h3 id='------line_intersect-line_one--line_two-'><code>.line_intersect line_one, line_two</code></h3>
<p>
Returns a point that represents the intersection of the lines.
</p>
-<h3 id='-----.distance-point_one,-point_two-'><code>.distance point_one, point_two</code></h3>
+<h3 id='------distance-point_one--point_two-'><code>.distance point_one, point_two</code></h3>
<p>
Returns the distance between two points.
</p>
-<h3 id='-----.cubic_bezier-t,-a,-b,-c,-d-'><code>.cubic_bezier t, a, b, c, d</code></h3>
+<h3 id='------cubic_bezier-t--a--b--c--d-'><code>.cubic_bezier t, a, b, c, d</code></h3>
<p>
Returns the cubic bezier function for tick_count <code>t</code> with anchors <code>a</code>, <code>b</code>, <code>c</code>, and <code>d</code>.
</p>
-<h2 id='----args.easing-'><code>args.easing</code></h2>
+<h2 id='----args-easing-'><code>args.easing</code></h2>
<p>
A set of functions that allow you to determine the current progression of an easing function.
</p>
-<h3 id='-----.ease-start_tick,-current_tick,-duration,-easing_functions-'><code>.ease start_tick, current_tick, duration, easing_functions</code></h3>
+<h3 id='------ease-start_tick--current_tick--duration--easing_functions-'><code>.ease start_tick, current_tick, duration, easing_functions</code></h3>
<p>
Given a start, current, duration, and easing function names, <code>ease</code> returns a number between 0 and 1 that represents the progress of an easing function.
</p>
@@ -1485,7 +1528,7 @@ This example will move a box at a linear speed from 0 to 1280.
args.outputs.solids << { x: 1280 * current_progress, y: 360, w: 10, h: 10 }
end
</code></pre>
-<h3 id='-----.ease_spline-start_tick,-current_tick,-duration,-spline-'><code>.ease_spline start_tick, current_tick, duration, spline</code></h3>
+<h3 id='------ease_spline-start_tick--current_tick--duration--spline-'><code>.ease_spline start_tick, current_tick, duration, spline</code></h3>
<p>
Given a start, current, duration, and a multiple bezier values, this function returns a number between 0 and 1 that represents the progress of an easing function.
</p>
@@ -1506,11 +1549,11 @@ This example will move a box at a linear speed from 0 to 1280 and then back to 0
args.outputs.solids << { x: 1280 * current_progress, y: 360, w: 10, h: 10 }
end
</code></pre>
-<h2 id='----args.string-'><code>args.string</code></h2>
+<h2 id='----args-string-'><code>args.string</code></h2>
<p>
Useful string functions not included in Ruby core libraries.
</p>
-<h3 id='-----.wrapped_lines-string,-max_character_length-'><code>.wrapped_lines string, max_character_length</code></h3>
+<h3 id='------wrapped_lines-string--max_character_length-'><code>.wrapped_lines string, max_character_length</code></h3>
<p>
This function will return a collection of strings given an input <code>string</code> and <code>max_character_length</code>. The collection of strings returned will split the input string into strings of <code>length <= max_character_length</code>.
</p>
@@ -1527,175 +1570,175 @@ teger dolor velit, ultricies vitae libero vel, aliquam imperdiet enim."
end
end
</code></pre>
-<h2 id='----args.grid-'><code>args.grid</code></h2>
+<h2 id='----args-grid-'><code>args.grid</code></h2>
<p>
Returns the virtual grid for the game.
</p>
-<h3 id='-----.name-'><code>.name</code></h3>
+<h3 id='------name-'><code>.name</code></h3>
<p>
Returns either <code>:origin_bottom_left</code> or <code>:origin_center</code>.
</p>
-<h3 id='-----.bottom-'><code>.bottom</code></h3>
+<h3 id='------bottom-'><code>.bottom</code></h3>
<p>
Returns the <code>y</code> value that represents the bottom of the grid.
</p>
-<h3 id='-----.top-'><code>.top</code></h3>
+<h3 id='------top-'><code>.top</code></h3>
<p>
Returns the <code>y</code> value that represents the top of the grid.
</p>
-<h3 id='-----.left-'><code>.left</code></h3>
+<h3 id='------left-'><code>.left</code></h3>
<p>
Returns the <code>x</code> value that represents the left of the grid.
</p>
-<h3 id='-----.right-'><code>.right</code></h3>
+<h3 id='------right-'><code>.right</code></h3>
<p>
Returns the <code>x</code> value that represents the right of the grid.
</p>
-<h3 id='-----.rect-'><code>.rect</code></h3>
+<h3 id='------rect-'><code>.rect</code></h3>
<p>
Returns a rectangle Primitive that represents the grid.
</p>
-<h3 id='-----.origin_bottom_left!-'><code>.origin_bottom_left!</code></h3>
+<h3 id='------origin_bottom_left!-'><code>.origin_bottom_left!</code></h3>
<p>
Change the grids coordinate system to 0, 0 at the bottom left corner.
</p>
-<h3 id='-----.origin_center!-'><code>.origin_center!</code></h3>
+<h3 id='------origin_center!-'><code>.origin_center!</code></h3>
<p>
Change the grids coordinate system to 0, 0 at the center of the screen.
</p>
-<h3 id='-----.w-'><code>.w</code></h3>
+<h3 id='------w-'><code>.w</code></h3>
<p>
Returns the grid's width (always 1280).
</p>
-<h3 id='-----.h-'><code>.h</code></h3>
+<h3 id='------h-'><code>.h</code></h3>
<p>
Returns the grid's height (always 720).
</p>
-<h2 id='----args.gtk-'><code>args.gtk</code></h2>
+<h2 id='----args-gtk-'><code>args.gtk</code></h2>
<p>
This represents the DragonRuby Game Toolkit's Runtime Environment and can be accessed via <code>args.gtk.METHOD</code>.
</p>
-<h3 id='-----.argv-'><code>.argv</code></h3>
+<h3 id='------argv-'><code>.argv</code></h3>
<p>
Returns a <code>String</code> that represents the parameters passed into the <code>./dragonruby</code> binary.
</p>
-<h3 id='-----.platform-'><code>.platform</code></h3>
+<h3 id='------platform-'><code>.platform</code></h3>
<p>
Returns a <code>String</code> representing the operating system the game is running on.
</p>
-<h3 id='-----.request_quit-'><code>.request_quit</code></h3>
+<h3 id='------request_quit-'><code>.request_quit</code></h3>
<p>
Request that the runtime quit the game.
</p>
-<h3 id='-----.write_file-path,-contents-'><code>.write_file path, contents</code></h3>
+<h3 id='------write_file-path--contents-'><code>.write_file path, contents</code></h3>
<p>
Writes/overwrites a file within the game directory + path.
</p>
-<h3 id='-----.write_file_root-'><code>.write_file_root</code></h3>
+<h3 id='------write_file_root-'><code>.write_file_root</code></h3>
<p>
Writes/overwrites a file within the root dragonruby binary directory + path.
</p>
-<h3 id='-----.append_file-path,-contents-'><code>.append_file path, contents</code></h3>
+<h3 id='------append_file-path--contents-'><code>.append_file path, contents</code></h3>
<p>
Append content to a file located at the game directory + path.
</p>
-<h3 id='-----.append_file_root-path,-contents-'><code>.append_file_root path, contents</code></h3>
+<h3 id='------append_file_root-path--contents-'><code>.append_file_root path, contents</code></h3>
<p>
Append content to a file located at the root dragonruby binary directory + path.
</p>
-<h3 id='-----.read_file-path-'><code>.read_file path</code></h3>
+<h3 id='------read_file-path-'><code>.read_file path</code></h3>
<p>
Reads a file from the sandboxed file system.
</p>
-<h3 id='-----.parse_xml-string,-parse_xml_file-path-'><code>.parse_xml string, parse_xml_file path</code></h3>
+<h3 id='------parse_xml-string--parse_xml_file-path-'><code>.parse_xml string, parse_xml_file path</code></h3>
<p>
Returns a <code>Hash</code> for a <code>String</code> that represents XML.
</p>
-<h3 id='-----.parse_json-string,-parse_json_file-path-'><code>.parse_json string, parse_json_file path</code></h3>
+<h3 id='------parse_json-string--parse_json_file-path-'><code>.parse_json string, parse_json_file path</code></h3>
<p>
Returns a <code>Hash</code> for a <code>String</code> that represents JSON.
</p>
-<h3 id='-----.http_get-url,-extra_headers-=-{}-'><code>.http_get url, extra_headers = {}</code></h3>
+<h3 id='------http_get-url--extra_headers-=-{}-'><code>.http_get url, extra_headers = {}</code></h3>
<p>
Creates an async task to perform an HTTP GET.
</p>
-<h3 id='-----.http_post-url,-form_fields-=-{},-extra_headers-=-{}-'><code>.http_post url, form_fields = {}, extra_headers = {}</code></h3>
+<h3 id='------http_post-url--form_fields-=-{}--extra_headers-=-{}-'><code>.http_post url, form_fields = {}, extra_headers = {}</code></h3>
<p>
Creates an async task to perform an HTTP POST.
</p>
-<h3 id='-----.reset-'><code>.reset</code></h3>
+<h3 id='------reset-'><code>.reset</code></h3>
<p>
Resets the game by deleting all data in <code>args.state</code> and setting <code>args.state.tick_count</code> back to <code>0</code>.
</p>
-<h3 id='-----.stop_music-'><code>.stop_music</code></h3>
+<h3 id='------stop_music-'><code>.stop_music</code></h3>
<p>
Stops all background music.
</p>
-<h3 id='-----.calcstringbox-str,-size_enum,-font-'><code>.calcstringbox str, size_enum, font</code></h3>
+<h3 id='------calcstringbox-str--size_enum--font-'><code>.calcstringbox str, size_enum, font</code></h3>
<p>
Returns a tuple with width and height of a string being rendered.
</p>
-<h3 id='-----.slowmo!-factor-'><code>.slowmo! factor</code></h3>
+<h3 id='------slowmo!-factor-'><code>.slowmo! factor</code></h3>
<p>
Slows the game down by the factor provided.
</p>
-<h3 id='-----.notify!-string-'><code>.notify! string</code></h3>
+<h3 id='------notify!-string-'><code>.notify! string</code></h3>
<p>
Renders a toast message at the bottom of the screen.
</p>
-<h3 id='-----.system-'><code>.system</code></h3>
+<h3 id='------system-'><code>.system</code></h3>
<p>
Invokes a shell command and prints the result to the console.
</p>
-<h3 id='-----.exec-'><code>.exec</code></h3>
+<h3 id='------exec-'><code>.exec</code></h3>
<p>
Invokes a shell command and returns a <code>String</code> that represents the result.
</p>
-<h3 id='-----.save_state-'><code>.save_state</code></h3>
+<h3 id='------save_state-'><code>.save_state</code></h3>
<p>
Saves the game state to <code>game_state.txt</code>.
</p>
-<h3 id='-----.load_state-'><code>.load_state</code></h3>
+<h3 id='------load_state-'><code>.load_state</code></h3>
<p>
Load <code>args.state</code> from <code>game_state.txt</code>.
</p>
-<h3 id='-----.serialize_state-file,-state-'><code>.serialize_state file, state</code></h3>
+<h3 id='------serialize_state-file--state-'><code>.serialize_state file, state</code></h3>
<p>
Saves entity state to a file. If only one parameter is provided a string is returned for state instead of writing to a file.
</p>
-<h3 id='-----.deserialize_state-file-'><code>.deserialize_state file</code></h3>
+<h3 id='------deserialize_state-file-'><code>.deserialize_state file</code></h3>
<p>
Returns entity state from a file or serialization data represented as a <code>String</code>.
</p>
-<h3 id='-----.reset_sprite-path-'><code>.reset_sprite path</code></h3>
+<h3 id='------reset_sprite-path-'><code>.reset_sprite path</code></h3>
<p>
Invalids the texture cache of a sprite.
</p>
-<h3 id='-----.show_cursor-'><code>.show_cursor</code></h3>
+<h3 id='------show_cursor-'><code>.show_cursor</code></h3>
<p>
Shows the mouse cursor.
</p>
-<h3 id='-----.hide_cursor-'><code>.hide_cursor</code></h3>
+<h3 id='------hide_cursor-'><code>.hide_cursor</code></h3>
<p>
Hides the mouse cursor.
</p>
-<h3 id='-----.cursor_shown?-'><code>.cursor_shown?</code></h3>
+<h3 id='------cursor_shown--'><code>.cursor_shown?</code></h3>
<p>
Returns <code>true</code> if the mouse cursor is shown.
</p>
-<h3 id='-----.set_window_fullscreen-enabled-'><code>.set_window_fullscreen enabled</code></h3>
+<h3 id='------set_window_fullscreen-enabled-'><code>.set_window_fullscreen enabled</code></h3>
<p>
Sets the game to either fullscreen (<code>enabled=true</code>) or windowed (<code>enabled=false)</code>.
</p>
-<h3 id='-----.openurl-url-'><code>.openurl url</code></h3>
+<h3 id='------openurl-url-'><code>.openurl url</code></h3>
<p>
Opens a url using the Operating System's default browser.
</p>
-<h3 id='-----.get_base_dir-'><code>.get_base_dir</code></h3>
+<h3 id='------get_base_dir-'><code>.get_base_dir</code></h3>
<p>
Returns the full path of the DragonRuby binary directory.
</p>
-<h3 id='-----.get_game_dir-'><code>.get_game_dir</code></h3>
+<h3 id='------get_game_dir-'><code>.get_game_dir</code></h3>
<p>
Returns the full path of the game directory in its sandboxed environment.
</p>
@@ -1869,11 +1912,11 @@ Assuming the array is an array of arrays, Given a block, each 2D array index inv
puts occupied_tiles
end
</code></pre>
-<h1 id='--docs---array#include_any?-'>DOCS: <code>Array#include_any?</code></h1>
+<h1 id='--docs---array#include_any--'>DOCS: <code>Array#include_any?</code></h1>
<p>
Given a collection of items, the function will return <code>true</code> if any of <code>self</code>'s items exists in the collection of items passed in:
</p>
-<h1 id='--docs---array#any_intersect_rect?-'>DOCS: <code>Array#any_intersect_rect?</code></h1>
+<h1 id='--docs---array#any_intersect_rect--'>DOCS: <code>Array#any_intersect_rect?</code></h1>
<p>
Assuming the array contains objects that respond to <code>left</code>, <code>right</code>, <code>top</code>, <code>bottom</code>, this method returns <code>true</code> if any of the elements within the array intersect the object being passed in. You are given an optional parameter called <code>tolerance</code> which informs how close to the other rectangles the elements need to be for it to be considered intersecting.
</p>
@@ -2018,7 +2061,7 @@ end
</code></pre>
<h2 id='---rendering-a-solid-using-an-array-with-colors-and-alpha'>Rendering a solid using an Array with colors and alpha</h2>
<p>
-The value for the color and alpha is an number between <code>0</code> and <code>255</code>. The alpha property is optional and will be set to <code>255</code> if not specified.
+The value for the color and alpha is a number between <code>0</code> and <code>255</code>. The alpha property is optional and will be set to <code>255</code> if not specified.
</p>
<p>
Creates a green solid rectangle with an opacity of 50%.
@@ -2047,7 +2090,7 @@ end
</code></pre>
<h2 id='---rendering-a-solid-using-a-class'>Rendering a solid using a Class</h2>
<p>
-You can also create a class with solid/border properties and render it as a primitive. ALL properties must on the class. *Additionally*, a method called <code>primitive_marker</code> must be defined on the class.
+You can also create a class with solid/border properties and render it as a primitive. ALL properties must be on the class. *Additionally*, a method called <code>primitive_marker</code> must be defined on the class.
</p>
<p>
Here is an example:
@@ -2100,6 +2143,93 @@ You have to use <code>args.outputs.borders</code>:
args.outputs.borders << [100, 100, 160, 90]
end
</code></pre>
+<h1 id='--docs---gtk--outputs#sprites-'>DOCS: <code>GTK::Outputs#sprites</code></h1>
+<p>
+Add primitives to this collection to render a sprite to the screen.
+</p>
+<h2 id='---rendering-a-sprite-using-an-array'>Rendering a sprite using an Array</h2>
+<p>
+Creates a sprite of a white circle located at 100, 100. 160 pixels wide and 90 pixels tall.
+</p>
+<pre><code class="language-ruby">def tick args
+ # X Y WIDTH HEIGHT PATH
+ args.outputs.sprites << [100, 100, 160, 90, "sprites/circle/white.png]
+end
+</code></pre>
+<h2 id='---rendering-a-sprite-using-an-array-with-colors-and-alpha'>Rendering a sprite using an Array with colors and alpha</h2>
+<p>
+The value for the color and alpha is a number between <code>0</code> and <code>255</code>. The alpha property is optional and will be set to <code>255</code> if not specified.
+</p>
+<p>
+Creates a green circle sprite with an opacity of 50%.
+</p>
+<pre><code class="language-ruby">def tick args
+ # X Y WIDTH HEIGHT PATH ANGLE ALPHA RED GREEN BLUE
+ args.outputs.sprites << [100, 100, 160, 90, "sprites/circle/white.png", 0, 128, 0, 255, 0]
+end
+</code></pre>
+<h2 id='---rendering-a-sprite-using-a-hash'>Rendering a sprite using a Hash</h2>
+<p>
+If you want a more readable invocation. You can use the following hash to create a sprite. Any parameters that are not specified will be given a default value. The keys of the hash can be provided in any order.
+</p>
+<pre><code class="language-ruby">def tick args
+ args.outputs.sprites << {
+ x: 0,
+ y: 0,
+ w: 100,
+ h: 100,
+ path: "sprites/circle/white.png",
+ angle: 0,
+ a: 255,
+ r: 0,
+ g: 255,
+ b: 0
+ }
+end
+</code></pre>
+<h2 id='---rendering-a-solid-using-a-class'>Rendering a solid using a Class</h2>
+<p>
+You can also create a class with solid/border properties and render it as a primitive. ALL properties must be on the class. *Additionally*, a method called <code>primitive_marker</code> must be defined on the class.
+</p>
+<p>
+Here is an example:
+</p>
+<pre><code class="language-ruby"># Create type with ALL sprite properties AND primitive_marker
+class Sprite
+ attr_accessor :x, :y, :w, :h, :path, :angle, :angle_anchor_x, :angle_anchor_y, :tile_x, :tile_y, :tile_w, :tile_h, :source_x, :source_y, :source_w, :source_h, :flip_horizontally, :flip_vertically, :a, :r, :g, :b
+
+ def primitive_marker
+ :sprite
+ end
+end
+
+# Inherit from type
+class Circle < Sprite
+# constructor
+ def initialize x, y, size, path
+ self.x = x
+ self.y = y
+ self.w = size
+ self.h = size
+ self.path = path
+ end
+ def serlialize
+ {x:self.x, y:self.y, w:self.w, h:self.h, path:self.path}
+ end
+
+ def inspect
+ serlialize.to_s
+ end
+
+ def to_s
+ serlialize.to_s
+ end
+end
+def tick args
+ # render circle sprite
+ args.outputs.sprites << Circle.new(10, 10, 32,"sprites/circle/white.png")
+end
+</code></pre>
<h1 id='--docs---gtk--outputs#screenshots-'>DOCS: <code>GTK::Outputs#screenshots</code></h1>
<p>
Add a hash to this collection to take a screenshot and save as png file. The keys of the hash can be provided in any order.
@@ -2160,12 +2290,12 @@ The <code>GTK::MousePoint</code> has the following properties.
<li><code>x</code>: Integer representing the mouse's x.</li>
<li><code>y</code>: Integer representing the mouse's y.</li>
<li><code>point</code>: Array with the <code>x</code> and <code>y</code> values.</li>
-<li><code>w</code>: Width of the point that always returns <code>0</code> (included so that it can seemlessly work with <code>GTK::Geometry</code> functions).</li>
-<li><code>h</code>: Height of the point that always returns <code>0</code> (included so that it can seemlessly work with <code>GTK::Geometry</code> functions).</li>
-<li><code>left</code>: This value is the same as <code>x</code> (included so that it can seemlessly work with <code>GTK::Geometry</code> functions).</li>
-<li><code>right</code>: This value is the same as <code>x</code> (included so that it can seemlessly work with <code>GTK::Geometry</code> functions).</li>
-<li><code>top</code>: This value is the same as <code>y</code> (included so that it can seemlessly work with <code>GTK::Geometry</code> functions).</li>
-<li><code>bottom</code>: This value is the same as <code>y</code> (included so that it can seemlessly work with <code>GTK::Geometry</code> functions).</li>
+<li><code>w</code>: Width of the point that always returns <code>0</code> (included so that it can seamlessly work with <code>GTK::Geometry</code> functions).</li>
+<li><code>h</code>: Height of the point that always returns <code>0</code> (included so that it can seamlessly work with <code>GTK::Geometry</code> functions).</li>
+<li><code>left</code>: This value is the same as <code>x</code> (included so that it can seamlessly work with <code>GTK::Geometry</code> functions).</li>
+<li><code>right</code>: This value is the same as <code>x</code> (included so that it can seamlessly work with <code>GTK::Geometry</code> functions).</li>
+<li><code>top</code>: This value is the same as <code>y</code> (included so that it can seamlessly work with <code>GTK::Geometry</code> functions).</li>
+<li><code>bottom</code>: This value is the same as <code>y</code> (included so that it can seamlessly work with <code>GTK::Geometry</code> functions).</li>
<li><code>created_at</code>: The tick (<code>args.state.tick_count</code>) that this structure was created.</li>
<li><code>global_created_at</code>: The global tick (<code>Kernel.global_tick_count</code>) that this structure was created.</li>
</ul>
@@ -2322,7 +2452,7 @@ And here is an example where the override parameter is passed in:
end
end
</code></pre>
-<h1 id='--docs---numeric#elapsed?-'>DOCS: <code>Numeric#elapsed?</code></h1>
+<h1 id='--docs---numeric#elapsed--'>DOCS: <code>Numeric#elapsed?</code></h1>
<p>
Returns true if <code>Numeric#elapsed_time</code> is greater than the number. An optional parameter can be passed into <code>elapsed?</code> which is added to the number before evaluating whether <code>elapsed?</code> is true.
</p>
@@ -2386,7 +2516,7 @@ Example usage (with optional parameter):
args.state.box_queue -= boxes_to_destroy
end
</code></pre>
-<h1 id='--docs---numeric#created?-'>DOCS: <code>Numeric#created?</code></h1>
+<h1 id='--docs---numeric#created--'>DOCS: <code>Numeric#created?</code></h1>
<p>
Returns true if <code>Numeric#elapsed_time == 0</code>. Essentially communicating that number is equal to the current frame.
</p>
@@ -2455,7 +2585,7 @@ end
Follows is a source code listing for all files that have been open sourced. This code can be found in the <code>./samples</code> directory.
</p>
<h2 id='---samples'>Samples</h2>
-<h3 id='----learn-ruby-optional---beginner-ruby-primer---automation.rb'>Learn Ruby Optional - Beginner Ruby Primer - automation.rb</h3>
+<h3 id='----learn-ruby-optional---beginner-ruby-primer---automation-rb'>Learn Ruby Optional - Beginner Ruby Primer - automation.rb</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_beginner_ruby_primer/app/automation.rb
# ==========================================================================
# _ _ ________ __ _ _____ _____ _______ ______ _ _ _ _ _ _
@@ -2579,7 +2709,7 @@ $gtk.schedule_callback 400 do
end
</code></pre>
-<h3 id='----learn-ruby-optional---beginner-ruby-primer---main.rb'>Learn Ruby Optional - Beginner Ruby Primer - main.rb</h3>
+<h3 id='----learn-ruby-optional---beginner-ruby-primer---main-rb'>Learn Ruby Optional - Beginner Ruby Primer - main.rb</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_beginner_ruby_primer/app/main.rb
# ==========================================================================
# _ _ ________ __ _ _____ _____ _______ ______ _ _ _ _ _ _
@@ -2900,7 +3030,7 @@ def outputs
end
</code></pre>
-<h3 id='----learn-ruby-optional---intermediate-ruby-primer---printing.txt'>Learn Ruby Optional - Intermediate Ruby Primer - printing.txt</h3>
+<h3 id='----learn-ruby-optional---intermediate-ruby-primer---printing-txt'>Learn Ruby Optional - Intermediate Ruby Primer - printing.txt</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/01_printing.txt
# ====================================================================================
# Commenting Code
@@ -2935,7 +3065,7 @@ repl do
end
</code></pre>
-<h3 id='----learn-ruby-optional---intermediate-ruby-primer---strings.txt'>Learn Ruby Optional - Intermediate Ruby Primer - strings.txt</h3>
+<h3 id='----learn-ruby-optional---intermediate-ruby-primer---strings-txt'>Learn Ruby Optional - Intermediate Ruby Primer - strings.txt</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/02_strings.txt
# ====================================================================================
# Strings
@@ -2954,7 +3084,7 @@ repl do
end
</code></pre>
-<h3 id='----learn-ruby-optional---intermediate-ruby-primer---numbers.txt'>Learn Ruby Optional - Intermediate Ruby Primer - numbers.txt</h3>
+<h3 id='----learn-ruby-optional---intermediate-ruby-primer---numbers-txt'>Learn Ruby Optional - Intermediate Ruby Primer - numbers.txt</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/03_numbers.txt
# ====================================================================================
# Numerics
@@ -2979,7 +3109,7 @@ repl do
end
</code></pre>
-<h3 id='----learn-ruby-optional---intermediate-ruby-primer---booleans.txt'>Learn Ruby Optional - Intermediate Ruby Primer - booleans.txt</h3>
+<h3 id='----learn-ruby-optional---intermediate-ruby-primer---booleans-txt'>Learn Ruby Optional - Intermediate Ruby Primer - booleans.txt</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/04_booleans.txt
# ====================================================================================
# Booleans
@@ -3015,7 +3145,7 @@ repl do
end
</code></pre>
-<h3 id='----learn-ruby-optional---intermediate-ruby-primer---conditionals.txt'>Learn Ruby Optional - Intermediate Ruby Primer - conditionals.txt</h3>
+<h3 id='----learn-ruby-optional---intermediate-ruby-primer---conditionals-txt'>Learn Ruby Optional - Intermediate Ruby Primer - conditionals.txt</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/05_conditionals.txt
# ====================================================================================
# Conditionals
@@ -3133,7 +3263,7 @@ repl do
end
</code></pre>
-<h3 id='----learn-ruby-optional---intermediate-ruby-primer---looping.txt'>Learn Ruby Optional - Intermediate Ruby Primer - looping.txt</h3>
+<h3 id='----learn-ruby-optional---intermediate-ruby-primer---looping-txt'>Learn Ruby Optional - Intermediate Ruby Primer - looping.txt</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/06_looping.txt
# ====================================================================================
# Looping
@@ -3192,7 +3322,7 @@ repl do
end
</code></pre>
-<h3 id='----learn-ruby-optional---intermediate-ruby-primer---functions.txt'>Learn Ruby Optional - Intermediate Ruby Primer - functions.txt</h3>
+<h3 id='----learn-ruby-optional---intermediate-ruby-primer---functions-txt'>Learn Ruby Optional - Intermediate Ruby Primer - functions.txt</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/07_functions.txt
# ====================================================================================
# Functions
@@ -3265,7 +3395,7 @@ repl do
end
</code></pre>
-<h3 id='----learn-ruby-optional---intermediate-ruby-primer---arrays.txt'>Learn Ruby Optional - Intermediate Ruby Primer - arrays.txt</h3>
+<h3 id='----learn-ruby-optional---intermediate-ruby-primer---arrays-txt'>Learn Ruby Optional - Intermediate Ruby Primer - arrays.txt</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/08_arrays.txt
# ====================================================================================
# Arrays
@@ -3479,14 +3609,14 @@ end
# ====================================================================================
</code></pre>
-<h3 id='----learn-ruby-optional---intermediate-ruby-primer---main.rb'>Learn Ruby Optional - Intermediate Ruby Primer - main.rb</h3>
+<h3 id='----learn-ruby-optional---intermediate-ruby-primer---main-rb'>Learn Ruby Optional - Intermediate Ruby Primer - main.rb</h3>
<pre><code class="language-ruby"># ./samples/00_learn_ruby_optional/00_intermediate_ruby_primer/app/main.rb
def tick args
args.outputs.labels << [640, 380, "Open repl.rb in the text editor of your choice and follow the document.", 0, 1]
end
</code></pre>
-<h3 id='----rendering-basics---labels---main.rb'>Rendering Basics - Labels - main.rb</h3>
+<h3 id='----rendering-basics---labels---main-rb'>Rendering Basics - Labels - main.rb</h3>
<pre><code class="language-ruby"># ./samples/01_rendering_basics/01_labels/app/main.rb
=begin
@@ -3557,7 +3687,7 @@ def tick args
g: 0,
b: 200,
a: 255,
- font: "manaspc.ttf" }.label
+ font: "manaspc.ttf" }.label!
# Primitives can hold anything, and can be given a label in the following forms
args.outputs.primitives << [690 + 150, 330 - 80, "Custom font (.primitives Array)", 0, 1, 125, 0, 200, 255, "manaspc.ttf" ].label
@@ -3571,7 +3701,7 @@ def tick args
g: 0,
b: 200,
a: 255,
- font: "manaspc.ttf" }.label
+ font: "manaspc.ttf" }.label!
end
def tick_instructions args, text, y = 715
@@ -3589,7 +3719,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----rendering-basics---lines---main.rb'>Rendering Basics - Lines - main.rb</h3>
+<h3 id='----rendering-basics---lines---main-rb'>Rendering Basics - Lines - main.rb</h3>
<pre><code class="language-ruby"># ./samples/01_rendering_basics/02_lines/app/main.rb
=begin
@@ -3647,7 +3777,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----rendering-basics---solids-borders---main.rb'>Rendering Basics - Solids Borders - main.rb</h3>
+<h3 id='----rendering-basics---solids-borders---main-rb'>Rendering Basics - Solids Borders - main.rb</h3>
<pre><code class="language-ruby"># ./samples/01_rendering_basics/03_solids_borders/app/main.rb
=begin
@@ -3717,7 +3847,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----rendering-basics---sprites---main.rb'>Rendering Basics - Sprites - main.rb</h3>
+<h3 id='----rendering-basics---sprites---main-rb'>Rendering Basics - Sprites - main.rb</h3>
<pre><code class="language-ruby"># ./samples/01_rendering_basics/04_sprites/app/main.rb
=begin
@@ -3764,7 +3894,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----rendering-basics---sounds---main.rb'>Rendering Basics - Sounds - main.rb</h3>
+<h3 id='----rendering-basics---sounds---main-rb'>Rendering Basics - Sounds - main.rb</h3>
<pre><code class="language-ruby"># ./samples/01_rendering_basics/05_sounds/app/main.rb
=begin
@@ -3799,768 +3929,7 @@ def tick args
end
</code></pre>
-<h3 id='----rendering-basics---audio-mixer---main.rb'>Rendering Basics - Audio Mixer - main.rb</h3>
-<pre><code class="language-ruby"># ./samples/01_rendering_basics/06_audio_mixer/app/main.rb
-$gtk.reset
-
-$boxsize = 30
-
-def render_sources args
- mouse_in_panel = (args.state.selected != 0) && args.inputs.mouse.position.inside_rect?([900, 450, 340, 250])
- mouse_new_down = (args.state.mouse_held == 1)
-
- if (mouse_new_down && !mouse_in_panel)
- args.state.selected = 0 # will reset below if we hit something.
- end
-
- args.audio.keys.each { |k|
- s = args.audio[k]
-
- if (mouse_new_down) && !mouse_in_panel && args.inputs.mouse.position.inside_rect?([s[:screenx], s[:screeny], $boxsize, $boxsize])
- args.state.selected = k
- args.state.dragging_source = true
- end
-
- isselected = (k == args.state.selected)
-
- if isselected && args.state.dragging_source
- # you can hang anything on the audio hashes you want, so we store the
- # actual screen position so it doesn't scale weirdly vs your mouse.
- s[:screenx] = args.inputs.mouse.x - ($boxsize / 2)
- s[:screeny] = args.inputs.mouse.y - ($boxsize / 2)
-
- s[:screeny] = 50 if s[:screeny] < 50
- s[:screeny] = (719 - $boxsize) if s[:screeny] > (719 - $boxsize)
- s[:screenx] = 0 if s[:screenx] < 0
- s[:screenx] = (1279 - $boxsize) if s[:screenx] > (1279 - $boxsize)
-
- s[:x] = ((s[:screenx] / 1279.0) * 2.0) - 1.0 # scale to -1.0 - 1.0 range
- s[:y] = ((s[:screeny] / 719.0) * 2.0) - 1.0 # scale to -1.0 - 1.0 range
- end
-
- color = isselected ? [ 0, 255, 0, 255 ] : [ 0, 0, 255, 255 ]
- args.outputs.primitives << [s[:screenx], s[:screeny], $boxsize, $boxsize, *color].solid
- }
-end
-
-def render_panel args
- s = args.audio[args.state.selected]
- return if s.nil?
- mouse_down = (args.state.mouse_held > 0)
-
- args.outputs.primitives << [900, 450, 340, 250, 127, 127, 200, 255].solid
- args.outputs.primitives << [1075, 690, "Source ##{args.state.selected}", 3, 1, 255, 255, 255].label
- args.outputs.primitives << [910, 660, 1230, 660, 255, 255, 255].line
- args.outputs.primitives << [910, 650, "screen: (#{s[:screenx].to_i}, #{s[:screeny].to_i})", 0, 0, 255, 255, 255].label
- args.outputs.primitives << [910, 625, "position: (#{s[:x].round(5).to_s[0..6]}, #{s[:y].round(5).to_s[0..6]})", 0, 0, 255, 255, 255].label
-
- slider = [1022, 586, 200, 7]
- if mouse_down && args.inputs.mouse.position.inside_rect?(slider)
- s[:pitch] = ((args.inputs.mouse.x - slider[0]).to_f / (slider[2]-1.0)) * 2.0
- end
- slidercolor = (s[:pitch] / 2.0) * 255
- args.outputs.primitives << [*slider, slidercolor, slidercolor, slidercolor, 255].solid
- args.outputs.primitives << [910, 600, "pitch: #{s[:pitch].round(3).to_s[0..2]}", 0, 0, 255, 255, 255].label
-
- slider = [1022, 561, 200, 7]
- if mouse_down && args.inputs.mouse.position.inside_rect?(slider)
- s[:gain] = (args.inputs.mouse.x - slider[0]).to_f / (slider[2]-1.0)
- end
- slidercolor = s[:gain] * 255
- args.outputs.primitives << [*slider, slidercolor, slidercolor, slidercolor, 255].solid
- args.outputs.primitives << [910, 575, "gain: #{s[:gain].round(3).to_s[0..2]}", 0, 0, 255, 255, 255].label
-
- checkbox = [1022, 533, 10, 12]
- if (args.state.mouse_held == 1) && args.inputs.mouse.position.inside_rect?(checkbox)
- s[:looping] = !s[:looping]
- end
- checkboxcolor = s[:looping] ? 255 : 0
- args.outputs.primitives << [*checkbox, checkboxcolor, checkboxcolor, checkboxcolor, 255].solid
- args.outputs.primitives << [910, 550, "looping:", 0, 0, 255, 255, 255].label
-
- checkbox = [1022, 508, 10, 12]
- if (args.state.mouse_held == 1) && args.inputs.mouse.position.inside_rect?(checkbox)
- s[:paused] = !s[:paused]
- end
- checkboxcolor = s[:paused] ? 255 : 0
- args.outputs.primitives << [*checkbox, checkboxcolor, checkboxcolor, checkboxcolor, 255].solid
- args.outputs.primitives << [910, 525, "paused:", 0, 0, 255, 255, 255].label
-
- button = [910, 460, 320, 20]
- if (args.state.mouse_held == 1) && args.inputs.mouse.position.inside_rect?(button)
- args.audio.delete(args.state.selected)
- args.state.selected = 0
- end
- args.outputs.primitives << [*button, 255, 0, 0, 255].solid
- args.outputs.primitives << [button[0] + (button[2] / 2), button[1]+20, "DELETE SOURCE", 0, 1, 255, 255, 0].label
-end
-
-def spawn_new_sound args, num
- input = nil
- input = "sounds/#{num}.#{(num == 6) ? 'ogg' : 'wav'}"
-
- # Spawn randomly in an area that won't be covered by UI.
- screenx = (rand * 600.0) + 200.0
- screeny = (rand * 400.0) + 100.0
-
- args.state.next_sound_index += 1
-
- # you can hang anything on the audio hashes you want, so we store the
- # actual screen position in here for convenience.
- args.audio[args.state.next_sound_index] = {
- input: input,
- screenx: screenx,
- screeny: screeny,
- x: ((screenx / 1279.0) * 2.0) - 1.0, # scale to -1.0 - 1.0 range
- y: ((screeny / 719.0) * 2.0) - 1.0, # scale to -1.0 - 1.0 range
- z: 0.0,
- gain: 1.0,
- pitch: 1.0,
- looping: true,
- paused: false
- }
-
- args.state.selected = args.state.next_sound_index
-end
-
-def render_launcher args
- total = 6
- x = (1280 - (total * $boxsize * 3)) / 2
- y = 10
- args.outputs.primitives << [0, 0, 1280, ((y*2) + $boxsize), 127, 127, 127, 255].solid
- for i in 1..total
- args.outputs.primitives << [x, y, $boxsize, $boxsize, 255, 255, 255, 255].solid
- args.outputs.primitives << [x+8, y+28, i.to_s, 3, 0, 0, 0, 255, 255].label
- if args.inputs.mouse.click && args.inputs.mouse.click.point.inside_rect?([x, y, $boxsize, $boxsize])
- spawn_new_sound args, i
- end
- x = x + ($boxsize * 3)
- end
-end
-
-def render_ui args
- render_launcher args
- render_panel args
-end
-
-def tick args
- args.state.mouse_held ||= 0
- args.state.dragging_source ||= false
- args.state.selected ||= 0
- args.state.next_sound_index ||= 0
-
- if args.inputs.mouse.up
- args.state.mouse_held = 0
- args.state.dragging_source = false
- elsif args.inputs.mouse.down || (args.state.mouse_held > 0)
- args.state.mouse_held += 1
- else
- end
-
- args.outputs.background_color = [ 0, 0, 0, 255 ]
- render_sources args
- render_ui args
-end
-
-</code></pre>
-<h3 id='----rendering-basics---sound-synthesis---main.rb'>Rendering Basics - Sound Synthesis - main.rb</h3>
-<pre><code class="language-ruby"># ./samples/01_rendering_basics/07_sound_synthesis/app/main.rb
-begin # region: top level tick methods
- def tick args
- defaults args
- render args
- input args
- process_audio_queue args
- end
-
- def defaults args
- args.state.sine_waves ||= {}
- args.state.square_waves ||= {}
- args.state.saw_tooth_waves ||= {}
- args.state.triangle_waves ||= {}
- args.state.audio_queue ||= []
- args.state.buttons ||= [
- (frequency_buttons args),
- (sine_wave_note_buttons args),
- (bell_buttons args),
- (square_wave_note_buttons args),
- (saw_tooth_wave_note_buttons args),
- (triangle_wave_note_buttons args),
- ].flatten
- end
-
- def render args
- args.outputs.borders << args.state.buttons.map { |b| b[:border] }
- args.outputs.labels << args.state.buttons.map { |b| b[:label] }
- args.outputs.labels << args.layout
- .rect(row: 0, col: 11.5)
- .yield_self { |r| r.merge y: r.y + r.h }
- .merge(text: "This is a Pro only feature. Click here to watch the YouTube video if you are on the Standard License.",
- alignment_enum: 1)
- end
-
-
- def input args
- args.state.buttons.each do |b|
- if args.inputs.mouse.click && (args.inputs.mouse.click.inside_rect? b[:rect])
- parameter_string = (b.slice :frequency, :note, :octave).map { |k, v| "#{k}: #{v}" }.join ", "
- args.gtk.notify! "#{b[:method_to_call]} #{parameter_string}"
- send b[:method_to_call], args, b
- end
- end
-
- if args.inputs.mouse.click && (args.inputs.mouse.click.inside_rect? (args.layout.rect(row: 0).yield_self { |r| r.merge y: r.y + r.h.half, h: r.h.half }))
- args.gtk.openurl 'https://www.youtube.com/watch?v=zEzovM5jT-k&ab_channel=AmirRajan'
- end
- end
-
- def process_audio_queue args
- to_queue = args.state.audio_queue.find_all { |v| v[:queue_at] <= args.tick_count }
- args.state.audio_queue -= to_queue
- to_queue.each { |a| args.audio[a[:id]] = a }
-
- args.audio.find_all { |k, v| v[:decay_rate] }
- .each { |k, v| v[:gain] -= v[:decay_rate] }
-
- sounds_to_stop = args.audio
- .find_all { |k, v| v[:stop_at] && args.state.tick_count >= v[:stop_at] }
- .map { |k, v| k }
-
- sounds_to_stop.each { |k| args.audio.delete k }
- end
-end
-
-begin # region: button definitions, ui layout, callback functions
- def button args, opts
- button_def = opts.merge rect: (args.layout.rect (opts.merge w: 2, h: 1))
-
- button_def[:border] = button_def[:rect].merge r: 0, g: 0, b: 0
-
- label_offset_x = 5
- label_offset_y = 30
-
- button_def[:label] = button_def[:rect].merge text: opts[:text],
- size_enum: -2.5,
- x: button_def[:rect].x + label_offset_x,
- y: button_def[:rect].y + label_offset_y
-
- button_def
- end
-
- def play_sine_wave args, sender
- queue_sine_wave args,
- frequency: sender[:frequency],
- duration: 1.seconds,
- fade_out: true
- end
-
- def play_note args, sender
- method_to_call = :queue_sine_wave
- method_to_call = :queue_square_wave if sender[:type] == :square
- method_to_call = :queue_saw_tooth_wave if sender[:type] == :saw_tooth
- method_to_call = :queue_triangle_wave if sender[:type] == :triangle
- method_to_call = :queue_bell if sender[:type] == :bell
-
- send method_to_call, args,
- frequency: (frequency_for note: sender[:note], octave: sender[:octave]),
- duration: 1.seconds,
- fade_out: true
- end
-
- def frequency_buttons args
- [
- (button args,
- row: 4.0, col: 0, text: "300hz",
- frequency: 300,
- method_to_call: :play_sine_wave),
- (button args,
- row: 5.0, col: 0, text: "400hz",
- frequency: 400,
- method_to_call: :play_sine_wave),
- (button args,
- row: 6.0, col: 0, text: "500hz",
- frequency: 500,
- method_to_call: :play_sine_wave),
- ]
- end
-
- def sine_wave_note_buttons args
- [
- (button args,
- row: 1.5, col: 2, text: "Sine C4",
- note: :c, octave: 4, type: :sine, method_to_call: :play_note),
- (button args,
- row: 2.5, col: 2, text: "Sine D4",
- note: :d, octave: 4, type: :sine, method_to_call: :play_note),
- (button args,
- row: 3.5, col: 2, text: "Sine E4",
- note: :e, octave: 4, type: :sine, method_to_call: :play_note),
- (button args,
- row: 4.5, col: 2, text: "Sine F4",
- note: :f, octave: 4, type: :sine, method_to_call: :play_note),
- (button args,
- row: 5.5, col: 2, text: "Sine G4",
- note: :g, octave: 4, type: :sine, method_to_call: :play_note),
- (button args,
- row: 6.5, col: 2, text: "Sine A5",
- note: :a, octave: 5, type: :sine, method_to_call: :play_note),
- (button args,
- row: 7.5, col: 2, text: "Sine B5",
- note: :b, octave: 5, type: :sine, method_to_call: :play_note),
- (button args,
- row: 8.5, col: 2, text: "Sine C5",
- note: :c, octave: 5, type: :sine, method_to_call: :play_note),
- ]
- end
-
- def square_wave_note_buttons args
- [
- (button args,
- row: 1.5, col: 6, text: "Square C4",
- note: :c, octave: 4, type: :square, method_to_call: :play_note),
- (button args,
- row: 2.5, col: 6, text: "Square D4",
- note: :d, octave: 4, type: :square, method_to_call: :play_note),
- (button args,
- row: 3.5, col: 6, text: "Square E4",
- note: :e, octave: 4, type: :square, method_to_call: :play_note),
- (button args,
- row: 4.5, col: 6, text: "Square F4",
- note: :f, octave: 4, type: :square, method_to_call: :play_note),
- (button args,
- row: 5.5, col: 6, text: "Square G4",
- note: :g, octave: 4, type: :square, method_to_call: :play_note),
- (button args,
- row: 6.5, col: 6, text: "Square A5",
- note: :a, octave: 5, type: :square, method_to_call: :play_note),
- (button args,
- row: 7.5, col: 6, text: "Square B5",
- note: :b, octave: 5, type: :square, method_to_call: :play_note),
- (button args,
- row: 8.5, col: 6, text: "Square C5",
- note: :c, octave: 5, type: :square, method_to_call: :play_note),
- ]
- end
- def saw_tooth_wave_note_buttons args
- [
- (button args,
- row: 1.5, col: 8, text: "Saw C4",
- note: :c, octave: 4, type: :saw_tooth, method_to_call: :play_note),
- (button args,
- row: 2.5, col: 8, text: "Saw D4",
- note: :d, octave: 4, type: :saw_tooth, method_to_call: :play_note),
- (button args,
- row: 3.5, col: 8, text: "Saw E4",
- note: :e, octave: 4, type: :saw_tooth, method_to_call: :play_note),
- (button args,
- row: 4.5, col: 8, text: "Saw F4",
- note: :f, octave: 4, type: :saw_tooth, method_to_call: :play_note),
- (button args,
- row: 5.5, col: 8, text: "Saw G4",
- note: :g, octave: 4, type: :saw_tooth, method_to_call: :play_note),
- (button args,
- row: 6.5, col: 8, text: "Saw A5",
- note: :a, octave: 5, type: :saw_tooth, method_to_call: :play_note),
- (button args,
- row: 7.5, col: 8, text: "Saw B5",
- note: :b, octave: 5, type: :saw_tooth, method_to_call: :play_note),
- (button args,
- row: 8.5, col: 8, text: "Saw C5",
- note: :c, octave: 5, type: :saw_tooth, method_to_call: :play_note),
- ]
- end
-
- def triangle_wave_note_buttons args
- [
- (button args,
- row: 1.5, col: 10, text: "Triangle C4",
- note: :c, octave: 4, type: :triangle, method_to_call: :play_note),
- (button args,
- row: 2.5, col: 10, text: "Triangle D4",
- note: :d, octave: 4, type: :triangle, method_to_call: :play_note),
- (button args,
- row: 3.5, col: 10, text: "Triangle E4",
- note: :e, octave: 4, type: :triangle, method_to_call: :play_note),
- (button args,
- row: 4.5, col: 10, text: "Triangle F4",
- note: :f, octave: 4, type: :triangle, method_to_call: :play_note),
- (button args,
- row: 5.5, col: 10, text: "Triangle G4",
- note: :g, octave: 4, type: :triangle, method_to_call: :play_note),
- (button args,
- row: 6.5, col: 10, text: "Triangle A5",
- note: :a, octave: 5, type: :triangle, method_to_call: :play_note),
- (button args,
- row: 7.5, col: 10, text: "Triangle B5",
- note: :b, octave: 5, type: :triangle, method_to_call: :play_note),
- (button args,
- row: 8.5, col: 10, text: "Triangle C5",
- note: :c, octave: 5, type: :triangle, method_to_call: :play_note),
- ]
- end
-
- def bell_buttons args
- [
- (button args,
- row: 1.5, col: 4, text: "Bell C4",
- note: :c, octave: 4, type: :bell, method_to_call: :play_note),
- (button args,
- row: 2.5, col: 4, text: "Bell D4",
- note: :d, octave: 4, type: :bell, method_to_call: :play_note),
- (button args,
- row: 3.5, col: 4, text: "Bell E4",
- note: :e, octave: 4, type: :bell, method_to_call: :play_note),
- (button args,
- row: 4.5, col: 4, text: "Bell F4",
- note: :f, octave: 4, type: :bell, method_to_call: :play_note),
- (button args,
- row: 5.5, col: 4, text: "Bell G4",
- note: :g, octave: 4, type: :bell, method_to_call: :play_note),
- (button args,
- row: 6.5, col: 4, text: "Bell A5",
- note: :a, octave: 5, type: :bell, method_to_call: :play_note),
- (button args,
- row: 7.5, col: 4, text: "Bell B5",
- note: :b, octave: 5, type: :bell, method_to_call: :play_note),
- (button args,
- row: 8.5, col: 4, text: "Bell C5",
- note: :c, octave: 5, type: :bell, method_to_call: :play_note),
- ]
- end
-end
-
-begin # region: wave generation
- begin # sine wave
- def defaults_sine_wave_for
- { frequency: 440, sample_rate: 48000 }
- end
-
- def sine_wave_for opts = {}
- opts = defaults_sine_wave_for.merge opts
- frequency = opts[:frequency]
- sample_rate = opts[:sample_rate]
- period_size = (sample_rate.fdiv frequency).ceil
- period_size.map_with_index do |i|
- Math::sin((2.0 * Math::PI) / (sample_rate.to_f / frequency.to_f) * i)
- end.to_a
- end
-
- def defaults_queue_sine_wave
- { frequency: 440, duration: 60, gain: 1.0, fade_out: false, queue_in: 0 }
- end
-
- def queue_sine_wave args, opts = {}
- opts = defaults_queue_sine_wave.merge opts
- frequency = opts[:frequency]
- sample_rate = 48000
-
- sine_wave = sine_wave_for frequency: frequency, sample_rate: sample_rate
- args.state.sine_waves[frequency] ||= sine_wave_for frequency: frequency, sample_rate: sample_rate
-
- proc = lambda do
- generate_audio_data args.state.sine_waves[frequency], sample_rate
- end
-
- audio_state = new_audio_state args, opts
- audio_state[:input] = [1, sample_rate, proc]
- queue_audio args, audio_state: audio_state, wave: sine_wave
- end
- end
-
- begin # region: square wave
- def defaults_square_wave_for
- { frequency: 440, sample_rate: 48000 }
- end
-
- def square_wave_for opts = {}
- opts = defaults_square_wave_for.merge opts
- sine_wave = sine_wave_for opts
- sine_wave.map do |v|
- if v >= 0
- 1.0
- else
- -1.0
- end
- end.to_a
- end
-
- def defaults_queue_square_wave
- { frequency: 440, duration: 60, gain: 0.3, fade_out: false, queue_in: 0 }
- end
-
- def queue_square_wave args, opts = {}
- opts = defaults_queue_square_wave.merge opts
- frequency = opts[:frequency]
- sample_rate = 48000
-
- square_wave = square_wave_for frequency: frequency, sample_rate: sample_rate
- args.state.square_waves[frequency] ||= square_wave_for frequency: frequency, sample_rate: sample_rate
-
- proc = lambda do
- generate_audio_data args.state.square_waves[frequency], sample_rate
- end
-
- audio_state = new_audio_state args, opts
- audio_state[:input] = [1, sample_rate, proc]
- queue_audio args, audio_state: audio_state, wave: square_wave
- end
- end
-
- begin # region: saw tooth wave
- def defaults_saw_tooth_wave_for
- { frequency: 440, sample_rate: 48000 }
- end
-
- def saw_tooth_wave_for opts = {}
- opts = defaults_saw_tooth_wave_for.merge opts
- sine_wave = sine_wave_for opts
- period_size = sine_wave.length
- sine_wave.map_with_index do |v, i|
- (((i % period_size).fdiv period_size) * 2) - 1
- end
- end
-
- def defaults_queue_saw_tooth_wave
- { frequency: 440, duration: 60, gain: 0.3, fade_out: false, queue_in: 0 }
- end
-
- def queue_saw_tooth_wave args, opts = {}
- opts = defaults_queue_saw_tooth_wave.merge opts
- frequency = opts[:frequency]
- sample_rate = 48000
-
- saw_tooth_wave = saw_tooth_wave_for frequency: frequency, sample_rate: sample_rate
- args.state.saw_tooth_waves[frequency] ||= saw_tooth_wave_for frequency: frequency, sample_rate: sample_rate
-
- proc = lambda do
- generate_audio_data args.state.saw_tooth_waves[frequency], sample_rate
- end
-
- audio_state = new_audio_state args, opts
- audio_state[:input] = [1, sample_rate, proc]
- queue_audio args, audio_state: audio_state, wave: saw_tooth_wave
- end
- end
-
- begin # region: triangle wave
- def defaults_triangle_wave_for
- { frequency: 440, sample_rate: 48000 }
- end
-
- def triangle_wave_for opts = {}
- opts = defaults_saw_tooth_wave_for.merge opts
- sine_wave = sine_wave_for opts
- period_size = sine_wave.length
- sine_wave.map_with_index do |v, i|
- ratio = (i.fdiv period_size)
- if ratio <= 0.5
- (ratio * 4) - 1
- else
- ratio -= 0.5
- 1 - (ratio * 4)
- end
- end
- end
-
- def defaults_queue_triangle_wave
- { frequency: 440, duration: 60, gain: 1.0, fade_out: false, queue_in: 0 }
- end
-
- def queue_triangle_wave args, opts = {}
- opts = defaults_queue_triangle_wave.merge opts
- frequency = opts[:frequency]
- sample_rate = 48000
-
- triangle_wave = triangle_wave_for frequency: frequency, sample_rate: sample_rate
- args.state.triangle_waves[frequency] ||= triangle_wave_for frequency: frequency, sample_rate: sample_rate
-
- proc = lambda do
- generate_audio_data args.state.triangle_waves[frequency], sample_rate
- end
-
- audio_state = new_audio_state args, opts
- audio_state[:input] = [1, sample_rate, proc]
- queue_audio args, audio_state: audio_state, wave: triangle_wave
- end
- end
-
- begin # region: bell
- def defaults_queue_bell
- { frequency: 440, duration: 1.seconds, queue_in: 0 }
- end
-
- def queue_bell args, opts = {}
- (bell_to_sine_waves (defaults_queue_bell.merge opts)).each { |b| queue_sine_wave args, b }
- end
-
- def bell_harmonics
- [
- { frequency_ratio: 0.5, duration_ratio: 1.00 },
- { frequency_ratio: 1.0, duration_ratio: 0.80 },
- { frequency_ratio: 2.0, duration_ratio: 0.60 },
- { frequency_ratio: 3.0, duration_ratio: 0.40 },
- { frequency_ratio: 4.2, duration_ratio: 0.25 },
- { frequency_ratio: 5.4, duration_ratio: 0.20 },
- { frequency_ratio: 6.8, duration_ratio: 0.15 }
- ]
- end
-
- def defaults_bell_to_sine_waves
- { frequency: 440, duration: 1.seconds, queue_in: 0 }
- end
-
- def bell_to_sine_waves opts = {}
- opts = defaults_bell_to_sine_waves.merge opts
- bell_harmonics.map do |b|
- {
- frequency: opts[:frequency] * b[:frequency_ratio],
- duration: opts[:duration] * b[:duration_ratio],
- queue_in: opts[:queue_in],
- gain: (1.fdiv bell_harmonics.length),
- fade_out: true
- }
- end
- end
- end
-
- begin # audio entity construction
- def generate_audio_data sine_wave, sample_rate
- sample_size = (sample_rate.fdiv (1000.fdiv 60)).ceil
- copy_count = (sample_size.fdiv sine_wave.length).ceil
- sine_wave * copy_count
- end
-
- def defaults_new_audio_state
- { frequency: 440, duration: 60, gain: 1.0, fade_out: false, queue_in: 0 }
- end
-
- def new_audio_state args, opts = {}
- opts = defaults_new_audio_state.merge opts
- decay_rate = 0
- decay_rate = 1.fdiv(opts[:duration]) * opts[:gain] if opts[:fade_out]
- frequency = opts[:frequency]
- sample_rate = 48000
-
- {
- id: (new_id! args),
- frequency: frequency,
- sample_rate: 48000,
- stop_at: args.tick_count + opts[:queue_in] + opts[:duration],
- gain: opts[:gain].to_f,
- queue_at: args.state.tick_count + opts[:queue_in],
- decay_rate: decay_rate,
- pitch: 1.0,
- looping: true,
- paused: false
- }
- end
-
- def queue_audio args, opts = {}
- graph_wave args, opts[:wave], opts[:audio_state][:frequency]
- args.state.audio_queue << opts[:audio_state]
- end
-
- def new_id! args
- args.state.audio_id ||= 0
- args.state.audio_id += 1
- end
-
- def graph_wave args, wave, frequency
- if args.state.tick_count != args.state.graphed_at
- args.outputs.static_lines.clear
- args.outputs.static_sprites.clear
- end
-
- wave = wave
-
- r, g, b = frequency.to_i % 85,
- frequency.to_i % 170,
- frequency.to_i % 255
-
- starting_rect = args.layout.rect(row: 5, col: 13)
- x_scale = 10
- y_scale = 100
- max_points = 25
-
- points = wave
- if wave.length > max_points
- resolution = wave.length.idiv max_points
- points = wave.find_all.with_index { |y, i| (i % resolution == 0) }
- end
-
- args.outputs.static_lines << points.map_with_index do |y, x|
- next_y = points[x + 1]
-
- if next_y
- {
- x: starting_rect.x + (x * x_scale),
- y: starting_rect.y + starting_rect.h.half + y_scale * y,
- x2: starting_rect.x + ((x + 1) * x_scale),
- y2: starting_rect.y + starting_rect.h.half + y_scale * next_y,
- r: r,
- g: g,
- b: b
- }
- end
- end
-
- args.outputs.static_sprites << points.map_with_index do |y, x|
- {
- x: (starting_rect.x + (x * x_scale)) - 2,
- y: (starting_rect.y + starting_rect.h.half + y_scale * y) - 2,
- w: 4,
- h: 4,
- path: 'sprites/square-white.png',
- r: r,
- g: g,
- b: b
- }
- end
-
- args.state.graphed_at = args.state.tick_count
- end
- end
-
- begin # region: musical note mapping
- def defaults_frequency_for
- { note: :a, octave: 5, sharp: false, flat: false }
- end
-
- def frequency_for opts = {}
- opts = defaults_frequency_for.merge opts
- octave_offset_multiplier = opts[:octave] - 5
- note = note_frequencies_octave_5[opts[:note]]
- if octave_offset_multiplier < 0
- note = note * 1 / (octave_offset_multiplier.abs + 1)
- elsif octave_offset_multiplier > 0
- note = note * (octave_offset_multiplier.abs + 1) / 1
- end
- note
- end
-
- def note_frequencies_octave_5
- {
- a: 440.0,
- a_sharp: 466.16, b_flat: 466.16,
- b: 493.88,
- c: 523.25,
- c_sharp: 554.37, d_flat: 587.33,
- d: 587.33,
- d_sharp: 622.25, e_flat: 659.25,
- e: 659.25,
- f: 698.25,
- f_sharp: 739.99, g_flat: 739.99,
- g: 783.99,
- g_sharp: 830.61, a_flat: 830.61
- }
- end
- end
-end
-
-$gtk.reset
-
-</code></pre>
-<h3 id='----input-basics---keyboard---main.rb'>Input Basics - Keyboard - main.rb</h3>
+<h3 id='----input-basics---keyboard---main-rb'>Input Basics - Keyboard - main.rb</h3>
<pre><code class="language-ruby"># ./samples/02_input_basics/01_keyboard/app/main.rb
=begin
@@ -4589,9 +3958,9 @@ APIs listing that haven't been encountered in a previous sample apps:
def tick args
tick_instructions args, "Sample app shows how keyboard events are registered and accessed.", 360
# Notice how small_font accounts for all the remaining parameters
- args.outputs.labels << [460, row_to_px(args, 0), "Current game time: #{args.state.tick_count}", small_font]
- args.outputs.labels << [460, row_to_px(args, 2), "Keyboard input: args.inputs.keyboard.key_up.h", small_font]
- args.outputs.labels << [460, row_to_px(args, 3), "Press \"h\" on the keyboard.", small_font]
+ args.outputs.labels << { x: 460, y: row_to_px(args, 0), text: "Current game time: #{args.state.tick_count}", size_enum: -1 }
+ args.outputs.labels << { x: 460, y: row_to_px(args, 2), text: "Keyboard input: args.inputs.keyboard.key_up.h", size_enum: -1 }
+ args.outputs.labels << { x: 460, y: row_to_px(args, 3), text: "Press \"h\" on the keyboard.", size_enum: -1 }
# Input on a specifc key can be found through args.inputs.keyboard.key_up followed by the key
if args.inputs.keyboard.key_up.h
@@ -4602,27 +3971,19 @@ def tick args
args.state.h_pressed_at ||= false
if args.state.h_pressed_at
- args.outputs.labels << [460, row_to_px(args, 4), "\"h\" was pressed at time: #{args.state.h_pressed_at}", small_font]
+ args.outputs.labels << { x: 460, y: row_to_px(args, 4), text: "\"h\" was pressed at time: #{args.state.h_pressed_at}", size_enum: -1 }
else
- args.outputs.labels << [460, row_to_px(args, 4), "\"h\" has never been pressed.", small_font]
+ args.outputs.labels << { x: 460, y: row_to_px(args, 4), text: "\"h\" has never been pressed.", size_enum: -1 }
end
tick_help_text args
end
-def small_font
- # This method provides some values for the construction of labels
- # Specifically, Size, Alignment, & RGBA
- # This makes it so that custom parameters don't have to be repeatedly typed.
- # Additionally "small_font" provides programmers with more information than some numbers
- [-2, 0, 0, 0, 0, 255]
-end
-
-def row_to_px args, row_number
+def row_to_px args, row_number, y_offset = 20
# This takes a row_number and converts it to pixels DragonRuby understands.
# Row 0 starts 5 units below the top of the grid
# Each row afterward is 20 units lower
- args.grid.top.shift_down(5).shift_down(20 * row_number)
+ args.grid.top - 5 - (y_offset * row_number)
end
# Don't worry about understanding the code within this method just yet.
@@ -4652,17 +4013,17 @@ def tick_help_text args
end
end
- args.outputs.labels << [10, row_to_px(args, 6), "Advanced Help:", small_font]
+ args.outputs.labels << { x: 10, y: row_to_px(args, 6), text: "This is the api for the keys you've pressed:", size_enum: -1, r: 180 }
if !args.state.help_available
args.outputs.labels << [10, row_to_px(args, 7), "Press a key and I'll show code to access the key and what value will be returned if you used the code.", small_font]
return
end
- args.outputs.labels << [10 , row_to_px(args, 7), "args.inputs.keyboard", small_font]
- args.outputs.labels << [330, row_to_px(args, 7), "args.inputs.keyboard.key_down", small_font]
- args.outputs.labels << [650, row_to_px(args, 7), "args.inputs.keyboard.key_held", small_font]
- args.outputs.labels << [990, row_to_px(args, 7), "args.inputs.keyboard.key_up", small_font]
+ args.outputs.labels << { x: 10 , y: row_to_px(args, 7), text: "args.inputs.keyboard", size_enum: -2 }
+ args.outputs.labels << { x: 330, y: row_to_px(args, 7), text: "args.inputs.keyboard.key_down", size_enum: -2 }
+ args.outputs.labels << { x: 650, y: row_to_px(args, 7), text: "args.inputs.keyboard.key_held", size_enum: -2 }
+ args.outputs.labels << { x: 990, y: row_to_px(args, 7), text: "args.inputs.keyboard.key_up", size_enum: -2 }
fill_history args, :key_value_history, :down_or_held, nil
fill_history args, :key_down_value_history, :down, :key_down
@@ -4708,12 +4069,8 @@ def render_help_labels args, history_key, state_key, keyboard_method, x
end
idx += 2
[
- [x, row_to_px(args, idx - 2),
- " .#{k} is #{current_value || "nil"}",
- small_font],
- [x, row_to_px(args, idx - 1),
- " was #{v}",
- small_font]
+ { x: x, y: row_to_px(args, idx + 0, 16), text: " .#{k} is #{current_value || "nil"}", size_enum: -2 },
+ { x: x, y: row_to_px(args, idx + 1, 16), text: " was #{v}", size_enum: -2 }
]
end
end
@@ -4728,13 +4085,49 @@ def tick_instructions args, text, y = 715
args.state.key_event_occurred = true
end
- args.outputs.debug << [0, y - 50, 1280, 60].solid
- args.outputs.debug << [640, y, text, 1, 1, 255, 255, 255].label
- args.outputs.debug << [640, y - 25, "(click to dismiss instructions)" , -2, 1, 255, 255, 255].label
+ args.outputs.debug << { x: 0, y: y - 50, w: 1280, h: 60 }.solid!
+ args.outputs.debug << { x: 640, y: y, text: text,
+ size_enum: 1, alignment_enum: 1, r: 255, g: 255, b: 255 }.label!
+ args.outputs.debug << { x: 640, y: y - 25, text: "(click to dismiss instructions)",
+ size_enum: -2, alignment_enum: 1, r: 255, g: 255, b: 255 }.label!
end
</code></pre>
-<h3 id='----input-basics---mouse---main.rb'>Input Basics - Mouse - main.rb</h3>
+<h3 id='----input-basics---moving-a-sprite---main-rb'>Input Basics - Moving A Sprite - main.rb</h3>
+<pre><code class="language-ruby"># ./samples/02_input_basics/01_moving_a_sprite/app/main.rb
+def tick args
+ # create a player and set default values
+ # for the player's x, y, w (width), and h (height)
+ args.state.player.x ||= 100
+ args.state.player.y ||= 100
+ args.state.player.w ||= 50
+ args.state.player.h ||= 50
+
+ # render the player to the screen
+ args.outputs.sprites << { x: args.state.player.x,
+ y: args.state.player.y,
+ w: args.state.player.w,
+ h: args.state.player.h,
+ path: 'sprites/square/green.png' }
+
+ # move the player around using the keyboard
+ if args.inputs.up
+ args.state.player.y += 10
+ elsif args.inputs.down
+ args.state.player.y -= 10
+ end
+
+ if args.inputs.left
+ args.state.player.x -= 10
+ elsif args.inputs.right
+ args.state.player.x += 10
+ end
+end
+
+$gtk.reset
+
+</code></pre>
+<h3 id='----input-basics---mouse---main-rb'>Input Basics - Mouse - main.rb</h3>
<pre><code class="language-ruby"># ./samples/02_input_basics/02_mouse/app/main.rb
=begin
@@ -4799,11 +4192,7 @@ def small_label args, x, row, message
# This method effectively combines the row_to_px and small_font methods
# It changes the given row value to a DragonRuby pixel value
# and adds the customization parameters
- [x, row_to_px(args, row), message, small_font]
-end
-
-def small_font
- [-2, 0, 0, 0, 0, 255]
+ { x: x, y: row_to_px(args, row), text: message, alignment_enum: -2 }
end
def row_to_px args, row_number
@@ -4819,13 +4208,13 @@ def tick_instructions args, text, y = 715
args.state.key_event_occurred = true
end
- args.outputs.debug << [0, y - 50, 1280, 60].solid
- args.outputs.debug << [640, y, text, 1, 1, 255, 255, 255].label
- args.outputs.debug << [640, y - 25, "(click to dismiss instructions)" , -2, 1, 255, 255, 255].label
+ args.outputs.debug << { x: 0, y: y - 50, w: 1280, h: 60 }.solid!
+ args.outputs.debug << { x: 640, y: y, text: text, size_enum: 1, alignment_enum: 1, r: 255, g: 255, b: 255 }.label!
+ args.outputs.debug << { x: 640, y: y - 25, text: "(click to dismiss instructions)", size_enum: -2, alignment_enum: 1, r: 255, g: 255, b: 255 }.label!
end
</code></pre>
-<h3 id='----input-basics---mouse-point-to-rect---main.rb'>Input Basics - Mouse Point To Rect - main.rb</h3>
+<h3 id='----input-basics---mouse-point-to-rect---main-rb'>Input Basics - Mouse Point To Rect - main.rb</h3>
<pre><code class="language-ruby"># ./samples/02_input_basics/03_mouse_point_to_rect/app/main.rb
=begin
@@ -4871,7 +4260,7 @@ def tick args
args.outputs.labels << small_label(args, x, 15, "Click inside the blue box maybe ---->")
- box = [785, 370, 50, 50, 0, 0, 170]
+ box = { x: 785, y: 370, w: 50, h: 50, r: 0, g: 0, b: 170 }
args.outputs.borders << box
# Saves the most recent click into args.state
@@ -4893,11 +4282,7 @@ def tick args
end
def small_label args, x, row, message
- [x, row_to_px(args, row), message, small_font]
-end
-
-def small_font
- [-2, 0, 0, 0, 0, 255]
+ { x: x, y: row_to_px(args, row), text: message, size_enum: -2 }
end
def row_to_px args, row_number
@@ -4913,13 +4298,13 @@ def tick_instructions args, text, y = 715
args.state.key_event_occurred = true
end
- args.outputs.debug << [0, y - 50, 1280, 60].solid
- args.outputs.debug << [640, y, text, 1, 1, 255, 255, 255].label
- args.outputs.debug << [640, y - 25, "(click to dismiss instructions)" , -2, 1, 255, 255, 255].label
+ args.outputs.debug << { x: 0, y: y - 50, w: 1280, h: 60 }.solid!
+ args.outputs.debug << { x: 640, y: y, text: text, size_enum: 1, alignment_enum: 1, r: 255, g: 255, b: 255 }.label!
+ args.outputs.debug << { x: 640, y: y - 25, text: "(click to dismiss instructions)", size_enum: -2, alignment_enum: 1, r: 255, g: 255, b: 255 }.label!
end
</code></pre>
-<h3 id='----input-basics---mouse-rect-to-rect---main.rb'>Input Basics - Mouse Rect To Rect - main.rb</h3>
+<h3 id='----input-basics---mouse-rect-to-rect---main-rb'>Input Basics - Mouse Rect To Rect - main.rb</h3>
<pre><code class="language-ruby"># ./samples/02_input_basics/04_mouse_rect_to_rect/app/main.rb
=begin
@@ -4965,9 +4350,15 @@ def tick args
# They are stored in game so that they do not get reset every tick
if args.inputs.mouse.click
if !args.state.box_collision_one
- args.state.box_collision_one = [args.inputs.mouse.click.point.x - 25, args.inputs.mouse.click.point.y - 25, 125, 125, 180, 0, 0, 180]
+ args.state.box_collision_one = { x: args.inputs.mouse.click.point.x - 25,
+ y: args.inputs.mouse.click.point.y - 25,
+ w: 125, h: 125,
+ r: 180, g: 0, b: 0, a: 180 }
elsif !args.state.box_collision_two
- args.state.box_collision_two = [args.inputs.mouse.click.point.x - 25, args.inputs.mouse.click.point.y - 25, 125, 125, 0, 0, 180, 180]
+ args.state.box_collision_two = { x: args.inputs.mouse.click.point.x - 25,
+ y: args.inputs.mouse.click.point.y - 25,
+ w: 125, h: 125,
+ r: 0, g: 0, b: 180, a: 180 }
else
args.state.box_collision_one = nil
args.state.box_collision_two = nil
@@ -4994,15 +4385,11 @@ def tick args
end
def small_label args, x, row, message
- [x, row_to_px(args, row), message, small_font]
-end
-
-def small_font
- [-2, 0, 0, 0, 0, 255]
+ { x: x, y: row_to_px(args, row), text: message, size_enum: -2 }
end
def row_to_px args, row_number
- args.grid.top.shift_down(5).shift_down(20 * row_number)
+ args.grid.top - 5 - (20 * row_number)
end
def tick_instructions args, text, y = 715
@@ -5020,7 +4407,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----input-basics---controller---main.rb'>Input Basics - Controller - main.rb</h3>
+<h3 id='----input-basics---controller---main-rb'>Input Basics - Controller - main.rb</h3>
<pre><code class="language-ruby"># ./samples/02_input_basics/05_controller/app/main.rb
=begin
@@ -5066,57 +4453,51 @@ class ControllerDemo
def process_inputs
state.buttons = []
- state.buttons << [100, 500, inputs.controller_one.key_held.l1, "L1"]
- state.buttons << [100, 600, inputs.controller_one.key_held.l2, "L2"]
-
- state.buttons << [1100, 500, inputs.controller_one.key_held.r1, "R1"]
- state.buttons << [1100, 600, inputs.controller_one.key_held.r2, "R2"]
-
- state.buttons << [540, 450, inputs.controller_one.key_held.select, "Select"]
- state.buttons << [660, 450, inputs.controller_one.key_held.start, "Start"]
-
- state.buttons << [200, 300, inputs.controller_one.key_held.left, "Left"]
- state.buttons << [300, 400, inputs.controller_one.key_held.up, "Up"]
- state.buttons << [400, 300, inputs.controller_one.key_held.right, "Right"]
- state.buttons << [300, 200, inputs.controller_one.key_held.down, "Down"]
-
- state.buttons << [800, 300, inputs.controller_one.key_held.x, "X"]
- state.buttons << [900, 400, inputs.controller_one.key_held.y, "Y"]
- state.buttons << [1000, 300, inputs.controller_one.key_held.a, "A"]
- state.buttons << [900, 200, inputs.controller_one.key_held.b, "B"]
-
- state.buttons << [450 + inputs.controller_one.left_analog_x_perc * 100,
- 100 + inputs.controller_one.left_analog_y_perc * 100,
- inputs.controller_one.key_held.l3,
- "L3"]
-
- state.buttons << [750 + inputs.controller_one.right_analog_x_perc * 100,
- 100 + inputs.controller_one.right_analog_y_perc * 100,
- inputs.controller_one.key_held.r3,
- "R3"]
+ state.buttons << { x: 100, y: 500, active: inputs.controller_one.key_held.l1, text: "L1"}
+ state.buttons << { x: 100, y: 600, active: inputs.controller_one.key_held.l2, text: "L2"}
+ state.buttons << { x: 1100, y: 500, active: inputs.controller_one.key_held.r1, text: "R1"}
+ state.buttons << { x: 1100, y: 600, active: inputs.controller_one.key_held.r2, text: "R2"}
+ state.buttons << { x: 540, y: 450, active: inputs.controller_one.key_held.select, text: "Select"}
+ state.buttons << { x: 660, y: 450, active: inputs.controller_one.key_held.start, text: "Start"}
+ state.buttons << { x: 200, y: 300, active: inputs.controller_one.key_held.left, text: "Left"}
+ state.buttons << { x: 300, y: 400, active: inputs.controller_one.key_held.up, text: "Up"}
+ state.buttons << { x: 400, y: 300, active: inputs.controller_one.key_held.right, text: "Right"}
+ state.buttons << { x: 300, y: 200, active: inputs.controller_one.key_held.down, text: "Down"}
+ state.buttons << { x: 800, y: 300, active: inputs.controller_one.key_held.x, text: "X"}
+ state.buttons << { x: 900, y: 400, active: inputs.controller_one.key_held.y, text: "Y"}
+ state.buttons << { x: 1000, y: 300, active: inputs.controller_one.key_held.a, text: "A"}
+ state.buttons << { x: 900, y: 200, active: inputs.controller_one.key_held.b, text: "B"}
+ state.buttons << { x: 450 + inputs.controller_one.left_analog_x_perc * 100,
+ y: 100 + inputs.controller_one.left_analog_y_perc * 100,
+ active: inputs.controller_one.key_held.l3,
+ text: "L3" }
+ state.buttons << { x: 750 + inputs.controller_one.right_analog_x_perc * 100,
+ y: 100 + inputs.controller_one.right_analog_y_perc * 100,
+ active: inputs.controller_one.key_held.r3,
+ text: "R3" }
end
# Gives each button a square shape.
# If the button is being pressed or held (which means it is considered active),
# the square is filled in. Otherwise, the button simply has a border.
def render
- state.buttons.each do |x, y, active, text|
- rect = [x, y, 75, 75]
+ state.buttons.each do |b|
+ rect = { x: b.x, y: b.y, w: 75, h: 75 }
- if active # if button is pressed
+ if b.active # if button is pressed
outputs.solids << rect # rect is output as solid (filled in)
else
outputs.borders << rect # otherwise, output as border
end
# Outputs the text of each button using labels.
- outputs.labels << [x, y + 95, text] # add 95 to place label above button
+ outputs.labels << { x: b.x, y: b.y + 95, text: b.text } # add 95 to place label above button
end
- outputs.labels << [10, 60, "Left Analog x: #{inputs.controller_one.left_analog_x_raw} (#{inputs.controller_one.left_analog_x_perc * 100}%)"]
- outputs.labels << [10, 30, "Left Analog y: #{inputs.controller_one.left_analog_y_raw} (#{inputs.controller_one.left_analog_y_perc * 100}%)"]
- outputs.labels << [900, 60, "Right Analog x: #{inputs.controller_one.right_analog_x_raw} (#{inputs.controller_one.right_analog_x_perc * 100}%)"]
- outputs.labels << [900, 30, "Right Analog y: #{inputs.controller_one.right_analog_y_raw} (#{inputs.controller_one.right_analog_y_perc * 100}%)"]
+ outputs.labels << { x: 10, y: 60, text: "Left Analog x: #{inputs.controller_one.left_analog_x_raw} (#{inputs.controller_one.left_analog_x_perc * 100}%)" }
+ outputs.labels << { x: 10, y: 30, text: "Left Analog y: #{inputs.controller_one.left_analog_y_raw} (#{inputs.controller_one.left_analog_y_perc * 100}%)" }
+ outputs.labels << { x: 900, y: 60, text: "Right Analog x: #{inputs.controller_one.right_analog_x_raw} (#{inputs.controller_one.right_analog_x_perc * 100}%)" }
+ outputs.labels << { x: 900, y: 30, text: "Right Analog y: #{inputs.controller_one.right_analog_y_raw} (#{inputs.controller_one.right_analog_y_perc * 100}%)" }
end
end
@@ -5150,7 +4531,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----input-basics---touch---main.rb'>Input Basics - Touch - main.rb</h3>
+<h3 id='----input-basics---touch---main-rb'>Input Basics - Touch - main.rb</h3>
<pre><code class="language-ruby"># ./samples/02_input_basics/06_touch/app/main.rb
def tick args
args.outputs.background_color = [ 0, 0, 0 ]
@@ -5165,10 +4546,12 @@ def tick args
# the next new touch will be finger_one again, but until then, new touches
# don't fill in earlier slots.
if !args.inputs.finger_one.nil?
- args.outputs.primitives << [640, 650, "Finger #1 is touching at (#{args.inputs.finger_one.x}, #{args.inputs.finger_one.y}).", 5, 1, 255, 255, 255].label
+ args.outputs.primitives << { x: 640, y: 650, text: "Finger #1 is touching at (#{args.inputs.finger_one.x}, #{args.inputs.finger_one.y}).",
+ size_enum: 5, alignment_enum: 1, r: 255, g: 255, b: 255 }.label!
end
if !args.inputs.finger_two.nil?
- args.outputs.primitives << [640, 600, "Finger #2 is touching at (#{args.inputs.finger_two.x}, #{args.inputs.finger_two.y}).", 5, 1, 255, 255, 255].label
+ args.outputs.primitives << { x: 640, y: 600, text: "Finger #2 is touching at (#{args.inputs.finger_two.x}, #{args.inputs.finger_two.y}).",
+ size_enum: 5, alignment_enum: 1, r: 255, g: 255, b: 255 }.label!
end
# Here's the more flexible interface: this will report as many simultaneous
@@ -5189,14 +4572,13 @@ def tick args
r = (color & 0xFF0000) >> 16
g = (color & 0x00FF00) >> 8
b = (color & 0x0000FF)
- args.outputs.primitives << [v.x - (size / 2), v.y + (size / 2), size, size, r, g, b, 255].solid
- args.outputs.primitives << [v.x, v.y + size, k.to_s, 0, 1, 0, 0, 0].label
+ args.outputs.primitives << { x: v.x - (size / 2), y: v.y + (size / 2), w: size, h: size, r: r, g: g, b: b, a: 255 }.solid!
+ args.outputs.primitives << { x: v.x, y: v.y + size, text: k.to_s, alignment_enum: 1 }.label!
}
end
-
</code></pre>
-<h3 id='----rendering-sprites---animation-using-separate-pngs---main.rb'>Rendering Sprites - Animation Using Separate Pngs - main.rb</h3>
+<h3 id='----rendering-sprites---animation-using-separate-pngs---main-rb'>Rendering Sprites - Animation Using Separate Pngs - main.rb</h3>
<pre><code class="language-ruby"># ./samples/03_rendering_sprites/01_animation_using_separate_pngs/app/main.rb
=begin
@@ -5231,6 +4613,8 @@ end
# in this tick "entry point": `looping_animation`, and the
# second method is `one_time_animation`.
def tick args
+ # uncomment the line below to see animation play out in slow motion
+ # args.gtk.slowmo! 6
looping_animation args
one_time_animation args
end
@@ -5263,22 +4647,22 @@ def looping_animation args
does_sprite_loop
# Now that we have `sprite_index, we can present the correct file.
- args.outputs.sprites << [100, 100, 100, 100, "sprites/dragon_fly_#{sprite_index}.png"]
+ args.outputs.sprites << { x: 100, y: 100, w: 100, h: 100, path: "sprites/dragon_fly_#{sprite_index}.png" }
# Try changing the numbers below to see how the animation changes:
- args.outputs.sprites << [100, 200, 100, 100, "sprites/dragon_fly_#{0.frame_index 6, 4, true}.png"]
+ args.outputs.sprites << { x: 100, y: 200, w: 100, h: 100, path: "sprites/dragon_fly_#{0.frame_index 6, 4, true}.png" }
end
# This function shows how to animate a sprite that executes
# only once when the "f" key is pressed.
def one_time_animation args
# This is just a label the shows instructions within the game.
- args.outputs.labels << [220, 350, "(press f to animate)"]
+ args.outputs.labels << { x: 220, y: 350, text: "(press f to animate)" }
# If "f" is pressed on the keyboard...
if args.inputs.keyboard.key_down.f
# Print the frame that "f" was pressed on.
- puts "Hello from main.rb! The \"f\" key was in the down state on frame: #{args.inputs.keyboard.key_down.f}"
+ puts "Hello from main.rb! The \"f\" key was in the down state on frame: #{args.state.tick_count}"
# And MOST IMPORTANTLY set the point it time to start the animation,
# equal to "now" which is represented as args.state.tick_count.
@@ -5311,7 +4695,7 @@ def one_time_animation args
sprite_index ||= 0
# Present the sprite.
- args.outputs.sprites << [100, 300, 100, 100, "sprites/dragon_fly_#{sprite_index}.png"]
+ args.outputs.sprites << { x: 100, y: 300, w: 100, h: 100, path: "sprites/dragon_fly_#{sprite_index}.png" }
tick_instructions args, "Sample app shows how to use Numeric#frame_index and string interpolation to animate a sprite over time."
end
@@ -5331,7 +4715,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----rendering-sprites---animation-using-sprite-sheet---main.rb'>Rendering Sprites - Animation Using Sprite Sheet - main.rb</h3>
+<h3 id='----rendering-sprites---animation-using-sprite-sheet---main-rb'>Rendering Sprites - Animation Using Sprite Sheet - main.rb</h3>
<pre><code class="language-ruby"># ./samples/03_rendering_sprites/02_animation_using_sprite_sheet/app/main.rb
def tick args
args.state.player.x ||= 100
@@ -5433,7 +4817,7 @@ def running_sprite args
end
</code></pre>
-<h3 id='----rendering-sprites---animation-states---main.rb'>Rendering Sprites - Animation States - main.rb</h3>
+<h3 id='----rendering-sprites---animation-states---main-rb'>Rendering Sprites - Animation States - main.rb</h3>
<pre><code class="language-ruby"># ./samples/03_rendering_sprites/03_animation_states/app/main.rb
class Game
attr_gtk
@@ -5620,7 +5004,7 @@ end
$gtk.reset
</code></pre>
-<h3 id='----rendering-sprites---color-and-rotation---main.rb'>Rendering Sprites - Color And Rotation - main.rb</h3>
+<h3 id='----rendering-sprites---color-and-rotation---main-rb'>Rendering Sprites - Color And Rotation - main.rb</h3>
<pre><code class="language-ruby"># ./samples/03_rendering_sprites/04_color_and_rotation/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -5850,7 +5234,7 @@ def source_rect state
end
</code></pre>
-<h3 id='----physics-and-collisions---simple---main.rb'>Physics And Collisions - Simple - main.rb</h3>
+<h3 id='----physics-and-collisions---simple---main-rb'>Physics And Collisions - Simple - main.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/01_simple/app/main.rb
=begin
@@ -5962,7 +5346,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----physics-and-collisions---moving-objects---main.rb'>Physics And Collisions - Moving Objects - main.rb</h3>
+<h3 id='----physics-and-collisions---moving-objects---main-rb'>Physics And Collisions - Moving Objects - main.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/02_moving_objects/app/main.rb
=begin
@@ -6266,7 +5650,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----physics-and-collisions---entities---main.rb'>Physics And Collisions - Entities - main.rb</h3>
+<h3 id='----physics-and-collisions---entities---main-rb'>Physics And Collisions - Entities - main.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/03_entities/app/main.rb
=begin
@@ -6421,7 +5805,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----physics-and-collisions---box-collision---main.rb'>Physics And Collisions - Box Collision - main.rb</h3>
+<h3 id='----physics-and-collisions---box-collision---main-rb'>Physics And Collisions - Box Collision - main.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/04_box_collision/app/main.rb
=begin
@@ -6762,7 +6146,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----physics-and-collisions---box-collision-2---main.rb'>Physics And Collisions - Box Collision 2 - main.rb</h3>
+<h3 id='----physics-and-collisions---box-collision-2---main-rb'>Physics And Collisions - Box Collision 2 - main.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/05_box_collision_2/app/main.rb
=begin
APIs listing that haven't been encountered in previous sample apps:
@@ -7236,7 +6620,7 @@ def tick args
end
</code></pre>
-<h3 id='----physics-and-collisions---box-collision-3---main.rb'>Physics And Collisions - Box Collision 3 - main.rb</h3>
+<h3 id='----physics-and-collisions---box-collision-3---main-rb'>Physics And Collisions - Box Collision 3 - main.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/06_box_collision_3/app/main.rb
class Game
attr_gtk
@@ -7286,9 +6670,9 @@ class Game
mouse_overlay = mouse_overlay.merge r: 255 if state.delete_mode
if state.mouse_held
- outputs.primitives << mouse_overlay.border
+ outputs.primitives << mouse_overlay.border!
else
- outputs.primitives << mouse_overlay.solid
+ outputs.primitives << mouse_overlay.solid!
end
end
@@ -7495,7 +6879,7 @@ def tick args
end
</code></pre>
-<h3 id='----physics-and-collisions---jump-physics---main.rb'>Physics And Collisions - Jump Physics - main.rb</h3>
+<h3 id='----physics-and-collisions---jump-physics---main-rb'>Physics And Collisions - Jump Physics - main.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/07_jump_physics/app/main.rb
=begin
@@ -7695,7 +7079,7 @@ def tick args
end
</code></pre>
-<h3 id='----physics-and-collisions---bouncing-on-collision---ball.rb'>Physics And Collisions - Bouncing On Collision - ball.rb</h3>
+<h3 id='----physics-and-collisions---bouncing-on-collision---ball-rb'>Physics And Collisions - Bouncing On Collision - ball.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/08_bouncing_on_collision/app/ball.rb
GRAVITY = -0.08
@@ -7786,7 +7170,7 @@ class Ball
end
</code></pre>
-<h3 id='----physics-and-collisions---bouncing-on-collision---block.rb'>Physics And Collisions - Bouncing On Collision - block.rb</h3>
+<h3 id='----physics-and-collisions---bouncing-on-collision---block-rb'>Physics And Collisions - Bouncing On Collision - block.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/08_bouncing_on_collision/app/block.rb
DEGREES_TO_RADIANS = Math::PI / 180
@@ -7949,7 +7333,7 @@ class Block
end
</code></pre>
-<h3 id='----physics-and-collisions---bouncing-on-collision---cannon.rb'>Physics And Collisions - Bouncing On Collision - cannon.rb</h3>
+<h3 id='----physics-and-collisions---bouncing-on-collision---cannon-rb'>Physics And Collisions - Bouncing On Collision - cannon.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/08_bouncing_on_collision/app/cannon.rb
class Cannon
def initialize args
@@ -7973,7 +7357,7 @@ class Cannon
end
</code></pre>
-<h3 id='----physics-and-collisions---bouncing-on-collision---main.rb'>Physics And Collisions - Bouncing On Collision - main.rb</h3>
+<h3 id='----physics-and-collisions---bouncing-on-collision---main-rb'>Physics And Collisions - Bouncing On Collision - main.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/08_bouncing_on_collision/app/main.rb
INFINITY= 10**10
@@ -8094,7 +7478,7 @@ def tick args
end
</code></pre>
-<h3 id='----physics-and-collisions---bouncing-on-collision---peg.rb'>Physics And Collisions - Bouncing On Collision - peg.rb</h3>
+<h3 id='----physics-and-collisions---bouncing-on-collision---peg-rb'>Physics And Collisions - Bouncing On Collision - peg.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/08_bouncing_on_collision/app/peg.rb
class Peg
def initialize(x, y, block_size)
@@ -8280,7 +7664,7 @@ class Peg
end
</code></pre>
-<h3 id='----physics-and-collisions---bouncing-on-collision---vector2d.rb'>Physics And Collisions - Bouncing On Collision - vector2d.rb</h3>
+<h3 id='----physics-and-collisions---bouncing-on-collision---vector2d-rb'>Physics And Collisions - Bouncing On Collision - vector2d.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/08_bouncing_on_collision/app/vector2d.rb
class Vector2d
attr_accessor :x, :y
@@ -8332,7 +7716,7 @@ class Vector2d
end
end
</code></pre>
-<h3 id='----physics-and-collisions---arbitrary-collision---ball.rb'>Physics And Collisions - Arbitrary Collision - ball.rb</h3>
+<h3 id='----physics-and-collisions---arbitrary-collision---ball-rb'>Physics And Collisions - Arbitrary Collision - ball.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/09_arbitrary_collision/app/ball.rb
class Ball
@@ -8502,7 +7886,7 @@ class Ball
end
</code></pre>
-<h3 id='----physics-and-collisions---arbitrary-collision---blocks.rb'>Physics And Collisions - Arbitrary Collision - blocks.rb</h3>
+<h3 id='----physics-and-collisions---arbitrary-collision---blocks-rb'>Physics And Collisions - Arbitrary Collision - blocks.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/09_arbitrary_collision/app/blocks.rb
MAX_COUNT=100
@@ -9124,7 +8508,7 @@ class Line
end
</code></pre>
-<h3 id='----physics-and-collisions---arbitrary-collision---linear_collider.rb'>Physics And Collisions - Arbitrary Collision - linear_collider.rb</h3>
+<h3 id='----physics-and-collisions---arbitrary-collision---linear_collider-rb'>Physics And Collisions - Arbitrary Collision - linear_collider.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/09_arbitrary_collision/app/linear_collider.rb
COLLISIONWIDTH=8
@@ -9308,7 +8692,7 @@ class LinearCollider
end
</code></pre>
-<h3 id='----physics-and-collisions---arbitrary-collision---main.rb'>Physics And Collisions - Arbitrary Collision - main.rb</h3>
+<h3 id='----physics-and-collisions---arbitrary-collision---main-rb'>Physics And Collisions - Arbitrary Collision - main.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/09_arbitrary_collision/app/main.rb
INFINITY= 10**10
MAX_VELOCITY = 8.0
@@ -9483,7 +8867,7 @@ def tick args
end
</code></pre>
-<h3 id='----physics-and-collisions---arbitrary-collision---paddle.rb'>Physics And Collisions - Arbitrary Collision - paddle.rb</h3>
+<h3 id='----physics-and-collisions---arbitrary-collision---paddle-rb'>Physics And Collisions - Arbitrary Collision - paddle.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/09_arbitrary_collision/app/paddle.rb
class Paddle
attr_accessor :enabled
@@ -9540,7 +8924,7 @@ class Paddle
end
</code></pre>
-<h3 id='----physics-and-collisions---arbitrary-collision---rectangle.rb'>Physics And Collisions - Arbitrary Collision - rectangle.rb</h3>
+<h3 id='----physics-and-collisions---arbitrary-collision---rectangle-rb'>Physics And Collisions - Arbitrary Collision - rectangle.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/09_arbitrary_collision/app/rectangle.rb
class Rectangle
def initialize args
@@ -9634,7 +9018,7 @@ class Rectangle
end
</code></pre>
-<h3 id='----physics-and-collisions---arbitrary-collision---square_collider.rb'>Physics And Collisions - Arbitrary Collision - square_collider.rb</h3>
+<h3 id='----physics-and-collisions---arbitrary-collision---square_collider-rb'>Physics And Collisions - Arbitrary Collision - square_collider.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/09_arbitrary_collision/app/square_collider.rb
class SquareCollider
@@ -9667,7 +9051,7 @@ class SquareCollider
end
</code></pre>
-<h3 id='----physics-and-collisions---arbitrary-collision---vector2d.rb'>Physics And Collisions - Arbitrary Collision - vector2d.rb</h3>
+<h3 id='----physics-and-collisions---arbitrary-collision---vector2d-rb'>Physics And Collisions - Arbitrary Collision - vector2d.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/09_arbitrary_collision/app/vector2d.rb
class Vector2d
attr_accessor :x, :y
@@ -9719,7 +9103,7 @@ class Vector2d
end
end
</code></pre>
-<h3 id='----physics-and-collisions---collision-with-object-removal---ball.rb'>Physics And Collisions - Collision With Object Removal - ball.rb</h3>
+<h3 id='----physics-and-collisions---collision-with-object-removal---ball-rb'>Physics And Collisions - Collision With Object Removal - ball.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/10_collision_with_object_removal/app/ball.rb
class Ball
#TODO limit accessors?
@@ -9754,7 +9138,7 @@ class Ball
end
</code></pre>
-<h3 id='----physics-and-collisions---collision-with-object-removal---linear_collider.rb'>Physics And Collisions - Collision With Object Removal - linear_collider.rb</h3>
+<h3 id='----physics-and-collisions---collision-with-object-removal---linear_collider-rb'>Physics And Collisions - Collision With Object Removal - linear_collider.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/10_collision_with_object_removal/app/linear_collider.rb
#The LinearCollider (theoretically) produces collisions upon a line segment defined point.y two x,y cordinates
@@ -9924,7 +9308,7 @@ class LinearCollider
end
</code></pre>
-<h3 id='----physics-and-collisions---collision-with-object-removal---main.rb'>Physics And Collisions - Collision With Object Removal - main.rb</h3>
+<h3 id='----physics-and-collisions---collision-with-object-removal---main-rb'>Physics And Collisions - Collision With Object Removal - main.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/10_collision_with_object_removal/app/main.rb
# coding: utf-8
INFINITY= 10**10
@@ -10117,7 +9501,7 @@ def tick args
end
</code></pre>
-<h3 id='----physics-and-collisions---collision-with-object-removal---paddle.rb'>Physics And Collisions - Collision With Object Removal - paddle.rb</h3>
+<h3 id='----physics-and-collisions---collision-with-object-removal---paddle-rb'>Physics And Collisions - Collision With Object Removal - paddle.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/10_collision_with_object_removal/app/paddle.rb
class Paddle
attr_accessor :enabled
@@ -10174,7 +9558,7 @@ class Paddle
end
</code></pre>
-<h3 id='----physics-and-collisions---collision-with-object-removal---tests.rb'>Physics And Collisions - Collision With Object Removal - tests.rb</h3>
+<h3 id='----physics-and-collisions---collision-with-object-removal---tests-rb'>Physics And Collisions - Collision With Object Removal - tests.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/10_collision_with_object_removal/app/tests.rb
# For advanced users:
# You can put some quick verification tests here, any method
@@ -10207,7 +9591,7 @@ $gtk.log_level = :off
$gtk.tests.start
</code></pre>
-<h3 id='----physics-and-collisions---collision-with-object-removal---vector2d.rb'>Physics And Collisions - Collision With Object Removal - vector2d.rb</h3>
+<h3 id='----physics-and-collisions---collision-with-object-removal---vector2d-rb'>Physics And Collisions - Collision With Object Removal - vector2d.rb</h3>
<pre><code class="language-ruby"># ./samples/04_physics_and_collisions/10_collision_with_object_removal/app/vector2d.rb
class Vector2d
@@ -10261,7 +9645,7 @@ class Vector2d
end
</code></pre>
-<h3 id='----mouse---mouse-click---main.rb'>Mouse - Mouse Click - main.rb</h3>
+<h3 id='----mouse---mouse-click---main-rb'>Mouse - Mouse Click - main.rb</h3>
<pre><code class="language-ruby"># ./samples/05_mouse/01_mouse_click/app/main.rb
=begin
@@ -10509,7 +9893,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----mouse---mouse-move---main.rb'>Mouse - Mouse Move - main.rb</h3>
+<h3 id='----mouse---mouse-move---main-rb'>Mouse - Mouse Move - main.rb</h3>
<pre><code class="language-ruby"># ./samples/05_mouse/02_mouse_move/app/main.rb
=begin
@@ -10809,7 +10193,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----mouse---mouse-move-paint-app---main.rb'>Mouse - Mouse Move Paint App - main.rb</h3>
+<h3 id='----mouse---mouse-move-paint-app---main-rb'>Mouse - Mouse Move Paint App - main.rb</h3>
<pre><code class="language-ruby"># ./samples/05_mouse/03_mouse_move_paint_app/app/main.rb
=begin
@@ -11053,7 +10437,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----mouse---coordinate-systems---main.rb'>Mouse - Coordinate Systems - main.rb</h3>
+<h3 id='----mouse---coordinate-systems---main-rb'>Mouse - Coordinate Systems - main.rb</h3>
<pre><code class="language-ruby"># ./samples/05_mouse/04_coordinate_systems/app/main.rb
=begin
@@ -11137,7 +10521,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----save-load---save-load-game---main.rb'>Save Load - Save Load Game - main.rb</h3>
+<h3 id='----save-load---save-load-game---main-rb'>Save Load - Save Load Game - main.rb</h3>
<pre><code class="language-ruby"># ./samples/06_save_load/01_save_load_game/app/main.rb
=begin
@@ -11530,7 +10914,1001 @@ def tick args
end
</code></pre>
-<h3 id='----advanced-rendering---simple-render-targets---main.rb'>Advanced Rendering - Simple Render Targets - main.rb</h3>
+<h3 id='----advanced-audio---audio-mixer---main-rb'>Advanced Audio - Audio Mixer - main.rb</h3>
+<pre><code class="language-ruby"># ./samples/07_advanced_audio/01_audio_mixer/app/main.rb
+# these are the properties that you can sent on args.audio
+def spawn_new_sound args, name, path
+ # Spawn randomly in an area that won't be covered by UI.
+ screenx = (rand * 600.0) + 200.0
+ screeny = (rand * 400.0) + 100.0
+
+ id = new_sound_id! args
+ # you can hang anything on the audio hashes you want, so we store the
+ # actual screen position in here for convenience.
+ args.audio[id] = {
+ name: name,
+ input: path,
+ screenx: screenx,
+ screeny: screeny,
+ x: ((screenx / 1279.0) * 2.0) - 1.0, # scale to -1.0 - 1.0 range
+ y: ((screeny / 719.0) * 2.0) - 1.0, # scale to -1.0 - 1.0 range
+ z: 0.0,
+ gain: 1.0,
+ pitch: 1.0,
+ looping: true,
+ paused: false
+ }
+
+ args.state.selected = id
+end
+
+# these are values you can change on the ~args.audio~ data structure
+def input_panel args
+ return unless args.state.panel
+ return if args.state.dragging
+
+ audio_entry = args.audio[args.state.selected]
+ results = args.state.panel
+
+ if args.state.mouse_state == :held && args.inputs.mouse.position.inside_rect?(results.pitch_slider_rect.rect)
+ audio_entry.pitch = 2.0 * ((args.inputs.mouse.x - results.pitch_slider_rect.x).to_f / (results.pitch_slider_rect.w - 1.0))
+ elsif args.state.mouse_state == :held && args.inputs.mouse.position.inside_rect?(results.playtime_slider_rect.rect)
+ audio_entry.playtime = audio_entry.length_ * ((args.inputs.mouse.x - results.playtime_slider_rect.x).to_f / (results.playtime_slider_rect.w - 1.0))
+ elsif args.state.mouse_state == :held && args.inputs.mouse.position.inside_rect?(results.gain_slider_rect.rect)
+ audio_entry.gain = (args.inputs.mouse.x - results.gain_slider_rect.x).to_f / (results.gain_slider_rect.w - 1.0)
+ elsif args.inputs.mouse.click && args.inputs.mouse.position.inside_rect?(results.looping_checkbox_rect.rect)
+ audio_entry.looping = !audio_entry.looping
+ elsif args.inputs.mouse.click && args.inputs.mouse.position.inside_rect?(results.paused_checkbox_rect.rect)
+ audio_entry.paused = !audio_entry.paused
+ elsif args.inputs.mouse.click && args.inputs.mouse.position.inside_rect?(results.delete_button_rect.rect)
+ args.audio.delete args.state.selected
+ end
+end
+
+def render_sources args
+ args.outputs.primitives << args.audio.keys.map do |k|
+ s = args.audio[k]
+
+ isselected = (k == args.state.selected)
+
+ color = isselected ? [ 0, 255, 0, 255 ] : [ 0, 0, 255, 255 ]
+ [
+ [s.screenx, s.screeny, args.state.boxsize, args.state.boxsize, *color].solid,
+
+ {
+ x: s.screenx + args.state.boxsize.half,
+ y: s.screeny,
+ text: s.name,
+ r: 255,
+ g: 255,
+ b: 255,
+ alignment_enum: 1
+ }.label!
+ ]
+ end
+end
+
+def playtime_str t
+ minutes = (t / 60.0).floor
+ seconds = t - (minutes * 60.0).to_f
+ return minutes.to_s + ':' + seconds.floor.to_s + ((seconds - seconds.floor).to_s + "000")[1..3]
+end
+
+def label_with_drop_shadow x, y, text
+ [
+ { x: x + 1, y: y + 1, text: text, vertical_alignment_enum: 1, alignment_enum: 1, r: 0, g: 0, b: 0 }.label!,
+ { x: x + 2, y: y + 0, text: text, vertical_alignment_enum: 1, alignment_enum: 1, r: 0, g: 0, b: 0 }.label!,
+ { x: x + 0, y: y + 1, text: text, vertical_alignment_enum: 1, alignment_enum: 1, r: 200, g: 200, b: 200 }.label!
+ ]
+end
+
+def check_box opts = {}
+ checkbox_template = opts.args.layout.rect(w: 0.5, h: 0.5, col: 2)
+ final_rect = checkbox_template.center_inside_rect_y(opts.args.layout.rect(row: opts.row, col: opts.col))
+ color = { r: 0, g: 0, b: 0 }
+ color = { r: 255, g: 255, b: 255 } if opts.checked
+
+ {
+ rect: final_rect,
+ primitives: [
+ (final_rect.to_solid color)
+ ]
+ }
+end
+
+def progress_bar opts = {}
+ outer_rect = opts.args.layout.rect(row: opts.row, col: opts.col, w: 5, h: 1)
+ color = opts.percentage * 255
+ baseline_progress_bar = opts.args
+ .layout
+ .rect(w: 5, h: 0.5)
+
+ final_rect = baseline_progress_bar.center_inside_rect(outer_rect)
+ center = final_rect.rect_center_point
+
+ {
+ rect: final_rect,
+ primitives: [
+ final_rect.merge(r: color, g: color, b: color, a: 128).solid!,
+ label_with_drop_shadow(center.x, center.y, opts.text)
+ ]
+ }
+end
+
+def panel_primitives args, audio_entry
+ results = { primitives: [] }
+
+ return results unless audio_entry
+
+ # this uses DRGTK's layout apis to layout the controls
+ # imagine the screen is split into equal cells (24 cells across, 12 cells up and down)
+ # args.layout.rect returns a hash which we merge values with to create primitives
+ # using args.layout.rect removes the need for pixel pushing
+
+ # args.outputs.debug << args.layout.debug_primitives(r: 255, g: 255, b: 255)
+
+ white_color = { r: 255, g: 255, b: 255 }
+ label_style = white_color.merge(vertical_alignment_enum: 1)
+
+ # panel background
+ results.primitives << args.layout.rect(row: 0, col: 0, w: 7, h: 6, include_col_gutter: true, include_row_gutter: true)
+ .border!(r: 255, g: 255, b: 255)
+
+ # title
+ results.primitives << args.layout.point(row: 0, col: 3.5, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "Source #{args.state.selected} (#{args.audio[args.state.selected].name})",
+ size_enum: 3,
+ alignment_enum: 1)
+
+ # seperator line
+ results.primitives << args.layout.rect(row: 1, col: 0, w: 7, h: 0)
+ .line!(white_color)
+
+ # screen location
+ results.primitives << args.layout.point(row: 1.0, col: 0, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "screen:")
+
+ results.primitives << args.layout.point(row: 1.0, col: 2, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "(#{audio_entry.screenx.to_i}, #{audio_entry.screeny.to_i})")
+
+ # position
+ results.primitives << args.layout.point(row: 1.5, col: 0, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "position:")
+
+ results.primitives << args.layout.point(row: 1.5, col: 2, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "(#{audio_entry[:x].round(5).to_s[0..6]}, #{audio_entry[:y].round(5).to_s[0..6]})")
+
+ results.primitives << args.layout.point(row: 2.0, col: 0, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "pitch:")
+
+ results.pitch_slider_rect = progress_bar(row: 2.0, col: 2,
+ percentage: audio_entry.pitch / 2.0,
+ text: "#{audio_entry.pitch.to_sf}",
+ args: args)
+
+ results.primitives << results.pitch_slider_rect.primitives
+
+ results.primitives << args.layout.point(row: 2.5, col: 0, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "playtime:")
+
+ results.playtime_slider_rect = progress_bar(args: args,
+ row: 2.5,
+ col: 2,
+ percentage: audio_entry.playtime / audio_entry.length_,
+ text: "#{playtime_str(audio_entry.playtime)} / #{playtime_str(audio_entry.length_)}")
+
+ results.primitives << results.playtime_slider_rect.primitives
+
+ results.primitives << args.layout.point(row: 3.0, col: 0, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "gain:")
+
+ results.gain_slider_rect = progress_bar(args: args,
+ row: 3.0,
+ col: 2,
+ percentage: audio_entry.gain,
+ text: "#{audio_entry.gain.to_sf}")
+
+ results.primitives << results.gain_slider_rect.primitives
+
+
+ results.primitives << args.layout.point(row: 3.5, col: 0, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "looping:")
+
+ checkbox_template = args.layout.rect(w: 0.5, h: 0.5, col: 2)
+
+ results.looping_checkbox_rect = check_box(args: args, row: 3.5, col: 2, checked: audio_entry.looping)
+ results.primitives << results.looping_checkbox_rect.primitives
+
+ results.primitives << args.layout.point(row: 4.0, col: 0, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "paused:")
+
+ checkbox_template = args.layout.rect(w: 0.5, h: 0.5, col: 2)
+
+ results.paused_checkbox_rect = check_box(args: args, row: 4.0, col: 2, checked: !audio_entry.paused)
+ results.primitives << results.paused_checkbox_rect.primitives
+
+ results.delete_button_rect = { rect: args.layout.rect(row: 5, col: 0, w: 7, h: 1) }
+
+ results.primitives << results.delete_button_rect.to_solid(r: 180)
+
+ results.primitives << args.layout.point(row: 5, col: 3.5, row_anchor: 0.5)
+ .merge(label_style)
+ .merge(text: "DELETE", alignment_enum: 1)
+
+ return results
+end
+
+def render_panel args
+ args.state.panel = nil
+ audio_entry = args.audio[args.state.selected]
+ return unless audio_entry
+
+ mouse_down = (args.state.mouse_held >= 0)
+ args.state.panel = panel_primitives args, audio_entry
+ args.outputs.primitives << args.state.panel.primitives
+end
+
+def new_sound_id! args
+ args.state.sound_id ||= 0
+ args.state.sound_id += 1
+ args.state.sound_id
+end
+
+def render_launcher args
+ args.outputs.primitives << args.state.spawn_sound_buttons.map(&:primitives)
+end
+
+def render_ui args
+ render_launcher args
+ render_panel args
+end
+
+def tick args
+ defaults args
+ render args
+ input args
+end
+
+def input args
+ if !args.audio[args.state.selected]
+ args.state.selected = nil
+ args.state.dragging = nil
+ end
+
+ # spawn button and node interaction
+ if args.inputs.mouse.click
+ spawn_sound_button = args.state.spawn_sound_buttons.find { |b| args.inputs.mouse.inside_rect? b.rect }
+
+ audio_click_key, audio_click_value = args.audio.find do |k, v|
+ args.inputs.mouse.inside_rect? [v.screenx, v.screeny, args.state.boxsize, args.state.boxsize]
+ end
+
+ if spawn_sound_button
+ args.state.selected = nil
+ spawn_new_sound args, spawn_sound_button.name, spawn_sound_button.path
+ elsif audio_click_key
+ args.state.selected = audio_click_key
+ end
+ end
+
+ if args.state.mouse_state == :held && args.state.selected
+ v = args.audio[args.state.selected]
+ if args.inputs.mouse.inside_rect? [v.screenx, v.screeny, args.state.boxsize, args.state.boxsize]
+ args.state.dragging = args.state.selected
+ end
+
+ if args.state.dragging
+ s = args.audio[args.state.selected]
+ # you can hang anything on the audio hashes you want, so we store the
+ # actual screen position so it doesn't scale weirdly vs your mouse.
+ s.screenx = args.inputs.mouse.x - (args.state.boxsize / 2)
+ s.screeny = args.inputs.mouse.y - (args.state.boxsize / 2)
+
+ s.screeny = 50 if s.screeny < 50
+ s.screeny = (719 - args.state.boxsize) if s.screeny > (719 - args.state.boxsize)
+ s.screenx = 0 if s.screenx < 0
+ s.screenx = (1279 - args.state.boxsize) if s.screenx > (1279 - args.state.boxsize)
+
+ s.x = ((s.screenx / 1279.0) * 2.0) - 1.0 # scale to -1.0 - 1.0 range
+ s.y = ((s.screeny / 719.0) * 2.0) - 1.0 # scale to -1.0 - 1.0 range
+ end
+ elsif args.state.mouse_state == :released
+ args.state.dragging = nil
+ end
+
+ input_panel args
+end
+
+def defaults args
+ args.state.mouse_state ||= :released
+ args.state.dragging_source ||= false
+ args.state.selected ||= 0
+ args.state.next_sound_index ||= 0
+ args.state.boxsize ||= 30
+ args.state.sound_files ||= [
+ { name: :tada, path: "sounds/tada.wav" },
+ { name: :splash, path: "sounds/splash.wav" },
+ { name: :drum, path: "sounds/drum.wav" },
+ { name: :spring, path: "sounds/spring.wav" },
+ { name: :music, path: "sounds/music.ogg" }
+ ]
+
+ # generate buttons based off the sound collection above
+ args.state.spawn_sound_buttons ||= begin
+ # create a group of buttons
+ # column centered (using col_offset to calculate the column offset)
+ # where each item is 2 columns apart
+ rects = args.layout.rect_group row: 11,
+ col_offset: {
+ count: args.state.sound_files.length,
+ w: 2
+ },
+ dcol: 2,
+ w: 2,
+ h: 1,
+ group: args.state.sound_files
+
+ # now that you have the rects
+ # construct the metadata for the buttons
+ rects.map do |rect|
+ {
+ rect: rect,
+ name: rect.name,
+ path: rect.path,
+ primitives: [
+ rect.to_border(r: 255, g: 255, b: 255),
+ rect.to_label(x: rect.center_x,
+ y: rect.center_y,
+ text: "#{rect.name}",
+ alignment_enum: 1,
+ vertical_alignment_enum: 1,
+ r: 255, g: 255, b: 255)
+ ]
+ }
+ end
+ end
+
+ if args.inputs.mouse.up
+ args.state.mouse_state = :released
+ args.state.dragging_source = false
+ elsif args.inputs.mouse.down
+ args.state.mouse_state = :held
+ end
+
+ args.outputs.background_color = [ 0, 0, 0, 255 ]
+end
+
+def render args
+ render_ui args
+ render_sources args
+end
+
+</code></pre>
+<h3 id='----advanced-audio---audio-mixer---server_ip_address-txt'>Advanced Audio - Audio Mixer - server_ip_address.txt</h3>
+<pre><code class="language-ruby"># ./samples/07_advanced_audio/01_audio_mixer/app/server_ip_address.txt
+192.168.1.65
+</code></pre>
+<h3 id='----advanced-audio---audio-mixer---metadata---ios_metadata-txt'>Advanced Audio - Audio Mixer - Metadata - ios_metadata.txt</h3>
+<pre><code class="language-ruby"># ./samples/07_advanced_audio/01_audio_mixer/metadata/ios_metadata.txt
+# ios_metadata.txt is used by the Pro version of DragonRuby Game Toolkit to create iOS apps.
+# Information about the Pro version can be found at: http://dragonruby.org/toolkit/game#purchase
+
+# teamid needs to be set to your assigned Team Id which can be found at https://developer.apple.com/account/#/membership/
+teamid=
+# appid needs to be set to your application identifier which can be found at https://developer.apple.com/account/resources/identifiers/list
+appid=
+# appname is the name you want to show up underneath the app icon on the device. Keep it under 10 characters.
+appname=
+
+</code></pre>
+<h3 id='----advanced-audio---sound-synthesis---main-rb'>Advanced Audio - Sound Synthesis - main.rb</h3>
+<pre><code class="language-ruby"># ./samples/07_advanced_audio/02_sound_synthesis/app/main.rb
+begin # region: top level tick methods
+ def tick args
+ defaults args
+ render args
+ input args
+ process_audio_queue args
+ end
+
+ def defaults args
+ args.state.sine_waves ||= {}
+ args.state.square_waves ||= {}
+ args.state.saw_tooth_waves ||= {}
+ args.state.triangle_waves ||= {}
+ args.state.audio_queue ||= []
+ args.state.buttons ||= [
+ (frequency_buttons args),
+ (sine_wave_note_buttons args),
+ (bell_buttons args),
+ (square_wave_note_buttons args),
+ (saw_tooth_wave_note_buttons args),
+ (triangle_wave_note_buttons args),
+ ].flatten
+ end
+
+ def render args
+ args.outputs.borders << args.state.buttons.map { |b| b[:border] }
+ args.outputs.labels << args.state.buttons.map { |b| b[:label] }
+ args.outputs.labels << args.layout
+ .rect(row: 0, col: 11.5)
+ .yield_self { |r| r.merge y: r.y + r.h }
+ .merge(text: "This is a Pro only feature. Click here to watch the YouTube video if you are on the Standard License.",
+ alignment_enum: 1)
+ end
+
+
+ def input args
+ args.state.buttons.each do |b|
+ if args.inputs.mouse.click && (args.inputs.mouse.click.inside_rect? b[:rect])
+ parameter_string = (b.slice :frequency, :note, :octave).map { |k, v| "#{k}: #{v}" }.join ", "
+ args.gtk.notify! "#{b[:method_to_call]} #{parameter_string}"
+ send b[:method_to_call], args, b
+ end
+ end
+
+ if args.inputs.mouse.click && (args.inputs.mouse.click.inside_rect? (args.layout.rect(row: 0).yield_self { |r| r.merge y: r.y + r.h.half, h: r.h.half }))
+ args.gtk.openurl 'https://www.youtube.com/watch?v=zEzovM5jT-k&ab_channel=AmirRajan'
+ end
+ end
+
+ def process_audio_queue args
+ to_queue = args.state.audio_queue.find_all { |v| v[:queue_at] <= args.tick_count }
+ args.state.audio_queue -= to_queue
+ to_queue.each { |a| args.audio[a[:id]] = a }
+
+ args.audio.find_all { |k, v| v[:decay_rate] }
+ .each { |k, v| v[:gain] -= v[:decay_rate] }
+
+ sounds_to_stop = args.audio
+ .find_all { |k, v| v[:stop_at] && args.state.tick_count >= v[:stop_at] }
+ .map { |k, v| k }
+
+ sounds_to_stop.each { |k| args.audio.delete k }
+ end
+end
+
+begin # region: button definitions, ui layout, callback functions
+ def button args, opts
+ button_def = opts.merge rect: (args.layout.rect (opts.merge w: 2, h: 1))
+
+ button_def[:border] = button_def[:rect].merge r: 0, g: 0, b: 0
+
+ label_offset_x = 5
+ label_offset_y = 30
+
+ button_def[:label] = button_def[:rect].merge text: opts[:text],
+ size_enum: -2.5,
+ x: button_def[:rect].x + label_offset_x,
+ y: button_def[:rect].y + label_offset_y
+
+ button_def
+ end
+
+ def play_sine_wave args, sender
+ queue_sine_wave args,
+ frequency: sender[:frequency],
+ duration: 1.seconds,
+ fade_out: true
+ end
+
+ def play_note args, sender
+ method_to_call = :queue_sine_wave
+ method_to_call = :queue_square_wave if sender[:type] == :square
+ method_to_call = :queue_saw_tooth_wave if sender[:type] == :saw_tooth
+ method_to_call = :queue_triangle_wave if sender[:type] == :triangle
+ method_to_call = :queue_bell if sender[:type] == :bell
+
+ send method_to_call, args,
+ frequency: (frequency_for note: sender[:note], octave: sender[:octave]),
+ duration: 1.seconds,
+ fade_out: true
+ end
+
+ def frequency_buttons args
+ [
+ (button args,
+ row: 4.0, col: 0, text: "300hz",
+ frequency: 300,
+ method_to_call: :play_sine_wave),
+ (button args,
+ row: 5.0, col: 0, text: "400hz",
+ frequency: 400,
+ method_to_call: :play_sine_wave),
+ (button args,
+ row: 6.0, col: 0, text: "500hz",
+ frequency: 500,
+ method_to_call: :play_sine_wave),
+ ]
+ end
+
+ def sine_wave_note_buttons args
+ [
+ (button args,
+ row: 1.5, col: 2, text: "Sine C4",
+ note: :c, octave: 4, type: :sine, method_to_call: :play_note),
+ (button args,
+ row: 2.5, col: 2, text: "Sine D4",
+ note: :d, octave: 4, type: :sine, method_to_call: :play_note),
+ (button args,
+ row: 3.5, col: 2, text: "Sine E4",
+ note: :e, octave: 4, type: :sine, method_to_call: :play_note),
+ (button args,
+ row: 4.5, col: 2, text: "Sine F4",
+ note: :f, octave: 4, type: :sine, method_to_call: :play_note),
+ (button args,
+ row: 5.5, col: 2, text: "Sine G4",
+ note: :g, octave: 4, type: :sine, method_to_call: :play_note),
+ (button args,
+ row: 6.5, col: 2, text: "Sine A5",
+ note: :a, octave: 5, type: :sine, method_to_call: :play_note),
+ (button args,
+ row: 7.5, col: 2, text: "Sine B5",
+ note: :b, octave: 5, type: :sine, method_to_call: :play_note),
+ (button args,
+ row: 8.5, col: 2, text: "Sine C5",
+ note: :c, octave: 5, type: :sine, method_to_call: :play_note),
+ ]
+ end
+
+ def square_wave_note_buttons args
+ [
+ (button args,
+ row: 1.5, col: 6, text: "Square C4",
+ note: :c, octave: 4, type: :square, method_to_call: :play_note),
+ (button args,
+ row: 2.5, col: 6, text: "Square D4",
+ note: :d, octave: 4, type: :square, method_to_call: :play_note),
+ (button args,
+ row: 3.5, col: 6, text: "Square E4",
+ note: :e, octave: 4, type: :square, method_to_call: :play_note),
+ (button args,
+ row: 4.5, col: 6, text: "Square F4",
+ note: :f, octave: 4, type: :square, method_to_call: :play_note),
+ (button args,
+ row: 5.5, col: 6, text: "Square G4",
+ note: :g, octave: 4, type: :square, method_to_call: :play_note),
+ (button args,
+ row: 6.5, col: 6, text: "Square A5",
+ note: :a, octave: 5, type: :square, method_to_call: :play_note),
+ (button args,
+ row: 7.5, col: 6, text: "Square B5",
+ note: :b, octave: 5, type: :square, method_to_call: :play_note),
+ (button args,
+ row: 8.5, col: 6, text: "Square C5",
+ note: :c, octave: 5, type: :square, method_to_call: :play_note),
+ ]
+ end
+ def saw_tooth_wave_note_buttons args
+ [
+ (button args,
+ row: 1.5, col: 8, text: "Saw C4",
+ note: :c, octave: 4, type: :saw_tooth, method_to_call: :play_note),
+ (button args,
+ row: 2.5, col: 8, text: "Saw D4",
+ note: :d, octave: 4, type: :saw_tooth, method_to_call: :play_note),
+ (button args,
+ row: 3.5, col: 8, text: "Saw E4",
+ note: :e, octave: 4, type: :saw_tooth, method_to_call: :play_note),
+ (button args,
+ row: 4.5, col: 8, text: "Saw F4",
+ note: :f, octave: 4, type: :saw_tooth, method_to_call: :play_note),
+ (button args,
+ row: 5.5, col: 8, text: "Saw G4",
+ note: :g, octave: 4, type: :saw_tooth, method_to_call: :play_note),
+ (button args,
+ row: 6.5, col: 8, text: "Saw A5",
+ note: :a, octave: 5, type: :saw_tooth, method_to_call: :play_note),
+ (button args,
+ row: 7.5, col: 8, text: "Saw B5",
+ note: :b, octave: 5, type: :saw_tooth, method_to_call: :play_note),
+ (button args,
+ row: 8.5, col: 8, text: "Saw C5",
+ note: :c, octave: 5, type: :saw_tooth, method_to_call: :play_note),
+ ]
+ end
+
+ def triangle_wave_note_buttons args
+ [
+ (button args,
+ row: 1.5, col: 10, text: "Triangle C4",
+ note: :c, octave: 4, type: :triangle, method_to_call: :play_note),
+ (button args,
+ row: 2.5, col: 10, text: "Triangle D4",
+ note: :d, octave: 4, type: :triangle, method_to_call: :play_note),
+ (button args,
+ row: 3.5, col: 10, text: "Triangle E4",
+ note: :e, octave: 4, type: :triangle, method_to_call: :play_note),
+ (button args,
+ row: 4.5, col: 10, text: "Triangle F4",
+ note: :f, octave: 4, type: :triangle, method_to_call: :play_note),
+ (button args,
+ row: 5.5, col: 10, text: "Triangle G4",
+ note: :g, octave: 4, type: :triangle, method_to_call: :play_note),
+ (button args,
+ row: 6.5, col: 10, text: "Triangle A5",
+ note: :a, octave: 5, type: :triangle, method_to_call: :play_note),
+ (button args,
+ row: 7.5, col: 10, text: "Triangle B5",
+ note: :b, octave: 5, type: :triangle, method_to_call: :play_note),
+ (button args,
+ row: 8.5, col: 10, text: "Triangle C5",
+ note: :c, octave: 5, type: :triangle, method_to_call: :play_note),
+ ]
+ end
+
+ def bell_buttons args
+ [
+ (button args,
+ row: 1.5, col: 4, text: "Bell C4",
+ note: :c, octave: 4, type: :bell, method_to_call: :play_note),
+ (button args,
+ row: 2.5, col: 4, text: "Bell D4",
+ note: :d, octave: 4, type: :bell, method_to_call: :play_note),
+ (button args,
+ row: 3.5, col: 4, text: "Bell E4",
+ note: :e, octave: 4, type: :bell, method_to_call: :play_note),
+ (button args,
+ row: 4.5, col: 4, text: "Bell F4",
+ note: :f, octave: 4, type: :bell, method_to_call: :play_note),
+ (button args,
+ row: 5.5, col: 4, text: "Bell G4",
+ note: :g, octave: 4, type: :bell, method_to_call: :play_note),
+ (button args,
+ row: 6.5, col: 4, text: "Bell A5",
+ note: :a, octave: 5, type: :bell, method_to_call: :play_note),
+ (button args,
+ row: 7.5, col: 4, text: "Bell B5",
+ note: :b, octave: 5, type: :bell, method_to_call: :play_note),
+ (button args,
+ row: 8.5, col: 4, text: "Bell C5",
+ note: :c, octave: 5, type: :bell, method_to_call: :play_note),
+ ]
+ end
+end
+
+begin # region: wave generation
+ begin # sine wave
+ def defaults_sine_wave_for
+ { frequency: 440, sample_rate: 48000 }
+ end
+
+ def sine_wave_for opts = {}
+ opts = defaults_sine_wave_for.merge opts
+ frequency = opts[:frequency]
+ sample_rate = opts[:sample_rate]
+ period_size = (sample_rate.fdiv frequency).ceil
+ period_size.map_with_index do |i|
+ Math::sin((2.0 * Math::PI) / (sample_rate.to_f / frequency.to_f) * i)
+ end.to_a
+ end
+
+ def defaults_queue_sine_wave
+ { frequency: 440, duration: 60, gain: 1.0, fade_out: false, queue_in: 0 }
+ end
+
+ def queue_sine_wave args, opts = {}
+ opts = defaults_queue_sine_wave.merge opts
+ frequency = opts[:frequency]
+ sample_rate = 48000
+
+ sine_wave = sine_wave_for frequency: frequency, sample_rate: sample_rate
+ args.state.sine_waves[frequency] ||= sine_wave_for frequency: frequency, sample_rate: sample_rate
+
+ proc = lambda do
+ generate_audio_data args.state.sine_waves[frequency], sample_rate
+ end
+
+ audio_state = new_audio_state args, opts
+ audio_state[:input] = [1, sample_rate, proc]
+ queue_audio args, audio_state: audio_state, wave: sine_wave
+ end
+ end
+
+ begin # region: square wave
+ def defaults_square_wave_for
+ { frequency: 440, sample_rate: 48000 }
+ end
+
+ def square_wave_for opts = {}
+ opts = defaults_square_wave_for.merge opts
+ sine_wave = sine_wave_for opts
+ sine_wave.map do |v|
+ if v >= 0
+ 1.0
+ else
+ -1.0
+ end
+ end.to_a
+ end
+
+ def defaults_queue_square_wave
+ { frequency: 440, duration: 60, gain: 0.3, fade_out: false, queue_in: 0 }
+ end
+
+ def queue_square_wave args, opts = {}
+ opts = defaults_queue_square_wave.merge opts
+ frequency = opts[:frequency]
+ sample_rate = 48000
+
+ square_wave = square_wave_for frequency: frequency, sample_rate: sample_rate
+ args.state.square_waves[frequency] ||= square_wave_for frequency: frequency, sample_rate: sample_rate
+
+ proc = lambda do
+ generate_audio_data args.state.square_waves[frequency], sample_rate
+ end
+
+ audio_state = new_audio_state args, opts
+ audio_state[:input] = [1, sample_rate, proc]
+ queue_audio args, audio_state: audio_state, wave: square_wave
+ end
+ end
+
+ begin # region: saw tooth wave
+ def defaults_saw_tooth_wave_for
+ { frequency: 440, sample_rate: 48000 }
+ end
+
+ def saw_tooth_wave_for opts = {}
+ opts = defaults_saw_tooth_wave_for.merge opts
+ sine_wave = sine_wave_for opts
+ period_size = sine_wave.length
+ sine_wave.map_with_index do |v, i|
+ (((i % period_size).fdiv period_size) * 2) - 1
+ end
+ end
+
+ def defaults_queue_saw_tooth_wave
+ { frequency: 440, duration: 60, gain: 0.3, fade_out: false, queue_in: 0 }
+ end
+
+ def queue_saw_tooth_wave args, opts = {}
+ opts = defaults_queue_saw_tooth_wave.merge opts
+ frequency = opts[:frequency]
+ sample_rate = 48000
+
+ saw_tooth_wave = saw_tooth_wave_for frequency: frequency, sample_rate: sample_rate
+ args.state.saw_tooth_waves[frequency] ||= saw_tooth_wave_for frequency: frequency, sample_rate: sample_rate
+
+ proc = lambda do
+ generate_audio_data args.state.saw_tooth_waves[frequency], sample_rate
+ end
+
+ audio_state = new_audio_state args, opts
+ audio_state[:input] = [1, sample_rate, proc]
+ queue_audio args, audio_state: audio_state, wave: saw_tooth_wave
+ end
+ end
+
+ begin # region: triangle wave
+ def defaults_triangle_wave_for
+ { frequency: 440, sample_rate: 48000 }
+ end
+
+ def triangle_wave_for opts = {}
+ opts = defaults_saw_tooth_wave_for.merge opts
+ sine_wave = sine_wave_for opts
+ period_size = sine_wave.length
+ sine_wave.map_with_index do |v, i|
+ ratio = (i.fdiv period_size)
+ if ratio <= 0.5
+ (ratio * 4) - 1
+ else
+ ratio -= 0.5
+ 1 - (ratio * 4)
+ end
+ end
+ end
+
+ def defaults_queue_triangle_wave
+ { frequency: 440, duration: 60, gain: 1.0, fade_out: false, queue_in: 0 }
+ end
+
+ def queue_triangle_wave args, opts = {}
+ opts = defaults_queue_triangle_wave.merge opts
+ frequency = opts[:frequency]
+ sample_rate = 48000
+
+ triangle_wave = triangle_wave_for frequency: frequency, sample_rate: sample_rate
+ args.state.triangle_waves[frequency] ||= triangle_wave_for frequency: frequency, sample_rate: sample_rate
+
+ proc = lambda do
+ generate_audio_data args.state.triangle_waves[frequency], sample_rate
+ end
+
+ audio_state = new_audio_state args, opts
+ audio_state[:input] = [1, sample_rate, proc]
+ queue_audio args, audio_state: audio_state, wave: triangle_wave
+ end
+ end
+
+ begin # region: bell
+ def defaults_queue_bell
+ { frequency: 440, duration: 1.seconds, queue_in: 0 }
+ end
+
+ def queue_bell args, opts = {}
+ (bell_to_sine_waves (defaults_queue_bell.merge opts)).each { |b| queue_sine_wave args, b }
+ end
+
+ def bell_harmonics
+ [
+ { frequency_ratio: 0.5, duration_ratio: 1.00 },
+ { frequency_ratio: 1.0, duration_ratio: 0.80 },
+ { frequency_ratio: 2.0, duration_ratio: 0.60 },
+ { frequency_ratio: 3.0, duration_ratio: 0.40 },
+ { frequency_ratio: 4.2, duration_ratio: 0.25 },
+ { frequency_ratio: 5.4, duration_ratio: 0.20 },
+ { frequency_ratio: 6.8, duration_ratio: 0.15 }
+ ]
+ end
+
+ def defaults_bell_to_sine_waves
+ { frequency: 440, duration: 1.seconds, queue_in: 0 }
+ end
+
+ def bell_to_sine_waves opts = {}
+ opts = defaults_bell_to_sine_waves.merge opts
+ bell_harmonics.map do |b|
+ {
+ frequency: opts[:frequency] * b[:frequency_ratio],
+ duration: opts[:duration] * b[:duration_ratio],
+ queue_in: opts[:queue_in],
+ gain: (1.fdiv bell_harmonics.length),
+ fade_out: true
+ }
+ end
+ end
+ end
+
+ begin # audio entity construction
+ def generate_audio_data sine_wave, sample_rate
+ sample_size = (sample_rate.fdiv (1000.fdiv 60)).ceil
+ copy_count = (sample_size.fdiv sine_wave.length).ceil
+ sine_wave * copy_count
+ end
+
+ def defaults_new_audio_state
+ { frequency: 440, duration: 60, gain: 1.0, fade_out: false, queue_in: 0 }
+ end
+
+ def new_audio_state args, opts = {}
+ opts = defaults_new_audio_state.merge opts
+ decay_rate = 0
+ decay_rate = 1.fdiv(opts[:duration]) * opts[:gain] if opts[:fade_out]
+ frequency = opts[:frequency]
+ sample_rate = 48000
+
+ {
+ id: (new_id! args),
+ frequency: frequency,
+ sample_rate: 48000,
+ stop_at: args.tick_count + opts[:queue_in] + opts[:duration],
+ gain: opts[:gain].to_f,
+ queue_at: args.state.tick_count + opts[:queue_in],
+ decay_rate: decay_rate,
+ pitch: 1.0,
+ looping: true,
+ paused: false
+ }
+ end
+
+ def queue_audio args, opts = {}
+ graph_wave args, opts[:wave], opts[:audio_state][:frequency]
+ args.state.audio_queue << opts[:audio_state]
+ end
+
+ def new_id! args
+ args.state.audio_id ||= 0
+ args.state.audio_id += 1
+ end
+
+ def graph_wave args, wave, frequency
+ if args.state.tick_count != args.state.graphed_at
+ args.outputs.static_lines.clear
+ args.outputs.static_sprites.clear
+ end
+
+ wave = wave
+
+ r, g, b = frequency.to_i % 85,
+ frequency.to_i % 170,
+ frequency.to_i % 255
+
+ starting_rect = args.layout.rect(row: 5, col: 13)
+ x_scale = 10
+ y_scale = 100
+ max_points = 25
+
+ points = wave
+ if wave.length > max_points
+ resolution = wave.length.idiv max_points
+ points = wave.find_all.with_index { |y, i| (i % resolution == 0) }
+ end
+
+ args.outputs.static_lines << points.map_with_index do |y, x|
+ next_y = points[x + 1]
+
+ if next_y
+ {
+ x: starting_rect.x + (x * x_scale),
+ y: starting_rect.y + starting_rect.h.half + y_scale * y,
+ x2: starting_rect.x + ((x + 1) * x_scale),
+ y2: starting_rect.y + starting_rect.h.half + y_scale * next_y,
+ r: r,
+ g: g,
+ b: b
+ }
+ end
+ end
+
+ args.outputs.static_sprites << points.map_with_index do |y, x|
+ {
+ x: (starting_rect.x + (x * x_scale)) - 2,
+ y: (starting_rect.y + starting_rect.h.half + y_scale * y) - 2,
+ w: 4,
+ h: 4,
+ path: 'sprites/square-white.png',
+ r: r,
+ g: g,
+ b: b
+ }
+ end
+
+ args.state.graphed_at = args.state.tick_count
+ end
+ end
+
+ begin # region: musical note mapping
+ def defaults_frequency_for
+ { note: :a, octave: 5, sharp: false, flat: false }
+ end
+
+ def frequency_for opts = {}
+ opts = defaults_frequency_for.merge opts
+ octave_offset_multiplier = opts[:octave] - 5
+ note = note_frequencies_octave_5[opts[:note]]
+ if octave_offset_multiplier < 0
+ note = note * 1 / (octave_offset_multiplier.abs + 1)
+ elsif octave_offset_multiplier > 0
+ note = note * (octave_offset_multiplier.abs + 1) / 1
+ end
+ note
+ end
+
+ def note_frequencies_octave_5
+ {
+ a: 440.0,
+ a_sharp: 466.16, b_flat: 466.16,
+ b: 493.88,
+ c: 523.25,
+ c_sharp: 554.37, d_flat: 587.33,
+ d: 587.33,
+ d_sharp: 622.25, e_flat: 659.25,
+ e: 659.25,
+ f: 698.25,
+ f_sharp: 739.99, g_flat: 739.99,
+ g: 783.99,
+ g_sharp: 830.61, a_flat: 830.61
+ }
+ end
+ end
+end
+
+$gtk.reset
+
+</code></pre>
+<h3 id='----advanced-rendering---simple-render-targets---main-rb'>Advanced Rendering - Simple Render Targets - main.rb</h3>
<pre><code class="language-ruby"># ./samples/07_advanced_rendering/01_simple_render_targets/app/main.rb
def tick args
# args.outputs.render_targets are really really powerful.
@@ -11586,7 +11964,7 @@ end
$gtk.reset
</code></pre>
-<h3 id='----advanced-rendering---render-targets-with-tile-manipulation---main.rb'>Advanced Rendering - Render Targets With Tile Manipulation - main.rb</h3>
+<h3 id='----advanced-rendering---render-targets-with-tile-manipulation---main-rb'>Advanced Rendering - Render Targets With Tile Manipulation - main.rb</h3>
<pre><code class="language-ruby"># ./samples/07_advanced_rendering/02_render_targets_with_tile_manipulation/app/main.rb
# This sample is meant to show you how to do that dripping transition thing
# at the start of the original Doom. Most of this file is here to animate
@@ -11685,7 +12063,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----advanced-rendering---render-target-viewports---main.rb'>Advanced Rendering - Render Target Viewports - main.rb</h3>
+<h3 id='----advanced-rendering---render-target-viewports---main-rb'>Advanced Rendering - Render Target Viewports - main.rb</h3>
<pre><code class="language-ruby"># ./samples/07_advanced_rendering/03_render_target_viewports/app/main.rb
=begin
@@ -12157,7 +12535,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----advanced-rendering---render-primitive-hierarchies---main.rb'>Advanced Rendering - Render Primitive Hierarchies - main.rb</h3>
+<h3 id='----advanced-rendering---render-primitive-hierarchies---main-rb'>Advanced Rendering - Render Primitive Hierarchies - main.rb</h3>
<pre><code class="language-ruby"># ./samples/07_advanced_rendering/04_render_primitive_hierarchies/app/main.rb
=begin
@@ -12333,7 +12711,7 @@ def collection_of_sprites args
end
</code></pre>
-<h3 id='----advanced-rendering---render-primitives-as-hash---main.rb'>Advanced Rendering - Render Primitives As Hash - main.rb</h3>
+<h3 id='----advanced-rendering---render-primitives-as-hash---main-rb'>Advanced Rendering - Render Primitives As Hash - main.rb</h3>
<pre><code class="language-ruby"># ./samples/07_advanced_rendering/05_render_primitives_as_hash/app/main.rb
=begin
@@ -12473,7 +12851,7 @@ def tick args
flip_horizontally: false,
angle_anchor_x: 0.5, # rotation center set to middle
angle_anchor_y: 0.5
- }.sprite
+ }.sprite!
# Outputs label as primitive using a hash
args.outputs.primitives << {
@@ -12487,7 +12865,7 @@ def tick args
b: 50,
a: 255, # transparency
font: "fonts/manaspc.ttf" # font style
- }.label
+ }.label!
# Outputs solid as primitive using a hash
args.outputs.primitives << {
@@ -12499,7 +12877,7 @@ def tick args
g: 50,
b: 50,
a: 255 # transparency
- }.solid
+ }.solid!
# Outputs border as primitive using a hash
# Same parameters as solid
@@ -12512,7 +12890,7 @@ def tick args
g: 50,
b: 50,
a: 255 # transparency
- }.border
+ }.border!
# Outputs line as primitive using a hash
args.outputs.primitives << {
@@ -12524,11 +12902,11 @@ def tick args
g: 50,
b: 50,
a: 255 # transparency
- }.line
+ }.line!
end
</code></pre>
-<h3 id='----advanced-rendering---pixel-arrays---main.rb'>Advanced Rendering - Pixel Arrays - main.rb</h3>
+<h3 id='----advanced-rendering---pixel-arrays---main-rb'>Advanced Rendering - Pixel Arrays - main.rb</h3>
<pre><code class="language-ruby"># ./samples/07_advanced_rendering/06_pixel_arrays/app/main.rb
$gtk.reset
@@ -12573,8 +12951,105 @@ end
</code></pre>
-<h3 id='----advanced-rendering---splitscreen-camera---main.rb'>Advanced Rendering - Splitscreen Camera - main.rb</h3>
-<pre><code class="language-ruby"># ./samples/07_advanced_rendering/07_splitscreen_camera/app/main.rb
+<h3 id='----advanced-rendering---simple-camera---main-rb'>Advanced Rendering - Simple Camera - main.rb</h3>
+<pre><code class="language-ruby"># ./samples/07_advanced_rendering/07_simple_camera/app/main.rb
+def tick args
+ # variables you can play around with
+ args.state.world.w ||= 1280
+ args.state.world.h ||= 720
+
+ args.state.player.x ||= 0
+ args.state.player.y ||= 0
+ args.state.player.size ||= 32
+
+ args.state.enemy.x ||= 700
+ args.state.enemy.y ||= 700
+ args.state.enemy.size ||= 16
+
+ args.state.camera.x ||= 640
+ args.state.camera.y ||= 300
+ args.state.camera.scale ||= 1.0
+ args.state.camera.show_empty_space ||= :yes
+
+ # instructions
+ args.outputs.primitives << { x: 0, y: 80.from_top, w: 360, h: 80, r: 0, g: 0, b: 0, a: 128 }.solid!
+ args.outputs.primitives << { x: 10, y: 10.from_top, text: "arrow keys to move around", r: 255, g: 255, b: 255}.label!
+ args.outputs.primitives << { x: 10, y: 30.from_top, text: "+/- to change zoom of camera", r: 255, g: 255, b: 255}.label!
+ args.outputs.primitives << { x: 10, y: 50.from_top, text: "tab to change camera edge behavior", r: 255, g: 255, b: 255}.label!
+
+ # render scene
+ args.outputs[:scene].w = args.state.world.w
+ args.outputs[:scene].h = args.state.world.h
+
+ args.outputs[:scene].solids << { x: 0, y: 0, w: args.state.world.w, h: args.state.world.h, r: 20, g: 60, b: 80 }
+ args.outputs[:scene].solids << { x: args.state.player.x, y: args.state.player.y,
+ w: args.state.player.size, h: args.state.player.size, r: 80, g: 155, b: 80 }
+ args.outputs[:scene].solids << { x: args.state.enemy.x, y: args.state.enemy.y,
+ w: args.state.enemy.size, h: args.state.enemy.size, r: 155, g: 80, b: 80 }
+
+ # render camera
+ scene_position = calc_scene_position args
+ args.outputs.sprites << { x: scene_position.x,
+ y: scene_position.y,
+ w: scene_position.w,
+ h: scene_position.h,
+ path: :scene }
+
+ # move player
+ if args.inputs.directional_angle
+ args.state.player.x += args.inputs.directional_angle.vector_x * 5
+ args.state.player.y += args.inputs.directional_angle.vector_y * 5
+ args.state.player.x = args.state.player.x.clamp(0, args.state.world.w - args.state.player.size)
+ args.state.player.y = args.state.player.y.clamp(0, args.state.world.h - args.state.player.size)
+ end
+
+ # +/- to zoom in and out
+ if args.inputs.keyboard.plus && args.state.tick_count.zmod?(3)
+ args.state.camera.scale += 0.05
+ elsif args.inputs.keyboard.hyphen && args.state.tick_count.zmod?(3)
+ args.state.camera.scale -= 0.05
+ elsif args.inputs.keyboard.key_down.tab
+ if args.state.camera.show_empty_space == :yes
+ args.state.camera.show_empty_space = :no
+ else
+ args.state.camera.show_empty_space = :yes
+ end
+ end
+
+ args.state.camera.scale = args.state.camera.scale.greater(0.1)
+end
+
+def calc_scene_position args
+ result = { x: args.state.camera.x - (args.state.player.x * args.state.camera.scale),
+ y: args.state.camera.y - (args.state.player.y * args.state.camera.scale),
+ w: args.state.world.w * args.state.camera.scale,
+ h: args.state.world.h * args.state.camera.scale,
+ scale: args.state.camera.scale }
+
+ return result if args.state.camera.show_empty_space == :yes
+
+ if result.w < args.grid.w
+ result.merge!(x: (args.grid.w - result.w).half)
+ elsif (args.state.player.x * result.scale) < args.grid.w.half
+ result.merge!(x: 10)
+ elsif (result.x + result.w) < args.grid.w
+ result.merge!(x: - result.w + (args.grid.w - 10))
+ end
+
+ if result.h < args.grid.h
+ result.merge!(y: (args.grid.h - result.h).half)
+ elsif (result.y) > 10
+ result.merge!(y: 10)
+ elsif (result.y + result.h) < args.grid.h
+ result.merge!(y: - result.h + (args.grid.h - 10))
+ end
+
+ result
+end
+
+</code></pre>
+<h3 id='----advanced-rendering---splitscreen-camera---main-rb'>Advanced Rendering - Splitscreen Camera - main.rb</h3>
+<pre><code class="language-ruby"># ./samples/07_advanced_rendering/08_splitscreen_camera/app/main.rb
class CameraMovement
attr_accessor :state, :inputs, :outputs, :grid
@@ -12972,8 +13447,8 @@ def tick args
end
</code></pre>
-<h3 id='----advanced-rendering---z-targeting-camera---main.rb'>Advanced Rendering - Z Targeting Camera - main.rb</h3>
-<pre><code class="language-ruby"># ./samples/07_advanced_rendering/08_z_targeting_camera/app/main.rb
+<h3 id='----advanced-rendering---z-targeting-camera---main-rb'>Advanced Rendering - Z Targeting Camera - main.rb</h3>
+<pre><code class="language-ruby"># ./samples/07_advanced_rendering/09_z_targeting_camera/app/main.rb
class Game
attr_gtk
@@ -13082,7 +13557,60 @@ end
$gtk.reset
</code></pre>
-<h3 id='----tweening-lerping-easing-functions---easing-functions---main.rb'>Tweening Lerping Easing Functions - Easing Functions - main.rb</h3>
+<h3 id='----advanced-rendering---blend-modes---main-rb'>Advanced Rendering - Blend Modes - main.rb</h3>
+<pre><code class="language-ruby"># ./samples/07_advanced_rendering/10_blend_modes/app/main.rb
+$gtk.reset
+
+def draw_blendmode args, mode
+ w = 160
+ h = w
+ args.state.x += (1280-w) / (args.state.blendmodes.length + 1)
+ x = args.state.x
+ y = (720 - h) / 2
+ s = 'sprites/blue-feathered.png'
+ args.outputs.sprites << { blendmode_enum: mode.value, x: x, y: y, w: w, h: h, path: s }
+ args.outputs.labels << [x + (w/2), y, mode.name.to_s, 1, 1, 255, 255, 255]
+end
+
+def tick args
+
+ # Different blend modes do different things, depending on what they
+ # blend against (in this case, the pixels of the background color).
+ args.state.bg_element ||= 1
+ args.state.bg_color ||= 255
+ args.state.bg_color_direction ||= 1
+ bg_r = (args.state.bg_element == 1) ? args.state.bg_color : 0
+ bg_g = (args.state.bg_element == 2) ? args.state.bg_color : 0
+ bg_b = (args.state.bg_element == 3) ? args.state.bg_color : 0
+ args.state.bg_color += args.state.bg_color_direction
+ if (args.state.bg_color_direction > 0) && (args.state.bg_color >= 255)
+ args.state.bg_color_direction = -1
+ args.state.bg_color = 255
+ elsif (args.state.bg_color_direction < 0) && (args.state.bg_color <= 0)
+ args.state.bg_color_direction = 1
+ args.state.bg_color = 0
+ args.state.bg_element += 1
+ if args.state.bg_element >= 4
+ args.state.bg_element = 1
+ end
+ end
+
+ args.outputs.background_color = [ bg_r, bg_g, bg_b, 255 ]
+
+ args.state.blendmodes ||= [
+ { name: :none, value: 0 },
+ { name: :blend, value: 1 },
+ { name: :add, value: 2 },
+ { name: :mod, value: 3 },
+ { name: :mul, value: 4 }
+ ]
+
+ args.state.x = 0 # reset this, draw_blendmode will increment it.
+ args.state.blendmodes.each { |blendmode| draw_blendmode args, blendmode }
+end
+
+</code></pre>
+<h3 id='----tweening-lerping-easing-functions---easing-functions---main-rb'>Tweening Lerping Easing Functions - Easing Functions - main.rb</h3>
<pre><code class="language-ruby"># ./samples/08_tweening_lerping_easing_functions/01_easing_functions/app/main.rb
def tick args
# STOP! Watch the following presentation first!!!!
@@ -13218,7 +13746,7 @@ module Easing
end
</code></pre>
-<h3 id='----tweening-lerping-easing-functions---cubic-bezier---main.rb'>Tweening Lerping Easing Functions - Cubic Bezier - main.rb</h3>
+<h3 id='----tweening-lerping-easing-functions---cubic-bezier---main-rb'>Tweening Lerping Easing Functions - Cubic Bezier - main.rb</h3>
<pre><code class="language-ruby"># ./samples/08_tweening_lerping_easing_functions/02_cubic_bezier/app/main.rb
def tick args
args.outputs.background_color = [33, 33, 33]
@@ -13283,7 +13811,7 @@ def pow n, to
end
</code></pre>
-<h3 id='----tweening-lerping-easing-functions---easing-using-spline---main.rb'>Tweening Lerping Easing Functions - Easing Using Spline - main.rb</h3>
+<h3 id='----tweening-lerping-easing-functions---easing-using-spline---main-rb'>Tweening Lerping Easing Functions - Easing Using Spline - main.rb</h3>
<pre><code class="language-ruby"># ./samples/08_tweening_lerping_easing_functions/03_easing_using_spline/app/main.rb
def tick args
args.state.duration = 10.seconds
@@ -13305,7 +13833,7 @@ def tick args
end
</code></pre>
-<h3 id='----tweening-lerping-easing-functions---parametric-enemy-movement---main.rb'>Tweening Lerping Easing Functions - Parametric Enemy Movement - main.rb</h3>
+<h3 id='----tweening-lerping-easing-functions---parametric-enemy-movement---main-rb'>Tweening Lerping Easing Functions - Parametric Enemy Movement - main.rb</h3>
<pre><code class="language-ruby"># ./samples/08_tweening_lerping_easing_functions/04_parametric_enemy_movement/app/main.rb
def new_star args
{ x: 1280.randomize(:ratio),
@@ -13522,7 +14050,7 @@ def tick args
end
</code></pre>
-<h3 id='----performance---sprites-as-hash---main.rb'>Performance - Sprites As Hash - main.rb</h3>
+<h3 id='----performance---sprites-as-hash---main-rb'>Performance - Sprites As Hash - main.rb</h3>
<pre><code class="language-ruby"># ./samples/09_performance/01_sprites_as_hash/app/main.rb
# Sprites represented as Hashes using the queue ~args.outputs.sprites~
@@ -13565,7 +14093,11 @@ def tick args
# sets console command when sample app initially opens
if Kernel.global_tick_count == 0
- puts "* INFO - Please specify the number of sprites to render."
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Sprites, Hashes"
+ puts "* INFO: Please specify the number of sprites to render."
args.gtk.console.set_command "reset_with count: 100"
end
@@ -13590,7 +14122,7 @@ def reset_with count: count
end
</code></pre>
-<h3 id='----performance---sprites-as-entities---main.rb'>Performance - Sprites As Entities - main.rb</h3>
+<h3 id='----performance---sprites-as-entities---main-rb'>Performance - Sprites As Entities - main.rb</h3>
<pre><code class="language-ruby"># ./samples/09_performance/02_sprites_as_entities/app/main.rb
# Sprites represented as Entities using the queue ~args.outputs.sprites~
# yields nicer access apis over Hashes, but require a bit more code upfront.
@@ -13633,7 +14165,11 @@ def tick args
# sets console command when sample app initially opens
if Kernel.global_tick_count == 0
- puts "* INFO - Please specify the number of sprites to render."
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Sprites, Open Entities"
+ puts "* INFO: Please specify the number of sprites to render."
args.gtk.console.set_command "reset_with count: 100"
end
@@ -13658,7 +14194,7 @@ def reset_with count: count
end
</code></pre>
-<h3 id='----performance---sprites-as-strict-entities---main.rb'>Performance - Sprites As Strict Entities - main.rb</h3>
+<h3 id='----performance---sprites-as-strict-entities---main-rb'>Performance - Sprites As Strict Entities - main.rb</h3>
<pre><code class="language-ruby"># ./samples/09_performance/03_sprites_as_strict_entities/app/main.rb
# Sprites represented as StrictEntities using the queue ~args.outputs.sprites~
# yields apis access similar to Entities, but all properties that can be set on the
@@ -13705,7 +14241,11 @@ def tick args
# sets console command when sample app initially opens
if Kernel.global_tick_count == 0
- puts "* INFO - Please specify the number of sprites to render."
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Sprites, Strict Entities"
+ puts "* INFO: Please specify the number of sprites to render."
args.gtk.console.set_command "reset_with count: 100"
end
@@ -13730,7 +14270,7 @@ def reset_with count: count
end
</code></pre>
-<h3 id='----performance---sprites-as-classes---main.rb'>Performance - Sprites As Classes - main.rb</h3>
+<h3 id='----performance---sprites-as-classes---main-rb'>Performance - Sprites As Classes - main.rb</h3>
<pre><code class="language-ruby"># ./samples/09_performance/04_sprites_as_classes/app/main.rb
# Sprites represented as Classes using the queue ~args.outputs.sprites~.
# gives you full control of property declaration and method invocation.
@@ -13760,6 +14300,11 @@ end
def tick args
# sets console command when sample app initially opens
if Kernel.global_tick_count == 0
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Sprites, Classes"
+ puts "* INFO: Please specify the number of sprites to render."
args.gtk.console.set_command "reset_with count: 100"
end
@@ -13784,7 +14329,7 @@ def reset_with count: count
end
</code></pre>
-<h3 id='----performance---static-sprites-as-classes---main.rb'>Performance - Static Sprites As Classes - main.rb</h3>
+<h3 id='----performance---static-sprites-as-classes---main-rb'>Performance - Static Sprites As Classes - main.rb</h3>
<pre><code class="language-ruby"># ./samples/09_performance/05_static_sprites_as_classes/app/main.rb
# Sprites represented as Classes using the queue ~args.outputs.static_sprites~.
# bypasses the queue behavior of ~args.outputs.sprites~. All instances are held
@@ -13815,19 +14360,24 @@ end
def tick args
# sets console command when sample app initially opens
if Kernel.global_tick_count == 0
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Static Sprites, Classes"
+ puts "* INFO: Please specify the number of sprites to render."
args.gtk.console.set_command "reset_with count: 100"
end
# init
if args.state.tick_count == 0
args.state.stars = args.state.star_count.map { |i| Star.new args.grid }
+ args.outputs.static_sprites << args.state.stars
end
# update
args.state.stars.each(&:move)
# render
- args.outputs.sprites << args.state.stars
args.outputs.background_color = [0, 0, 0]
args.outputs.primitives << args.gtk.current_framerate_primitives
end
@@ -13839,7 +14389,7 @@ def reset_with count: count
end
</code></pre>
-<h3 id='----performance---static-sprites-as-classes-with-custom-drawing---main.rb'>Performance - Static Sprites As Classes With Custom Drawing - main.rb</h3>
+<h3 id='----performance---static-sprites-as-classes-with-custom-drawing---main-rb'>Performance - Static Sprites As Classes With Custom Drawing - main.rb</h3>
<pre><code class="language-ruby"># ./samples/09_performance/06_static_sprites_as_classes_with_custom_drawing/app/main.rb
# Sprites represented as Classes, with a draw_override method, and using the queue ~args.outputs.static_sprites~.
# is the fastest approach. This is comparable to what other game engines set as the default behavior.
@@ -13883,10 +14433,21 @@ class Star
# path,
# angle,
# alpha, red_saturation, green_saturation, blue_saturation
+ # tile_x, tile_y, tile_w, tile_h,
# flip_horizontally, flip_vertically,
- # tile_x, tile_y, tile_w, tile_h
# angle_anchor_x, angle_anchor_y,
# source_x, source_y, source_w, source_h
+
+ # The argument order for ffi_draw.draw_sprite_4 is:
+ # x, y, w, h,
+ # path,
+ # angle,
+ # alpha, red_saturation, green_saturation, blue_saturation
+ # tile_x, tile_y, tile_w, tile_h,
+ # flip_horizontally, flip_vertically,
+ # angle_anchor_x, angle_anchor_y,
+ # source_x, source_y, source_w, source_h,
+ # blendmode_enum
end
end
@@ -13894,6 +14455,11 @@ end
def tick args
# sets console command when sample app initially opens
if Kernel.global_tick_count == 0
+ puts ""
+ puts ""
+ puts "========================================================="
+ puts "* INFO: Static Sprites, Classes, Draw Override"
+ puts "* INFO: Please specify the number of sprites to render."
args.gtk.console.set_command "reset_with count: 100"
end
@@ -13915,7 +14481,7 @@ def reset_with count: count
end
</code></pre>
-<h3 id='----performance---collision-limits---main.rb'>Performance - Collision Limits - main.rb</h3>
+<h3 id='----performance---collision-limits---main-rb'>Performance - Collision Limits - main.rb</h3>
<pre><code class="language-ruby"># ./samples/09_performance/07_collision_limits/app/main.rb
=begin
@@ -13974,7 +14540,7 @@ end
$gtk.reset
</code></pre>
-<h3 id='----advanced-debugging---trace-debugging---main.rb'>Advanced Debugging - Trace Debugging - main.rb</h3>
+<h3 id='----advanced-debugging---trace-debugging---main-rb'>Advanced Debugging - Trace Debugging - main.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/01_trace_debugging/app/main.rb
class Game
attr_gtk
@@ -14031,7 +14597,7 @@ def tick args
end
</code></pre>
-<h3 id='----advanced-debugging---trace-debugging-classes---main.rb'>Advanced Debugging - Trace Debugging Classes - main.rb</h3>
+<h3 id='----advanced-debugging---trace-debugging-classes---main-rb'>Advanced Debugging - Trace Debugging Classes - main.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/02_trace_debugging_classes/app/main.rb
class Foobar
def initialize
@@ -14057,7 +14623,54 @@ def tick args
end
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---exception_raising_tests.rb'>Advanced Debugging - Unit Tests - exception_raising_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---benchmark_api_tests-rb'>Advanced Debugging - Unit Tests - benchmark_api_tests.rb</h3>
+<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/benchmark_api_tests.rb
+def test_benchmark_api args, assert
+ result = args.gtk.benchmark iterations: 100,
+ only_one: -> () {
+ r = 0
+ (1..100).each do |i|
+ r += 1
+ end
+ }
+
+ assert.equal! result.first_place.name, :only_one
+
+ result = args.gtk.benchmark iterations: 100,
+ iterations_100: -> () {
+ r = 0
+ (1..100).each do |i|
+ r += 1
+ end
+ },
+ iterations_50: -> () {
+ r = 0
+ (1..50).each do |i|
+ r += 1
+ end
+ }
+
+ assert.equal! result.first_place.name, :iterations_50
+
+ result = args.gtk.benchmark iterations: 1,
+ iterations_100: -> () {
+ r = 0
+ (1..100).each do |i|
+ r += 1
+ end
+ },
+ iterations_50: -> () {
+ r = 0
+ (1..50).each do |i|
+ r += 1
+ end
+ }
+
+ assert.equal! result.too_small_to_measure, true
+end
+
+</code></pre>
+<h3 id='----advanced-debugging---unit-tests---exception_raising_tests-rb'>Advanced Debugging - Unit Tests - exception_raising_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/exception_raising_tests.rb
begin :shared
class ExceptionalClass
@@ -14080,7 +14693,7 @@ $gtk.reset 100
$gtk.log_level = :off
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---fn_tests.rb'>Advanced Debugging - Unit Tests - fn_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---fn_tests-rb'>Advanced Debugging - Unit Tests - fn_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/fn_tests.rb
def infinity
1 / 0
@@ -14264,13 +14877,13 @@ def test_array_hash args, assert
end
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---gen_docs.rb'>Advanced Debugging - Unit Tests - gen_docs.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---gen_docs-rb'>Advanced Debugging - Unit Tests - gen_docs.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/gen_docs.rb
# ./dragonruby mygame --eval samples/99_zz_gtk_unit_tests/gen_docs.rb --no-tick
Kernel.export_docs!
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---geometry_tests.rb'>Advanced Debugging - Unit Tests - geometry_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---geometry_tests-rb'>Advanced Debugging - Unit Tests - geometry_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/geometry_tests.rb
begin :shared
def primitive_representations x, y, w, h
@@ -14388,7 +15001,7 @@ $gtk.reset 100
$gtk.log_level = :off
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---http_tests.rb'>Advanced Debugging - Unit Tests - http_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---http_tests-rb'>Advanced Debugging - Unit Tests - http_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/http_tests.rb
def try_assert_or_schedule args, assert
if $result[:complete]
@@ -14414,7 +15027,7 @@ $gtk.reset 100
$gtk.log_level = :off
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---nil_coercion_tests.rb'>Advanced Debugging - Unit Tests - nil_coercion_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---nil_coercion_tests-rb'>Advanced Debugging - Unit Tests - nil_coercion_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/nil_coercion_tests.rb
# numbers
def test_open_entity_add_number args, assert
@@ -14510,7 +15123,7 @@ def test_open_entity_nil_bug args, assert
end
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---object_to_primitive_tests.rb'>Advanced Debugging - Unit Tests - object_to_primitive_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---object_to_primitive_tests-rb'>Advanced Debugging - Unit Tests - object_to_primitive_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/object_to_primitive_tests.rb
class PlayerSpriteForTest
end
@@ -14530,7 +15143,7 @@ $gtk.reset 100
$gtk.log_level = :off
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---parsing_tests.rb'>Advanced Debugging - Unit Tests - parsing_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---parsing_tests-rb'>Advanced Debugging - Unit Tests - parsing_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/parsing_tests.rb
def test_parse_json args, assert
result = args.gtk.parse_json '{ "name": "John Doe", "aliases": ["JD"] }'
@@ -14561,7 +15174,141 @@ $gtk.reset 100
$gtk.log_level = :off
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---require_tests.rb'>Advanced Debugging - Unit Tests - require_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---pretty_format_tests-rb'>Advanced Debugging - Unit Tests - pretty_format_tests.rb</h3>
+<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/pretty_format_tests.rb
+def H opts
+ opts
+end
+
+def A *opts
+ opts
+end
+
+def assert_format args, assert, hash, expected
+ actual = args.fn.pretty_format hash
+ assert.are_equal! actual, expected
+end
+
+def test_pretty_print args, assert
+ # =============================
+ # hash with single value
+ # =============================
+ input = (H first_name: "John")
+ expected = <<-S
+{:first_name "John"}
+S
+ (assert_format args, assert, input, expected)
+
+ # =============================
+ # hash with two values
+ # =============================
+ input = (H first_name: "John", last_name: "Smith")
+ expected = <<-S
+{:first_name "John"
+ :last_name "Smith"}
+S
+
+ (assert_format args, assert, input, expected)
+
+ # =============================
+ # hash with inner hash
+ # =============================
+ input = (H first_name: "John",
+ last_name: "Smith",
+ middle_initial: "I",
+ so: (H first_name: "Pocahontas",
+ last_name: "Tsenacommacah"),
+ friends: (A (H first_name: "Side", last_name: "Kick"),
+ (H first_name: "Tim", last_name: "Wizard")))
+ expected = <<-S
+{:first_name "John"
+ :last_name "Smith"
+ :middle_initial "I"
+ :so {:first_name "Pocahontas"
+ :last_name "Tsenacommacah"}
+ :friends [{:first_name "Side"
+ :last_name "Kick"}
+ {:first_name "Tim"
+ :last_name "Wizard"}]}
+S
+
+ (assert_format args, assert, input, expected)
+
+ # =============================
+ # array with one value
+ # =============================
+ input = (A 1)
+ expected = <<-S
+[1]
+S
+ (assert_format args, assert, input, expected)
+
+ # =============================
+ # array with multiple values
+ # =============================
+ input = (A 1, 2, 3)
+ expected = <<-S
+[1
+ 2
+ 3]
+S
+ (assert_format args, assert, input, expected)
+
+ # =============================
+ # array with multiple values hashes
+ # =============================
+ input = (A (H first_name: "Side", last_name: "Kick"),
+ (H first_name: "Tim", last_name: "Wizard"))
+ expected = <<-S
+[{:first_name "Side"
+ :last_name "Kick"}
+ {:first_name "Tim"
+ :last_name "Wizard"}]
+S
+
+ (assert_format args, assert, input, expected)
+end
+
+def test_nested_nested args, assert
+ # =============================
+ # nested array in nested hash
+ # =============================
+ input = (H type: :root,
+ text: "Root",
+ children: (A (H level: 1,
+ text: "Level 1",
+ children: (A (H level: 2,
+ text: "Level 2",
+ children: [])))))
+
+ expected = <<-S
+{:type :root
+ :text "Root"
+ :children [{:level 1
+ :text "Level 1"
+ :children [{:level 2
+ :text "Level 2"
+ :children []}]}]}
+
+S
+
+ (assert_format args, assert, input, expected)
+end
+
+def test_scene args, assert
+ script = <<-S
+* Scene 1
+** Narrator
+They say happy endings don't exist.
+** Narrator
+They say true love is a lie.
+S
+ input = parse_org args, script
+ puts (args.fn.pretty_format input)
+end
+
+</code></pre>
+<h3 id='----advanced-debugging---unit-tests---require_tests-rb'>Advanced Debugging - Unit Tests - require_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/require_tests.rb
def write_src path, src
$gtk.write_file path, src
@@ -14603,7 +15350,7 @@ def test_require args, assert
end
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---serialize_deserialize_tests.rb'>Advanced Debugging - Unit Tests - serialize_deserialize_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---serialize_deserialize_tests-rb'>Advanced Debugging - Unit Tests - serialize_deserialize_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/serialize_deserialize_tests.rb
def test_serialize args, assert
GTK::Entity.__reset_id__!
@@ -14722,7 +15469,7 @@ def test_by_reference_state_strict_entities args, assert
end
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---state_serialization_experimental_tests.rb'>Advanced Debugging - Unit Tests - state_serialization_experimental_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---state_serialization_experimental_tests-rb'>Advanced Debugging - Unit Tests - state_serialization_experimental_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/state_serialization_experimental_tests.rb
MAX_CODE_GEN_LENGTH = 50
@@ -14832,7 +15579,7 @@ $gtk.reset 100
$gtk.log_level = :off
</code></pre>
-<h3 id='----advanced-debugging---unit-tests---suggest_autocompletion_tests.rb'>Advanced Debugging - Unit Tests - suggest_autocompletion_tests.rb</h3>
+<h3 id='----advanced-debugging---unit-tests---suggest_autocompletion_tests-rb'>Advanced Debugging - Unit Tests - suggest_autocompletion_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/10_advanced_debugging/03_unit_tests/suggest_autocompletion_tests.rb
def default_suggest_autocompletion args
{
@@ -14874,7 +15621,7 @@ S
end
</code></pre>
-<h3 id='----http---retrieve-images---main.rb'>Http - Retrieve Images - main.rb</h3>
+<h3 id='----http---retrieve-images---main-rb'>Http - Retrieve Images - main.rb</h3>
<pre><code class="language-ruby"># ./samples/11_http/01_retrieve_images/app/main.rb
def tick args
args.outputs.background_color = [0, 0, 0]
@@ -14931,7 +15678,7 @@ def tick args
end
</code></pre>
-<h3 id='----http---web-server---main.rb'>Http - Web Server - main.rb</h3>
+<h3 id='----http---web-server---main-rb'>Http - Web Server - main.rb</h3>
<pre><code class="language-ruby"># ./samples/11_http/02_web_server/app/main.rb
def tick args
args.state.port ||= 3000
@@ -14962,7 +15709,7 @@ def tick args
end
</code></pre>
-<h3 id='----c-extensions---basics---main.rb'>C Extensions - Basics - main.rb</h3>
+<h3 id='----c-extensions---basics---main-rb'>C Extensions - Basics - main.rb</h3>
<pre><code class="language-ruby"># ./samples/12_c_extensions/01_basics/app/main.rb
$gtk.ffi_misc.gtk_dlopen("ext")
include FFI::CExt
@@ -14976,7 +15723,7 @@ end
</code></pre>
-<h3 id='----c-extensions---intermediate---main.rb'>C Extensions - Intermediate - main.rb</h3>
+<h3 id='----c-extensions---intermediate---main-rb'>C Extensions - Intermediate - main.rb</h3>
<pre><code class="language-ruby"># ./samples/12_c_extensions/02_intermediate/app/main.rb
$gtk.ffi_misc.gtk_dlopen("ext")
include FFI::RE
@@ -14999,7 +15746,7 @@ def tick args
end
</code></pre>
-<h3 id='----c-extensions---native-pixel-arrays---main.rb'>C Extensions - Native Pixel Arrays - main.rb</h3>
+<h3 id='----c-extensions---native-pixel-arrays---main-rb'>C Extensions - Native Pixel Arrays - main.rb</h3>
<pre><code class="language-ruby"># ./samples/12_c_extensions/03_native_pixel_arrays/app/main.rb
$gtk.ffi_misc.gtk_dlopen("ext")
include FFI::CExt
@@ -15025,7 +15772,7 @@ end
</code></pre>
-<h3 id='----path-finding-algorithms---breadth-first-search---main.rb'>Path Finding Algorithms - Breadth First Search - main.rb</h3>
+<h3 id='----path-finding-algorithms---breadth-first-search---main-rb'>Path Finding Algorithms - Breadth First Search - main.rb</h3>
<pre><code class="language-ruby"># ./samples/13_path_finding_algorithms/01_breadth_first_search/app/main.rb
# A visual demonstration of a breadth first search
# Inspired by https://www.redblobgames.com/pathfinding/a-star/introduction.html
@@ -15721,7 +16468,7 @@ def reset
end
</code></pre>
-<h3 id='----path-finding-algorithms---detailed-breadth-first-search---main.rb'>Path Finding Algorithms - Detailed Breadth First Search - main.rb</h3>
+<h3 id='----path-finding-algorithms---detailed-breadth-first-search---main-rb'>Path Finding Algorithms - Detailed Breadth First Search - main.rb</h3>
<pre><code class="language-ruby"># ./samples/13_path_finding_algorithms/02_detailed_breadth_first_search/app/main.rb
# A visual demonstration of a breadth first search
# Inspired by https://www.redblobgames.com/pathfinding/a-star/introduction.html
@@ -16371,7 +17118,7 @@ def reset
end
</code></pre>
-<h3 id='----path-finding-algorithms---breadcrumbs---main.rb'>Path Finding Algorithms - Breadcrumbs - main.rb</h3>
+<h3 id='----path-finding-algorithms---breadcrumbs---main-rb'>Path Finding Algorithms - Breadcrumbs - main.rb</h3>
<pre><code class="language-ruby"># ./samples/13_path_finding_algorithms/03_breadcrumbs/app/main.rb
class Breadcrumbs
attr_gtk
@@ -16920,7 +17667,7 @@ end
# end
</code></pre>
-<h3 id='----path-finding-algorithms---early-exit---main.rb'>Path Finding Algorithms - Early Exit - main.rb</h3>
+<h3 id='----path-finding-algorithms---early-exit---main-rb'>Path Finding Algorithms - Early Exit - main.rb</h3>
<pre><code class="language-ruby"># ./samples/13_path_finding_algorithms/04_early_exit/app/main.rb
# Comparison of a breadth first search with and without early exit
# Inspired by https://www.redblobgames.com/pathfinding/a-star/introduction.html
@@ -17555,7 +18302,7 @@ def reset
end
</code></pre>
-<h3 id='----path-finding-algorithms---dijkstra---main.rb'>Path Finding Algorithms - Dijkstra - main.rb</h3>
+<h3 id='----path-finding-algorithms---dijkstra---main-rb'>Path Finding Algorithms - Dijkstra - main.rb</h3>
<pre><code class="language-ruby"># ./samples/13_path_finding_algorithms/05_dijkstra/app/main.rb
# Demonstrates how Dijkstra's Algorithm allows movement costs to be considered
@@ -18403,7 +19150,7 @@ def reset
end
</code></pre>
-<h3 id='----path-finding-algorithms---heuristic---main.rb'>Path Finding Algorithms - Heuristic - main.rb</h3>
+<h3 id='----path-finding-algorithms---heuristic---main-rb'>Path Finding Algorithms - Heuristic - main.rb</h3>
<pre><code class="language-ruby"># ./samples/13_path_finding_algorithms/06_heuristic/app/main.rb
# This program is inspired by https://www.redblobgames.com/pathfinding/a-star/introduction.html
@@ -19387,7 +20134,7 @@ def reset
end
</code></pre>
-<h3 id='----path-finding-algorithms---heuristic-with-walls---main.rb'>Path Finding Algorithms - Heuristic With Walls - main.rb</h3>
+<h3 id='----path-finding-algorithms---heuristic-with-walls---main-rb'>Path Finding Algorithms - Heuristic With Walls - main.rb</h3>
<pre><code class="language-ruby"># ./samples/13_path_finding_algorithms/07_heuristic_with_walls/app/main.rb
# This program is inspired by https://www.redblobgames.com/pathfinding/a-star/introduction.html
# The effectiveness of the Heuristic search algorithm is shown through this demonstration.
@@ -20404,7 +21151,7 @@ def reset
end
</code></pre>
-<h3 id='----path-finding-algorithms---a-star---main.rb'>Path Finding Algorithms - A Star - main.rb</h3>
+<h3 id='----path-finding-algorithms---a-star---main-rb'>Path Finding Algorithms - A Star - main.rb</h3>
<pre><code class="language-ruby"># ./samples/13_path_finding_algorithms/08_a_star/app/main.rb
# This program is inspired by https://www.redblobgames.com/pathfinding/a-star/introduction.html
@@ -21437,7 +22184,7 @@ def reset
end
</code></pre>
-<h3 id='----path-finding-algorithms---tower-defense---main.rb'>Path Finding Algorithms - Tower Defense - main.rb</h3>
+<h3 id='----path-finding-algorithms---tower-defense---main-rb'>Path Finding Algorithms - Tower Defense - main.rb</h3>
<pre><code class="language-ruby"># ./samples/13_path_finding_algorithms/09_tower_defense/app/main.rb
# An example of some major components in a tower defence game
# The pathing of the tanks is determined by A* algorithm -- try editing the walls
@@ -21742,7 +22489,7 @@ def a_star_color
end
</code></pre>
-<h3 id='----3d---3d-cube---main.rb'>3d - 3d Cube - main.rb</h3>
+<h3 id='----3d---3d-cube---main-rb'>3d - 3d Cube - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_3d/01_3d_cube/app/main.rb
STARTX = 0.0
STARTY = 0.0
@@ -21796,7 +22543,7 @@ end
$gtk.reset
</code></pre>
-<h3 id='----3d---wireframe---main.rb'>3d - Wireframe - main.rb</h3>
+<h3 id='----3d---wireframe---main-rb'>3d - Wireframe - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_3d/02_wireframe/app/main.rb
def tick args
args.state.model ||= Object3D.new('data/shuttle.off')
@@ -21949,11 +22696,11 @@ class Vertex
end
end
</code></pre>
-<h3 id='----3d---wireframe---data---what-is-this.txt'>3d - Wireframe - Data - what-is-this.txt</h3>
+<h3 id='----3d---wireframe---data---what-is-this-txt'>3d - Wireframe - Data - what-is-this.txt</h3>
<pre><code class="language-ruby"># ./samples/99_genre_3d/02_wireframe/data/what-is-this.txt
https://en.wikipedia.org/wiki/OFF_(file_format)
</code></pre>
-<h3 id='----arcade---bullet-hell---main.rb'>Arcade - Bullet Hell - main.rb</h3>
+<h3 id='----arcade---bullet-hell---main-rb'>Arcade - Bullet Hell - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_arcade/bullet_hell/app/main.rb
def tick args
args.state.base_columns ||= 10.times.map { |n| 50 * n + 1280 / 2 - 5 * 50 + 5 }
@@ -22146,7 +22893,7 @@ def update_enemy_positions args
end
</code></pre>
-<h3 id='----arcade---dueling-starships---main.rb'>Arcade - Dueling Starships - main.rb</h3>
+<h3 id='----arcade---dueling-starships---main-rb'>Arcade - Dueling Starships - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_arcade/dueling_starships/app/main.rb
class DuelingSpaceships
attr_accessor :state, :inputs, :outputs, :grid
@@ -22515,14 +23262,14 @@ def tick args
end
</code></pre>
-<h3 id='----arcade/flappy-dragon/credits.txt'>arcade/flappy dragon/credits.txt</h3>
+<h3 id='----arcade/flappy-dragon/credits-txt'>arcade/flappy dragon/credits.txt</h3>
<pre><code class="language-ruby"># ./samples/99_genre_arcade/flappy_dragon/CREDITS.txt
code: Amir Rajan, https://twitter.com/amirrajan
graphics and audio: Nick Culbertson, https://twitter.com/MobyPixel
</code></pre>
-<h3 id='----arcade/flappy-dragon/main.rb'>arcade/flappy dragon/main.rb</h3>
+<h3 id='----arcade/flappy-dragon/main-rb'>arcade/flappy dragon/main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_arcade/flappy_dragon/app/main.rb
class FlappyDragon
attr_accessor :grid, :inputs, :state, :outputs
@@ -22886,7 +23633,7 @@ def tick args
end
</code></pre>
-<h3 id='----arcade---pong---main.rb'>Arcade - Pong - main.rb</h3>
+<h3 id='----arcade---pong---main-rb'>Arcade - Pong - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_arcade/pong/app/main.rb
def tick args
defaults args
@@ -23049,7 +23796,7 @@ begin :assets
end
</code></pre>
-<h3 id='----arcade---snakemoji---main.rb'>Arcade - Snakemoji - main.rb</h3>
+<h3 id='----arcade---snakemoji---main-rb'>Arcade - Snakemoji - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_arcade/snakemoji/app/main.rb
# coding: utf-8
################################
@@ -23218,7 +23965,7 @@ def defaults 🎮
end
</code></pre>
-<h3 id='----arcade---solar-system---main.rb'>Arcade - Solar System - main.rb</h3>
+<h3 id='----arcade---solar-system---main-rb'>Arcade - Solar System - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_arcade/solar_system/app/main.rb
# Focused tutorial video: https://s3.amazonaws.com/s3.dragonruby.org/dragonruby-nddnug-workshop.mp4
# Workshop/Presentation which provides motivation for creating a game engine: https://www.youtube.com/watch?v=S3CFce1arC8
@@ -23330,7 +24077,7 @@ def r
end
</code></pre>
-<h3 id='----arcade---sound-golf---main.rb'>Arcade - Sound Golf - main.rb</h3>
+<h3 id='----arcade---sound-golf---main-rb'>Arcade - Sound Golf - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_arcade/sound_golf/app/main.rb
=begin
@@ -23524,7 +24271,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----arcade---twinstick---main.rb'>Arcade - Twinstick - main.rb</h3>
+<h3 id='----arcade---twinstick---main-rb'>Arcade - Twinstick - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_arcade/twinstick/app/main.rb
def tick args
args.state.player ||= {x: 600, y: 320, w: 80, h: 80, path: 'sprites/circle-white.png', vx: 0, vy: 0, health: 10, cooldown: 0, score: 0}
@@ -23678,7 +24425,7 @@ def shoot_directional_vector args
[dx, dy]
end
</code></pre>
-<h3 id='----crafting---craft-game-starting-point---main.rb'>Crafting - Craft Game Starting Point - main.rb</h3>
+<h3 id='----crafting---craft-game-starting-point---main-rb'>Crafting - Craft Game Starting Point - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_crafting/craft_game_starting_point/app/main.rb
# ==================================================
# A NOTE TO JAM CRAFT PARTICIPANTS:
@@ -24105,7 +24852,439 @@ end
$gtk.reset
</code></pre>
-<h3 id='----dev-tools---add-buttons-to-console---main.rb'>Dev Tools - Add Buttons To Console - main.rb</h3>
+<h3 id='----crafting---farming-game-starting-point---main-rb'>Crafting - Farming Game Starting Point - main.rb</h3>
+<pre><code class="language-ruby"># ./samples/99_genre_crafting/farming_game_starting_point/app/main.rb
+def tick args
+ args.state.tile_size = 80
+ args.state.player_speed = 4
+ args.state.player ||= tile(args, 7, 3, 0, 128, 180)
+ generate_map args
+ #press j to plant a green onion
+ if args.inputs.keyboard.j
+ #change this part you can change what you want to plant
+ args.state.walls << tile(args, ((args.state.player.x+80)/args.state.tile_size), ((args.state.player.y)/args.state.tile_size), 255, 255, 255)
+ args.state.plants << tile(args, ((args.state.player.x+80)/args.state.tile_size), ((args.state.player.y+80)/args.state.tile_size), 0, 160, 0)
+ end
+ # Adds walls, background, and player to args.outputs.solids so they appear on screen
+ args.outputs.solids << [0,0,1280,720, 237,189,101]
+ args.outputs.sprites << [0, 0, 1280, 720, 'sprites/background.png']
+ args.outputs.solids << args.state.walls
+ args.outputs.solids << args.state.player
+ args.outputs.solids << args.state.plants
+ args.outputs.labels << [320, 640, "press J to plant", 3, 1, 255, 0, 0, 200]
+
+ move_player args, -1, 0 if args.inputs.keyboard.left # x position decreases by 1 if left key is pressed
+ move_player args, 1, 0 if args.inputs.keyboard.right # x position increases by 1 if right key is pressed
+ move_player args, 0, 1 if args.inputs.keyboard.up # y position increases by 1 if up is pressed
+ move_player args, 0, -1 if args.inputs.keyboard.down # y position decreases by 1 if down is pressed
+end
+
+# Sets position, size, and color of the tile
+def tile args, x, y, *color
+ [x * args.state.tile_size, # sets definition for array using method parameters
+ y * args.state.tile_size, # multiplying by tile_size sets x and y to correct position using pixel values
+ args.state.tile_size,
+ args.state.tile_size,
+ *color]
+end
+
+# Creates map by adding tiles to the wall, as well as a goal (that the player needs to reach)
+def generate_map args
+ return if args.state.area
+
+ # Creates the area of the map. There are 9 rows running horizontally across the screen
+ # and 16 columns running vertically on the screen. Any spot with a "1" is not
+ # open for the player to move into (and is green), and any spot with a "0" is available
+ # for the player to move in.
+ args.state.area = [
+ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
+ [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,],
+ [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,],
+ [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,],
+ [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,],
+ [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,],
+ [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,],
+ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
+ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
+ ].reverse # reverses the order of the area collection
+
+ # By reversing the order, the way that the area appears above is how it appears
+ # on the screen in the game. If we did not reverse, the map would appear inverted.
+
+ #The wall starts off with no tiles.
+ args.state.walls = []
+ args.state.plants = []
+
+ # If v is 1, a green tile is added to args.state.walls.
+ # If v is 2, a black tile is created as the goal.
+ args.state.area.map_2d do |y, x, v|
+ if v == 1
+ args.state.walls << tile(args, x, y, 255, 160, 156) # green tile
+ end
+ end
+end
+
+# Allows the player to move their box around the screen
+def move_player args, *vector
+ box = args.state.player.shift_rect(vector) # box is able to move at an angle
+
+ # If the player's box hits a wall, it is not able to move further in that direction
+ return if args.state.walls
+ .any_intersect_rect?(box)
+
+ # Player's box is able to move at angles (not just the four general directions) fast
+ args.state.player =
+ args.state.player
+ .shift_rect(vector.x * args.state.player_speed, # if we don't multiply by speed, then
+ vector.y * args.state.player_speed) # the box will move extremely slow
+end
+
+</code></pre>
+<h3 id='----crafting---farming-game-starting-point---repl-rb'>Crafting - Farming Game Starting Point - repl.rb</h3>
+<pre><code class="language-ruby"># ./samples/99_genre_crafting/farming_game_starting_point/app/repl.rb
+# ===============================================================
+# Welcome to repl.rb
+# ===============================================================
+# You can experiement with code within this file. Code in this
+# file is only executed when you save (and only excecuted ONCE).
+# ===============================================================
+
+# ===============================================================
+# REMOVE the "x" from the word "xrepl" and save the file to RUN
+# the code in between the do/end block delimiters.
+# ===============================================================
+
+# ===============================================================
+# ADD the "x" to the word "repl" (make it xrepl) and save the
+# file to IGNORE the code in between the do/end block delimiters.
+# ===============================================================
+
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ puts "The result of 1 + 2 is: #{1 + 2}"
+end
+
+# ====================================================================================
+# Ruby Crash Course:
+# Strings, Numeric, Booleans, Conditionals, Looping, Enumerables, Arrays
+# ====================================================================================
+
+# ====================================================================================
+# Strings
+# ====================================================================================
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ message = "Hello World"
+ puts "The value of message is: " + message
+ puts "Any value can be interpolated within a string using \#{}."
+ puts "Interpolated message: #{message}."
+ puts 'This #{message} is not interpolated because the string uses single quotes.'
+end
+
+# ====================================================================================
+# Numerics
+# ====================================================================================
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ a = 10
+ puts "The value of a is: #{a}"
+ puts "a + 1 is: #{a + 1}"
+ puts "a / 3 is: #{a / 3}"
+end
+
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ b = 10.12
+ puts "The value of b is: #{b}"
+ puts "b + 1 is: #{b + 1}"
+ puts "b as an integer is: #{b.to_i}"
+ puts ''
+end
+
+# ====================================================================================
+# Booleans
+# ====================================================================================
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ c = 30
+ puts "The value of c is #{c}."
+
+ if c
+ puts "This if statement ran because c is truthy."
+ end
+end
+
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ d = false
+ puts "The value of d is #{d}."
+
+ if !d
+ puts "This if statement ran because d is falsey, using the not operator (!) makes d evaluate to true."
+ end
+
+ e = nil
+ puts "Nil is also considered falsey. The value of e is: #{e}."
+
+ if !e
+ puts "This if statement ran because e is nil (a falsey value)."
+ end
+end
+
+# ====================================================================================
+# Conditionals
+# ====================================================================================
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ i_am_true = true
+ i_am_nil = nil
+ i_am_false = false
+ i_am_hi = "hi"
+
+ puts "======== if statement"
+ i_am_one = 1
+ if i_am_one
+ puts "This was printed because i_am_one is truthy."
+ end
+
+ puts "======== if/else statement"
+ if i_am_false
+ puts "This will NOT get printed because i_am_false is false."
+ else
+ puts "This was printed because i_am_false is false."
+ end
+
+ puts "======== if/elsif/else statement"
+ if i_am_false
+ puts "This will NOT get printed because i_am_false is false."
+ elsif i_am_true
+ puts "This was printed because i_am_true is true."
+ else
+ puts "This will NOT get printed i_am_true was true."
+ end
+
+ puts "======== case statement "
+ i_am_one = 1
+ case i_am_one
+ when 10
+ puts "case equaled: 10"
+ when 9
+ puts "case equaled: 9"
+ when 5
+ puts "case equaled: 5"
+ when 1
+ puts "case equaled: 1"
+ else
+ puts "Value wasn't cased."
+ end
+
+ puts "======== different types of comparisons"
+ if 4 == 4
+ puts "equal (4 == 4)"
+ end
+
+ if 4 != 3
+ puts "not equal (4 != 3)"
+ end
+
+ if 3 < 4
+ puts "less than (3 < 4)"
+ end
+
+ if 4 > 3
+ puts "greater than (4 > 3)"
+ end
+
+ if ((4 > 3) || (3 < 4) || false)
+ puts "or statement ((4 > 3) || (3 < 4) || false)"
+ end
+
+ if ((4 > 3) && (3 < 4))
+ puts "and statement ((4 > 3) && (3 < 4))"
+ end
+end
+
+# ====================================================================================
+# Looping
+# ====================================================================================
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ puts "======== times block"
+ 3.times do |i|
+ puts i
+ end
+ puts "======== range block exclusive"
+ (0...3).each do |i|
+ puts i
+ end
+ puts "======== range block inclusive"
+ (0..3).each do |i|
+ puts i
+ end
+end
+
+# ====================================================================================
+# Enumerables
+# ====================================================================================
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ puts "======== array each"
+ colors = ["red", "blue", "yellow"]
+ colors.each do |color|
+ puts color
+ end
+
+ puts '======== array each_with_index'
+ colors = ["red", "blue", "yellow"]
+ colors.each_with_index do |color, i|
+ puts "#{color} at index #{i}"
+ end
+end
+
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ puts "======== single parameter function"
+ def add_one_to n
+ n + 5
+ end
+
+ puts add_one_to(3)
+
+ puts "======== function with default value"
+ def function_with_default_value v = 10
+ v * 10
+ end
+
+ puts "passing three: #{function_with_default_value(3)}"
+ puts "passing nil: #{function_with_default_value}"
+
+ puts "======== Or Equal (||=) operator for nil values"
+ def function_with_nil_default_with_local a = nil
+ result = a
+ result ||= "or equal operator was exected and set a default value"
+ end
+
+ puts "passing 'hi': #{function_with_nil_default_with_local 'hi'}"
+ puts "passing nil: #{function_with_nil_default_with_local}"
+end
+
+# ====================================================================================
+# Arrays
+# ====================================================================================
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ puts "======== Create an array with the numbers 1 to 10."
+ one_to_ten = (1..10).to_a
+ puts one_to_ten
+
+ puts "======== Create a new array that only contains even numbers from the previous array."
+ one_to_ten = (1..10).to_a
+ evens = one_to_ten.find_all do |number|
+ number % 2 == 0
+ end
+ puts evens
+
+ puts "======== Create a new array that rejects odd numbers."
+ one_to_ten = (1..10).to_a
+ also_even = one_to_ten.reject do |number|
+ number % 2 != 0
+ end
+ puts also_even
+
+ puts "======== Create an array that doubles every number."
+ one_to_ten = (1..10).to_a
+ doubled = one_to_ten.map do |number|
+ number * 2
+ end
+ puts doubled
+
+ puts "======== Create an array that selects only odd numbers and then multiply those by 10."
+ one_to_ten = (1..10).to_a
+ odd_doubled = one_to_ten.find_all do |number|
+ number % 2 != 0
+ end.map do |odd_number|
+ odd_number * 10
+ end
+ puts odd_doubled
+
+ puts "======== All combination of numbers 1 to 10."
+ one_to_ten = (1..10).to_a
+ all_combinations = one_to_ten.product(one_to_ten)
+ puts all_combinations
+
+ puts "======== All uniq combinations of numbers. For example: [1, 2] is the same as [2, 1]."
+ one_to_ten = (1..10).to_a
+ uniq_combinations =
+ one_to_ten.product(one_to_ten)
+ .map do |unsorted_number|
+ unsorted_number.sort
+ end.uniq
+ puts uniq_combinations
+end
+
+# ====================================================================================
+# Advanced Arrays
+# ====================================================================================
+# Remove the x from xrepl to run the code. Add the x back to ignore to code.
+xrepl do
+ puts "======== All unique Pythagorean Triples between 1 and 40 sorted by area of the triangle."
+
+ one_to_hundred = (1..40).to_a
+ triples =
+ one_to_hundred.product(one_to_hundred).map do |width, height|
+ [width, height, Math.sqrt(width ** 2 + height ** 2)]
+ end.find_all do |_, _, hypotenuse|
+ hypotenuse.to_i == hypotenuse
+ end.map do |triangle|
+ triangle.map(&:to_i)
+ end.uniq do |triangle|
+ triangle.sort
+ end.map do |width, height, hypotenuse|
+ [width, height, hypotenuse, (width * height) / 2]
+ end.sort_by do |_, _, _, area|
+ area
+ end
+
+ triples.each do |width, height, hypotenuse, area|
+ puts "(#{width}, #{height}, #{hypotenuse}) = #{area}"
+ end
+end
+
+</code></pre>
+<h3 id='----crafting---farming-game-starting-point---tests-rb'>Crafting - Farming Game Starting Point - tests.rb</h3>
+<pre><code class="language-ruby"># ./samples/99_genre_crafting/farming_game_starting_point/app/tests.rb
+# For advanced users:
+# You can put some quick verification tests here, any method
+# that starts with the `test_` will be run when you save this file.
+
+# Here is an example test and game
+
+# To run the test: ./dragonruby mygame --eval app/tests.rb --no-tick
+
+class MySuperHappyFunGame
+ attr_gtk
+
+ def tick
+ outputs.solids << [100, 100, 300, 300]
+ end
+end
+
+def test_universe args, assert
+ game = MySuperHappyFunGame.new
+ game.args = args
+ game.tick
+ assert.true! args.outputs.solids.length == 1, "failure: a solid was not added after tick"
+ assert.false! 1 == 2, "failure: some how, 1 equals 2, the world is ending"
+ puts "test_universe completed successfully"
+end
+
+puts "running tests"
+$gtk.reset 100
+$gtk.log_level = :off
+$gtk.tests.start
+
+</code></pre>
+<h3 id='----dev-tools---add-buttons-to-console---main-rb'>Dev Tools - Add Buttons To Console - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_dev_tools/add_buttons_to_console/app/main.rb
# You can customize the buttons that show up in the Console.
class GTK::Console::Menu
@@ -24167,7 +25346,7 @@ def tick args
end
</code></pre>
-<h3 id='----dev-tools---animation-creator-starting-point---main.rb'>Dev Tools - Animation Creator Starting Point - main.rb</h3>
+<h3 id='----dev-tools---animation-creator-starting-point---main-rb'>Dev Tools - Animation Creator Starting Point - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_dev_tools/animation_creator_starting_point/app/main.rb
class OneBitLowrezPaint
attr_gtk
@@ -24272,12 +25451,12 @@ class OneBitLowrezPaint
label = { x: b.x + state.buttons_frame_selection.size.half,
y: b.y,
text: "#{i + 1}", r: 180, g: 180, b: 180,
- size_enum: -4, alignment_enum: 1 }.label
+ size_enum: -4, alignment_enum: 1 }.label!
- selection_border = b.merge(r: 40, g: 40, b: 40).border
+ selection_border = b.merge(r: 40, g: 40, b: 40).border!
if i == state.animation_frames_selected_index
- selection_border = b.merge(r: 40, g: 230, b: 200).border
+ selection_border = b.merge(r: 40, g: 230, b: 200).border!
end
[selection_border, label]
@@ -24616,7 +25795,7 @@ end
# $gtk.reset
</code></pre>
-<h3 id='----dev-tools---tile-editor-starting-point---main.rb'>Dev Tools - Tile Editor Starting Point - main.rb</h3>
+<h3 id='----dev-tools---tile-editor-starting-point---main-rb'>Dev Tools - Tile Editor Starting Point - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_dev_tools/tile_editor_starting_point/app/main.rb
=begin
@@ -25011,7 +26190,525 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----lowrez---nokia-3310---main.rb'>Lowrez - Nokia 3310 - main.rb</h3>
+<h3 id='----dungeon-crawl---classics-jam---main-rb'>Dungeon Crawl - Classics Jam - main.rb</h3>
+<pre><code class="language-ruby"># ./samples/99_genre_dungeon_crawl/classics_jam/app/main.rb
+class Game
+ attr_gtk
+
+ def tick
+ defaults
+ render
+ input
+ calc
+ end
+
+ def defaults
+ player.x ||= 640
+ player.y ||= 360
+ player.w ||= 16
+ player.h ||= 16
+ player.attacked_at ||= -1
+ player.angle ||= 0
+ player.future_player ||= future_player_position 0, 0
+ player.projectiles ||= []
+ player.damage ||= 0
+ state.level ||= create_level level_one_template
+ end
+
+ def render
+ outputs.sprites << level.walls.map do |w|
+ w.merge(path: 'sprites/square/gray.png')
+ end
+
+ outputs.sprites << level.spawn_locations.map do |s|
+ s.merge(path: 'sprites/square/blue.png')
+ end
+
+ outputs.sprites << player.projectiles.map do |p|
+ p.merge(path: 'sprites/square/blue.png')
+ end
+
+ outputs.sprites << level.enemies.map do |e|
+ e.merge(path: 'sprites/square/red.png')
+ end
+
+ outputs.sprites << player.merge(path: 'sprites/circle/green.png', angle: player.angle)
+
+ outputs.labels << { x: 30, y: 30.from_top, text: "damage: #{player.damage || 0}" }
+ end
+
+ def input
+ player.angle = inputs.directional_angle || player.angle
+ if inputs.controller_one.key_down.a || inputs.keyboard.key_down.space
+ player.attacked_at = state.tick_count
+ end
+ end
+
+ def calc
+ calc_player
+ calc_projectiles
+ calc_enemies
+ calc_spawn_locations
+ end
+
+ def calc_player
+ if player.attacked_at == state.tick_count
+ player.projectiles << { at: state.tick_count,
+ x: player.x,
+ y: player.y,
+ angle: player.angle,
+ w: 4,
+ h: 4 }.center_inside_rect(player)
+ end
+
+ if player.attacked_at.elapsed_time > 5
+ future_player = future_player_position inputs.left_right * 2, inputs.up_down * 2
+ future_player_collision = future_collision player, future_player, level.walls
+ player.x = future_player_collision.x if !future_player_collision.dx_collision
+ player.y = future_player_collision.y if !future_player_collision.dy_collision
+ end
+ end
+
+ def calc_projectile_collisions entities
+ entities.each do |e|
+ e.damage ||= 0
+ player.projectiles.each do |p|
+ if !p.collided && (p.intersect_rect? e)
+ p.collided = true
+ e.damage += 1
+ end
+ end
+ end
+ end
+
+ def calc_projectiles
+ player.projectiles.map! do |p|
+ dx, dy = p.angle.vector 10
+ p.merge(x: p.x + dx, y: p.y + dy)
+ end
+
+ calc_projectile_collisions level.walls + level.enemies + level.spawn_locations
+ player.projectiles.reject! { |p| p.at.elapsed_time > 10000 }
+ player.projectiles.reject! { |p| p.collided }
+ level.enemies.reject! { |e| e.damage > e.hp }
+ level.spawn_locations.reject! { |s| s.damage > s.hp }
+ end
+
+ def calc_enemies
+ level.enemies.map! do |e|
+ dx = 0
+ dx = 1 if e.x < player.x
+ dx = -1 if e.x > player.x
+ dy = 0
+ dy = 1 if e.y < player.y
+ dy = -1 if e.y > player.y
+ future_e = future_entity_position dx, dy, e
+ future_e_collision = future_collision e, future_e, level.enemies + level.walls
+ e.next_x = e.x
+ e.next_y = e.y
+ e.next_x = future_e_collision.x if !future_e_collision.dx_collision
+ e.next_y = future_e_collision.y if !future_e_collision.dy_collision
+ e
+ end
+
+ level.enemies.map! do |e|
+ e.x = e.next_x
+ e.y = e.next_y
+ e
+ end
+
+ level.enemies.each do |e|
+ player.damage += 1 if e.intersect_rect? player
+ end
+ end
+
+ def calc_spawn_locations
+ level.spawn_locations.map! do |s|
+ s.merge(countdown: s.countdown - 1)
+ end
+ level.spawn_locations
+ .find_all { |s| s.countdown.neg? }
+ .each do |s|
+ s.countdown = s.rate
+ s.merge(countdown: s.rate)
+ new_enemy = create_enemy s
+ if !(level.enemies.find { |e| e.intersect_rect? new_enemy })
+ level.enemies << new_enemy
+ end
+ end
+ end
+
+ def create_enemy spawn_location
+ to_cell(spawn_location.ordinal_x, spawn_location.ordinal_y).merge hp: 2
+ end
+
+ def create_level level_template
+ {
+ walls: level_template.walls.map { |w| to_cell(w.ordinal_x, w.ordinal_y).merge(w) },
+ enemies: [],
+ spawn_locations: level_template.spawn_locations.map { |s| to_cell(s.ordinal_x, s.ordinal_y).merge(s) }
+ }
+ end
+
+ def level_one_template
+ {
+ walls: [{ ordinal_x: 25, ordinal_y: 20},
+ { ordinal_x: 25, ordinal_y: 21},
+ { ordinal_x: 25, ordinal_y: 22},
+ { ordinal_x: 25, ordinal_y: 23}],
+ spawn_locations: [{ ordinal_x: 10, ordinal_y: 10, rate: 120, countdown: 0, hp: 5 }]
+ }
+ end
+
+ def player
+ state.player ||= {}
+ end
+
+ def level
+ state.level ||= {}
+ end
+
+ def future_collision entity, future_entity, others
+ dx_collision = others.find { |o| o != entity && (o.intersect_rect? future_entity.dx) }
+ dy_collision = others.find { |o| o != entity && (o.intersect_rect? future_entity.dy) }
+
+ {
+ dx_collision: dx_collision,
+ x: future_entity.dx.x,
+ dy_collision: dy_collision,
+ y: future_entity.dy.y
+ }
+ end
+
+ def future_entity_position dx, dy, entity
+ {
+ dx: entity.merge(x: entity.x + dx),
+ dy: entity.merge(y: entity.y + dy),
+ both: entity.merge(x: entity.x + dx, y: entity.y + dy)
+ }
+ end
+
+ def future_player_position dx, dy
+ future_entity_position dx, dy, player
+ end
+
+ def to_cell ordinal_x, ordinal_y
+ { x: ordinal_x * 16, y: ordinal_y * 16, w: 16, h: 16 }
+ end
+end
+
+def tick args
+ $game ||= Game.new
+ $game.args = args
+ $game.tick
+end
+
+$gtk.reset
+$game = nil
+
+</code></pre>
+<h3 id='----fighting---special-move-inputs---main-rb'>Fighting - Special Move Inputs - main.rb</h3>
+<pre><code class="language-ruby"># ./samples/99_genre_fighting/01_special_move_inputs/app/main.rb
+def tick args
+ #tick_instructions args, "Use LEFT and RIGHT arrow keys to move and SPACE to jump."
+ defaults args
+ render args
+ input args
+ calc args
+end
+
+# sets default values and creates empty collections
+# initialization only happens in the first frame
+def defaults args
+ fiddle args
+
+ args.state.tick_count = args.state.tick_count
+ args.state.bridge_top = 128
+ args.state.player.x ||= 0 # initializes player's properties
+ args.state.player.y ||= args.state.bridge_top
+ args.state.player.w ||= 64
+ args.state.player.h ||= 64
+ args.state.player.dy ||= 0
+ args.state.player.dx ||= 0
+ args.state.player.r ||= 0
+ args.state.game_over_at ||= 0
+ args.state.animation_time ||=0
+
+ args.state.timeleft ||=0
+ args.state.timeright ||=0
+ args.state.lastpush ||=0
+
+ args.state.inputlist ||= ["j","k","l"]
+end
+
+# sets enemy, player, hammer values
+def fiddle args
+ args.state.gravity = -0.5
+ args.state.player_jump_power = 10 # sets player values
+ args.state.player_jump_power_duration = 5
+ args.state.player_max_run_speed = 20
+ args.state.player_speed_slowdown_rate = 0.9
+ args.state.player_acceleration = 0.9
+end
+
+# outputs objects onto the screen
+def render args
+ if (args.state.player.dx < 0.01) && (args.state.player.dx > -0.01)
+ args.state.player.dx = 0
+ end
+
+ #move list
+ (args.layout.rect_group row: 0, col_from_right: 8, drow: 0.3,
+ merge: { vertical_alignment_enum: 0, size_enum: -2 },
+ group: [
+ { text: "move: WASD" },
+ { text: "jump: Space" },
+ { text: "attack forwards: J (while on ground" },
+ { text: "attack upwards: K (while on groud)" },
+ { text: "attack backwards: J (while on ground and holding A)" },
+ { text: "attack downwards: K (while in air)" },
+ { text: "dash attack: J, K in quick succession." },
+ { text: "shield: hold J, K at the same time." },
+ { text: "dash backwards: A, A in quick succession." },
+ ]).into args.outputs.labels
+
+ # registered moves
+ args.outputs.labels << { x: 0.to_layout_col,
+ y: 0.to_layout_row,
+ text: "input history",
+ size_enum: -2,
+ vertical_alignment_enum: 0 }
+
+ (args.state.inputlist.take(5)).map do |s|
+ { text: s, size_enum: -2, vertical_alignment_enum: 0 }
+ end.yield_self do |group|
+ (args.layout.rect_group row: 0.3, col: 0, drow: 0.3, group: group).into args.outputs.labels
+ end
+
+
+ #sprites
+ player = [args.state.player.x, args.state.player.y,
+ args.state.player.w, args.state.player.h,
+ "sprites/square/white.png",
+ args.state.player.r]
+
+ playershield = [args.state.player.x - 20, args.state.player.y - 10,
+ args.state.player.w + 20, args.state.player.h + 20,
+ "sprites/square/blue.png",
+ args.state.player.r,
+ 0]
+
+ playerjab = [args.state.player.x + 32, args.state.player.y,
+ args.state.player.w, args.state.player.h,
+ "sprites/isometric/indigo.png",
+ args.state.player.r,
+ 0]
+
+ playerupper = [args.state.player.x, args.state.player.y + 32,
+ args.state.player.w, args.state.player.h,
+ "sprites/isometric/indigo.png",
+ args.state.player.r+90,
+ 0]
+
+ if ((args.state.tick_count - args.state.lastpush) <= 15)
+ if (args.state.inputlist[0] == "<<")
+ player = [args.state.player.x, args.state.player.y,
+ args.state.player.w, args.state.player.h,
+ "sprites/square/yellow.png", args.state.player.r]
+ end
+
+ if (args.state.inputlist[0] == "shield")
+ player = [args.state.player.x, args.state.player.y,
+ args.state.player.w, args.state.player.h,
+ "sprites/square/indigo.png", args.state.player.r]
+
+ playershield = [args.state.player.x - 10, args.state.player.y - 10,
+ args.state.player.w + 20, args.state.player.h + 20,
+ "sprites/square/blue.png", args.state.player.r, 50]
+ end
+
+ if (args.state.inputlist[0] == "back-attack")
+ playerjab = [args.state.player.x - 20, args.state.player.y,
+ args.state.player.w - 10, args.state.player.h,
+ "sprites/isometric/indigo.png", args.state.player.r, 255]
+ end
+
+ if (args.state.inputlist[0] == "forward-attack")
+ playerjab = [args.state.player.x + 32, args.state.player.y,
+ args.state.player.w, args.state.player.h,
+ "sprites/isometric/indigo.png", args.state.player.r, 255]
+ end
+
+ if (args.state.inputlist[0] == "up-attack")
+ playerupper = [args.state.player.x, args.state.player.y + 32,
+ args.state.player.w, args.state.player.h,
+ "sprites/isometric/indigo.png", args.state.player.r + 90, 255]
+ end
+
+ if (args.state.inputlist[0] == "dair")
+ playerupper = [args.state.player.x, args.state.player.y - 32,
+ args.state.player.w, args.state.player.h,
+ "sprites/isometric/indigo.png", args.state.player.r + 90, 255]
+ end
+
+ if (args.state.inputlist[0] == "dash-attack")
+ playerupper = [args.state.player.x, args.state.player.y + 32,
+ args.state.player.w, args.state.player.h,
+ "sprites/isometric/violet.png", args.state.player.r + 90, 255]
+
+ playerjab = [args.state.player.x + 32, args.state.player.y,
+ args.state.player.w, args.state.player.h,
+ "sprites/isometric/violet.png", args.state.player.r, 255]
+ end
+ end
+
+ args.outputs.sprites << playerjab
+ args.outputs.sprites << playerupper
+ args.outputs.sprites << player
+ args.outputs.sprites << playershield
+
+ args.outputs.solids << 20.map_with_index do |i| # uses 20 squares to form bridge
+ [i * 64, args.state.bridge_top - 64, 64, 64]
+ end
+end
+
+# Performs calculations to move objects on the screen
+def calc args
+ # Since velocity is the change in position, the change in x increases by dx. Same with y and dy.
+ args.state.player.x += args.state.player.dx
+ args.state.player.y += args.state.player.dy
+
+ # Since acceleration is the change in velocity, the change in y (dy) increases every frame
+ args.state.player.dy += args.state.gravity
+
+ # player's y position is either current y position or y position of top of
+ # bridge, whichever has a greater value
+ # ensures that the player never goes below the bridge
+ args.state.player.y = args.state.player.y.greater(args.state.bridge_top)
+
+ # player's x position is either the current x position or 0, whichever has a greater value
+ # ensures that the player doesn't go too far left (out of the screen's scope)
+ args.state.player.x = args.state.player.x.greater(0)
+
+ # player is not falling if it is located on the top of the bridge
+ args.state.player.falling = false if args.state.player.y == args.state.bridge_top
+ #args.state.player.rect = [args.state.player.x, args.state.player.y, args.state.player.h, args.state.player.w] # sets definition for player
+end
+
+# Resets the player by changing its properties back to the values they had at initialization
+def reset_player args
+ args.state.player.x = 0
+ args.state.player.y = args.state.bridge_top
+ args.state.player.dy = 0
+ args.state.player.dx = 0
+ args.state.enemy.hammers.clear # empties hammer collection
+ args.state.enemy.hammer_queue.clear # empties hammer_queue
+ args.state.game_over_at = args.state.tick_count # game_over_at set to current frame (or passage of time)
+end
+
+# Processes input from the user to move the player
+def input args
+ if args.state.inputlist.length > 5
+ args.state.inputlist.pop
+ end
+
+ should_process_special_move = (args.inputs.keyboard.key_down.j) ||
+ (args.inputs.keyboard.key_down.k) ||
+ (args.inputs.keyboard.key_down.a) ||
+ (args.inputs.keyboard.key_down.d) ||
+ (args.inputs.controller_one.key_down.y) ||
+ (args.inputs.controller_one.key_down.x) ||
+ (args.inputs.controller_one.key_down.left) ||
+ (args.inputs.controller_one.key_down.right)
+
+ if (should_process_special_move)
+ if (args.inputs.keyboard.key_down.j && args.inputs.keyboard.key_down.k) ||
+ (args.inputs.controller_one.key_down.x && args.inputs.controller_one.key_down.y)
+ args.state.inputlist.unshift("shield")
+ elsif (args.inputs.keyboard.key_down.k || args.inputs.controller_one.key_down.y) &&
+ (args.state.inputlist[0] == "forward-attack") && ((args.state.tick_count - args.state.lastpush) <= 15)
+ args.state.inputlist.unshift("dash-attack")
+ args.state.player.dx = 20
+ elsif (args.inputs.keyboard.key_down.j && args.inputs.keyboard.a) ||
+ (args.inputs.controller_one.key_down.x && args.inputs.controller_one.key_down.left)
+ args.state.inputlist.unshift("back-attack")
+ elsif ( args.inputs.controller_one.key_down.x || args.inputs.keyboard.key_down.j)
+ args.state.inputlist.unshift("forward-attack")
+ elsif (args.inputs.keyboard.key_down.k || args.inputs.controller_one.key_down.y) &&
+ (args.state.player.y > 128)
+ args.state.inputlist.unshift("dair")
+ elsif (args.inputs.keyboard.key_down.k || args.inputs.controller_one.key_down.y)
+ args.state.inputlist.unshift("up-attack")
+ elsif (args.inputs.controller_one.key_down.left || args.inputs.keyboard.key_down.a) &&
+ (args.state.inputlist[0] == "<") &&
+ ((args.state.tick_count - args.state.lastpush) <= 10)
+ args.state.inputlist.unshift("<<")
+ args.state.player.dx = -15
+ elsif (args.inputs.controller_one.key_down.left || args.inputs.keyboard.key_down.a)
+ args.state.inputlist.unshift("<")
+ args.state.timeleft = args.state.tick_count
+ elsif (args.inputs.controller_one.key_down.right || args.inputs.keyboard.key_down.d)
+ args.state.inputlist.unshift(">")
+ end
+
+ args.state.lastpush = args.state.tick_count
+ end
+
+ if args.inputs.keyboard.space || args.inputs.controller_one.r2 # if the user presses the space bar
+ args.state.player.jumped_at ||= args.state.tick_count # jumped_at is set to current frame
+
+ # if the time that has passed since the jump is less than the player's jump duration and
+ # the player is not falling
+ if args.state.player.jumped_at.elapsed_time < args.state.player_jump_power_duration && !args.state.player.falling
+ args.state.player.dy = args.state.player_jump_power # change in y is set to power of player's jump
+ end
+ end
+
+ # if the space bar is in the "up" state (or not being pressed down)
+ if args.inputs.keyboard.key_up.space || args.inputs.controller_one.key_up.r2
+ args.state.player.jumped_at = nil # jumped_at is empty
+ args.state.player.falling = true # the player is falling
+ end
+
+ if args.inputs.left # if left key is pressed
+ if args.state.player.dx < -5
+ args.state.player.dx = args.state.player.dx
+ else
+ args.state.player.dx = -5
+ end
+
+ elsif args.inputs.right # if right key is pressed
+ if args.state.player.dx > 5
+ args.state.player.dx = args.state.player.dx
+ else
+ args.state.player.dx = 5
+ end
+ else
+ args.state.player.dx *= args.state.player_speed_slowdown_rate # dx is scaled down
+ end
+
+ if ((args.state.player.dx).abs > 5) #&& ((args.state.tick_count - args.state.lastpush) <= 10)
+ args.state.player.dx *= 0.95
+ end
+end
+
+def tick_instructions args, text, y = 715
+ return if args.state.key_event_occurred
+ if args.inputs.mouse.click ||
+ args.inputs.keyboard.directional_vector ||
+ args.inputs.keyboard.key_down.enter ||
+ args.inputs.keyboard.key_down.space ||
+ args.inputs.keyboard.key_down.escape
+ args.state.key_event_occurred = true
+ end
+
+ args.outputs.debug << [0, y - 50, 1280, 60].solid
+ args.outputs.debug << [640, y, text, 1, 1, 255, 255, 255].label
+ args.outputs.debug << [640, y - 25, "(click to dismiss instructions)" , -2, 1, 255, 255, 255].label
+end
+
+</code></pre>
+<h3 id='----lowrez---nokia-3310---main-rb'>Lowrez - Nokia 3310 - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_lowrez/nokia_3310/app/main.rb
require 'app/nokia.rb'
@@ -25620,7 +27317,7 @@ def render_debug args
text: text,
size_enum: -1.5,
r: 255, g: 255, b: 255
- }.label
+ }.label!
end
args.outputs.debug << {
@@ -25630,7 +27327,7 @@ def render_debug args
size_enum: -0.5,
alignment_enum: 1,
r: 255, g: 255, b: 255
- }.label
+ }.label!
end
def snake_demo args
@@ -25640,7 +27337,7 @@ end
$gtk.reset
</code></pre>
-<h3 id='----lowrez---nokia-3310---nokia.rb'>Lowrez - Nokia 3310 - nokia.rb</h3>
+<h3 id='----lowrez---nokia-3310---nokia-rb'>Lowrez - Nokia 3310 - nokia.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_lowrez/nokia_3310/app/nokia.rb
# Emulation of a 64x64 canvas. Don't change this file unless you know what you're doing :-)
# Head over to main.rb and study the code there.
@@ -25880,7 +27577,7 @@ module GTK
g: 240,
b: 216,
a: 100
- }.line
+ }.line!
end
(NOKIA_WIDTH + 1).map_with_index do |i|
@@ -25893,7 +27590,7 @@ module GTK
g: 240,
b: 216,
a: 100
- }.line
+ }.line!
end
@args.state.overlay_rendered = true
@@ -25903,7 +27600,7 @@ module GTK
end
</code></pre>
-<h3 id='----lowrez---resolution-64x64---lowrez.rb'>Lowrez - Resolution 64x64 - lowrez.rb</h3>
+<h3 id='----lowrez---resolution-64x64---lowrez-rb'>Lowrez - Resolution 64x64 - lowrez.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_lowrez/resolution_64x64/app/lowrez.rb
# Emulation of a 64x64 canvas. Don't change this file unless you know what you're doing :-)
# Head over to main.rb and study the code there.
@@ -26077,7 +27774,7 @@ module GTK
end
</code></pre>
-<h3 id='----lowrez---resolution-64x64---main.rb'>Lowrez - Resolution 64x64 - main.rb</h3>
+<h3 id='----lowrez---resolution-64x64---main-rb'>Lowrez - Resolution 64x64 - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_lowrez/resolution_64x64/app/main.rb
require 'app/lowrez.rb'
@@ -26641,7 +28338,7 @@ def render_debug args
g: 128,
b: 128,
a: 80
- }.line
+ }.line!
args.outputs.static_debug << {
x: LOWREZ_X_OFFSET + (i * 10),
@@ -26652,7 +28349,7 @@ def render_debug args
g: 128,
b: 128,
a: 80
- }.line
+ }.line!
end
end
@@ -26679,7 +28376,7 @@ def render_debug args
y: 720 - (i * 20),
text: text,
size_enum: -1.5
- }.label
+ }.label!
end
args.outputs.debug << {
@@ -26688,13 +28385,13 @@ def render_debug args
text: "INFO: dev mode is currently enabled. Comment out the invocation of ~render_debug~ within the ~tick~ method to hide the debug layer.",
size_enum: -0.5,
alignment_enum: 1
- }.label
+ }.label!
end
$gtk.reset
</code></pre>
-<h3 id='----platformer---clepto-frog---main.rb'>Platformer - Clepto Frog - main.rb</h3>
+<h3 id='----platformer---clepto-frog---main-rb'>Platformer - Clepto Frog - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_platformer/clepto_frog/app/main.rb
MAP_FILE_PATH = 'app/map.txt'
@@ -27562,7 +29259,7 @@ def tick_instructions args, text, y = 715
end
</code></pre>
-<h3 id='----platformer---clepto-frog---map.rb'>Platformer - Clepto Frog - map.rb</h3>
+<h3 id='----platformer---clepto-frog---map-rb'>Platformer - Clepto Frog - map.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_platformer/clepto_frog/app/map.rb
$collisions = [
[326, 463, 64, 64],
@@ -28591,14 +30288,14 @@ $mugs = [
]
</code></pre>
-<h3 id='----platformer---gorillas-basic---credits.txt'>Platformer - Gorillas Basic - credits.txt</h3>
+<h3 id='----platformer---gorillas-basic---credits-txt'>Platformer - Gorillas Basic - credits.txt</h3>
<pre><code class="language-ruby"># ./samples/99_genre_platformer/gorillas_basic/CREDITS.txt
code: Amir Rajan, https://twitter.com/amirrajan
graphics: Nick Culbertson, https://twitter.com/MobyPixel
</code></pre>
-<h3 id='----platformer---gorillas-basic---main.rb'>Platformer - Gorillas Basic - main.rb</h3>
+<h3 id='----platformer---gorillas-basic---main-rb'>Platformer - Gorillas Basic - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_platformer/gorillas_basic/app/main.rb
class YouSoBasicGorillas
attr_accessor :outputs, :grid, :state, :inputs
@@ -28975,7 +30672,7 @@ def tick args
end
</code></pre>
-<h3 id='----platformer---gorillas-basic---tests.rb'>Platformer - Gorillas Basic - tests.rb</h3>
+<h3 id='----platformer---gorillas-basic---tests-rb'>Platformer - Gorillas Basic - tests.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_platformer/gorillas_basic/app/tests.rb
$gtk.reset 100
$gtk.supress_framerate_warning = true
@@ -28983,7 +30680,7 @@ $gtk.require 'app/tests/building_generation_tests.rb'
$gtk.tests.start
</code></pre>
-<h3 id='----platformer---gorillas-basic---tests---building_generation_tests.rb'>Platformer - Gorillas Basic - Tests - building_generation_tests.rb</h3>
+<h3 id='----platformer---gorillas-basic---tests---building_generation_tests-rb'>Platformer - Gorillas Basic - Tests - building_generation_tests.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_platformer/gorillas_basic/app/tests/building_generation_tests.rb
def test_solids args, assert
game = YouSoBasicGorillas.new
@@ -29002,7 +30699,7 @@ def test_solids args, assert
end
</code></pre>
-<h3 id='----platformer---the-little-probe---main.rb'>Platformer - The Little Probe - main.rb</h3>
+<h3 id='----platformer---the-little-probe---main-rb'>Platformer - The Little Probe - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_platformer/the_little_probe/app/main.rb
class FallingCircle
attr_gtk
@@ -29893,7 +31590,7 @@ def reset
end
</code></pre>
-<h3 id='----platformer---the-little-probe---data---level.txt'>Platformer - The Little Probe - Data - level.txt</h3>
+<h3 id='----platformer---the-little-probe---data---level-txt'>Platformer - The Little Probe - Data - level.txt</h3>
<pre><code class="language-ruby"># ./samples/99_genre_platformer/the_little_probe/data/level.txt
640,8840,1180,8840
-60,10220,0,9960
@@ -31377,7 +33074,7 @@ end
1910,11280,2200,11180
923.0029599285435,11398.99893503157,1264.002959928544,11351.99893503157
</code></pre>
-<h3 id='----platformer---the-little-probe---data---level_lava.txt'>Platformer - The Little Probe - Data - level_lava.txt</h3>
+<h3 id='----platformer---the-little-probe---data---level_lava-txt'>Platformer - The Little Probe - Data - level_lava.txt</h3>
<pre><code class="language-ruby"># ./samples/99_genre_platformer/the_little_probe/data/level_lava.txt
100,10740,500,10780
500,10780,960,10760
@@ -31615,7 +33312,7 @@ end
2200,11130,2360,11090
1840,11230,2200,11130
</code></pre>
-<h3 id='----rpg-narrative---choose-your-own-adventure---decision.rb'>Rpg Narrative - Choose Your Own Adventure - decision.rb</h3>
+<h3 id='----rpg-narrative---choose-your-own-adventure---decision-rb'>Rpg Narrative - Choose Your Own Adventure - decision.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/choose_your_own_adventure/app/decision.rb
# Hey there! Welcome to Four Decisions. Here is how you
# create your decision tree. Remove =being and =end from the text to
@@ -31656,7 +33353,7 @@ def game
end
</code></pre>
-<h3 id='----rpg-narrative---choose-your-own-adventure---main.rb'>Rpg Narrative - Choose Your Own Adventure - main.rb</h3>
+<h3 id='----rpg-narrative---choose-your-own-adventure---main-rb'>Rpg Narrative - Choose Your Own Adventure - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/choose_your_own_adventure/app/main.rb
=begin
@@ -31792,7 +33489,7 @@ end
$gtk.reset
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---lowrez_simulator.rb'>Rpg Narrative - Return Of Serenity - lowrez_simulator.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---lowrez_simulator-rb'>Rpg Narrative - Return Of Serenity - lowrez_simulator.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/lowrez_simulator.rb
###################################################################################
# YOU CAN PLAY AROUND WITH THE CODE BELOW, BUT USE CAUTION AS THIS IS WHAT EMULATES
@@ -31887,7 +33584,7 @@ def render_gridlines_if_needed args
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---main.rb'>Rpg Narrative - Return Of Serenity - main.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---main-rb'>Rpg Narrative - Return Of Serenity - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/main.rb
require 'app/require.rb'
@@ -32364,7 +34061,7 @@ def player_xs args, x, y
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---require.rb'>Rpg Narrative - Return Of Serenity - require.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---require-rb'>Rpg Narrative - Return Of Serenity - require.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/require.rb
require 'app/lowrez_simulator.rb'
require 'app/storyline_day_one.rb'
@@ -32379,7 +34076,7 @@ require 'app/storyline_final_decision.rb'
require 'app/storyline.rb'
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---storyline.rb'>Rpg Narrative - Return Of Serenity - storyline.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---storyline-rb'>Rpg Narrative - Return Of Serenity - storyline.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline.rb
def hotspot_top
[4, 61, 56, 3]
@@ -32529,7 +34226,7 @@ def reload_current_scene
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---storyline_anka.rb'>Rpg Narrative - Return Of Serenity - storyline_anka.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---storyline_anka-rb'>Rpg Narrative - Return Of Serenity - storyline_anka.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_anka.rb
def anka_inside_room args
{
@@ -32660,7 +34357,7 @@ def replied_to_anka_back_home args
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---storyline_blinking_light.rb'>Rpg Narrative - Return Of Serenity - storyline_blinking_light.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---storyline_blinking_light-rb'>Rpg Narrative - Return Of Serenity - storyline_blinking_light.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_blinking_light.rb
def the_blinking_light args
{
@@ -32739,7 +34436,7 @@ def blinking_light_inside_mainframe args
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---storyline_day_one.rb'>Rpg Narrative - Return Of Serenity - storyline_day_one.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---storyline_day_one-rb'>Rpg Narrative - Return Of Serenity - storyline_day_one.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_day_one.rb
def day_one_beginning args
{
@@ -32949,7 +34646,7 @@ def explaining_the_special_power_inside_computer args
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---storyline_final_decision.rb'>Rpg Narrative - Return Of Serenity - storyline_final_decision.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---storyline_final_decision-rb'>Rpg Narrative - Return Of Serenity - storyline_final_decision.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_final_decision.rb
def final_decision_side_of_home args
{
@@ -33089,7 +34786,7 @@ def final_decision_ship_status_shared args
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---storyline_final_message.rb'>Rpg Narrative - Return Of Serenity - storyline_final_message.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---storyline_final_message-rb'>Rpg Narrative - Return Of Serenity - storyline_final_message.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_final_message.rb
def final_message_sad args
{
@@ -33309,7 +35006,7 @@ def final_message_summary args
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---storyline_serenity_alive.rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_alive.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---storyline_serenity_alive-rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_alive.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_serenity_alive.rb
def serenity_alive_side_of_home args
{
@@ -33532,7 +35229,7 @@ def serenity_alive_current_message args
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---storyline_serenity_bio.rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_bio.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---storyline_serenity_bio-rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_bio.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_serenity_bio.rb
def serenity_bio_infront_of_home args
{
@@ -33687,7 +35384,7 @@ def bad_dream_last_reply args
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---storyline_serenity_introduction.rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_introduction.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---storyline_serenity_introduction-rb'>Rpg Narrative - Return Of Serenity - storyline_serenity_introduction.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_serenity_introduction.rb
# decision_graph "Message from Sasha",
# "I should reply.",
@@ -33786,7 +35483,7 @@ def replied_to_introduction_side_of_home args
end
</code></pre>
-<h3 id='----rpg-narrative---return-of-serenity---storyline_speed_of_light.rb'>Rpg Narrative - Return Of Serenity - storyline_speed_of_light.rb</h3>
+<h3 id='----rpg-narrative---return-of-serenity---storyline_speed_of_light-rb'>Rpg Narrative - Return Of Serenity - storyline_speed_of_light.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_narrative/return_of_serenity/app/storyline_speed_of_light.rb
def speed_of_light_front_of_home args
{
@@ -33894,7 +35591,7 @@ def speed_of_light_end_of_day args
end
</code></pre>
-<h3 id='----rpg-roguelike---roguelike-starting-point---constants.rb'>Rpg Roguelike - Roguelike Starting Point - constants.rb</h3>
+<h3 id='----rpg-roguelike---roguelike-starting-point---constants-rb'>Rpg Roguelike - Roguelike Starting Point - constants.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_roguelike/01_roguelike_starting_point/app/constants.rb
SHOW_LEGEND = true
SOURCE_TILE_SIZE = 16
@@ -33906,7 +35603,7 @@ TILE_B = 0
TILE_A = 255
</code></pre>
-<h3 id='----rpg-roguelike---roguelike-starting-point---legend.rb'>Rpg Roguelike - Roguelike Starting Point - legend.rb</h3>
+<h3 id='----rpg-roguelike---roguelike-starting-point---legend-rb'>Rpg Roguelike - Roguelike Starting Point - legend.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_roguelike/01_roguelike_starting_point/app/legend.rb
def tick_legend args
return unless SHOW_LEGEND
@@ -33975,7 +35672,7 @@ def tick_legend args
end
</code></pre>
-<h3 id='----rpg-roguelike---roguelike-starting-point---main.rb'>Rpg Roguelike - Roguelike Starting Point - main.rb</h3>
+<h3 id='----rpg-roguelike---roguelike-starting-point---main-rb'>Rpg Roguelike - Roguelike Starting Point - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_roguelike/01_roguelike_starting_point/app/main.rb
require 'app/constants.rb'
require 'app/sprite_lookup.rb'
@@ -34076,7 +35773,7 @@ def tile_in_game x, y, tile_key
end
</code></pre>
-<h3 id='----rpg-roguelike---roguelike-starting-point---sprite_lookup.rb'>Rpg Roguelike - Roguelike Starting Point - sprite_lookup.rb</h3>
+<h3 id='----rpg-roguelike---roguelike-starting-point---sprite_lookup-rb'>Rpg Roguelike - Roguelike Starting Point - sprite_lookup.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_roguelike/01_roguelike_starting_point/app/sprite_lookup.rb
def sprite_lookup
{
@@ -34204,7 +35901,7 @@ end
$gtk.args.state.reserved.sprite_lookup = sprite_lookup
</code></pre>
-<h3 id='----rpg-roguelike---roguelike-line-of-sight---main.rb'>Rpg Roguelike - Roguelike Line Of Sight - main.rb</h3>
+<h3 id='----rpg-roguelike---roguelike-line-of-sight---main-rb'>Rpg Roguelike - Roguelike Line Of Sight - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_roguelike/02_roguelike_line_of_sight/app/main.rb
=begin
@@ -34647,7 +36344,7 @@ def tick args
end
</code></pre>
-<h3 id='----rpg-tactical---hexagonal-grid---main.rb'>Rpg Tactical - Hexagonal Grid - main.rb</h3>
+<h3 id='----rpg-tactical---hexagonal-grid---main-rb'>Rpg Tactical - Hexagonal Grid - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_tactical/hexagonal_grid/app/main.rb
class HexagonTileGame
attr_gtk
@@ -34719,7 +36416,7 @@ end
$gtk.reset
</code></pre>
-<h3 id='----rpg-tactical---isometric-grid---main.rb'>Rpg Tactical - Isometric Grid - main.rb</h3>
+<h3 id='----rpg-tactical---isometric-grid---main-rb'>Rpg Tactical - Isometric Grid - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_tactical/isometric_grid/app/main.rb
class Isometric
attr_accessor :grid, :inputs, :state, :outputs
@@ -34985,7 +36682,7 @@ def tick args
end
</code></pre>
-<h3 id='----rpg-topdown---topdown-starting-point---main.rb'>Rpg Topdown - Topdown Starting Point - main.rb</h3>
+<h3 id='----rpg-topdown---topdown-starting-point---main-rb'>Rpg Topdown - Topdown Starting Point - main.rb</h3>
<pre><code class="language-ruby"># ./samples/99_genre_rpg_topdown/topdown_starting_point/app/main.rb
=begin
@@ -35101,7 +36798,7 @@ end
<p>
Follows is a source code listing for all files that have been open sourced. This code can be found online at <a href='https://github.com/DragonRuby/dragonruby-game-toolkit-contrib/'>https://github.com/DragonRuby/dragonruby-game-toolkit-contrib/</a>.
</p>
-<h3 id='----args.rb'>args.rb</h3>
+<h3 id='----args-rb'>args.rb</h3>
<pre><code class="language-ruby"># ./dragon/args.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -35115,58 +36812,21 @@ module GTK
class Args
include ArgsDeprecated
include Serialize
-
- # Contains information related to input devices and input events.
- #
- # @return [Inputs]
attr_accessor :inputs
-
- # Contains the means to interact with output devices such as the screen.
- #
- # @return [Outputs]
attr_accessor :outputs
-
- # Contains the means to interact with the audio mixer.
- #
- # @return [Hash]
attr_accessor :audio
-
- # Contains display size information to assist in positioning things on the screen.
- #
- # @return [Grid]
attr_accessor :grid
-
- # Provides access to game play recording facilities within Game Toolkit.
- #
- # @return [Recording]
attr_accessor :recording
-
- # Gives you access to geometry related functions.
- #
- # @return [Geometry]
attr_accessor :geometry
-
attr_accessor :fn
-
- # This is where you'll put state associated with your video game.
- #
- # @return [OpenEntity]
attr_accessor :state
-
- # Gives you access to the top level DragonRuby runtime.
- #
- # @return [Runtime]
+ attr_accessor :temp_state
attr_accessor :runtime
alias_method :gtk, :runtime
-
attr_accessor :passes
-
attr_accessor :wizards
-
attr_accessor :layout
-
attr_accessor :easing
-
attr_accessor :string
def initialize runtime, recording
@@ -35175,6 +36835,7 @@ module GTK
@audio = {}
@passes = []
@state = OpenEntity.new
+ @temp_state = OpenEntity.new
@state.tick_count = -1
@runtime = runtime
@recording = recording
@@ -35204,11 +36865,12 @@ module GTK
def serialize
{
- state: state.as_hash,
- inputs: inputs.serialize,
- passes: passes.serialize,
- outputs: outputs.serialize,
- grid: grid.serialize
+ state: state.as_hash,
+ temp_state: temp_state.as_hash,
+ inputs: inputs.serialize,
+ passes: passes.serialize,
+ outputs: outputs.serialize,
+ grid: grid.serialize
}
end
@@ -35344,7 +37006,7 @@ module GTK
end
</code></pre>
-<h3 id='----assert.rb'>assert.rb</h3>
+<h3 id='----assert-rb'>assert.rb</h3>
<pre><code class="language-ruby"># ./dragon/assert.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -35372,10 +37034,10 @@ To add an assertion open up this class and write:
class Assert
def custom_assertion actual, expected, message = nil
- # this tell Game Toolkit that an assertion was performed (so that the test isn't marked inconclusive).
+ # this tells Game Toolkit that an assertion was performed (so that the test isn't marked inconclusive).
@assertion_performed = true
- # perform your custom logic here and rais an exception to denote a failure.
+ # perform your custom logic here and raise an exception to denote a failure.
raise "Some Error. #{message}."
end
@@ -35385,14 +37047,14 @@ end
attr :assertion_performed
=begin
-Us this if you are throwing your own exceptions and you want to mark the tests as ran (so that it wont be marked as inconclusive).
+Use this if you are throwing your own exceptions and you want to mark the tests as ran (so that it wont be marked as inconclusive).
=end
def ok!
@assertion_performed = true
end
=begin
-Assert if a value is a thruthy value. All assert method take an optional final parameter that is the message to display to the user.
+Assert if a value is a truthy value. All assert methods take an optional final parameter that is the message to display to the user.
@example
@@ -35446,7 +37108,7 @@ end
@assertion_performed = true
if actual != expected
actual_string = "#{actual}#{actual.nil? ? " (nil) " : " " }".strip
- message = "actual:\n#{actual_string}\n\ndid not equal\n\nexpected:\n#{expected}.\n#{message}"
+ message = "actual:\n#{actual_string}\n\ndid not equal\n\nexpected:\n#{expected}\n#{message}"
raise message
end
nil
@@ -35456,7 +37118,7 @@ end
@assertion_performed = true
if actual == expected
actual_string = "#{actual}#{actual.nil? ? " (nil) " : " " }".strip
- message = "actual:\n#{actual_string}\n\nequaled\n\nexpected:\n#{expected}.\n#{message}"
+ message = "actual:\n#{actual_string}\n\nequaled\n\nexpected:\n#{expected}\n#{message}"
raise message
end
nil
@@ -35486,7 +37148,7 @@ end
end
</code></pre>
-<h3 id='----attr_gtk.rb'>attr_gtk.rb</h3>
+<h3 id='----attr_gtk-rb'>attr_gtk.rb</h3>
<pre><code class="language-ruby"># ./dragon/attr_gtk.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -35509,6 +37171,10 @@ module AttrGTK
args.state
end
+ def temp_state
+ args.temp_state
+ end
+
def inputs
args.inputs
end
@@ -35536,10 +37202,18 @@ module AttrGTK
def layout
args.layout
end
+
+ def new_entity entity_type, init_hash = nil, &block
+ args.state.new_entity entity_type, init_hash, &block
+ end
+
+ def new_entity_strict entity_type, init_hash = nil, &block
+ args.state.new_entity_strict entity_type, init_hash, &block
+ end
end
</code></pre>
-<h3 id='----attr_sprite.rb'>attr_sprite.rb</h3>
+<h3 id='----attr_sprite-rb'>attr_sprite.rb</h3>
<pre><code class="language-ruby"># ./dragon/attr_sprite.rb
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -35580,7 +37254,7 @@ module AttrSprite
attr_accessor :x, :y, :w, :h, :path, :angle, :a, :r, :g, :b, :tile_x,
:tile_y, :tile_w, :tile_h, :flip_horizontally,
:flip_vertically, :angle_anchor_x, :angle_anchor_y, :id,
- :source_x, :source_y, :source_w, :source_h
+ :source_x, :source_y, :source_w, :source_h, :blendmode_enum
def primitive_marker
:sprite
@@ -35600,7 +37274,7 @@ module AttrSprite
end
</code></pre>
-<h3 id='----console.rb'>console.rb</h3>
+<h3 id='----console-rb'>console.rb</h3>
<pre><code class="language-ruby"># ./dragon/console.rb
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -35623,7 +37297,7 @@ module GTK
:font_style, :menu
def initialize
- @font_style = FontStyle.new(font: 'font.ttf', size_enum: -1, line_height: 1.1)
+ @font_style = FontStyle.new(font: 'font.ttf', size_enum: -1.5, line_height: 1.1)
@menu = Menu.new self
@disabled = false
@log_offset = 0
@@ -35643,6 +37317,8 @@ module GTK
@text_color = Color.new [255, 255, 255]
@error_color = Color.new [200, 50, 50]
@header_color = Color.new [100, 200, 220]
+ @code_color = Color.new [210, 168, 255]
+ @comment_color = Color.new [0, 200, 100]
@animation_duration = 1.seconds
@shown_at = -1
load_history
@@ -35917,6 +37593,8 @@ S
if cmd == 'quit' || cmd == ':wq' || cmd == ':q!' || cmd == ':q' || cmd == ':wqa'
$gtk.request_quit
+ elsif cmd.start_with? ':'
+ send ((cmd.gsub '-', '_').gsub ':', '')
else
puts "-> #{cmd}"
begin
@@ -35925,13 +37603,19 @@ S
if $results.nil?
puts "=> nil"
elsif $results == :console_silent_eval
+ # do nothing since the console is silent
else
puts "=> #{$results}"
end
@last_command_errored = false
rescue Exception => e
try_search_docs e
- puts "* EXCEPTION: #{e}"
+ # if an exception is thrown and the bactrace includes something helpful, then show it
+ if (e.backtrace || []).first && (e.backtrace.first.include? "(eval)")
+ puts "* EXCEPTION: #{e}"
+ else
+ puts "* EXCEPTION: #{e}\n#{e.__backtrace_to_org__}"
+ end
end
end
end
@@ -36158,6 +37842,11 @@ S
end
render_log_offset args
+
+ args.outputs.reserved << { x: 10.from_right, y: @bottom + 10,
+ text: "Press CTRL+g or ESCAPE to clear the prompt.",
+ vertical_alignment_enum: 0,
+ alignment_enum: 2, r: 80, g: 80, b: 80 }.label!
end
def render_log_offset args
@@ -36180,7 +37869,7 @@ S
end
def include_subdued_markers? text
- include_any_words? text, subdued_markers
+ (text.start_with? "* INFO: ") && (include_any_words? text, subdued_markers)
end
def include_any_words? text, words
@@ -36326,8 +38015,32 @@ S
(log_entry.start_with? "**** ")
end
+ def code? log_entry
+ (just_symbol? log_entry) || (codeblock_marker? log_entry)
+ end
+
+ def just_symbol? log_entry
+ scrubbed = log_entry.gsub("*", "").strip
+ (scrubbed.start_with? ":") && (!scrubbed.include? " ") && (!scrubbed.include? "=>")
+ end
+
+ def code_comment? log_entry
+ return true if log_entry.strip.start_with?("# ")
+ return false
+ end
+
+ def codeblock_marker? log_entry
+ return true if log_entry.strip.start_with?("#+begin_src")
+ return true if log_entry.strip.start_with?("#+end_src")
+ return false
+ end
+
def color_for_log_entry(log_entry)
- if include_row_marker? log_entry
+ if code? log_entry
+ @code_color
+ elsif code_comment? log_entry
+ @comment_color
+ elsif include_row_marker? log_entry
@text_color
elsif include_error_marker? log_entry
@error_color
@@ -36374,7 +38087,7 @@ S
end
</code></pre>
-<h3 id='----console_color.rb'>console_color.rb</h3>
+<h3 id='----console_color-rb'>console_color.rb</h3>
<pre><code class="language-ruby"># ./dragon/console_color.rb
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -36400,6 +38113,10 @@ module GTK
@color
end
+ def to_s
+ "GTK::Console::Color #{to_h}"
+ end
+
def to_h
{ r: @color[0], g: @color[1], b: @color[2], a: @color[3] }
end
@@ -36408,7 +38125,7 @@ module GTK
end
</code></pre>
-<h3 id='----console_font_style.rb'>console_font_style.rb</h3>
+<h3 id='----console_font_style-rb'>console_font_style.rb</h3>
<pre><code class="language-ruby"># ./dragon/console_font_style.rb
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -36445,14 +38162,14 @@ module GTK
size_enum: size_enum,
alignment_enum: alignment_enum,
**color.to_h,
- }.label
+ }.label!
end
end
end
end
</code></pre>
-<h3 id='----console_menu.rb'>console_menu.rb</h3>
+<h3 id='----console_menu-rb'>console_menu.rb</h3>
<pre><code class="language-ruby"># ./dragon/console_menu.rb
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -36507,7 +38224,7 @@ module GTK
def itch_wizard_clicked
@console.scroll_to_bottom
- $wizards.itch.start
+ $wizards.itch.restart
end
def docs_clicked
@@ -36532,6 +38249,7 @@ module GTK
@buttons = [
(button id: :record, row: 0, col: 9, text: "record gameplay", method: :record_clicked),
(button id: :replay, row: 0, col: 10, text: "start replay", method: :replay_clicked),
+ *custom_buttons
]
elsif @menu_shown == :hidden
@buttons = [
@@ -36590,8 +38308,8 @@ module GTK
method: method
}.let do |entity|
primitives = []
- primitives << entity[:rect].merge(a: 164).solid
- primitives << entity[:rect].merge(r: 255, g: 255, b: 255).border
+ primitives << entity[:rect].solid!(a: 164)
+ primitives << entity[:rect].border!(r: 255, g: 255, b: 255)
primitives << text.wrapped_lines(5)
.map_with_index do |l, i|
[
@@ -36615,7 +38333,7 @@ module GTK
end
</code></pre>
-<h3 id='----console_prompt.rb'>console_prompt.rb</h3>
+<h3 id='----console_prompt-rb'>console_prompt.rb</h3>
<pre><code class="language-ruby"># ./dragon/console_prompt.rb
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -36793,17 +38511,17 @@ S
"#{" " * (string_width.length - c.length) } #{c} |"
end.join
- # remove seperators between empty values
+ # remove separators between empty values
formated_row = formated_row.gsub(" | ", " ")
puts formated_row
end
- def pretty_print_row_seperator string_width, cell_width, column_width, columns
+ def pretty_print_row_separator string_width, cell_width, column_width, columns
# this is a joint: +--------
column_joint = "+#{"-" * cell_width}"
- # multiple joints create a row seperator: +----+----+
+ # multiple joints create a row separator: +----+----+
puts (column_joint * columns) + "+"
end
@@ -36812,12 +38530,12 @@ S
args.outputs.reserved << (@cursor_color.to_h.merge x: x + @cursor_position_px + 0.5,
y: y + 5,
x2: x + @cursor_position_px + 0.5,
- y2: y + @font_style.letter_size.y + 5)
+ y2: y + @font_style.letter_size.y + 4)
args.outputs.reserved << (@cursor_color.to_h.merge x: x + @cursor_position_px + 1,
y: y + 5,
x2: x + @cursor_position_px + 1,
- y2: y + @font_style.letter_size.y + 5)
+ y2: y + @font_style.letter_size.y + 4)
# debugging rectangle for string
# args.outputs.reserved << (@cursor_color.to_h.merge x: x,
@@ -36892,7 +38610,7 @@ S
end
</code></pre>
-<h3 id='----controller.rb'>controller.rb</h3>
+<h3 id='----controller-rb'>controller.rb</h3>
<pre><code class="language-ruby"># ./dragon/controller.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -37018,7 +38736,7 @@ end
</code></pre>
-<h3 id='----controller/config.rb'>controller/config.rb</h3>
+<h3 id='----controller/config-rb'>controller/config.rb</h3>
<pre><code class="language-ruby"># ./dragon/controller/config.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -37421,7 +39139,7 @@ module GTK
end
</code></pre>
-<h3 id='----controller/keys.rb'>controller/keys.rb</h3>
+<h3 id='----controller/keys-rb'>controller/keys.rb</h3>
<pre><code class="language-ruby"># ./dragon/controller/keys.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -37439,7 +39157,7 @@ module GTK
:l1, :r1,
:l2, :r2,
:l3, :r3,
- :start, :select,
+ :start, :select, :home,
:directional_up, :directional_down, :directional_left, :directional_right
].freeze
@@ -37447,6 +39165,22 @@ module GTK
attr label
end
+ def back
+ @select
+ end
+
+ def back= value
+ @select = value
+ end
+
+ def guide
+ @home
+ end
+
+ def guide= value
+ @home = value
+ end
+
# Activate a key.
#
# @return [void]
@@ -37476,7 +39210,7 @@ module GTK
end
</code></pre>
-<h3 id='----directional_input_helper_methods.rb'>directional_input_helper_methods.rb</h3>
+<h3 id='----directional_input_helper_methods-rb'>directional_input_helper_methods.rb</h3>
<pre><code class="language-ruby"># ./dragon/directional_input_helper_methods.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -37493,7 +39227,7 @@ module GTK
error_message = <<-S
* ERROR
-The GTK::DirectionalKeys module should only be included in objects that respond to the following api heirarchy:
+The GTK::DirectionalKeys module should only be included in objects that respond to the following api hierarchy:
- (#{ directional_methods.join("|") })
- key_held.(#{ directional_methods.join("|") })
@@ -37550,6 +39284,12 @@ S
end
end
+ def directional_angle
+ return nil unless directional_vector
+
+ Math.atan2(up_down, left_right).to_degrees
+ end
+
def method_missing m, *args
# combine the key with ctrl_
if m.to_s.start_with?("ctrl_")
@@ -37572,7 +39312,7 @@ S
end
</code></pre>
-<h3 id='----easing.rb'>easing.rb</h3>
+<h3 id='----easing-rb'>easing.rb</h3>
<pre><code class="language-ruby"># ./dragon/easing.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -37672,7 +39412,7 @@ end
Easing = GTK::Easing
</code></pre>
-<h3 id='----entity.rb'>entity.rb</h3>
+<h3 id='----entity-rb'>entity.rb</h3>
<pre><code class="language-ruby"># ./dragon/entity.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -37767,7 +39507,7 @@ S
end
</code></pre>
-<h3 id='----geometry.rb'>geometry.rb</h3>
+<h3 id='----geometry-rb'>geometry.rb</h3>
<pre><code class="language-ruby"># ./dragon/geometry.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -37776,6 +39516,22 @@ end
module GTK
module Geometry
+ def self.rotate_point point, angle, around = nil
+ s = Math.sin a.to_radians
+ c = Math.cos a.to_radians
+ px = point.x
+ py = point.y
+ cx = 0
+ cy = 0
+ if around
+ cx = around.x
+ cy = around.y
+ end
+
+ point.merge(x: ((px - cx) * c - (py - cy) * s) + cx,
+ y: ((px - cx) * s + (py - cy) * c) + cy)
+ end
+
# Returns f(t) for a cubic Bezier curve.
def self.cubic_bezier t, a, b, c, d
s = 1 - t
@@ -37857,7 +39613,7 @@ module GTK
rescue Exception => e
raise e, <<-S
* ERROR:
-center_inside_rect for self #{self} and other_rect #{other_rect}. Failed with exception #{e}.
+center_inside_rect for self #{self} and other_rect #{other_rect}.\n#{e}.
S
end
@@ -37874,7 +39630,7 @@ S
rescue Exception => e
raise e, <<-S
* ERROR:
-center_inside_rect_x for self #{self} and other_rect #{other_rect}. Failed with exception #{e}.
+center_inside_rect_x for self #{self} and other_rect #{other_rect}.\n#{e}.
S
end
@@ -37891,7 +39647,7 @@ S
rescue Exception => e
raise e, <<-S
* ERROR:
-center_inside_rect_y for self #{self} and other_rect #{other_rect}. Failed with exception #{e}.
+center_inside_rect_y for self #{self} and other_rect #{other_rect}.\n#{e}.
S
end
@@ -37900,7 +39656,7 @@ S
end
- # Returns a primitive that is anchored/repositioned based off its retangle.
+ # Returns a primitive that is anchored/repositioned based off its rectangle.
# @gtk
def anchor_rect anchor_x, anchor_y
current_w = self.w
@@ -38036,10 +39792,10 @@ S
# @gtk
def self.intersect_rect? rect_one, rect_two, tolerance = 0.1
- return false if rect_one.right - tolerance < rect_two.left + tolerance
- return false if rect_one.left + tolerance > rect_two.right - tolerance
- return false if rect_one.top - tolerance < rect_two.bottom + tolerance
- return false if rect_one.bottom + tolerance > rect_two.top - tolerance
+ return false if ((rect_one.x + rect_one.w) - tolerance) < (rect_two.x + tolerance)
+ return false if (rect_one.x + tolerance) > ((rect_two.x + rect_two.w) - tolerance)
+ return false if ((rect_one.y + rect_one.h) - tolerance) < (rect_two.y + tolerance)
+ return false if (rect_one.y + tolerance) > ((rect_two.y + rect_two.h) - tolerance)
return true
rescue Exception => e
context_help_rect_one = (rect_one.__help_contract_implementation contract_intersect_rect?)[:not_implemented_methods]
@@ -38067,6 +39823,7 @@ S
- rect_one: #{rect_one}
- rect_two: #{rect_two}
#{context_help}
+\n#{e}
S
end
@@ -38077,14 +39834,14 @@ S
y = y.shift_down(size * anchor_y)
[x, y, size, size]
rescue Exception => e
- raise e, ":to_square failed for size: #{size} x: #{x} y: #{y} anchor_x: #{anchor_x} anchor_y: #{anchor_y}."
+ raise e, ":to_square failed for size: #{size} x: #{x} y: #{y} anchor_x: #{anchor_x} anchor_y: #{anchor_y}.\n#{e}"
end
# @gtk
def self.distance point_one, point_two
Math.sqrt((point_two.x - point_one.x)**2 + (point_two.y - point_one.y)**2)
rescue Exception => e
- raise e, ":distance failed for point_one: #{point_one} point_two #{point_two}."
+ raise e, ":distance failed for point_one: #{point_one} point_two #{point_two}.\n#{e}"
end
# @gtk
@@ -38093,31 +39850,34 @@ S
d_x = end_point.x - start_point.x
Math::PI.+(Math.atan2(d_y, d_x)).to_degrees
rescue Exception => e
- raise e, ":angle_from failed for start_point: #{start_point} end_point: #{end_point}."
+ raise e, ":angle_from failed for start_point: #{start_point} end_point: #{end_point}.\n#{e}"
end
# @gtk
def self.angle_to start_point, end_point
angle_from end_point, start_point
rescue Exception => e
- raise e, ":angle_to failed for start_point: #{start_point} end_point: #{end_point}."
+ raise e, ":angle_to failed for start_point: #{start_point} end_point: #{end_point}.\n#{e}"
end
# @gtk
def self.point_inside_circle? point, circle_center_point, radius
(point.x - circle_center_point.x) ** 2 + (point.y - circle_center_point.y) ** 2 < radius ** 2
rescue Exception => e
- raise e, ":point_inside_circle? failed for point: #{point} circle_center_point: #{circle_center_point} radius: #{radius}"
+ raise e, ":point_inside_circle? failed for point: #{point} circle_center_point: #{circle_center_point} radius: #{radius}.\n#{e}"
end
# @gtk
def self.inside_rect? inner_rect, outer_rect, tolerance = 0.0
+ return nil if !inner_rect
+ return nil if !outer_rect
+
inner_rect.x + tolerance >= outer_rect.x - tolerance &&
- inner_rect.right - tolerance <= outer_rect.right + tolerance &&
+ (inner_rect.x + inner_rect.w) - tolerance <= (outer_rect.x + outer_rect.w) + tolerance &&
inner_rect.y + tolerance >= outer_rect.y - tolerance &&
- inner_rect.top - tolerance <= outer_rect.top + tolerance
+ (inner_rect.y + inner_rect.h) - tolerance <= (outer_rect.y + outer_rect.h) + tolerance
rescue Exception => e
- raise e, ":inside_rect? failed for inner_rect: #{inner_rect} outer_rect: #{outer_rect}."
+ raise e, ":inside_rect? failed for inner_rect: #{inner_rect} outer_rect: #{outer_rect}.\n#{e}"
end
# @gtk
@@ -38152,7 +39912,7 @@ S
return rect
end
rescue Exception => e
- raise e, ":scale_rect_extended failed for rect: #{rect} percentage_x: #{percentage_x} percentage_y: #{percentage_y} anchors_x: #{anchor_x} anchor_y: #{anchor_y}."
+ raise e, ":scale_rect_extended failed for rect: #{rect} percentage_x: #{percentage_x} percentage_y: #{percentage_y} anchors_x: #{anchor_x} anchor_y: #{anchor_y}.\n#{e}"
end
# @gtk
@@ -38166,13 +39926,27 @@ S
anchor_x: anchor_x,
anchor_y: anchor_y
rescue Exception => e
- raise e, ":scale_rect failed for rect: #{rect} percentage: #{percentage} anchors [#{anchor_x} (x), #{anchor_y} (y)]."
+ raise e, ":scale_rect failed for rect: #{rect} percentage: #{percentage} anchors [#{anchor_x} (x), #{anchor_y} (y)].\n#{e}"
+ end
+
+ def self.rect_to_line rect
+ l = rect.to_hash.line
+ l.merge(x2: l.x + l.w - 1,
+ y2: l.y + l.h)
+ end
+
+ def self.rect_center_point rect
+ { x: rect.x + rect.w.half, y: rect.y + rect.h.half }
+ end
+
+ def rect_center_point
+ Geometry.rect_center_point self
end
end # module Geometry
end # module GTK
</code></pre>
-<h3 id='----grid.rb'>grid.rb</h3>
+<h3 id='----grid-rb'>grid.rb</h3>
<pre><code class="language-ruby"># ./dragon/grid.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -38361,11 +40135,19 @@ module GTK
def bottom_right
[@right, @bottom].point
end
+
+ def x
+ 0
+ end
+
+ def y
+ 0
+ end
end
end
</code></pre>
-<h3 id='----inputs.rb'>inputs.rb</h3>
+<h3 id='----inputs-rb'>inputs.rb</h3>
<pre><code class="language-ruby"># ./dragon/inputs.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -38560,6 +40342,30 @@ module GTK
}
end
+ def self.method_to_key_hash
+ return @method_to_key_hash if @method_to_key_hash
+ @method_to_key_hash = {}
+ string_representation_overrides ||= {
+ backspace: '\b'
+ }
+ char_to_method_hash.each do |k, v|
+ v.each do |vi|
+ t = { char_or_raw_key: k }
+
+ if k.is_a? Numeric
+ t[:raw_key] = k
+ t[:string_representation] = "raw_key == #{k}"
+ else
+ t[:char] = k
+ t[:string_representation] = "\"#{k.strip}\""
+ end
+
+ @method_to_key_hash[vi] = t
+ end
+ end
+ @method_to_key_hash
+ end
+
def self.char_to_method char, int = nil
methods = char_to_method_hash[char] || char_to_method_hash[int]
methods ? methods.dup : [char.to_sym || int]
@@ -38674,24 +40480,32 @@ S
end
def method_missing m, *args
- begin
- define_singleton_method(m) do
- r = self.instance_variable_get("@#{m.without_ending_bang}".to_sym)
- clear_key m
- return r
- end
+ if KeyboardKeys.method_to_key_hash[m.without_ending_bang]
+ begin
+ define_singleton_method(m) do
+ r = self.instance_variable_get("@#{m.without_ending_bang}".to_sym)
+ clear_key m
+ return r
+ end
- return self.send m
- rescue Exception => e
- log_important "#{e}"
+ return self.send m
+ rescue Exception => e
+ log_important "#{e}"
+ end
end
+ did_you_mean = KeyboardKeys.method_to_key_hash.find_all do |k, v|
+ k.to_s[0..1] == m.to_s[0..1]
+ end.map {|k, v| ":#{k} (#{v[:string_representation]})" }
+ did_you_mean_string = ""
+ did_you_mean_string = ". Did you mean #{did_you_mean.join ", "}?"
+
raise <<-S
* ERROR:
-There is no member on the keyboard called #{m}. Here is a to_s representation of what's available:
-
-#{KeyboardKeys.char_to_method_hash.map { |k, v| "[#{k} => #{v.join(",")}]" }.join(" ")}
+#{KeyboardKeys.method_to_key_hash.map { |k, v| "** :#{k} #{v.string_representation}" }.join("\n")}
+There is no key on the keyboard called :#{m}#{did_you_mean_string}.
+Full list of available keys =:points_up:=.
S
end
@@ -39075,6 +40889,10 @@ module GTK
(controller_one && controller_one.directional_vector)
end
+ def directional_angle
+ keyboard.directional_angle || (controller_one && controller_one.directional_angle)
+ end
+
# Returns a signal indicating right (`1`), left (`-1`), or neither ('0').
#
# @return [Integer]
@@ -39142,21 +40960,14 @@ module GTK
end
</code></pre>
-<h3 id='----ios_wizard.rb'>ios_wizard.rb</h3>
+<h3 id='----ios_wizard-rb'>ios_wizard.rb</h3>
<pre><code class="language-ruby"># ./dragon/ios_wizard.rb
+# Contributors outside of DragonRuby who also hold Copyright: Michał Dudziński
# Copyright 2019 DragonRuby LLC
# MIT License
# ios_wizard.rb has been released under MIT (*only this file*).
-class WizardException < Exception
- attr_accessor :console_primitives
-
- def initialize *console_primitives
- @console_primitives = console_primitives
- end
-end
-
-class IOSWizard
+class IOSWizard < Wizard
def initialize
@doctor_executed_at = 0
end
@@ -39169,23 +40980,45 @@ class IOSWizard
@steps ||= []
end
- def steps_development_build
+ def prerequisite_steps
[
:check_for_xcode,
:check_for_brew,
:check_for_certs,
- :check_for_device,
- :check_for_dev_profile,
+ ]
+ end
+
+ def app_metadata_retrieval_steps
+ [
:determine_team_identifier,
:determine_app_name,
:determine_app_id,
- :blow_away_temp,
+ ]
+ end
+
+ def steps_development_build
+ [
+ *prerequisite_steps,
+
+ :check_for_device,
+ :check_for_dev_profile,
+
+ *app_metadata_retrieval_steps,
+
+ :clear_tmp_directory,
:stage_app,
+
:development_write_info_plist,
+
:write_entitlements_plist,
:compile_icons,
- :create_payload_directory,
+ :clear_payload_directory,
+
+ :create_payload_directory_dev,
+
+ :create_payload,
:code_sign_payload,
+
:create_ipa,
:deploy
]
@@ -39193,20 +41026,27 @@ class IOSWizard
def steps_production_build
[
- :check_for_xcode,
- :check_for_brew,
- :check_for_certs,
+ *prerequisite_steps,
+
:check_for_distribution_profile,
- :determine_team_identifier,
- :determine_app_name,
- :determine_app_id,
- :blow_away_temp,
+ :determine_app_version,
+
+ *app_metadata_retrieval_steps,
+
+ :clear_tmp_directory,
:stage_app,
+
:production_write_info_plist,
+
:write_entitlements_plist,
:compile_icons,
- :create_payload_directory,
+ :clear_payload_directory,
+
+ :create_payload_directory_prod,
+
+ :create_payload,
:code_sign_payload,
+
:create_ipa,
:print_publish_help
]
@@ -39242,6 +41082,8 @@ class IOSWizard
@steps = steps_development_build
@steps = steps_production_build if @production_build
@certificate_name = nil
+ @app_version = opts[:version]
+ @app_version = "1.0" if @opts[:env] == :dev && !@app_version
init_wizard_status
log_info "Starting iOS Wizard so we can deploy to your device."
@start_at = Kernel.global_tick_count
@@ -39263,8 +41105,10 @@ class IOSWizard
log "=" * $console.console_text_width
else
log_error e.to_s
+ log e.__backtrace_to_org__
end
+ init_wizard_status
$console.set_command "$wizards.ios.start env: :#{@opts[:env]}"
end
@@ -39371,13 +41215,66 @@ class IOSWizard
return "profiles/development.mobileprovision"
end
+ def ios_metadata_template
+ <<-S
+# ios_metadata.txt is used by the Pro version of DragonRuby Game Toolkit to create iOS apps.
+# Information about the Pro version can be found at: http://dragonruby.org/toolkit/game#purchase
+
+# teamid needs to be set to your assigned Team Id which can be found at https://developer.apple.com/account/#/membership/
+teamid=
+# appid needs to be set to your application identifier which can be found at https://developer.apple.com/account/resources/identifiers/list
+appid=
+# appname is the name you want to show up underneath the app icon on the device. Keep it under 10 characters.
+appname=
+S
+ end
+
+ def ios_metadata
+ contents = $gtk.read_file 'metadata/ios_metadata.txt'
+
+ if !contents
+ $gtk.write_file 'metadata/ios_metadata.txt', ios_metadata_template
+ contents = $gtk.read_file 'metadata/ios_metadata.txt'
+ end
+
+ kvps = contents.each_line
+ .reject { |l| l.strip.length == 0 || (l.strip.start_with? "#") }
+ .map do |l|
+ key, value = l.split("=")
+ [key.strip.to_sym, value.strip]
+ end.flatten
+ Hash[*kvps]
+ end
+
+ def game_metadata
+ contents = $gtk.read_file 'metadata/game_metadata.txt'
+
+ kvps = contents.each_line
+ .reject { |l| l.strip.length == 0 || (l.strip.start_with? "#") }
+ .map do |l|
+ key, value = l.split("=")
+ [key.strip.to_sym, value.strip]
+ end.flatten
+ Hash[*kvps]
+ end
+
+ def raise_ios_metadata_required
+ raise WizardException.new(
+ "* mygame/metadata/ios_metadata.txt needs to be filled out.",
+ "You need to update metadata/ios_metadata.txt with a valid teamid, appname, and appid.",
+ "Instructions for where the values should come from are within metadata/ios_metadata.txt."
+ )
+ end
+
def determine_team_identifier
- @team_name = (team_identifier_from_provisioning_profile @opts[:env])
- log_info "Team Identifer is: #{@team_name}"
+ @team_id = (ios_metadata.teamid || "")
+ raise_ios_metadata_required if @team_id.strip.length == 0
+ log_info "Team Identifer is: #{@team_id}"
end
def determine_app_name
- @app_name = (provisioning_profile_xml @opts[:env])[:children].first[:children].first[:children][1][:children].first[:data]
+ @app_name = (ios_metadata.appname || "")
+ raise_ios_metadata_required if @app_name.strip.length == 0
log_info "App name is: #{@app_name}."
end
@@ -39401,36 +41298,9 @@ class IOSWizard
$gtk.parse_xml scrubbed
end
- def app_id_from_provisioning_profile environment
- application_identifier_index = (provisioning_profile_xml environment)[:children][0][:children][0][:children][13][:children][0][:children][0][:data]
- (provisioning_profile_xml environment)[:children][0][:children][0][:children][13][:children].each.with_index do |node, i|
- if node[:children] && node[:children][0] && node[:children][0][:data] == "application-identifier"
- application_identifier_index = i
- break
- end
- end
-
- app_id_with_team_identifier = (provisioning_profile_xml environment)[:children].first[:children].first[:children][13][:children][application_identifier_index + 1][:children].first[:data]
- team_identifer = team_identifier_from_provisioning_profile environment
- app_id_with_team_identifier.gsub "#{team_identifer}.", ""
- end
-
- def team_identifier_from_provisioning_profile environment
- team_identifer_index = (provisioning_profile_xml environment)[:children][0][:children][0][:children][13][:children][0][:children][0][:data]
-
- (provisioning_profile_xml environment)[:children][0][:children][0][:children][13][:children].each.with_index do |node, i|
- if node[:children] && node[:children][0] && node[:children][0][:data] == "com.apple.developer.team-identifier"
- team_identifer_index = i
- break
- end
- end
-
- (provisioning_profile_xml environment)[:children].first[:children].first[:children][13][:children][team_identifer_index + 1][:children].first[:data]
- end
-
def determine_app_id
- @app_id = app_id_from_provisioning_profile @opts[:env]
-
+ @app_id = ios_metadata.appid
+ raise_ios_metadata_required if @app_id.strip.length == 0
log_info "App Identifier is set to : #{@app_id}"
end
@@ -39449,7 +41319,7 @@ class IOSWizard
end
end
- def blow_away_temp
+ def clear_tmp_directory
sh "rm -rf #{tmp_directory}"
end
@@ -39590,7 +41460,8 @@ XML
log_info "Creating Entitlements.plist"
- $gtk.write_file_root "tmp/ios/Entitlements.plist", entitlement_plist_string.gsub(":app_id", "#{@team_name}.#{@app_id}").strip
+ $gtk.write_file_root "tmp/ios/Entitlements.plist", entitlement_plist_string.gsub(":app_id", "#{@team_id}.#{@app_id}").strip
+ $gtk.write_file_root "tmp/ios/Entitlements.txt", entitlement_plist_string.gsub(":app_id", "#{@team_id}.#{@app_id}").strip
sh "/usr/bin/plutil -convert binary1 \"#{tmp_directory}/Entitlements.plist\""
sh "/usr/bin/plutil -convert xml1 \"#{tmp_directory}/Entitlements.plist\""
@@ -39628,15 +41499,15 @@ XML
<key>CFBundleExecutable</key>
<string>:app_name</string>
<key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
+ <string>:app_version</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>5.6</string>
+ <string>:app_version</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
- <string>5.6</string>
+ <string>:app_version</string>
<key>CFBundleIcons</key>
<dict>
<key>CFBundlePrimaryIcon</key>
@@ -39785,13 +41656,13 @@ XML
<key>CFBundleIdentifier</key>
<string>:app_id</string>
<key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
+ <string>:app_version</string>
<key>CFBundleName</key>
<string>:app_name</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>5.2</string>
+ <string>:app_version</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
@@ -39799,7 +41670,7 @@ XML
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
- <string>5.2</string>
+ <string>:app_version</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
@@ -39885,6 +41756,7 @@ XML
info_plist_string.gsub!(":app_id", @app_id)
$gtk.write_file_root "tmp/ios/#{@app_name}.app/Info.plist", info_plist_string.strip
+ $gtk.write_file_root "tmp/ios/Info.txt", info_plist_string.strip
@info_plist_written = true
end
@@ -39938,13 +41810,13 @@ XML
<key>CFBundleIdentifier</key>
<string>:app_id</string>
<key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
+ <string>:app_version</string>
<key>CFBundleName</key>
<string>:app_name</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>5.2</string>
+ <string>:app_version</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
@@ -39952,7 +41824,7 @@ XML
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
- <string>5.2</string>
+ <string>:app_version</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
@@ -40036,8 +41908,10 @@ XML
info_plist_string.gsub!(":app_name", @app_name)
info_plist_string.gsub!(":app_id", @app_id)
+ info_plist_string.gsub!(":app_version", @app_version)
$gtk.write_file_root "tmp/ios/#{@app_name}.app/Info.plist", info_plist_string.strip
+ $gtk.write_file_root "tmp/ios/Info.txt", info_plist_string.strip
@info_plist_written = true
end
@@ -40059,28 +41933,53 @@ XML
"#{relative_path}/#{$gtk.cli_arguments[:dragonruby]}"
end
- def write_ip_address
+ def embed_mobileprovision
+ sh %Q[cp #{@provisioning_profile_path} "#{app_path}/embedded.mobileprovision"]
+ sh %Q[/usr/bin/plutil -convert binary1 "#{app_path}/Info.plist"]
+ end
+
+ def clear_payload_directory
+ sh %Q[rm "#{@app_name}".ipa]
+ sh %Q[rm -rf "#{app_path}/app"]
+ sh %Q[rm -rf "#{app_path}/sounds"]
+ sh %Q[rm -rf "#{app_path}/sprites"]
+ sh %Q[rm -rf "#{app_path}/data"]
+ sh %Q[rm -rf "#{app_path}/fonts"]
+ end
+
+ def stage_app
+ sh %Q[cp -r "#{root_folder}/app/" "#{app_path}/app/"]
+ sh %Q[cp -r "#{root_folder}/sounds/" "#{app_path}/sounds/"]
+ sh %Q[cp -r "#{root_folder}/sprites/" "#{app_path}/sprites/"]
+ sh %Q[cp -r "#{root_folder}/data/" "#{app_path}/data/"]
+ sh %Q[cp -r "#{root_folder}/fonts/" "#{app_path}/fonts/"]
+ end
+
+ def create_payload
+ sh %Q[mkdir -p #{tmp_directory}/ipa_root/Payload]
+ sh %Q[cp -r "#{app_path}" "#{tmp_directory}/ipa_root/Payload"]
+ sh %Q[chmod -R 755 "#{tmp_directory}/ipa_root/Payload"]
+ end
+
+ def create_payload_directory_dev
+ # write dev machine's ip address for hotloading
$gtk.write_file "app/server_ip_address.txt", $gtk.ffi_misc.get_local_ip_address.strip
+
+ embed_mobileprovision
+ clear_payload_directory
+ stage_app
end
- def create_payload_directory
- sh "cp #{@provisioning_profile_path} \"#{app_path}/embedded.mobileprovision\""
- sh "/usr/bin/plutil -convert binary1 \"#{app_path}/Info.plist\""
- write_ip_address
- sh "rm \"#{@app_name}\".ipa"
- sh "rm -rf \"#{app_path}/app\""
- sh "rm -rf \"#{app_path}/sounds\""
- sh "rm -rf \"#{app_path}/sprites\""
- sh "rm -rf \"#{app_path}/data\""
- sh "rm -rf \"#{app_path}/fonts\""
- sh "cp -r \"#{root_folder}/app/\" \"#{app_path}/app/\""
- sh "cp -r \"#{root_folder}/sounds/\" \"#{app_path}/sounds/\""
- sh "cp -r \"#{root_folder}/sprites/\" \"#{app_path}/sprites/\""
- sh "cp -r \"#{root_folder}/data/\" \"#{app_path}/data/\""
- sh "cp -r \"#{root_folder}/fonts/\" \"#{app_path}/fonts/\""
- sh "mkdir -p #{tmp_directory}/ipa_root/Payload"
- sh "cp -r \"#{app_path}\" \"#{tmp_directory}/ipa_root/Payload\""
- sh "chmod -R 755 \"#{tmp_directory}/ipa_root/Payload\""
+ def create_payload_directory_prod
+ # production builds does not hotload ip address
+ sh %Q[rm "#{root_folder}/app/server_ip_address.txt"]
+
+ embed_mobileprovision
+ stage_app
+
+ # production build marker
+ sh %Q[mkdir -p "#{app_path}/metadata/"]
+ sh %Q[touch metadata/DRAGONRUBY_PRODUCTION_BUILD]
end
def create_ipa
@@ -40113,10 +42012,22 @@ SCRIPT
end
def print_publish_help
- log_info "Go to https://appstoreconnect.apple.com/apps and create an App if you haven't already done so."
- log_info "Go to https://appleid.apple.com and create a 'Application Specific Password'."
- log_info "To upload your app, Download Transporter from the App Store https://apps.apple.com/us/app/transporter/id1450874784?mt=12."
- log_info "Your app is located at ./tmp/ios/#{@app_name}.ipa"
+ has_transporter = (sh "ls /Applications/Transporter.app").include? "Contents"
+ if !has_transporter
+ $gtk.openurl "https://apps.apple.com/us/app/transporter/id1450874784?mt=12"
+ $console.set_command "$wizards.ios.start env: :#{@opts[:env]}, version: \"#{@opts[:version]}\""
+ raise WizardException.new(
+ "* To upload your app, Download Transporter from the App Store https://apps.apple.com/us/app/transporter/id1450874784?mt=12."
+ )
+ else
+ sh "mkdir ./tmp/ios/intermediary_artifacts"
+ sh "mv \"#{tmp_directory}/#{@app_name}.app\" #{tmp_directory}/intermediary_artifacts/"
+ sh "mv \"#{tmp_directory}/do_zip.sh\" #{tmp_directory}/intermediary_artifacts"
+ sh "mv \"#{tmp_directory}/Entitlements.plist\" #{tmp_directory}/intermediary_artifacts"
+ sh "mv \"#{tmp_directory}/ipa_root\" #{tmp_directory}/intermediary_artifacts/"
+ sh "open /Applications/Transporter.app"
+ sh "open ./tmp/ios/"
+ end
end
def compile_icons
@@ -40137,47 +42048,43 @@ S
sh "cp -r \"#{root_folder}/native/\" \"#{app_path}/native/\""
sh "CODESIGN_ALLOCATE=\"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate\" /usr/bin/codesign -f -s \"#{@certificate_name}\" --entitlements #{tmp_directory}/Entitlements.plist \"#{tmp_directory}/#{@app_name}.app/native/ios-device/ext.dylib\""
end
+
+ def set_version version
+ @app_version = version
+ start env: @opts[:env], version: version
+ end
+
+ def app_version
+ log_info "Attempting to retrieve App Version from metadata/ios_metadata.txt."
+ ios_version_number = (ios_metadata.version || "").strip
+ if ios_version_number.length == 0
+ log_info "Not found. Attempting to retrieve App Version from metadata/game_metadata.txt."
+ ios_version_number = (game_metadata.version || "").strip
+ end
+ ios_version_number
+ end
+
+ def determine_app_version
+ @app_version = app_version
+ return if @app_version
+ end
end
</code></pre>
-<h3 id='----itch_wizard.rb'>itch_wizard.rb</h3>
+<h3 id='----itch_wizard-rb'>itch_wizard.rb</h3>
<pre><code class="language-ruby"># ./dragon/itch_wizard.rb
# Copyright 2019 DragonRuby LLC
# MIT License
# itch_wizard.rb has been released under MIT (*only this file*).
-class ItchWizard
+class ItchWizard < Wizard
def steps
[
:check_metadata,
- :deploy
+ :deploy,
]
end
- def metadata_file_path
- "metadata/game_metadata.txt"
- end
-
- def get_metadata
- metadata = $gtk.read_file metadata_file_path
-
- if !metadata
- write_blank_metadata
- metadata = $gtk.read_file metadata_file_path
- end
-
- dev_id, dev_title, game_id, game_title, version, icon = *metadata.each_line.to_a
-
- {
- dev_id: dev_id.strip,
- dev_title: dev_title.strip,
- game_id: game_id.strip,
- game_title: game_title.strip,
- version: version.strip,
- icon: icon.strip
- }
- end
-
def write_blank_metadata
$gtk.write_file metadata_file_path, <<-S.strip
#devid=myname
@@ -40195,7 +42102,7 @@ S
write_blank_metadata
end
- if metadata_text.each_line.to_a.length != 6
+ if metadata_text.strip.each_line.to_a.length < 6
write_blank_metadata
end
@@ -40207,70 +42114,67 @@ S
if metadata[:dev_id].start_with?("#") || !@dev_id
log "* PROMPT: Please provide your username for Itch."
- $console.set_command "$wizards.itch.set_dev_id \"your-itch-username\""
+ $console.set_command "$wizards.itch.set_dev_id \"#{metadata[:dev_id]}\""
return :need_dev_id
end
if metadata[:dev_title].start_with?("#") || !@dev_title
log "* PROMPT: Please provide developer's/company's name that you want displayed."
- $console.set_command "$wizards.itch.set_dev_title \"Your Name\""
+ $console.set_command "$wizards.itch.set_dev_title \"#{metadata[:dev_title]}\""
return :need_dev_title
end
if metadata[:game_id].start_with?("#") || !@game_id
log "* PROMPT: Please provide the id for you game. This is the id you specified when you set up a new game page on Itch."
- $console.set_command "$wizards.itch.set_game_id \"your-game-id\""
+ $console.set_command "$wizards.itch.set_game_id \"#{metadata[:game_id]}\""
return :need_game_id
end
if metadata[:game_title].start_with?("#") || !@game_title
log "* PROMPT: Please provide the display name for your game. (This can include spaces)"
- $console.set_command "$wizards.itch.set_game_title \"Your Game\""
+ $console.set_command "$wizards.itch.set_game_title \"#{metadata[:game_title]}\""
return :need_game_title
end
if metadata[:version].start_with?("#") || !@version
log "* PROMPT: Please provide the version for your game."
- $console.set_command "$wizards.itch.set_version \"1.0\""
+ $console.set_command "$wizards.itch.set_version \"#{metadata[:version]}\""
return :need_version
end
if metadata[:icon].start_with?("#") || !@icon
log "* PROMPT: Please provide icon path for your game."
- $console.set_command "$wizards.itch.set_icon \"icon.png\""
+ $console.set_command "$wizards.itch.set_icon \"#{metadata[:icon]}\""
return :need_icon
end
+ puts "here!! success!!!"
+
return :success
end
def set_dev_id value
@dev_id = value
- write_metadata
start
end
def set_dev_title value
@dev_title = value
- write_metadata
start
end
def set_game_id value
@game_id = value
- write_metadata
start
end
def set_game_title value
@game_title = value
- write_metadata
start
end
def set_version value
@version = value
- write_metadata
start
end
@@ -40313,7 +42217,7 @@ S
end
if @icon
- text += "icon=metadata/#{@icon}\n"
+ text += "icon=#{@icon}\n"
else
text += "#icon=metadata/icon.png\n"
end
@@ -40331,10 +42235,25 @@ S
def deploy
log_info "* Running dragonruby-publish: #{package_command}"
- results = $gtk.exec package_command
+ $gtk.openurl "http://itch.io/dashboard" if $gtk.platform == "Mac OS X"
+ if $gtk.platform? :mac
+ $gtk.exec "rm -rf ./builds"
+ end
+ results = $gtk.exec "#{package_command} --only-package"
+ puts File.expand_path("./builds")
+
log "#+begin_src"
log results
log "#+end_src"
+
+ if $gtk.platform? :mac
+ $gtk.exec "open ./builds/"
+ elsif $gtk.platform? :windows
+ $gtk.exec "powershell \"ii .\""
+ end
+
+ $gtk.openurl "https://itch.io/dashboard"
+
:success
end
@@ -40345,7 +42264,7 @@ S
steps.each do |m|
begin
log_info "Running Itch Wizard Step: ~$wizards.itch.#{m}~"
- result = (send m) || :success if @wizard_status[m][:result] != :success
+ result = (send m) || :success
@wizard_status[m][:result] = result
if result != :success
log_info "Exiting wizard. :#{result}"
@@ -40412,7 +42331,7 @@ S
end
</code></pre>
-<h3 id='----layout.rb'>layout.rb</h3>
+<h3 id='----layout-rb'>layout.rb</h3>
<pre><code class="language-ruby"># ./dragon/layout.rb
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -40692,10 +42611,18 @@ module GTK
device.grid_area.row_count
end
+ def row_max_index
+ row_count - 1
+ end
+
def col_count
device.grid_area.col_count
end
+ def col_max_index
+ col_count - 1
+ end
+
def gutter_height
device.grid_area.gutter
end
@@ -40718,18 +42645,124 @@ module GTK
def rect_defaults
{
- row: nil,
- col: nil,
- h: 1,
- w: 1,
- dx: 0,
- dy: 0,
- rect: :control_rect
+ row: nil,
+ col: nil,
+ h: 1,
+ w: 1,
+ dx: 0,
+ dx_ratio: 1,
+ dy: 0,
+ dy_ratio: 1,
+ dh_ratio: 1,
+ dw_ratio: 1,
+ merge: nil,
+ rect: :control_rect
}
end
- def rect opts
+ def row n
+ (rect row: n, col: 0, w: 0, h: 0).x
+ end
+
+ def row_from_bottom n
+ (rect row: row_count - n, col: 0, w: 0, h: 0).x
+ end
+
+ def col n
+ (rect row: 0, col: n, w: 0, h: 0).y
+ end
+
+ def col_from_right n
+ (rect row: 0, col: col_max_index - n, w: 0, h: 0).y
+ end
+
+ def w n
+ (rect row: 0, col: 0, w: n, h: 1).w
+ end
+
+ def h n
+ (rect row: 0, col: 0, w: 1, h: n).h
+ end
+
+ def rect_group opts
+ group = opts.group
+ r = opts.row || 0
+ r = row_max_index - opts.row_from_bottom if opts.row_from_bottom
+ c = opts.col || 0
+ c = col_max_index - opts.col_from_right if opts.col_from_right
+ drow = opts.drow || 0
+ dcol = opts.dcol || 0
+ w = opts.w || 0
+ h = opts.h || 0
+ merge = opts[:merge]
+
+ running_row = r
+ running_col = c
+
+ running_col = calc_col_offset(opts.col_offset) if opts.col_offset
+ running_row = calc_row_offset(opts.row_offset) if opts.row_offset
+
+ group.map do |i|
+ group_layout_opts = i.layout || {}
+ group_layout_opts = group_layout_opts.merge row: running_row,
+ col: running_col,
+ merge: merge,
+ w: w, h: h
+ result = (rect group_layout_opts).merge i
+
+ if (i.is_a? Hash) && (i.primitive_marker == :label)
+ if i.alignment_enum == 1
+ result.x += result.w.half
+ elsif i.alignment_enum == 2
+ result.x += result.w
+ end
+ end
+
+ running_row += drow
+ running_col += dcol
+ result
+ end
+ end
+
+ def calc_row_offset opts = {}
+ count = opts[:count] || opts[:length] || 0
+ h = opts.h || 1
+ (row_count - (count * h)) / 2.0
+ end
+
+ def calc_col_offset opts = {}
+ count = opts[:count] || opts[:length] || 0
+ w = opts.w || 1
+ (col_count - (count * w)) / 2.0
+ end
+
+ def point opts = {}
+ opts.w = 1
+ opts.h = 1
+ opts.row ||= 0
+ opts.col ||= 0
+ r = rect opts
+ r.x += r.w * opts.col_anchor if opts.col_anchor
+ r.y += r.h * opts.row_anchor if opts.row_anchor
+ r
+ end
+
+ def rect *all_opts
+ if all_opts.length == 1
+ opts = all_opts.first
+ else
+ opts = {}
+ all_opts.each do |o|
+ opts.merge! o
+ end
+ end
+
+ opts.row = row_max_index - opts.row_from_bottom if opts.row_from_bottom
+ opts.col = col_max_index - opts.col_from_right if opts.col_from_right
opts = rect_defaults.merge opts
+ opts.row ||= 0
+ opts.col ||= 0
+
result = send opts[:rect]
if opts[:row] && opts[:col] && opts[:w] && opts[:h]
col = rect_col opts[:col], opts[:w]
@@ -40737,7 +42770,9 @@ module GTK
result = control_rect.merge x: col.x,
y: row.y,
w: col.w,
- h: row.h
+ h: row.h,
+ center_x: col.center_x,
+ center_y: row.center_y
elsif opts[:row] && !opts[:col]
result = rect_row opts[:row], opts[:h]
elsif !opts[:row] && opts[:col]
@@ -40775,13 +42810,21 @@ module GTK
result[:h] += device.grid_area.gutter * 2
end
- result[:x] += opts[:dx] if opts[:dx]
- result[:y] += opts[:dy] if opts[:dy]
- result[:w] += opts[:dw] if opts[:dw]
- result[:h] += opts[:dh] if opts[:dh]
+ result[:x] += opts[:dx] if opts[:dx]
+ result[:x] *= opts[:dx_ratio] if opts[:dx_ratio]
+ result[:y] += opts[:dy] if opts[:dy]
+ result[:y] *= opts[:dy_ratio] if opts[:dy_ratio]
+ result[:w] += opts[:dw] if opts[:dw]
+ result[:w] *= opts[:dw_ratio] if opts[:dw_ratio]
+ result[:h] += opts[:dh] if opts[:dh]
+ result[:h] *= opts[:dh_ratio] if opts[:dh_ratio]
+ result.merge! opts[:merge] if opts[:merge]
result[:row] = opts[:row]
result[:col] = opts[:col]
+ result[:h] = result[:h].clamp 0
+ result[:w] = result[:w].clamp 0
+
if $gtk.args.grid.name == :center
result[:x] -= 640
result[:y] -= 360
@@ -40816,7 +42859,7 @@ module GTK
row_y = device.h - row_y - row_h
- result = control_rect.merge y: row_y, h: row_h
+ result = control_rect.merge y: row_y, h: row_h, center_y: (row_y + row_h.half)
@rect_cache[:row][index][h] = result
@rect_cache[:row][index][h]
end
@@ -40839,7 +42882,7 @@ module GTK
col_w = col_w.to_i
col_w -= 1 if col_w.odd?
- result = control_rect.merge x: col_x, w: col_w
+ result = control_rect.merge x: col_x, w: col_w, center_x: (col_x + col_w.half)
@rect_cache[:col][index][w] = result
@rect_cache[:col][index][w]
end
@@ -40890,6 +42933,26 @@ module GTK
@device
end
+ def debug_primitives opts = {}
+ @primitives ||= col_count.map_with_index do |col|
+ row_count.map_with_index do |row|
+ cell = rect row: row, col: col
+ center = Geometry.rect_center_point cell
+ [
+ cell.merge(opts).border,
+ cell.merge(opts)
+ .label!(x: center.x,
+ y: center.y,
+ text: "#{row},#{col}",
+ size_enum: -3,
+ vertical_alignment_enum: 1,
+ alignment_enum: 1)
+ ]
+ end
+ end
+ @primitives
+ end
+
def serialize
{
device: @device.serialize,
@@ -40903,11 +42966,18 @@ module GTK
def to_s
serialize.to_s
end
+
+ def reset
+ @primitives = nil
+ @rect_cache ||= {}
+ @rect_cache.clear
+ end
+
end
end
</code></pre>
-<h3 id='----log.rb'>log.rb</h3>
+<h3 id='----log-rb'>log.rb</h3>
<pre><code class="language-ruby"># ./dragon/log.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -41040,6 +43110,11 @@ module GTK
self.puts message
end
+ def self.reset
+ @once = {}
+ nil
+ end
+
def self.puts_once *ids, message
id = "#{ids}"
@once ||= {}
@@ -41175,7 +43250,52 @@ class Object
end
</code></pre>
-<h3 id='----numeric.rb'>numeric.rb</h3>
+<h3 id='----metadata-rb'>metadata.rb</h3>
+<pre><code class="language-ruby"># ./dragon/metadata.rb
+# Contributors outside of DragonRuby who also hold Copyright: Michał Dudziński
+# Copyright 2021 DragonRuby LLC
+# MIT License
+# metadata.rb has been released under MIT (*only this file*).
+
+module Metadata
+ def metadata_file_path
+ "metadata/game_metadata.txt"
+ end
+
+ def get_metadata
+ metadata = $gtk.read_file metadata_file_path
+
+ if !metadata
+ write_blank_metadata
+ metadata = $gtk.read_file metadata_file_path
+ end
+
+ dev_id, dev_title, game_id, game_title, version, icon = *metadata.each_line.to_a
+
+ {
+ dev_id: dev_id.strip,
+ dev_title: dev_title.strip,
+ game_id: game_id.strip,
+ game_title: game_title.strip,
+ version: version.strip,
+ icon: icon.strip
+ }
+ end
+
+ def write_blank_metadata
+ $gtk.write_file metadata_file_path, <<-S.strip
+#devid=myname
+#devtitle=My Name
+#gameid=mygame
+#gametitle=My Game
+#version=0.1
+#icon=metadata/icon.png
+S
+ end
+end
+
+</code></pre>
+<h3 id='----numeric-rb'>numeric.rb</h3>
<pre><code class="language-ruby"># ./dragon/numeric.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -41192,6 +43312,35 @@ class Numeric
alias_method :lte, :<=
alias_method :__original_eq_eq__, :== unless Numeric.instance_methods.include? :__original_eq_eq__
+ def to_layout_row opts = {}
+ $layout.rect(row: self,
+ col: opts.col || 0,
+ w: opts.w || 0,
+ h: opts.h || 0).y
+ end
+
+ def to_layout_col opts = {}
+ $layout.rect(row: 0,
+ col: self,
+ w: opts.w || 0,
+ h: opts.h || 0).x
+ end
+
+ def to_layout_w
+ $layout.rect(row: 0, col: 0, w: self, h: 1).w
+ end
+
+ def to_layout_h
+ $layout.rect(row: 0, col: 0, w: 1, h: self).h
+ end
+
+ def to_layout_row_from_bottom opts = {}
+ ($layout.row_max_index - self).to_layout_row opts
+ end
+
+ def to_layout_col_from_right opts = {}
+ ($layout.col_max_index - self).to_layout_col opts
+ end
# Converts a numeric value representing seconds into frames.
#
@@ -41207,10 +43356,26 @@ class Numeric
self / 2.0
end
+ def third
+ self / 3.0
+ end
+
+ def quarter
+ self / 4.0
+ end
+
def to_byte
clamp(0, 255).to_i
end
+ def clamp *opts
+ min = (opts.at 0)
+ max = (opts.at 1)
+ return min if min && self < min
+ return max if max && self > max
+ return self
+ end
+
def clamp_wrap min, max
max, min = min, max if min > max
return self if self >= min && self <= max
@@ -41435,7 +43600,7 @@ S
self * Math::PI.fdiv(180)
end
- # Converts a number representing an angle in radians to degress.
+ # Converts a number representing an angle in radians to degrees.
#
# @gtk
def to_degrees
@@ -41452,21 +43617,21 @@ S
GTK::Geometry.to_square(self, x, y, anchor_x, anchor_y)
end
- # Returns a normal vector for a number that represents an angle in degress.
+ # Returns a normal vector for a number that represents an angle in degrees.
#
# @gtk
def vector max_value = 1
[vector_x(max_value), vector_y(max_value)]
end
- # Returns the y component of a normal vector for a number that represents an angle in degress.
+ # Returns the y component of a normal vector for a number that represents an angle in degrees.
#
# @gtk
def vector_y max_value = 1
max_value * Math.sin(self.to_radians)
end
- # Returns the x component of a normal vector for a number that represents an angle in degress.
+ # Returns the x component of a normal vector for a number that represents an angle in degrees.
#
# @gtk
def vector_x max_value = 1
@@ -41493,6 +43658,18 @@ S
(self % n) == 0
end
+ def multiply n
+ self * n
+ end
+
+ def fmult n
+ self * n.to_f
+ end
+
+ def imult n
+ (self * n).to_i
+ end
+
def mult n
self * n
end
@@ -41614,12 +43791,6 @@ S
return gt other
end
- def == other
- return true if __original_eq_eq__ other
- return __original_eq_eq__ other.entity_id if other.is_a? OpenEntity
- return false
- end
-
# @gtk
def map
unless block_given?
@@ -41706,29 +43877,29 @@ S
end
def - other
- return nil unless other
- super
+ return self unless other
+ self - other
rescue Exception => e
__raise_arithmetic_exception__ other, :-, e
end
def + other
- return nil unless other
- super
+ return self unless other
+ self + other
rescue Exception => e
__raise_arithmetic_exception__ other, :+, e
end
def * other
- return nil unless other
- super
+ return self unless other
+ self * other
rescue Exception => e
__raise_arithmetic_exception__ other, :*, e
end
def / other
- return nil unless other
- super
+ return self unless other
+ self / other
rescue Exception => e
__raise_arithmetic_exception__ other, :/, e
end
@@ -41758,6 +43929,10 @@ S
def self.clamp n, min, max
n.clamp min, max
end
+
+ def mid? l, r
+ (between? l, r) || (between? r, l)
+ end
end
class Fixnum
@@ -41784,39 +43959,33 @@ class Fixnum
end
def + other
- return nil unless other
- super
+ return self unless other
+ self + other
rescue Exception => e
__raise_arithmetic_exception__ other, :+, e
end
def * other
- return nil unless other
- super
+ return self unless other
+ self * other
rescue Exception => e
__raise_arithmetic_exception__ other, :*, e
end
def / other
- return nil unless other
- super
+ return self unless other
+ self / other
rescue Exception => e
__raise_arithmetic_exception__ other, :/, e
end
def - other
- return nil unless other
- super
+ return self unless other
+ self - other
rescue Exception => e
__raise_arithmetic_exception__ other, :-, e
end
- def == other
- return true if __original_eq_eq__ other
- return __original_eq_eq__ other.entity_id if other.is_a? GTK::OpenEntity
- return false
- end
-
# Returns `-1` if the number is less than `0`. `+1` if the number
# is greater than `0`. Returns `0` if the number is equal to `0`.
#
@@ -41873,28 +44042,28 @@ class Float
alias_method :__original_divide__, :- unless Float.instance_methods.include? :__original_divide__
def - other
- return nil unless other
+ return self unless other
super
rescue Exception => e
__raise_arithmetic_exception__ other, :-, e
end
def + other
- return nil unless other
+ return self unless other
super
rescue Exception => e
__raise_arithmetic_exception__ other, :+, e
end
def * other
- return nil unless other
+ return self unless other
super
rescue Exception => e
__raise_arithmetic_exception__ other, :*, e
end
def / other
- return nil unless other
+ return self unless other
super
rescue Exception => e
__raise_arithmetic_exception__ other, :/, e
@@ -41941,10 +44110,14 @@ class Integer
def nan?
false
end
+
+ def center other
+ (self - other).abs.fdiv(2)
+ end
end
</code></pre>
-<h3 id='----remote_hotload_client.rb'>remote_hotload_client.rb</h3>
+<h3 id='----remote_hotload_client-rb'>remote_hotload_client.rb</h3>
<pre><code class="language-ruby"># ./dragon/remote_hotload_client.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -41995,7 +44168,7 @@ module GTK
def local_state
@local_state ||= OpenEntity.new
@local_state.hotload_client ||= @local_state.new_entity(:hotload_client,
- notes: "This enitity is used by DragonRuby Game Toolkit to provide you hotloading on remote machines.",
+ notes: "This entity is used by DragonRuby Game Toolkit to provide you hotloading on remote machines.",
changes: { },
changes_queue: [],
reloaded_files_times: [])
@@ -42141,7 +44314,7 @@ module GTK
end
</code></pre>
-<h3 id='----runtime/autocomplete.rb'>runtime/autocomplete.rb</h3>
+<h3 id='----runtime/autocomplete-rb'>runtime/autocomplete.rb</h3>
<pre><code class="language-ruby"># ./dragon/runtime/autocomplete.rb
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -42169,7 +44342,7 @@ module GTK
sub_index = index - previous_line[:sum]
word = (cursor_line[:line][0..sub_index - 1]).strip
token = (word.split " ")[-1]
- dots = (token.split ".")
+ dots = (token.split ".").flat_map { |s| s.split "[" }.flat_map { |s| s.split "]" }.flat_map { |s| s.split "(" }.flat_map { |s| s.split ")" }
dot = dots[-1]
end
@@ -42190,6 +44363,10 @@ module GTK
ignores ||= []
ignores = [ignores].flatten
keys = keys.map { |k| k.to_s }
+ keys = keys.reject { |k| k.include? '"' }
+ .reject { |k| k.start_with? "'" }
+ .reject { |k| k.include? "," }
+ .reject { |k| k.start_with? "#" }
others = ["def", "end"] +
[ :entity_keys_by_ref,
:entity_name,
@@ -42247,6 +44424,10 @@ module GTK
return autocomplete_filter_methods lookup_result.call if lookup_result
+ if dot[0].upcase == dot[0] && (Object.const_defined? dot.to_sym)
+ return (Object.const_get dot.to_sym).autocomplete_methods
+ end
+
start_collecting = false
dots_after_state = dots.find_all do |s|
if s == "state"
@@ -42262,10 +44443,16 @@ module GTK
target = target.as_hash[k.to_sym] if target.respond_to? :as_hash
end
- return autocomplete_filter_methods target.as_hash.keys
+ if target.respond_to? :as_hash
+ return autocomplete_filter_methods target.as_hash.keys
+ else
+ return autocomplete_filter_methods target.autocomplete_methods
+ end
end
+ text = text.each_line.reject { |l| l.strip.start_with? "#" }.join "\n"
+ text = text.each_line.map { |l| l.split("#").first }.join "\n"
text.gsub!("[", " ")
text.gsub!("]", " ")
text.gsub!("(", " ")
@@ -42281,153 +44468,155 @@ module GTK
end # end GTK
</code></pre>
-<h3 id='----runtime/draw.rb'>runtime/draw.rb</h3>
-<pre><code class="language-ruby"># ./dragon/runtime/draw.rb
+<h3 id='----runtime/benchmark-rb'>runtime/benchmark.rb</h3>
+<pre><code class="language-ruby"># ./dragon/runtime/benchmark.rb
# Copyright 2019 DragonRuby LLC
# MIT License
-# draw.rb has been released under MIT (*only this file*).
+# benchmark.rb has been released under MIT (*only this file*).
module GTK
class Runtime
- module Draw
- def primitives pass
- if $top_level.respond_to? :primitives_override
- return $top_level.tick_render @args, pass
- end
-
- # Don't change this draw order unless you understand
- # the implications.
-
- # pass.solids.each { |s| draw_solid s }
- # while loops are faster than each with block
+ module Benchmark
+ def benchmark_single iterations, name, proc
+ log <<-S
+** Invoking :#{name}...
+S
+ time_start = Time.now
idx = 0
- length = pass.solids.length
- while idx < pass.solids.length
- draw_solid (pass.solids.at idx) # accessing an array using .value instead of [] is faster
+ r = nil
+ while idx < iterations
+ r = proc.call
idx += 1
end
- # pass.static_solids.each { |s| draw_solid s }
- idx = 0
- length = pass.static_solids.length
- while idx < length
- draw_solid (pass.static_solids.at idx)
- idx += 1
- end
+ result = (Time.now - time_start).round 3
- # pass.sprites.each { |s| draw_sprite s }
- idx = 0
- length = pass.sprites.length
- while idx < length
- draw_sprite (pass.sprites.at idx)
- idx += 1
- end
+ { name: name,
+ time: result,
+ time_ms: (result * 1000).to_i }
+ end
- # pass.static_sprites.each { |s| draw_sprite s }
- idx = 0
- length = pass.static_sprites.length
- while idx < length
- draw_sprite (pass.static_sprites.at idx)
- idx += 1
- end
+ def benchmark opts = {}
+ iterations = opts.iterations
- # pass.primitives.each { |p| draw_primitive p }
- idx = 0
- length = pass.primitives.length
- while idx < length
- draw_primitive (pass.primitives.at idx)
- idx += 1
- end
+ log <<-S
+* BENCHMARK: Started
+** Caller: #{(caller || []).first}
+** Iterations: #{iterations}
+S
+ procs = opts.find_all { |k, v| v.respond_to? :call }
+
+ times = procs.map do |(name, proc)|
+ benchmark_single iterations, name, proc
+ end.sort_by { |r| r.time }
+
+ first_place = times.first
+ second_place = times.second || first_place
+
+ times = times.map do |candidate|
+ average_time = first_place.time
+ .add(candidate.time)
+ .abs
+ .fdiv(2)
+
+ difference_percentage = 0
+ if average_time == 0
+ difference_percentage = 0
+ else
+ difference_percentage = first_place.time
+ .subtract(candidate.time)
+ .abs
+ .fdiv(average_time)
+ .imult(100)
+ end
- # pass.static_primitives.each { |p| draw_primitive p }
- idx = 0
- length = pass.static_primitives.length
- while idx < length
- draw_primitive (pass.static_primitives.at idx)
- idx += 1
+ difference_time = ((first_place.time - candidate.time) * 1000).round
+ candidate.merge(difference_percentage: difference_percentage,
+ difference_time: difference_time)
end
- # pass.labels.each { |l| draw_label l }
- idx = 0
- length = pass.labels.length
- while idx < length
- draw_label (pass.labels.at idx)
- idx += 1
+ too_small_to_measure = false
+ if (first_place.time + second_place.time) == 0
+ too_small_to_measure = true
+ difference_percentage = 0
+ log <<-S
+* BENCHMARK: Average time for experiments were too small. Increase the number of iterations.
+S
+ else
+ difference_percentage = (((first_place.time - second_place.time).abs.fdiv((first_place.time + second_place.time).abs.fdiv(2))) * 100).round
end
- # pass.static_labels.each { |l| draw_label l }
- idx = 0
- length = pass.static_labels.length
- while idx < length
- draw_label (pass.static_labels.at idx)
- idx += 1
- end
+ difference_time = first_place.time.-(second_place.time).*(1000).abs.round
- # pass.lines.each { |l| draw_line l }
- idx = 0
- length = pass.lines.length
- while idx < length
- draw_line (pass.lines.at idx)
- idx += 1
- end
+ r = {
+ iterations: iterations,
+ first_place: first_place,
+ second_place: second_place,
+ difference_time: difference_time,
+ difference_percentage: difference_percentage,
+ times: times,
+ too_small_to_measure: too_small_to_measure
+ }
- # pass.static_lines.each { |l| draw_line l }
- idx = 0
- length = pass.static_lines.length
- while idx < pass.static_lines.length
- draw_line (pass.static_lines.at idx)
- idx += 1
- end
+ log_message = []
+ only_one_result = first_place.name == second_place.name
- # pass.borders.each { |b| draw_border b }
- idx = 0
- length = pass.borders.length
- while idx < length
- draw_border (pass.borders.at idx)
- idx += 1
+ if only_one_result
+ log <<-S
+* BENCHMARK: #{r.first_place.name} completed in #{r.first_place.time_ms}ms."
+S
+ else
+ log <<-S
+* BENCHMARK: #{r.message}
+** Fastest: #{r.first_place.name.inspect}
+** Second: #{r.second_place.name.inspect}
+** Margin: #{r.difference_percentage}% (#{r.difference_time.abs}ms) #{r.first_place.time_ms}ms vs #{r.second_place.time_ms}ms.
+** Times:
+#{r.times.map { |t| "*** #{t.name}: #{t.time_ms}ms (#{t.difference_percentage}% #{t.difference_time.abs}ms)." }.join("\n")}
+S
end
- # pass.static_borders.each { |b| draw_border b }
- idx = 0
- length = pass.static_borders.length
- while idx < length
- draw_border (pass.static_borders.at idx)
- idx += 1
- end
+ r
+ end
+ end
+ end
+end
- if !$gtk.production
- # pass.debug.each { |r| draw_primitive r }
- idx = 0
- length = pass.debug.length
- while idx < length
- draw_primitive (pass.debug.at idx)
- idx += 1
- end
+</code></pre>
+<h3 id='----runtime/draw-rb'>runtime/draw.rb</h3>
+<pre><code class="language-ruby"># ./dragon/runtime/draw.rb
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# draw.rb has been released under MIT (*only this file*).
- # pass.static_debug.each { |r| draw_primitive r }
- idx = 0
- length = pass.static_debug.length
- while idx < length
- draw_primitive (pass.static_debug.at idx)
- idx += 1
- end
+module GTK
+ class Runtime
+ module Draw
+ def primitives pass
+ if $top_level.respond_to? :primitives_override
+ return $top_level.tick_render @args, pass
end
- # pass.reserved.each { |r| draw_primitive r }
- idx = 0
- length = pass.reserved.length
- while idx < length
- draw_primitive (pass.reserved.at idx)
- idx += 1
- end
+ fn.each_send pass.solids, self, :draw_solid
+ fn.each_send pass.static_solids, self, :draw_solid
+ fn.each_send pass.sprites, self, :draw_sprite
+ fn.each_send pass.static_sprites, self, :draw_sprite
+ fn.each_send pass.primitives, self, :draw_primitive
+ fn.each_send pass.static_primitives, self, :draw_primitive
+ fn.each_send pass.labels, self, :draw_label
+ fn.each_send pass.static_labels, self, :draw_label
+ fn.each_send pass.lines, self, :draw_line
+ fn.each_send pass.static_lines, self, :draw_line
+ fn.each_send pass.borders, self, :draw_border
+ fn.each_send pass.static_borders, self, :draw_border
- # pass.static_reserved.each { |r| draw_primitive r }
- idx = 0
- length = pass.static_reserved.length
- while idx < length
- draw_primitive (pass.static_reserved.at idx)
- idx += 1
+ if !$gtk.production
+ fn.each_send pass.debug, self, :draw_primitive
+ fn.each_send pass.static_debug, self, :draw_primitive
end
+
+ fn.each_send pass.reserved, self, :draw_primitive
+ fn.each_send pass.static_reserved, self, :draw_primitive
rescue Exception => e
pause!
pretty_print_exception_and_export! e
@@ -42438,7 +44627,9 @@ module GTK
if s.respond_to? :draw_override
s.draw_override @ffi_draw
else
- @ffi_draw.draw_solid s.x, s.y, s.w, s.h, s.r, s.g, s.b, s.a
+ @ffi_draw.draw_solid_2 s.x, s.y, s.w, s.h,
+ s.r, s.g, s.b, s.a,
+ (s.blendmode_enum || 1)
end
rescue Exception => e
raise_conversion_for_rendering_failed s, e, :solid
@@ -42449,14 +44640,15 @@ module GTK
if s.respond_to? :draw_override
s.draw_override @ffi_draw
else
- @ffi_draw.draw_sprite_3 s.x, s.y, s.w, s.h,
- s.path.s_or_default,
+ @ffi_draw.draw_sprite_4 s.x, s.y, s.w, s.h,
+ (s.path || '').to_s,
s.angle,
s.a, s.r, s.g, s.b,
s.tile_x, s.tile_y, s.tile_w, s.tile_h,
!!s.flip_horizontally, !!s.flip_vertically,
s.angle_anchor_x, s.angle_anchor_y,
- s.source_x, s.source_y, s.source_w, s.source_h
+ s.source_x, s.source_y, s.source_w, s.source_h,
+ (s.blendmode_enum || 1)
end
rescue Exception => e
raise_conversion_for_rendering_failed s, e, :sprite
@@ -42467,7 +44659,7 @@ module GTK
if s.respond_to? :draw_override
s.draw_override @ffi_draw
else
- @ffi_draw.draw_screenshot s.path.s_or_default,
+ @ffi_draw.draw_screenshot (s.path || '').to_s,
s.x, s.y, s.w, s.h,
s.angle,
s.a, s.r, s.g, s.b,
@@ -42485,10 +44677,13 @@ module GTK
if l.respond_to? :draw_override
l.draw_override @ffi_draw
else
- @ffi_draw.draw_label l.x, l.y, l.text.s_or_default,
- l.size_enum, l.alignment_enum,
- l.r, l.g, l.b, l.a,
- l.font.s_or_default(nil)
+ @ffi_draw.draw_label_3 l.x, l.y,
+ (l.text || '').to_s,
+ l.size_enum, l.alignment_enum,
+ l.r, l.g, l.b, l.a,
+ l.font,
+ (l.vertical_alignment_enum || 2),
+ (l.blendmode_enum || 1)
end
rescue Exception => e
raise_conversion_for_rendering_failed l, e, :label
@@ -42499,7 +44694,21 @@ module GTK
if l.respond_to? :draw_override
l.draw_override @ffi_draw
else
- @ffi_draw.draw_line l.x, l.y, l.x2, l.y2, l.r, l.g, l.b, l.a
+ if l.x2
+ @ffi_draw.draw_line_2 l.x, l.y, l.x2, l.y2,
+ l.r, l.g, l.b, l.a,
+ (l.blendmode_enum || 1)
+ else
+ w = l.w || 0
+ w = 1 if w == 0
+ h = l.h || 0
+ h = 1 if h == 0
+ @ffi_draw.draw_line_2 l.x, l.y,
+ l.x + w - 1,
+ l.y + h - 1,
+ l.r, l.g, l.b, l.a,
+ (l.blendmode_enum || 1)
+ end
end
rescue Exception => e
raise_conversion_for_rendering_failed l, e, :line
@@ -42510,7 +44719,9 @@ module GTK
if s.respond_to? :draw_override
s.draw_override @ffi_draw
else
- @ffi_draw.draw_border s.x, s.y, s.w, s.h, s.r, s.g, s.b, s.a
+ @ffi_draw.draw_border_2 s.x, s.y, s.w, s.h,
+ s.r, s.g, s.b, s.a,
+ (s.blendmode_enum || 1)
end
rescue Exception => e
raise_conversion_for_rendering_failed s, e, :border
@@ -42530,13 +44741,12 @@ module GTK
pause!
pretty_print_exception_and_export! e
end
-
end
end
end
</code></pre>
-<h3 id='----runtime/framerate.rb'>runtime/framerate.rb</h3>
+<h3 id='----runtime/framerate-rb'>runtime/framerate.rb</h3>
<pre><code class="language-ruby"># ./dragon/runtime/framerate.rb
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -42623,7 +44833,7 @@ module GTK
end # end module GTK
</code></pre>
-<h3 id='----runtime/framerate_diagnostics.rb'>runtime/framerate_diagnostics.rb</h3>
+<h3 id='----runtime/framerate_diagnostics-rb'>runtime/framerate_diagnostics.rb</h3>
<pre><code class="language-ruby"># ./dragon/runtime/framerate_diagnostics.rb
# Copyright 2019 DragonRuby LLC
# MIT License
@@ -42742,7 +44952,7 @@ If this warning is getting annoying put the following in your tick method:
def framerate_diagnostics_primitives
[
- { x: 0, y: 93.from_top, w: 500, h: 93, a: 128 }.solid,
+ { x: 0, y: 93.from_top, w: 500, h: 93, a: 128 }.solid!,
{
x: 5,
y: 5.from_top,
@@ -42751,7 +44961,7 @@ If this warning is getting annoying put the following in your tick method:
g: 255,
b: 255,
size_enum: -2
- }.label,
+ }.label!,
{
x: 5,
y: 20.from_top,
@@ -42760,7 +44970,7 @@ If this warning is getting annoying put the following in your tick method:
g: 255,
b: 255,
size_enum: -2
- }.label,
+ }.label!,
{
x: 5,
y: 35.from_top,
@@ -42769,7 +44979,7 @@ If this warning is getting annoying put the following in your tick method:
g: 255,
b: 255,
size_enum: -2
- }.label,
+ }.label!,
{
x: 5,
y: 50.from_top,
@@ -42778,7 +44988,7 @@ If this warning is getting annoying put the following in your tick method:
g: 255,
b: 255,
size_enum: -2
- }.label,
+ }.label!,
{
x: 5,
y: 65.from_top,
@@ -42787,7 +44997,7 @@ If this warning is getting annoying put the following in your tick method:
g: 255,
b: 255,
size_enum: -2
- }.label,
+ }.label!,
]
end
@@ -42796,7 +45006,7 @@ If this warning is getting annoying put the following in your tick method:
end
</code></pre>
-<h3 id='----runtime/hotload.rb'>runtime/hotload.rb</h3>
+<h3 id='----runtime/hotload-rb'>runtime/hotload.rb</h3>
<pre><code class="language-ruby"># ./dragon/runtime/hotload.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -42810,7 +45020,14 @@ module GTK
def hotload_init
@hotload_if_needed = 0
@mailbox_if_needed = 0
+
+ # schema for file_mtimes
+ # { FILE_PATH: { current: (Time as Fixnum),
+ # last: (Time as Fixnum) },
+ # FILE_PATH: { current: (Time as Fixnum),
+ # last: (Time as Fixnum) } }
@file_mtimes = { }
+
@suppress_mailbox = true
files_to_reload.each { |f| init_mtimes f }
init_mtimes 'app/mailbox.rb'
@@ -42848,6 +45065,7 @@ module GTK
'dragon/symbol.rb',
'dragon/numeric_deprecated.rb',
'dragon/numeric.rb',
+ 'dragon/hash_deprecated.rb',
'dragon/hash.rb',
'dragon/outputs_deprecated.rb',
'dragon/array_docs.rb',
@@ -42880,6 +45098,7 @@ module GTK
'dragon/trace.rb',
'dragon/readme_docs.rb',
'dragon/hotload_client.rb',
+ 'dragon/wizards.rb',
'dragon/ios_wizard.rb',
'dragon/itch_wizard.rb',
] + core_files_to_reload + @required_files
@@ -42898,10 +45117,8 @@ module GTK
end
def init_mtimes file
- current_key = "current_#{file}".to_sym
- last_key = "last_#{file}".to_sym
- @file_mtimes[current_key] ||= @ffi_file.mtime(file)
- @file_mtimes[last_key] ||= @ffi_file.mtime(file)
+ @file_mtimes[file] ||= { current: @ffi_file.mtime(file),
+ last: @ffi_file.mtime(file) }
end
def hotload_source_files
@@ -42933,32 +45150,43 @@ module GTK
end
def hotload_if_needed
+ return if Kernel.tick_count < 0
hotload_source_files
check_mailbox
end
def on_load_succeeded file
- @rcb_sender.files_reloaded << file
- @rcb_sender.reloaded_files << file
+ self.files_reloaded << file
+ self.reloaded_files << file
Trace.untrace_classes!
end
+ def reset_all_mtimes
+ @file_mtimes.each do |file, _|
+ @file_mtimes[file].current = @ffi_file.mtime(file)
+ @file_mtimes[file].last = @file_mtimes[file].current
+ end
+
+ files_to_reload.each do |file, _|
+ @file_mtimes[file] ||= {}
+ @file_mtimes[file].current = @ffi_file.mtime(file)
+ @file_mtimes[file].last = @file_mtimes[file].current
+ end
+ end
+
def reload_if_needed file, force = false
- current_key = "current_#{file}".to_sym
- last_key = "last_#{file}".to_sym
- @file_mtimes[current_key] ||= nil
- @file_mtimes[last_key] ||= nil
- @file_mtimes[current_key] = @ffi_file.mtime(file)
- return if !force && @file_mtimes[last_key] == @file_mtimes[current_key]
+ @file_mtimes[file] ||= { current: @ffi_file.mtime(file), last: @ffi_file.mtime(file) }
+ @file_mtimes[file].current = @ffi_file.mtime(file)
+ return if !force && @file_mtimes[file].current == @file_mtimes[file].last
on_load_succeeded file if reload_ruby_file file
- @file_mtimes[last_key] = @file_mtimes[current_key]
+ @file_mtimes[file].last = @file_mtimes[file].current
end
end
end
end
</code></pre>
-<h3 id='----string.rb'>string.rb</h3>
+<h3 id='----string-rb'>string.rb</h3>
<pre><code class="language-ruby"># ./dragon/string.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -42991,6 +45219,30 @@ S
end
end
+ def char_byte
+ return nil if self.length == 0
+ c = self.each_char.first.bytes
+ c = c.first if c.is_a? Enumerable
+ c
+ end
+
+ def insert_character_at index, char
+ t = each_char.to_a
+ t = (t.insert index, char)
+ t.join
+ end
+
+ def excluding_character_at index
+ t = each_char.to_a
+ t.delete_at index
+ t.join
+ end
+
+ def excluding_last_character
+ return "" if self.length <= 1
+ return excluding_character_at(self.length - 1)
+ end
+
def end_with_bang?
self[-1] == "!"
end
@@ -43070,7 +45322,7 @@ S
end
</code></pre>
-<h3 id='----tests.rb'>tests.rb</h3>
+<h3 id='----tests-rb'>tests.rb</h3>
<pre><code class="language-ruby"># ./dragon/tests.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -43206,14 +45458,14 @@ S
log "#{self.failed.length} test(s) failed."
self.failed.each do |h|
log "**** Test name: :#{h[:m]}"
- log "#{h[:e].to_s.gsub("* ERROR:", "").strip}"
+ log "#{h[:e].to_s.gsub("* ERROR:", "").strip}\n#{h[:e].__backtrace_to_org__}"
end
end
end
end
</code></pre>
-<h3 id='----trace.rb'>trace.rb</h3>
+<h3 id='----trace-rb'>trace.rb</h3>
<pre><code class="language-ruby"># ./dragon/trace.rb
# coding: utf-8
# Copyright 2019 DragonRuby LLC
@@ -43401,12 +45653,46 @@ module GTK
end
</code></pre>
-<h3 id='----wizards.rb'>wizards.rb</h3>
+<h3 id='----wizards-rb'>wizards.rb</h3>
<pre><code class="language-ruby"># ./dragon/wizards.rb
# Copyright 2019 DragonRuby LLC
# MIT License
# wizards.rb has been released under MIT (*only this file*).
+class Wizard
+ def metadata_file_path
+ "metadata/game_metadata.txt"
+ end
+
+ def get_metadata
+ metadata = $gtk.read_file metadata_file_path
+
+ if !metadata
+ write_blank_metadata
+ metadata = $gtk.read_file metadata_file_path
+ end
+
+ dev_id, dev_title, game_id, game_title, version, icon = *metadata.each_line.to_a
+
+ {
+ dev_id: dev_id.strip.gsub("#", "").gsub("devid=", ""),
+ dev_title: dev_title.strip.gsub("#", "").gsub("devtitle=", ""),
+ game_id: game_id.strip.gsub("#", "").gsub("gameid=", ""),
+ game_title: game_title.strip.gsub("#", "").gsub("gametitle=", ""),
+ version: version.strip.gsub("#", "").gsub("version=", ""),
+ icon: icon.strip.gsub("#", "").gsub("icon=", "")
+ }
+ end
+end
+
+class WizardException < Exception
+ attr_accessor :console_primitives
+
+ def initialize *console_primitives
+ @console_primitives = console_primitives
+ end
+end
+
module GTK
class Wizards
attr_accessor :ios, :itch