summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--deploy_template/CHANGELOG.txt690
-rw-r--r--deploy_template/CHEATSHEET.txt232
-rw-r--r--deploy_template/README.txt634
-rw-r--r--deploy_template/mygame/app/tests.rb9
-rw-r--r--deploy_template/mygame/documentation/02-labels.md20
-rw-r--r--deploy_template/mygame/documentation/05-sprites.md4
-rw-r--r--deploy_template/mygame/documentation/99-todo.md89
-rw-r--r--deploy_template/mygame/metadata/game_metadata.txt6
-rw-r--r--deploy_template/mygame/metadata/icon.pngbin0 -> 157056 bytes
-rw-r--r--deploy_template/mygame/sprites/circle-black.pngbin0 -> 1882 bytes
-rw-r--r--deploy_template/mygame/sprites/circle-blue.pngbin0 -> 2901 bytes
-rw-r--r--deploy_template/mygame/sprites/circle-gray.pngbin0 -> 3006 bytes
-rw-r--r--deploy_template/mygame/sprites/circle-green.pngbin0 -> 2887 bytes
-rw-r--r--deploy_template/mygame/sprites/circle-indigo.pngbin0 -> 2433 bytes
-rw-r--r--deploy_template/mygame/sprites/circle-orange.pngbin0 -> 2670 bytes
-rw-r--r--deploy_template/mygame/sprites/circle-red.pngbin0 -> 2233 bytes
-rw-r--r--deploy_template/mygame/sprites/circle-violet.pngbin0 -> 2439 bytes
-rw-r--r--deploy_template/mygame/sprites/circle-white.pngbin0 -> 1754 bytes
-rw-r--r--deploy_template/mygame/sprites/circle-yellow.pngbin0 -> 2456 bytes
-rw-r--r--deploy_template/mygame/sprites/hexagon-black.pngbin0 -> 2602 bytes
-rw-r--r--deploy_template/mygame/sprites/hexagon-blue.pngbin0 -> 4842 bytes
-rw-r--r--deploy_template/mygame/sprites/hexagon-gray.pngbin0 -> 5184 bytes
-rw-r--r--deploy_template/mygame/sprites/hexagon-green.pngbin0 -> 4695 bytes
-rw-r--r--deploy_template/mygame/sprites/hexagon-indigo.pngbin0 -> 4918 bytes
-rw-r--r--deploy_template/mygame/sprites/hexagon-orange.pngbin0 -> 4825 bytes
-rw-r--r--deploy_template/mygame/sprites/hexagon-red.pngbin0 -> 3753 bytes
-rw-r--r--deploy_template/mygame/sprites/hexagon-violet.pngbin0 -> 5069 bytes
-rw-r--r--deploy_template/mygame/sprites/hexagon-white.pngbin0 -> 5326 bytes
-rw-r--r--deploy_template/mygame/sprites/hexagon-yellow.pngbin0 -> 5249 bytes
-rw-r--r--deploy_template/mygame/sprites/isometric-black.pngbin0 -> 264 bytes
-rw-r--r--deploy_template/mygame/sprites/isometric-blue.pngbin0 -> 361 bytes
-rw-r--r--deploy_template/mygame/sprites/isometric-gray.pngbin0 -> 493 bytes
-rw-r--r--deploy_template/mygame/sprites/isometric-green.pngbin0 -> 361 bytes
-rw-r--r--deploy_template/mygame/sprites/isometric-indigo.pngbin0 -> 361 bytes
-rw-r--r--deploy_template/mygame/sprites/isometric-orange.pngbin0 -> 361 bytes
-rw-r--r--deploy_template/mygame/sprites/isometric-red.pngbin0 -> 361 bytes
-rw-r--r--deploy_template/mygame/sprites/isometric-violet.pngbin0 -> 361 bytes
-rw-r--r--deploy_template/mygame/sprites/isometric-white.pngbin0 -> 361 bytes
-rw-r--r--deploy_template/mygame/sprites/isometric-yellow.pngbin0 -> 361 bytes
-rw-r--r--deploy_template/mygame/sprites/square-black.pngbin0 -> 250 bytes
-rw-r--r--deploy_template/mygame/sprites/square-blue.pngbin0 -> 283 bytes
-rw-r--r--deploy_template/mygame/sprites/square-gray.pngbin0 -> 251 bytes
-rw-r--r--deploy_template/mygame/sprites/square-green.pngbin0 -> 283 bytes
-rw-r--r--deploy_template/mygame/sprites/square-indigo.pngbin0 -> 283 bytes
-rw-r--r--deploy_template/mygame/sprites/square-orange.pngbin0 -> 282 bytes
-rw-r--r--deploy_template/mygame/sprites/square-red.pngbin0 -> 274 bytes
-rw-r--r--deploy_template/mygame/sprites/square-violet.pngbin0 -> 284 bytes
-rw-r--r--deploy_template/mygame/sprites/square-white.pngbin0 -> 279 bytes
-rw-r--r--deploy_template/mygame/sprites/square-yellow.pngbin0 -> 286 bytes
-rw-r--r--deploy_template/open-source-licenses.txt215
-rw-r--r--dragon/args.rb164
-rw-r--r--dragon/assert.rb51
-rw-r--r--dragon/attr_gtk.rb40
-rw-r--r--dragon/console.rb7
-rw-r--r--dragon/docs.rb47
-rw-r--r--dragon/geometry.rb253
-rw-r--r--dragon/help.rb72
-rw-r--r--dragon/index.rb22
-rw-r--r--dragon/inputs.rb132
-rw-r--r--dragon/log.rb236
-rw-r--r--dragon/numeric.rb527
-rw-r--r--dragon/string.rb98
-rw-r--r--dragon/tests.rb136
-rw-r--r--dragon/trace.rb150
64 files changed, 3270 insertions, 564 deletions
diff --git a/deploy_template/CHANGELOG.txt b/deploy_template/CHANGELOG.txt
new file mode 100644
index 0000000..9bde121
--- /dev/null
+++ b/deploy_template/CHANGELOG.txt
@@ -0,0 +1,690 @@
+= 20200225 =
+
+ * [Bugfix] Fixed macOS compatibility back to Mac OS X 10.9 or so.
+
+= 20200224 =
+
+ * [Bugfix] Some of the deprecation notices where throwing an exception. This has been fixed.
+ * [API] $gtk.system(cmd) has been added. You'll find this helpful for running cli programs from
+ Heads Up Display. It's probably not a good idea to use this in a production game (since you'll
+ be responsible for making sure it works on all platforms).
+
+= 20200218 =
+
+ * [API] Enhanced screenshotting api that can be used for image manipulation.
+ Take a look at the painting sample app.
+ Example usage: `args.outputs.screenshots << [0, 0, 100, 100, 'bottom-left-corner.png']`.
+ * [BREAKING] Outputs#static_background_color has been renamed to Outputs#background_color.
+ * [API] Outputs#debug and Outputs#static_debug layer has been added. You can use this layer
+ to draw all your guide lines and helper primitives. When the game is published, this layer
+ will not render.
+
+= 20200217 =
+
+ * [Bugfix] `dragonruby-publish` would only build html5. It now builds
+ all of the platforms again. Ryan "The Juggernaut" Gordon has given Amir
+ a warning and has told him to be more careful releasing. Amir cackled
+ in defiance.
+
+= 20200213 =
+
+ * [API] Added Float#pos? and Float#neg?.
+ * [Samples] Sample added to show how to use directional_vector and sprite sheets.
+ * [Samples] Updated 01_api_01_labels sample app to show how to render a label
+ as an array or hash.
+ * [Bugfix] Fixed incorrectly named value for labels in 11_hash_primitives sample app.
+
+= 20200211 =
+
+ * [API] Added `args.inputs.directional_vector` and
+ `args.inputs.(keyboard|controller_one|controller_two).directional_vector.
+ The sample app to demonstrate the use of this feature is pending.
+ * [API] Added Numeric#pos? and Numeric#neg?.
+ * [Bugfix] Fixed looping issues with ogg files and popping issues with
+ playing sounds in general.
+ * [Bugfix] `args.gtk.console.toast :message, "some message"` would fail because
+ of an invalid method name.
+ * [News] Amir (the CEO of DragonRuby LLP) wrote a 2019 year end review. You can
+ read it here: http://www.rubymotion.com/news/2020/01/02/year-end-review.html.
+ * [News] Expect the frequency of updates of GTK to increase. Ryan let Amir have
+ the deployment passwords, so the rate limiter is now gone :3
+
+= 20200202 =
+
+ * [API] Hash now supports :scale_rect.
+ * [Samples] Added sample app that shows how to create a hexagon based grid.
+ * [Support] Initial work on CHEATSHEET.txt.
+ * [API] Added args.inputs.keyboard.ctrl_* which will return true if Ctrl is
+ combined with another key.
+ * [API] Added args.inputs.click (which only returns the point or nil).
+ * [API] Added Numeric#even? and Numeric#odd?.
+ * [API] Added Geometry#point_inside_circle?(point, circle_point, radius).
+
+= 2020130 =
+
+ * [Performance] Rendering api optimizations. Initial tests show that
+ DragonRuby Game Toolkit can now render more sprites (and calculate
+ more collisions) than Unity 2D. Checkmate.
+ * [Support] Fixed documentation for labels (the hash properties are
+ called size_enum, and alignment_enum). The documentation can be
+ found under mygame/documentation.
+ * [Support] Improved help text for exceptions related to ambiguous use
+ of primitives.
+ * [Bugfix] Requiring multiple ruby files will no long "blip" an
+ exception on startup.
+
+= 20191201 =
+
+ * [Samples] Added sample game called The Little Probe that demonstrates
+ line collision.
+ * [Samples] Experiments with squares and cubes in 3D.
+ * [Support] HTML5 games now package a favicon.
+ * [Samples] [Support] Quite a few of the sample apps have been updated to
+ include an api listing at the top (expansion of documentation).
+ * [API] Initial work for http has been created. Take a look at the
+ http sample app to see how to use it. Take a look at
+ `samples/99_zz_gtk_unit_tests` for a test suite that asserts async
+ http.
+ * [Support] [Samples] Added a sample app that shows how create
+ collision detection associated with constraint points against
+ a ramp. This sample app also demostrates the use of `gtk.slowmo!`
+ which you can use the slow down the tick execution of your game
+ to see things frame by frame (still experimental).
+ * [Support] Added sprites to default template folder. The sprites
+ are `sprites/square-COLOR.png` and `sprites/circle-COLOR.png` where
+ the colors are of the rainbow ROY G. BIV (eg `sprites/square-red.png`).
+ * [Sample] Added a sample app that shows how to use the
+ `static_sprites` rendering api which is the fastest way to render
+ a sprite (but also hangs on the instances by reference as opposed
+ to treating the collection as a queue... a trade off between
+ immutablility and speed).
+ * [API] Added the `attr_sprite` class macro which can be mixed into
+ a class so that it quacks like a sprite. The Sprite Limits sample
+ app has been updated to use this macro.
+ * [Support] In the event of an exception, the class hierarchy for
+ the object that threw the exception is provided.
+ * [Support] In the event of a :method_missing exception, the
+ instance's API is searched for methods that look like the one you
+ were trying to call. Those recommendations are printed to the
+ console.
+ * [Samples] [Support] Significant enhancements have been made to the
+ test harness. Take a look at `samples/99_zz_gtk_unit_tests` to see
+ some of the test suites that are being fleshed out. These test
+ suites are used as regression during builds. More will come.
+ * [Samples] Unit tests added for geometry apis.
+ * [Samples] Unit tests added for parsing json and xml.
+ * [Bugfix] HTML5 builds no longer fail at startup with an audio
+ initialization error message.
+ * [Bugfix] The $gtk.write_file API change was a mistake. The actual
+ bug it was meant to resolve has been fixed. The responsible
+ parties have been brutally disciplined.
+ * [BREAKING] `gtk_args` class macro has been renamed to
+ `attr_gtk`. This is a little easier to remember because it follows
+ the same pattern as `attr_accessor`.
+ * [BREAKING] `PRIMITIVE.w(idth)_half` and `PRIMITIVE.h(eight)_half`
+ have been deprecated. Use `PRIMITIVE.w.half` (Numeric#half).
+ * [BREAKING] `PRIMITIVE.angle_given_point` has been deprecated. Use
+ `PRIMITIVE.angle_from`.
+ * [API] `PRIMITIVE.angle_to` has been added. Take a look at
+ `samples/99_zz_gtk_unit_tests` for usages.
+ * [BREAKING] `intersects_rect?` with an `s` has been deprecated. Use
+ `intersect_rect?` instead.
+ NOTE: Ruby's naming convention is to generally *not* include the
+ \"s\" for interrogative method names (methods that end with a ?
+ [question mark]). It doesn't sound grammatically correct, but that
+ has been the rule for a long time (and why intersects_rect? has
+ been deprecated).
+ * [Samples] Added a white label version of Clepto Frog, a Ludam Dare
+ game built by Amir, Karen, and Rye. You can see the final version
+ (with all assets) here: https://amirrajan.itch.io/clepto-frog. The
+ code is horrible. Who wrote this crap?
+ * [Bugfix] Fixed looping issues with `.ogg`. The follow statement
+ will now correctly work:
+ ```
+ def tick args
+ if args.state.tick_count == 0
+ args.outputs.sounds << 'sounds/sample.ogg'
+ end
+ end
+ ```
+ * [API] Added `args.gtk.stop_music` to stop all looping music.
+ * [API] Added `args.geometry` which contains stateless functions
+ that exist on primitives. For a full listing of methods open up
+ the console and type `args.geometry.help`. A lot of these methods
+ are exercised in the `samples/99_zz_gtk_unit_tests` test suite.
+ * [Support] The --no-tick switch for ./dragonruby will now hide the
+ game window (it's a good way to run "headless" unit
+ tests/regressions suites). Usage: `./dragonruby mygame --eval
+ some_ruby_file.rb --no-tick`.
+ * [BREAKING] gtk.on_ticks has been deprecated, use the better named
+ gtk.scheduled_callbacks instead.
+ * [BREAKING] gtk.on_tick TICKCOUNT { BLOCK } has been deprecated, use the better named
+ gtk.schedule_callback TICKCOUNT { BLOCK } instead.
+
+= release-20190930 =
+
+ * [Samples] Added sample app that shows how trace can be used within a class.
+ * [Support] Added $gtk.log_level. Valid values are :on,
+ :off. When the value is set to :on, GTK log mesages will show up
+ in the DragonRuby Console *AND* be written to logs/log.txt. When the
+ value is set to :off, GTK log messages will *NOT* show up in the
+ console, but will *STILL* be written to logs/log.txt
+ * [API] Added args.inputs.mouse.(click|up|down).(x|y) so you don't have to do
+ args.inputs.mouse.click.point.
+ * [Support] You can change your window title at runtime with
+ $gtk.set_window_title('new title'). YOU MUST SET UP YOUR GAME'S METADATA
+ CORRECTLY EVEN IF YOU USE THIS FUNCTION.
+ * [Support] The macOS build is now compiled with Link-Time
+ Optimization, as an experiment, which makes your games a little faster and
+ your downloads a little smaller.
+ * [Support] We've split the open source licenses out of README.txt
+ to their own file, which is packaged with your games, to be a good citizen
+ of the world. If you add other open source stuff, just copy
+ open-source-licenses.txt into your game's folder and add your own stuff
+ to it; that will package with your game instead of the original text file.
+ * [Support] Added JSON parsing. Try $gtk.parse_json(myJsonString) or
+ $gtk.parse_json_file(filename)
+ * [Support] Added XML parsing. Try $gtk.parse_xml(myXmlString) or
+ $gtk.parse_xml_file(filename)
+ * [BREAKING] There is a new replay data format that is less crappy. But it breaks
+ existing replay data. You'll need to re-record your replays (sorry T_T).
+ To record a replay of gameplay, you can run ./dragonruby mygame --record.
+ When you close the game, a file called last_replay.txt will be created.
+ You can re-run a replay as a means to perform visual regression using
+ ./dragonruby mygame --replay last_replay.txt
+ * [Support] Added a --production command line option for running an
+ unpublished game as if it were published.
+ * [Support] We now offer bleeding edge builds on the "experimental"
+ channel on itch.io. If you want those, go to where you downloaded this
+ package, and look for the "experimental" download instead. These are
+ expected to be less stable and pushed as we need to test things out or
+ hotfix a bug that isn't ready to roll into an official release. If this is
+ your jam, though, go for it.
+ * [OSS] Thank you to StardragonEX, phaedryx, and pusewicz for contributing
+ to GTK documentation located at github.com/DragonRuby/dragonruby-game-toolkit-contrib.
+ * [Support] Enabling trace! on an object now outputs
+ all trace data to a file as opposed to just standard out. This will
+ make trace debugging significantly more useful to developers that
+ don't have a high-buffer-history terminal running.
+ * [Samples] Added platformer that deals with moving objects, jumping, and dealing with inertia.
+ * [Samples] Added sample showing how to render an isometric grid
+ (like Into The Breach).
+ * [Samples] Sample added showing how to use trace! debugging when you
+ are having trouble with why an exception is being thrown.
+ * [Samples] Many of the sample apps have had their methods reorganized
+ for consistency in reading. They also have comments added to them.
+ * [Experimental] If the game has been running for over a minute, and cannot
+ keep a stable 60 fps, the game's rendering will be skipped every other
+ frame to save process cycles (tick method will still execute as fast
+ as possible, but results from them method will only be rendered at 30 fps).
+
+= release-20190912 =
+
+ * [Bugfix] dragonruby-publish now correctly builds HTML5 packages when
+ there's a "'" character in the game's name (etc).
+ * [Bugfix] dragonruby-httpd now serves paths with spaces in them correctly.
+ * [Bugfix] dragonruby-publish now ignores __MACOSX directories (trash that
+ macOS tends to generate when you double-click a .zip file to unpack it
+ from the Finder).
+
+= release-20190909 =
+
+ * [Bugfix] HTML5 builds' "click-to-play" UI now scales the icon.
+ * [Bugfix] args.gtk.writefile(path, content [, write_to_game_dir = true])
+ now writes file to the game folder as opposed to the root directory.
+ If you need to write to the root directory provide false as the third
+ parameter to write file.
+ * [Experimental] There is now a special file in mygame called mailbox.rb.
+ When `args.gtk.suppress_mailbox = false`, mailbox.rb will be checked for
+ changes at a high frequency (10 times a second). Because this an
+ experimental feature, the default value of `args.gtk.suppress_mailbox` is
+ TRUE. You can use this file as a means to communicate with GTK between process.
+ There is a sample app that shows how to use the mailbox.rb file.
+ * [Support] You can now have multiple mouse buttons!
+ args.inputs.mouse.click and .up will still be set if there was a mouse
+ button change for the current tick, but you should look at
+ args.inputs.mouse.button_left (or _middle or _right or _x1 or _x2) as a
+ bool to see if it's currently pressed down. More than one might be pressed,
+ and more than one button might have changed in the one .click you'll get.
+ The same is true for .up
+ * [Support] You can now see the mouse wheel (or your trackpad
+ pretending to be a mouse wheel when you stroke it appropriately)!
+ All wheel input since the last tick is added together. You can check if
+ args.inputs.mouse.wheel isn't nil to decide if the wheel has moved for
+ this tick.
+ ```ruby
+ m = args.inputs.mouse
+ if m.wheel
+ puts("The wheel moved #{m.wheel.x} left/right and #{m.wheel.y} up/down")
+ end
+ ```
+
+= release-20190829 =
+
+ * [Community] Discord link: http://discord.dragonruby.org and Youtube link: http://youtube.dragonruby.org.
+ * [Support] Plugging in an unrecognized controller will now make DragonRuby pop up a
+ UI to let the user configure it. During this time your game will receive no
+ tick calls and so will be effectively paused. It resumes once the user has configured the
+ controller or abandoned it. This is a work in progress, but we already
+ think it's pretty cool.
+ * [Experimental] [Advanced] You can start up ./dragonruby by passing in --eval file_path. The file passed in will
+ execute on startup. Additionally you can pass in --eval file_path --no-tick which will
+ exit ./dragonruby immediately after loading all source, and running the file passed to eval.
+ * [Experimental] [Advanced] `on_tick` callback has been added to $gtk. This can be used to run some form of automation.
+ For example, you can run the Dueling Starships sample app with the following inside of repl.rb.
+ ```ruby
+ # Reset the game and sent the RNG seed to 100
+ $gtk.reset 100
+
+ # Remove any existing callbacks.
+ $gtk.on_ticks.clear
+
+ # One second into the game, hold down the right directional
+ # on controller one.
+ $gtk.on_tick 60 do
+ $gtk.args.inputs.controller_one.key_held.right = true
+ end
+
+ # On frame 80, release the right directional, and
+ # hold down R1.
+ $gtk.on_tick 80 do
+ $gtk.args.inputs.controller_one.key_held.right = false
+ $gtk.args.inputs.controller_one.key_up.right = true
+ $gtk.args.inputs.controller_one.key_held.r1 = true
+ end
+ ```
+ There is a full blown automation script under samples/00_beginner_ruby_primer/automation.rb
+ ./samples/00_beginner_ruby_primer $ ../../dragonruby . --eval app/automation.rb
+ * [Support] Exceptions `game_state_*.txt files are now written to an exceptions directory
+ instead of cluttering up the root.
+ * [Support] Launching dragonruby with --fullscreen on the command line makes the game fullscreen.
+ * [Support] Launching dragonruby-publish from any directory with no command line arguments
+ and without a "mygame" folder in the current working directory will
+ cause it to look for "mygame" in the same directory as dragonruby-publish
+ itself. Which is to say: it'll work in the default configuration if you
+ double-click it from the macOS Finder.
+ * [Samples] New sample app called 02_collisions_02_moving_objects has been added.
+ * [Support] Previous console messages are subdued if unhandled exception is resolved.
+ This removes visual confusion if another exception is thrown (easier to determine what the current exception is).
+ * [Support] Added api documentation about thruthy_keys for keyboards and controllers.
+ * [API] [Experimental] Hashes now quack like render primitives. For example some_hash[:x] is the same as
+ some_hash.x and can be interchangeable with some_array.x (this is a work in progress
+ so there may be some geometric/collision apis that aren't covered).
+ * [Support] Usability of Console and it's interaction with repl.rb is SIGNIFICANTLY better.
+ Take a look at the new repl.rb file under mygame/repl.rb to see an interactive
+ crash course of Ruby that shows how to use variables, functions, conditionals,
+ loops, and arrays. Special thanks to @raulrita (https://www.twitch.tv/raulrita)
+ for live streaming and bringing light to these enhancements.
+ * [Support] `puts` statements that begin with "====" are rendered as teal in the Console. This
+ provides a visual seperation that will help with print line debugging.
+ * [OSS] The DragonRuby Game Toolkit Console has been open sourced under an MIT license. You can find it
+ here: https://github.com/DragonRuby/dragonruby-game-toolkit-contrib
+
+= release-20190823 =
+
+ * [Support] The mygame directory now contains a documentation folder that provides high level
+ APIs for the engine (it's a work in progress, but a good starting point).
+ * [Samples] A sample app called "hash primitives" has been added that shows how you can use a Hash
+ to render a primitive. This will make specifying sprite's advanced properites much easier.
+ * [Samples] The sprite limits sample app shows how you can ducktype a class and render it as a sprite.
+ Doing this is a tiny bit more work, but there is a huge perfomance benefit.
+ * [Bugfix] Internal limits total textures/render targets/fonts is removed.
+ * [BREAKING] args.dragon has been deprecated, you must now use the new property args.gtk.
+ * [BREAKING] args.game has been deprecated, you must now use the new property args.state.
+ * [BREAKING] args.gtk.root has been removed and all attributes have been moved to args.gtk.
+ * [BREAKING] args.gtk(.root).mouse_focus has been removed, use args.inputs.mouse.has_focus.
+ * [BREAKING] args.gtk(.root).keyboard_focus has been removed, use args.inputs.keyboard.has_focus.
+ * [BREAKING] $dragon has been removed, you must now use $gtk.
+ * [BREAKING] $view has been removed and functionality has been moved to $gtk, use that variable instead.
+
+= release-20190816 =
+
+ * [Bugfix] HTML5: Fixed crash on startup on Chrome if the game's icon isn't tiny.
+ * [Samples] Added sample app that shows how you can make a paint app (05_mouse_move_paint_app).
+ * [Samples] Added sample app that shows how you can make a tile editor (05_mouse_move_tile_editor).
+ * [Samples] Added LOWREZ Jam 2019 game that Amir built: Return of Serenity (99_sample_game_return_of_serenity).
+ * [Samples] Added Metroidvania sample app which is a great starting point for the "Metroidvania Month" Jam on Itch.io.
+ * [Support] :ordinal_indicator (º) character added to args.inputs.keyboard. It can be used to bring up the GTK console.
+
+= release-20190813 =
+
+ * [Samples] Added sample app that shows off controller input.
+ * [API] `args.inputs.keyboard.key_down.delete is now available and works in the GTK console.
+ * [Bugfix] Requiring a ruby file that doesn't exist will return an error instead of crashing.
+ * [Support] Console coloring added for exceptions.
+ * [Support] When running trace!, if an exception occurs. The last method invoked will
+ be provided in the details.
+
+= release-20190806 =
+
+ * [Bugfix] Having $gtk.reset at the bottom of your main.rb will not cause a recursive require
+ of all files.
+ * [Support] In the event of an exception, the source code will not be searched if the
+ search term is less than three characters.
+ * [Samples] A Roguelike starting point sample app has been added.
+ * [Support] If a primitive rendering fails, the primitive type will now be included
+ with the exception.
+ * [API] The property `args.outputs.static_background_color = [0, 0, 0]` is now exposed. This allows
+ you to control the color of the letterbox around your game. Some of the sample apps have been
+ updated to use this property (for example Dueling Starships).
+
+= release-20190803 =
+
+ * [Bugfix] `gtk_attr` now included the `inputs` attr_accessor.
+ * [Website] The initial version of http://fiddle.dragonruby.org has
+ been created. Try it out.
+ * [Support] Eight new beginner sample apps have been added
+ which breakdown the tech demo into consumable pieces (with comments).
+ * [Support] The two introductory Ruby primers now contain links
+ to video tutorials that you can use to follow along.
+ * [Support] A game/sample app called Snakemoji has been added. Game
+ development should be fun and about experimentation. This sample app
+ was certainly built in the spirit of this. A big thank you to
+ Anton K. (ai Doge) for this contribution.
+ * [Support] Added $gtk.trace!(an_object) which will detailed print execution
+ information. This should make it much easier to track down exceptions.
+ * [Support] All source files are auto reloaded on save or when
+ $gtk.reset is executed.
+ * [Support] § (:section_sign) can now be used to open up the
+ DragonRuby GTK Console.
+
+= release-20190731 =
+
+ * [Bugfix] Fixed bug in dragon ruby console returning evalued value.
+ * [Support] Updated collisions sample app with comments.
+ * [Support] Added comments for sprite animation sample app.
+ * [Support] dragonruby-publish will look for your game in the
+ "mygame" directory if not otherwise specified on the command line.
+ * [Support] dragonruby-publish now puts packaged builds in
+ "builds" directory instead of ".dragonruby/builds" so you can actually
+ find them.
+
+= release-20190712 =
+
+ * [Bugfix] dragonruby-publish ignores .git/.hg/.svn directories.
+
+= release-20190711 =
+
+ * [Bugfix] Bug fix for Easing module rename. Sorry about that!
+ * [Typo] Fixed grammar in sprite limits explanation.
+
+= release-20190709 =
+
+ * [Bugfix] Text scaling now works on Windows. Resize the window and your
+ fonts should stay crisp now!
+ * [Bugfix] dragonruby-httpd on Windows now has proper EXE metadata.
+ * [API] Commonly used properties on `args` are now accessible as top
+ level methods:
+
+ ```
+ def tick args
+ args.(solids|sprites|lines|labels|borders|
+ click|click_at|mouse|controller_one|controller_two|
+ keyboard)
+ end
+ ```
+ * [BREAKING] `args.game` has been deprecated is favor of the better
+ named property `args.state`.
+ * [Support] DragonRuby GTK Console now accepts input
+ immediately (specifically while it's animating).
+ * [API] Class macro `gtk_args` has been added. Instead of having to
+ do:
+
+ ```
+ class Game
+ attr_accessor :args, :grid, :state, :inputs, :outputs, :gtk, :passes,
+ :current_scene, :other_custom_attrs
+
+ def tick
+ end
+ end
+
+ def tick args
+ $game.args = args
+ $game.grid = args.grid
+ $game.state = args.state
+ $game.outputs = args.outputs
+ $game.gtk = args.gtk
+ $game.passes = args.passes
+ $game.tick
+ end
+ ```
+
+ You can now do:
+
+ ```
+ class Game
+ gtk_args
+ attr_accessor :current_scene, :other_custom_attrs
+
+ def tick
+ end
+ end
+
+ def tick args
+ $game.args = args
+ $game.tick
+ end
+ ```
+ * [API] [BREAKING] The globally accessible GTK Runtime has been renamed `$dragon` to
+ `$gtk` (you can still use $dragon for now, but it is strongly
+ recommended that you update your usages to $gtk).
+ * [API] A new entity type has been introduced and is accessible via `args.state.new_entity_strict`
+ the usage of StrictEntity over OpenEntity (`args.state.new_entity`) yield significantly faster
+ property access. The downside is that `args.state.new_entity_strict` requires
+ you to define all properties upfront within the implicit block. You will recieve
+ an exception if you attempt to access a property that hasn't be
+ pre-defined. For usage info and preformance differences, take a look at the Sprite Limit
+ sample app.
+ * [Support] Exception messages have been significantly improved. Hashes and Type .to_s
+ information is well formatted. "stack too deep" exceptions resolved.
+ * [API] [BREAKING] `args.outputs.PRIMITIVES +=` is no longer supported. Use `args.outputs.PRIMITIVES <<`
+ for all concatenation of primitives to the outputs collection (trying to pick between += and << was confusing,
+ we settled on <<).
+ * [Support] Framerate warnings wait 10 seconds before calculating the moving average. If your
+ framerates begin to drop, consider using `args.state.new_entity_static` for game structures that have been
+ fleshed out.
+ * [Performance] Rendering of primitives is can support over twice as many sprites at 60 fps (see Sprit Limits
+ sample app for demonstration).
+ * [Support] Headless testing has been added. Take a look at the Basic Gorillas sample app to see
+ how headless testing can help you dial into frame-by-frame problems within your game.
+ * [Samples] The "Controller Analog Usage Advanced Sprites" sample
+ app now has a helper function with named parameters to create the
+ sprite. For example, if you needed to flip a sprite vertically,
+ you'd have to do the following:
+
+ ```
+ args.outputs.sprites << [0, 0, 100, 100,
+ 'fighter.png',
+ 0,
+ 255, 255, 255, 255,
+ 0, 0, -1, -1, false, true]
+ ```
+
+ With the helper method, you can write the following:
+
+ ```
+ args.outputs.sprites << create_sprite(x: 0, y: 0, w: 100, h: 100, vflip: true)
+ ```
+
+ We're still chewing on the API above before it get's integrated
+ into GTK proper.
+ * [API] "Superscript Two" can be used to bring up the DragonRuby
+ Console. People with international keyboards (which don't have a ~
+ key) can now use the `superscript_two` key (which is in the same
+ place as the ~).
+ * [API] All keyboard attributes now have a `!` variant which will
+ clear the key if the value was true. Example:
+
+ ```
+ args.inputs.keyboard.key_down.up # returns true
+ args.inputs.keyboard.key_down.up # still returns true
+ ```
+
+ VS
+
+ ```
+ args.inputs.keyboard.key_down.up! # returns true
+ args.inputs.keyboard.key_down.up # now returns false for the rest of this tick
+ ```
+ * [Samples] Added a sample app called "Sprite Animation and Keyboard
+ Input" that shows how to do repeating and one-time sprite
+ animations driven by keyboard input.
+ * [Samples] All sample apps have the MIT License added to them (to
+ remove any ambiguity with regards to if you can use them for
+ commercial purposes).
+ * [HTML5] Games published to HTML5 now has a loading progress bar.
+ * [Samples] Added sample app called "Coordinate Systems" that show
+ the two coordinate systems supported by the GTK.
+ * [API] `args.inputs.mouse` now respects `args.dragon.origin_center!`.
+ * [Samples] Added two sample apps called "Collision" and "Collision
+ and Entities" that show how to perform collision detection with
+ draw primitives and `args.state.new_entity`.
+ * [Samples] Added an interactive sample app called "Beginner Ruby
+ Primer" that does a better job of introducing you to the language.
+ * [Samples] [Video] Amir facilitated a workshop at a local user
+ group. The source code for the workshop is located in a sample app
+ called "NDDNUG Workshop". The video was recorded and you can use
+ that to code along: (https://www.youtube.com/watch?v=S3CFce1arC8).
+ * [Bugfix] Windows and Mac icon generation in dragonruby-publish was
+ broken in the previous build. Sorry! Fixed now.
+ * [Bugfix] DragonRuby binaries are now codesigned on macOS. We are still
+ working on signing games packaged by dragonruby-publish, but stay tuned!
+
+= release-20190604 =
+
+ * [BREAKING] `perc_to_zero` and `perc_to_one` have been deprecated
+ and now throw and informative exception that will help you fix the
+ problem. Moving forward, you'll need to use the new `lerp` APIs
+ (details further down).
+ * [BREAKING] `intersects_rect?` now takes in an optional parameter
+ called `tolerance`. This parameter's default is set to `0.1`. The
+ original tolerance value was set to `0`. So if you still want a
+ tolerance of `0`, you'll need to update your `intersect_rect?`
+ calls to: `intersects_rect?(other_rect, 0)`.
+ * [IMPORTANT] [API] [Video] A Quake-style Heads Up Display (HUD),
+ has been added. You can access this console by pressing the "~"
+ key. This console can be used to experiment with Ruby, print debug
+ logging, and diagnose errors. Here is Ryan showing the console in
+ action: (https://www.youtube.com/watch?v=hHgV11F2ZPY)
+ * [IMPORTANT] [API] [Video] Added the ability to create replays so you can
+ do visual regression of your game. Here is this record/replay capability in
+ action: (https://www.youtube.com/watch?v=ev0UMVBe-fY)
+ ```
+ args.dragon.start_recording(RNG_SEED)
+ args.dragon.stop_recording(filename)
+ args.dragon.start_replay(filename)
+ args.dragon.stop_replay
+ ```
+
+ You can record your game on startup using the following command
+ (it'll automatically save when you close the game):
+
+ ```
+ ./dragonruby(.exe) --record
+ ```
+ * [API] Rendering primitives now support `float` values for position
+ and size.
+ * [API] [Sample] [Video] Lerping/Easing APIs have been added. There is a
+ sample app that shows all the things you can do with them. For
+ philosophical motivations as to why the APIs look the way they do
+ (and just simply a fantastic presentation), watch this
+ presentation given by Squirrel Esierloh *NO REALLY YOU SHOULD WATCH THIS PRESENTATION*:
+ "Math for Game Programmers: Fast and Funky 1D Nonlinear Transformations" (https://www.youtube.com/watch?v=mr5xkf6zSzk)
+ * [API] CTAG files now ship with releases. This will let you quickly
+ see the APIs available in DragonRuby GTK.
+ * [Sample] Added a "prerequisite" sample app that gives you a crash
+ course of Ruby the programming language.
+ * [Sample] The composition of primitives in DragonRuby GTK are
+ incredibly flexible. A sample app called "Fluid Primitives" has
+ been beed added to show this flexibility.
+ * [MacOS] [Linux] [Windows] If your screen resolution is below 720p,
+ the game will start at a smaller (but still aspect-correct) resolution.
+ * [Sample] Sample added showing `intersects_rect?` collision
+ tollerances as a topdown level (similar to what's
+ in Zelda for the NES).
+
+= release-20190516 =
+
+ * [Community] A big thank you to Nick Culbertson (@mobypixel) for
+ creating the art and music for these games.
+ * [HTML5] [Demo] [Experimental] Experimental deployment to HTML5 added. You can
+ play the HTML5 version here: (https://dragonruby.itch.io/flappydragon).
+ * [HTML5] `dragonruby-httpd` binary added so that you can test your
+ HTML5 game locally.
+ * [RaspberryPI] [Video] [Experimental] Experimental support added to Rasberry Pi. You can
+ play DragonRuby GTK games, _develop them and publish them_.
+ Here's a video of Ryan playing Flappy Dragon on his DIY Arcade
+ Machine: (https://www.youtube.com/watch?v=DCvFMKsvG-Q).
+ * [API] Mouse movement can now be tracked: `args,inputs.mouse.position`.
+ * [API] Experimental API added for taking screenshots: `args.dragon.root.take_screenshot = true`.
+ * [API] Analog support for controllers added: `args.inputs.controller_one.left_analog_x_perc`.
+ * [API] [Experimental] Mouse and keyboard focus status are available for use:
+ ```
+ args.dragon.root.mouse_focus
+ args.dragon.root.keyboard_focus
+ ```
+ * [Samples] Added sample app that shows how to use mouse position.
+ * [Samples] Flappy Dragon reference implementation significantly polished.
+ * [Samples] [Demo] Added BASIC Gorillas reference implementation. Playable
+ here: (https://dragonruby.itch.io/basicgorillas).
+ * [Samples] Added sample app that shows analog controller support in
+ action. The sample also shows how to manipulate a sprite's
+ center of rotation, crop, and horizontal/vertical orientation:
+ ```
+ [
+ x, y, w, h, # decimal values (scales implicitly)
+ path, # string
+ angle, # in degrees
+ a, # alpha (0 to 255)
+ r, g, b, # color *saturation*
+ source_x, source_y, source_w, source_h, (crop, must be given in original pixels)
+ flip_h, flip_v, (boolean values)
+ rotation_anchor_x, rotation_anchor_y (decimal between 0 and 1/ratio from bottom left)
+ ]
+ ```
+ * [API] Added `args.dragon.calcstringbox(str, size_enum, font)`
+ function that can be used to calculate the `rect` for a string.
+
+= release-20190427 =
+
+ * [Packaging] [Windows] Packaging Windows builds of your game now sets a proper icon and
+ metadata in the final .exe.
+ * [API] Keyboard input is improved dramatically, so you can get reasonable
+ key state in your game.
+ * [Packaging] You can now specify an application icon in your game_metadata.txt
+ file instead of possibly having a second copy of the same file in
+ metadata/icon.png.
+ * [Sample] [Video] [Demo] Added a full-blown game/reference implementation called
+ `flappy_dragon` under the `samples` directory. Here's a quick five
+ second video showing the game in action:
+ (https://www.youtube.com/watch?v=ZQYRlVA1ru0). You can play it
+ yourself here: (https://dragonruby.itch.io/flappydragon).
+
+= release-20190422 =
+
+ * [Packaging] Version.txt file added that shows the GIT commit that was
+ deployed.
+ * [Packaging] Fixed duplicate "Copying x to y ..." message in `dragon-publish`.
+ * [Packaging] Automatically package DragonRuby's font and logo so copying the
+ DragonRuby GTK binary around doesn't cause errors.
+ * [Linux] [Windows] Line rendering fixes on Linux and Windows.
+ * [Windows] Bug fix to `golf_with_musical_note` (sound tech demo) sample app where sound
+ wouldn't play on Windows.
+ * [Windows] README.txt file formatting updated so that it looks correct in
+ `notepad.exe`.
+ * [Packaging] Default icon added to `mygame`.
+ * [Samples] Reworked `doomwipe` (render targets tech demo) sample app so that
+ it's less eratic before the effect is revealed.
+ * [Windows] Fixed bug where rendering would stop on Windows if the screen was
+ resized.
+ * [Size] Deleted files that don't need to be packaged with DragonRuby GTK.
+
+= release-20190419 =
+
+ * [IMPORTANT] First release. Hot off the presses. Ready to take over the world! As
+ soon as we fix that one bug. Oh and that one. Oh and that one too.
+ * [Community] The community forum is here: (https://dragonruby.itch.io/dragonruby-gtk/community).
+ * [Community] Or you can join the Slack channel at: (http://slack.rubymotion.com/).
+ * [Community] Ryan (@icculus) and Amir (@amirrajan) are both on
+ Twitter and always happy to help anyone that reaches out to them.
diff --git a/deploy_template/CHEATSHEET.txt b/deploy_template/CHEATSHEET.txt
new file mode 100644
index 0000000..e35f38f
--- /dev/null
+++ b/deploy_template/CHEATSHEET.txt
@@ -0,0 +1,232 @@
+# DragonRuby Game Toolkit Cheatsheet
+
+A detailed documentation listing is located at
+`mygame/documentation`. For real world sample usages of GTK's APIs,
+take a look at the `samples` directory. The sample apps are ordered by
+beginner to advanced. So look at them in order to get the most out of
+them.
+
+# Minimum Code for Game
+
+The minimum amount of code required for a game is a file named
+`mygame/main.rb` with the following:
+
+```ruby
+def tick args
+ args.outputs.labels << [640, 360, "Hello World"]
+end
+```
+
+# Args: `args`
+
+All of GTK's functionality hangs off of `args`.
+
+## Args' Outputs: `args.outputs`
+
+All render `primitive`s are accessible under `args.outputs`.
+
+### Labels: `args.outputs.labels`
+
+`args.outputs.labels` is used to render labels.
+
+Labels are how you display text. This code will go directly inside of the `def tick args` method.
+
+- **Minimum Code**
+
+```ruby
+# X Y TEXT
+args.outputs.labels << [640, 360, "I am a black label."]
+```
+
+- **A Colored Label**
+
+```ruby
+# A colored label
+# X Y TEXT, RED GREEN BLUE ALPHA
+args.outputs.labels << [640, 360, "I am a redish label.", 255, 128, 128, 255]
+```
+
+- **Extended Capabilities**
+
+```ruby
+# A colored label
+# X Y TEXT SIZE ALIGNMENT RED GREEN BLUE ALPHA FONT FILE
+args.outputs.labels << [640, 360, "Hello world", 0, 1, 0, 0, 0, 255, "fonts/coolfont.ttf"]
+```
+
+A `SIZE` of `0` represents "default size". A negative value will decrease
+the label size. A positive value will increase the label's size.
+
+An `ALIGNMENT` of `0` represents "left aligned". `1` represents "center aligned". `2` represents "right aligned".
+
+- **Named Parameters/Additional Metadata**
+
+You can add additional metadata about your game within a label, which requires you to use a `Hash` instead.
+
+```ruby
+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",
+ # You can add any properties you like (this will be ignored/won't cause errors)
+ game_data_one: "Something",
+ game_data_two: {
+ value_1: "value",
+ value_2: "value two",
+ a_number: 15
+ }
+}
+```
+
+- **Getting The Size of a Piece of Text: `args.gtk.calcstringbox`**
+
+```ruby
+def tick args
+ # local variable
+ # TEXT SIZE_ENUM FONT
+ text_size = args.gtk.args.calcstringbox("some string", 0, "font.ttf")
+
+ # print size of a label to screen using Ruby's string formatting capabilities: #{}
+ args.outputs.labels << [640, 360, "the label's size is: #{text_size.x}, #{text_size.y}, #{text_size.w}, #{text_size.h}"]
+end
+```
+
+### Sprites: `args.outputs.sprites`
+
+`args.outputs.sprites` is used to render sprites.
+
+All primitives in GTK have the same considerations as detailed in the Labels section.
+
+- **Minimum Code**
+
+```ruby
+# X Y WIDTH HEIGHT PATH
+args.outputs.sprites << [100, 100, 32, 64, "sprites/player.png"]
+```
+
+- **Extended Capabilities**
+
+```ruby
+args.outputs.sprites << [
+ 100, # X
+ 100, # Y
+ 32, # W
+ 64, # H
+ "player.png", # PATH
+ 0, # ANGLE
+ 255, # ALPHA
+ 0, # RED_SATURATION
+ 255, # GREEN_SATURATION
+ 0, # BLUE_SATURATION
+ 0, # TILE_X
+ 0, # TILE_Y
+ 32, # TILE_W
+ 32 # TILE_H
+]
+```
+
+- **Named Parameters/Additional Metadata**
+
+Here are all the properties for `sprites`:
+
+```ruby
+args.outputs.sprites << {
+ x: 100,
+ y: 100,
+ w: 100,
+ h: 100,
+ path: "sprites/player.png",
+ angle: 0,
+ a, 255
+ r: 255,
+ g: 255,
+ b: 255,
+ tile_x: 0,
+ tile_y: 0,
+ tile_w: -1,
+ tile_h: -1,
+ flip_vertically: false,
+ flip_horizontally: false,
+ angle_anchor_x: 0.5,
+ angle_anchor_y: 1.0
+}
+```
+
+### Sounds `args.outputs.sounds`
+
+Sounds that end `.wav` will play once:
+`args.outputs.sounds << 'something.wav'`.
+
+Sounds that end `.ogg` is considered background music and will loop:
+`args.outputs.sounds << 'background_music.ogg'`.
+
+If you want to play a `.ogg` once as if it were a sound effect, you can do:
+`args.gtk.queue_sound 'some-ogg.ogg'`
+
+## Args' State `args.state`
+
+`args.state` is where you can put all of your game state.
+
+- **Tick Count `args.state.tick_count`**
+
+GTK has a fixed time step of 60 frames per second. You can access the current `tick_count` using `args.state.tick_count`:
+
+```ruby
+def tick args
+ # Render a label showing the current tick_count.
+ args.outputs.labels << [360, 640, args.state.tick_count]
+end
+```
+
+- **Working With "Open" Game State**
+
+`args.state` is a "open" data structure that allows you to define
+properties of any structure. You don't need to define any kind of
+`class`.
+
+To initialize your game state, use the `||=` operator. Any value on
+the right side of `||=` will only be assigned `once`.
+
+To assign a value every frame, just use the `=` operator, but _make
+sure_ you've initalized a default value.
+
+```ruby
+def tick args
+ # initialize your game state ONCE
+ args.player.x ||= 0
+ args.player.y ||= 0
+ args.player.hp ||= 100
+
+ # increment the x position of the character by one every frame
+ args.player.x += 1
+
+ # Render a sprite with a label above the sprite
+
+ # X Y W H PATH
+ args.outputs.sprites << [args.player.x, args.player.y, 32, 32 "player.png"]
+
+ # X Y TEXT
+ args.outputs.labels << [args.player.x, args.player.y - 50, args.player.hp]
+end
+```
+
+## Args' Inputs: `args.inputs`
+
+# Numeric
+
+## Numeric#elapsed?
+
+Returns true if a numeric value plus an offset represents a point
+in time that has elapsed. This is related to args.state.tick_count.
+
+```
+args.state.attacked_at ||= args.state.tick_count
+puts args.state.attacked_at.elapsed? 60 # will print false after one second.
+```
diff --git a/deploy_template/README.txt b/deploy_template/README.txt
index 80050db..2d00b4c 100644
--- a/deploy_template/README.txt
+++ b/deploy_template/README.txt
@@ -1,407 +1,369 @@
-Join the Discord: http://discord.dragonruby.org
-Community Forums: https://dragonruby.itch.io/dragonruby-gtk/community
-Free Training Course: http://dragonruby.school
+* Introduction
-Welcome!
+ Hello world! Do the things in this README file and you'll be well on your way to
+ building video games!
-Here's just a little push to get you started.
+* Join the community!
-If you want to write a game, it's no different than writing any other
-program for any other framework: there are a few simple rules that might be
-new to you, but more or less programming is programming no matter what you
-are building.
+ Those who use DragonRuby are called Dragon Riders. This identity is
+ incredibly important to us. When someone asks you:
-Did you not know that? Did you think you couldn't write a game because you're
-a "web guy" or you're writing Java at a desk job? Stop letting people tell
-you that you can't, because you already have everything you need.
+ > What game engine do you use?
-Here, we're going to be programming in a language called "Ruby." In the
-interest of full disclosure, I wrote the C parts of this toolkit and Ruby
-looks a little strange to me, but I'm going to walk you through the basics
-because we're all learning together, and if you mostly think of yourself as
-someone that writes C (or C++, C#, Objective-C), PHP, or Java, then you're
-only a step behind me right now.
+ You can proudly reply with:
-Here's the most important thing you should know: Ruby lets you do some
-complicated things really easily, and you can learn that stuff later. I'm
-going to show you one or two cool tricks, but that's all.
-
-Do you know what an if statement is? A for-loop? An array? That's all you'll
-need to start.
+ > I am a Dragon Rider.
-If you don't know how to program, no worries! Watching these two videos will
-help tremendously:
+** Subscribe to the News Letter
-- https://s3.amazonaws.com/s3.dragonruby.org/dragonruby-gtk-primer.mp4
-- https://s3.amazonaws.com/s3.dragonruby.org/dragonruby-gtk-intermediate.mp4
+ The News Letter will keep you in the loop with regards to
+ http://dragonrubydispatch.com/
-Did you watch the videos? Great!
+** Join the Discord
-Ok, here are few rules with regards to game development with GTK:
-
-- Your game is all going to happen under one function...
-- ...that runs 60 times a second...
-- ...and has to tell the computer what to draw each time.
-
-That's an entire video game in one run-on sentence.
-
-Here's that function. You're going to want to put this in mygame/app/main.rb,
-because that's where we'll look for it by default. Load it up in your favorite
-text editor.
-
-
-def tick args
- args.outputs.labels << [ 580, 400, 'Hello World!' ]
-end
-
-Now run "dragonruby" ...did you get a window with "Hello World!" written in
-it? Good, you're officially a game developer!
-
-mygame/app/main.rb, is where the Ruby source code is located. This looks a little strange, so
-I'll break it down line by line. In Ruby, a '#' character starts a single-line
-comment, so I'll talk about this inline.
-
-# This "def"ines a function, named "tick," which takes a single argument
-# named "args". DragonRuby looks for this function and calls it every
-# frame, 60 times a second. "args" is a magic structure with lots of
-# information in it. You can set variables in there for your own game state,
-# and every frame it will updated if keys are pressed, joysticks moved,
-# mice clicked, etc.
-def tick args
-
- # One of the things in "args" is the "outputs" object that your game uses
- # to draw things. Afraid of rendering APIs? No problem. In DragonRuby,
- # you use arrays to draw things and we figure out the details.
- # If you want to draw text on the screen, you give it an array (the thing
- # in the [ brackets ]), with an X and Y coordinate and the text to draw.
- # The "<<" thing says "append this array onto the list of them at
- # args.outputs.labels)
- args.outputs.labels << [ 580, 400, 'Hello World!' ]
-end
-
-# Once your "tick" function finishes, we look at all the arrays you made and
-# figure out how to draw it. You don't need to know about graphics APIs.
-# You're just setting up some arrays! DragonRuby clears out these arrays
-# every frame, so you just need to add what you need _right now_ each time.
-
-Now let's spice this up a little.
-
-We're going to add some graphics. Each 2D image in DragonRuby is called a
-"sprite," and to use them, you just make sure they exist in a reasonable file
-format (png, jpg, gif, bmp, etc) and specify them by filename. The first time
-you use one, DragonRuby will load it and keep it in video memory for fast
-access in the future. If you use a filename that doesn't exist, you get a fun
-checkerboard pattern!
-
-There's a "dragonruby.png" file included, just to get you started. Let's have
-it draw every frame with our text:
-
-def tick args
- args.outputs.labels << [ 580, 400, 'Hello World!' ]
- args.outputs.sprites << [ 576, 100, 128, 101, 'dragonruby.png' ]
-end
-
-(ProTip: you don't have to restart DragonRuby to test your changes; when you
-save main.rb, DragonRuby will notice and reload your program.)
-
-That ".sprites" line says "add a sprite to the list of sprites we're drawing,
-and draw it at position (576, 100) at a size of 128x101 pixels, and you can
-find the image to draw at dragonruby.png.
-
-Quick note about coordinates: (0, 0) is the bottom left corner of the screen,
-and positive numbers go up and to the right. This is more "geometrically
-correct," even if it's not how you remember doing 2D graphics, but we chose
-this for a simpler reason: when you're making Super Mario Brothers and you
-want Mario to jump, you should be able to add to Mario's y position as he
-goes up and subtract as he falls. It makes things easier to understand.
-
-Also: your game screen is _always_ 1280x720 pixels. If you resize the window,
-we will scale and letterbox everything appropriately, so you never have to
-worry about different resolutions.
-
-Ok, now we have an image on the screen, let's animate it:
-
-def tick args
- args.state.rotation ||= 0
- args.outputs.labels << [ 580, 400, 'Hello World!' ]
- args.outputs.sprites << [ 576, 100, 128, 101, 'dragonruby.png', args.state.rotation ]
- args.state.rotation -= 1
-end
+ Amir (one of the creators of DragonRuby) is always available to help
+ you out. So take the time to join the community Discord. The invite linke is located at:
-Now you can see that this function is getting called a lot!
-
-Here's a fun Ruby thing: "args.state.rotation ||= 0" is shorthand for "if
-args.state.rotation isn't initialized, set it to zero." It's a nice way to
-embed your initialization code right next to where you need the variable.
-
-args.state is a place you can hang your own data and have it survive past the
-life of the function call. In this case, the current rotation of our sprite,
-which is happily spinning at 60 frames per second. If you don't specify
-rotation (or alpha, or color modulation, or a source rectangle, etc),
-DragonRuby picks a reasonable default, and the array is ordered by the most
-likely things you need to tell us: position, size, name.
-
-One thing we decided to do in DragonRuby is not make you worry about delta
-time: your function runs at 60 frames per second (about 16 milliseconds) and
-that's that. Having to worry about framerate is something massive triple-AAA
-games do, but for fun little 2D games? You'd have to work really hard to not
-hit 60fps. All your drawing is happening on a GPU designed to run Fortnite
-quickly; it can definitely handle this.
-
-Since we didn't make you worry about delta time, you can just move the
-rotation by 1 every time and it works without you having to keep track of
-time and math. Want it to move faster? Subtract 2.
-
-Now, let's move that image around.
-
-def tick args
- args.state.rotation ||= 0
- args.state.x ||= 576
- args.state.y ||= 100
-
- if args.inputs.mouse.click
- args.state.x = args.inputs.mouse.click.point.x - 64
- args.state.y = args.inputs.mouse.click.point.y - 50
- end
-
- args.outputs.labels << [ 580, 400, 'Hello World!' ]
- args.outputs.sprites << [ args.state.x, args.state.y, 128, 101, 'dragonruby.png', args.state.rotation ]
-
- args.state.rotation -= 1
-end
-
-Everywhere you click your mouse, the image moves there. We set a default
-location for it with args.state.x ||= 576, and then we change those variables
-when we see the mouse button in action. You can get at the keyboard and game
-controllers in similar ways.
+ DragonRuby Discord: http://discord.dragonruby.org
-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 args.output anymore.
+** Introduce Yourself on the Forums
-If you want to get a good idea of what's available to you, please check out
-the "samples" directory: in there, the "tech_demo" directory is a good dumping
-ground of features, and many of the others are little starter games. Just
-go to the samples directory, find the sample you want to run, and double click
-"dragonruby" within the sample folder.
+ Take a moment to introducing yourself on the community forum:
-There is also a lot more you _can't_ do with DragonRuby, at least not yet.
-We are excited about the potential of this, so we wanted to get it in your
-hands right away. We intend to add a bunch of features and we would love
-feedback on what needs work and what you want that isn't there.
+ Stickied Community Post: https://itch.io/t/526689/dragonruby-gtk-discord-server-created-join-it-dammit
-But now, it's time to show your friends and family that you're a real game
-developer! Let's package up what we have and let them play it!
+ This provides community members a registry of everyone using
+ DragonRuby. Itch.io holds a lot of game jams, and it'd be awesome if
+ Dragon Riders had a central place to find each other.
-Let's just give it a few bits of information. Point your text editor at
-mygame/metadata/game_metadata.txt and make it look like this:
-
-devid=bob
-devtitle=Bob The Game Developer
-gameid=mygame
-gametitle=My Game
-version=0.1
-
-(obviously you should change it if your name isn't Bob.)
-
-See that other program? dragonruby-publish? Let's use that to package up your
-game. Run this from the command line:
-
-./dragonruby-publish --only-package mygame
+* Determine how you want to start learning based on your experience level!
-(if you're on Windows, don't put the "./" on the front. That's a Mac and
-Linux thing.)
+ Follows are sections pertaining to your experience level as a
+ programer and experience level with coding in a dynamic language.
-This should spit out packaged versions of your game for Windows, Linux and
-macOS that you can hand out to friends and family however you like. They
-just have to download and double-click it!
+** If you have zero experience with programming.
-But if you want to get _really_ fancy: Set up a free account on
-https://itch.io/, with the same login as you specified for "devid" in
-game_metadata.txt, and a product with the gameid. Set a price for it. And
-then run...
-
-./dragonruby-publish mygame
+ If you have no programing experience at all. You'll want to take the
+ time to see what DragonRuby is like before jumping in to code. Watch
+ the following videos in order (each one is only ~20 minutes long).
-...and DragonRuby will package _and publish_ your game to itch.io! Tell your
-friends to go to your game's very own webpage and buy it!
+ Don't attempt to code anything shown in the video yet, just watch them to
+ get familiar with the language and how games are built.
-If you make changes to your game, just re-run dragonruby-publish and it'll
-update the downloads for you.
+ 1. Beginner Introduction to Ruby: https://www.youtube.com/watch?v=ixw7TJhU08E
+ 2. Intermediate Introduction to Ruby Syntax: https://www.youtube.com/watch?v=HG-XRZ5Ppgc
+ 3. Intermediate Introduction to Arrays in Ruby: https://www.youtube.com/watch?v=N72sEYFRqfo
-And that's all! We hope you find DragonRuby useful, and more importantly we
-hope you have fun playing around with it. Please check out
-https://dragonruby.itch.io/dragonruby-gtk as we add new features and improve
-this toolkit based on your feedback!
+ Once you have watched all the videos. Then (and only then) go back
+ through the videos and follow along. Here are the locations for the
+ samples:
-BORING LEGAL STUFF AND CREDIT WHERE CREDIT IS DUE:
-(if you don't read software licenses, you're done with this README now. IT IS
-STRONGLY RECOMMENDED THAT YOU GO THROUGH ALL THE SAMPLE APPS!!)
+ 1. Beginner Introduction to Ruby: samples/00_beginner_ruby_primer
+ 2. Intermediate Tutorials: samples/00_intermediate_ruby_primer
-DragonRuby uses the following open source libraries!
+** If you do not know Ruby, but have experience with C# (Unity) or GML (GameMaker)
-- mRuby: https://mruby.org/
+ Those engines rot your brain. Forget the concepts that the forced you
+ to learn. Game development is so much simpler than what they make you
+ do. Please, try your best to set aside the concepts those engines
+ teach (we promise our approach to game development is much much easier).
-Copyright (c) 2019 mruby developers
+ Watch these videos to get familiar with the Ruby language and
+ programming environment (they are ~20 min each so it'll be quick):
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
+ 1. Beginner Introduction to Ruby: https://www.youtube.com/watch?v=ixw7TJhU08E
+ 2. Intermediate Introduction to Ruby Syntax: https://www.youtube.com/watch?v=HG-XRZ5Ppgc
+ 3. Intermediate Introduction to Arrays in Ruby: https://www.youtube.com/watch?v=N72sEYFRqfo
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
+ You may also want to try this free course provided at http://dragonruby.school.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
+ After you've watch the videos, you'll be ready to go to the next section.
+** You are a dev that is familiar with a dynamically typed language (Ruby, Lua, Python, or JavaScript).
-- Simple Directmedia Layer: https://www.libsdl.org/
+*** STEP 1: Work through this Hello World tutorial
-Simple DirectMedia Layer
-Copyright (C) 1997-2019 Sam Lantinga <[email protected]>
+ This tutorial is provided by Ryan C Gordon (check out his wikipedia
+ page). We call him "The Juggernaut":
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any damages
-arising from the use of this software.
+ Welcome!
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it
-freely, subject to the following restrictions:
+ Here's just a little push to get you started if you're new to programming or
+ game development.
-1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
-2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
-3. This notice may not be removed or altered from any source distribution.
+ If you want to write a game, it's no different than writing any other
+ program for any other framework: there are a few simple rules that might be
+ new to you, but more or less programming is programming no matter what you
+ are building.
+ Did you not know that? Did you think you couldn't write a game because you're
+ a "web guy" or you're writing Java at a desk job? Stop letting people tell
+ you that you can't, because you already have everything you need.
-- stb_vorbis, stb_image, stb_truetype: https://github.com/nothings/stb/
+ Here, we're going to be programming in a language called "Ruby." In the
+ interest of full disclosure, I (Ryan "The Juggernaut" Gordon) wrote the C
+ parts of this toolkit and Ruby looks a little strange to me (Amir Rajan wrote the
+ Ruby parts), but I'm going to walk you through the basics because we're all
+ learning together, and if you mostly think of yourself as someone that writes
+ C (or C++, C#, Objective-C), PHP, or Java, then you're only a step behind me right now.
-This is free and unencumbered software released into the public domain.
-Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
-software, either in source code form or as a compiled binary, for any purpose,
-commercial or non-commercial, and by any means.
-In jurisdictions that recognize copyright laws, the author or authors of this
-software dedicate any and all copyright interest in the software to the public
-domain. We make this dedication for the benefit of the public at large and to
-the detriment of our heirs and successors. We intend this dedication to be an
-overt act of relinquishment in perpetuity of all present and future rights to
-this software under copyright law.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Here's the most important thing you should know: Ruby lets you do some
+ complicated things really easily, and you can learn that stuff later. I'm
+ going to show you one or two cool tricks, but that's all.
+ Do you know what an if statement is? A for-loop? An array? That's all you'll
+ need to start.
-- lodepng: https://lodev.org/lodepng/
+ Ok, here are few rules with regards to game development with GTK:
-Copyright (c) 2005-2018 Lode Vandevenne
+ - Your game is all going to happen under one function...
+ - ...that runs 60 times a second...
+ - ...and has to tell the computer what to draw each time.
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any damages
-arising from the use of this software.
+ That's an entire video game in one run-on sentence.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it
-freely, subject to the following restrictions:
+ Here's that function. You're going to want to put this in mygame/app/main.rb,
+ because that's where we'll look for it by default. Load it up in your favorite
+ text editor.
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
+ #+begin_src ruby
+ def tick args
+ args.outputs.labels << [ 580, 400, 'Hello World!' ]
+ end
+ #+end_src
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
+ Now run `dragonruby` ...did you get a window with "Hello World!" written in
+ it? Good, you're officially a game developer!
- 3. This notice may not be removed or altered from any source
- distribution.
+ `mygame/app/main.rb`, is where the Ruby source code is located. This looks a little strange, so
+ I'll break it down line by line. In Ruby, a '#' character starts a single-line
+ comment, so I'll talk about this inline.
+ #+begin_src ruby
-- miniz: https://github.com/richgel999/miniz
+ # This "def"ines a function, named "tick," which takes a single argument
+ # named "args". DragonRuby looks for this function and calls it every
+ # frame, 60 times a second. "args" is a magic structure with lots of
+ # information in it. You can set variables in there for your own game state,
+ # and every frame it will updated if keys are pressed, joysticks moved,
+ # mice clicked, etc.
+ def tick args
-Copyright 2013-2014 RAD Game Tools and Valve Software
-Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+ # One of the things in "args" is the "outputs" object that your game uses
+ # to draw things. Afraid of rendering APIs? No problem. In DragonRuby,
+ # you use arrays to draw things and we figure out the details.
+ # If you want to draw text on the screen, you give it an array (the thing
+ # in the [ brackets ]), with an X and Y coordinate and the text to draw.
+ # The "<<" thing says "append this array onto the list of them at
+ # args.outputs.labels)
+ args.outputs.labels << [ 580, 400, 'Hello World!' ]
+ end
-All Rights Reserved.
+ #+end_src
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+ Once your `tick` function finishes, we look at all the arrays you made and
+ figure out how to draw it. You don't need to know about graphics APIs.
+ You're just setting up some arrays! DragonRuby clears out these arrays
+ every frame, so you just need to add what you need _right now_ each time.
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
+ Now let's spice this up a little.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+ We're going to add some graphics. Each 2D image in DragonRuby is called a
+ "sprite," and to use them, you just make sure they exist in a reasonable file
+ format (png, jpg, gif, bmp, etc) and specify them by filename. The first time
+ you use one, DragonRuby will load it and keep it in video memory for fast
+ access in the future. If you use a filename that doesn't exist, you get a fun
+ checkerboard pattern!
+ There's a "dragonruby.png" file included, just to get you started. Let's have
+ it draw every frame with our text:
-- MojoAL: https://hg.icculus.org/icculus/mojoAL/
+ #+begin_src ruby
- Copyright (c) 2018 Ryan C. Gordon and others.
+ def tick args
+ args.outputs.labels << [ 580, 400, 'Hello World!' ]
+ args.outputs.sprites << [ 576, 100, 128, 101, 'dragonruby.png' ]
+ end
- This software is provided 'as-is', without any express or implied warranty.
- In no event will the authors be held liable for any damages arising from
- the use of this software.
+ #+end_src
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
+ (ProTip: you don't have to restart DragonRuby to test your changes; when you
+ save main.rb, DragonRuby will notice and reload your program.)
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software in a
- product, an acknowledgment in the product documentation would be
- appreciated but is not required.
+ That `.sprites` line says "add a sprite to the list of sprites we're drawing,
+ and draw it at position (576, 100) at a size of 128x101 pixels". You can
+ find the image to draw at dragonruby.png.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
+ Quick note about coordinates: (0, 0) is the bottom left corner of the screen,
+ and positive numbers go up and to the right. This is more "geometrically
+ correct," even if it's not how you remember doing 2D graphics, but we chose
+ this for a simpler reason: when you're making Super Mario Brothers and you
+ want Mario to jump, you should be able to add to Mario's y position as he
+ goes up and subtract as he falls. It makes things easier to understand.
- 3. This notice may not be removed or altered from any source distribution.
+ Also: your game screen is _always_ 1280x720 pixels. If you resize the window,
+ we will scale and letterbox everything appropriately, so you never have to
+ worry about different resolutions.
- Ryan C. Gordon <[email protected]>
+ Ok, now we have an image on the screen, let's animate it:
+ #+begin_src ruby
-- PhysicsFS: https://icculus.org/physfs/
+ def tick args
+ args.state.rotation ||= 0
+ args.outputs.labels << [ 580, 400, 'Hello World!' ]
+ args.outputs.sprites << [ 576, 100, 128, 101, 'dragonruby.png', args.state.rotation ]
+ args.state.rotation -= 1
+ end
- Copyright (c) 2001-2019 Ryan C. Gordon and others.
+ #+end_src
- This software is provided 'as-is', without any express or implied warranty.
- In no event will the authors be held liable for any damages arising from
- the use of this software.
+ Now you can see that this function is getting called a lot!
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
+ Here's a fun Ruby thing: `args.state.rotation ||= 0` is shorthand for "if
+ args.state.rotation isn't initialized, set it to zero." It's a nice way to
+ embed your initialization code right next to where you need the variable.
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software in a
- product, an acknowledgment in the product documentation would be
- appreciated but is not required.
+ `args.state` is a place you can hang your own data and have it survive past the
+ life of the function call. In this case, the current rotation of our sprite,
+ which is happily spinning at 60 frames per second. If you don't specify
+ rotation (or alpha, or color modulation, or a source rectangle, etc),
+ DragonRuby picks a reasonable default, and the array is ordered by the most
+ likely things you need to tell us: position, size, name.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
+ One thing we decided to do in DragonRuby is not make you worry about delta
+ time: your function runs at 60 frames per second (about 16 milliseconds) and
+ that's that. Having to worry about framerate is something massive triple-AAA
+ games do, but for fun little 2D games? You'd have to work really hard to not
+ hit 60fps. All your drawing is happening on a GPU designed to run Fortnite
+ quickly; it can definitely handle this.
- 3. This notice may not be removed or altered from any source distribution.
+ Since we didn't make you worry about delta time, you can just move the
+ rotation by 1 every time and it works without you having to keep track of
+ time and math. Want it to move faster? Subtract 2.
- Ryan C. Gordon <[email protected]>
+ Now, let's move that image around.
+
+ #+begin_src ruby
+
+ def tick args
+ args.state.rotation ||= 0
+ args.state.x ||= 576
+ args.state.y ||= 100
+
+ if args.inputs.mouse.click
+ args.state.x = args.inputs.mouse.click.point.x - 64
+ args.state.y = args.inputs.mouse.click.point.y - 50
+ end
+
+ args.outputs.labels << [ 580, 400, 'Hello World!' ]
+ args.outputs.sprites << [ args.state.x, args.state.y, 128, 101, 'dragonruby.png', args.state.rotation ]
+
+ args.state.rotation -= 1
+ end
+
+ #+end_src
+
+ Everywhere you click your mouse, the image moves there. We set a default
+ location for it with args.state.x ||= 576, and then we change those variables
+ when we see the mouse button in action. You can get at the keyboard and game
+ controllers in similar ways.
+
+ 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 args.output anymore.
+
+*** STEP 2: Read the CHEATSHEET.txt
+
+ Go to the file CHEATSHEET.txt and skim through it quickly to get a
+ feel for some of the other APIs you have access to. If you need even
+ more details you'll find them at `mygame/documentation`.
+
+*** STEP 3: Run each sample app in order and read the code.
+
+ The sample apps located in the `sample` directory are ordered by
+ increasing complexity. Run each one of them and read through the
+ code. Play around by changing values and see how they change the game.
+
+*** STEP 4: Editor integration.
+
+ There is a file called `vim-ctags` and `emacs-ctags`. The data in
+ these files are standard output provided by Exuberent CTAGS. Most
+ editors have a "ctags plugin" so just search for that plugin for your
+ editor and point it to these files.
+
+*** STEP 5: Get in the habit of reading the CHANGELOG
+
+ We are constantly adding new features to the engine. Be sure to read
+ the changelog with every release.
+
+* How to publish your game.
+
+ 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!
+
+** STEP 1: Create a new Game in Itch.io.
+
+ Log into Itch.io and go to https://itch.io/game/new.
+
+ - Title: Give your game a Title. This value represents your `gametitle`.
+ - Project URL: Set your project url. This value represents your `gameid`.
+ - Classification: Keep this as Game.
+ - Kind of Project: Select HTML from the drop down list. Dont worry,
+ the HTML project type _aslo supports binary downloads_.
+ - Uploads: Skip this section for now.
+ - Embed Options: Set the dropdown value to "Click to launch in fullscreen".
+ DO NOT use the Embed in page option. iFrames are not reliable with
+ regards to capturing input.
+
+ You can fill out all the other options later.
+
+** STEP 2: Go to mygame/metadata/metadata.txt and update it.
+
+ Point your text editor at mygame/metadata/game_metadata.txt and
+ make it look like this: (Remove the `#` at the beginning of each line).
+
+ #+begin_src text
+ devid=bob
+ devtitle=Bob The Game Developer
+ gameid=mygame
+ gametitle=My Game
+ version=0.1
+ #+end_src
+
+ The `devid` property is the username you use to log into Itch.io.
+ The `devtitle` is your name or company name (it can contain spaces).
+ The `gameid` is the Project URL value (see details in STEP 1).
+ The `gametitle` is the name of your game (it can contain spaces).
+ The `version` can be any `major.minor` number format.
+
+** STEP 3: Build your game for distribution.
+
+ Open up the terminal and run this from the command line:
+
+ #+begin_src sh
+ ./dragonruby-publish --only-package mygame
+ #+end_src
+
+ (if you're on Windows, don't put the "./" on the front. That's a Mac and
+ Linux thing.)
+
+ A directory called `./build` will be created that contains your
+ binaries. You can upload this to Itch.io manually. For the HTML
+ version of your game after you upload it. Check the checkbox labeled
+ "This file will be played in the browser".
+
+ For subsequent updates you can use an automated deployment to Itch.io:
+
+ #+begin_src sh
+ ./dragonruby-publish mygame
+ #+end_src
+
+ DragonRuby will package _and publish_ your game to itch.io! Tell your
+ friends to go to your game's very own webpage and buy it!
+
+ If you make changes to your game, just re-run dragonruby-publish and it'll
+ update the downloads for you.
diff --git a/deploy_template/mygame/app/tests.rb b/deploy_template/mygame/app/tests.rb
index 1dc452a..a60c8be 100644
--- a/deploy_template/mygame/app/tests.rb
+++ b/deploy_template/mygame/app/tests.rb
@@ -2,10 +2,12 @@
# 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
+# Here is an example test and game
+
+# To run the test: ./dragonruby mygame --eval tests.rb --no-tick
class MySuperHappyFunGame
- gtk_args
+ attr_gtk
def tick
outputs.solids << [100, 100, 300, 300]
@@ -21,4 +23,7 @@ def test_universe args, assert
puts "test_universe completed successfully"
end
+puts "running tests"
+$gtk.reset 100
+$gtk.log_level = :off
$gtk.tests.start
diff --git a/deploy_template/mygame/documentation/02-labels.md b/deploy_template/mygame/documentation/02-labels.md
index 2adf5e1..ea2642e 100644
--- a/deploy_template/mygame/documentation/02-labels.md
+++ b/deploy_template/mygame/documentation/02-labels.md
@@ -84,16 +84,16 @@ using the helper method (providing all the parameters).
```ruby
args.outputs.labels << {
- x: 200,
- y: 550,
- text: "dragonruby",
- size: 2,
- alignment: 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"
}
```
diff --git a/deploy_template/mygame/documentation/05-sprites.md b/deploy_template/mygame/documentation/05-sprites.md
index 3648fc4..c80b46c 100644
--- a/deploy_template/mygame/documentation/05-sprites.md
+++ b/deploy_template/mygame/documentation/05-sprites.md
@@ -168,7 +168,7 @@ args.outputs.sprites << [ 100, # X
false, # FLIP_HORIZONTALLY
false, # FLIP_VERTICALLY
0.5, # ANGLE_ANCHOR_X
- 1.0] # ANGLE_ANCHOR_Y
+ 1.0] # ANCHOR_Y
```
## Hash (Advanced)
@@ -185,7 +185,7 @@ args.outputs.sprites << {
h: 100,
path: "sprites/player.png",
angle: 0,
- a: 255,
+ a, 255
r: 255,
g: 255,
b: 255,
diff --git a/deploy_template/mygame/documentation/99-todo.md b/deploy_template/mygame/documentation/99-todo.md
new file mode 100644
index 0000000..39c542a
--- /dev/null
+++ b/deploy_template/mygame/documentation/99-todo.md
@@ -0,0 +1,89 @@
+# Documentation That Needs to be Organized
+
+## Class macro gtk_args
+
+Here's how you can use the `gtk_args` class method:
+
+```ruby
+class Game
+ gtk_args
+ attr_accessor :current_scene, :other_custom_attrs
+
+ def tick
+ end
+end
+
+$game = Game.new
+
+def tick args
+ $game.args = args
+ $game.tick
+end
+```
+
+The code above is the similar to:
+
+```ruby
+class Game
+ attr_accessor :args, :grid, :state, :inputs, :outputs, :gtk, :passes,
+ :current_scene, :other_custom_attrs
+
+ def tick
+ end
+end
+
+$game = Game.new
+
+def tick args
+ $game.args = args
+ $game.grid = args.grid
+ $game.state = args.state
+ $game.outputs = args.outputs
+ $game.gtk = args.gtk
+ $game.passes = args.passes
+ $game.tick
+end
+```
+
+## Monkey patching the runtime
+
+You're on your own if you do this :grimacing:
+
+```ruby
+module GTK
+ class Runtime
+ alias_method :__original_tick_core__, :tick_core unless Runtime.instance_methods.include?(:__original_tick_core__)
+
+ def tick_core
+ __original_tick_core__
+ $top_level.oh @args
+ $top_level.god @args
+ $top_level.why @args
+ end
+ end
+end
+
+def tick args
+end
+
+def oh args
+end
+
+def god args
+end
+
+def why args
+end
+```
+
+## MP3's to Wav converstion script:
+
+```ruby
+`ls .`.each_line.to_a.map do |l|
+ l = l.strip
+ if l.end_with? "mp3"
+ `ffmpeg -i #{l} -acodec pcm_s16le -ar 44100 prep-#{l.split(".")[0]}.wav`
+ `ffmpeg -y -i prep-#{l.split(".")[0]}.wav -f wav -bitexact -acodec pcm_s16le -ar 44100 -ac 1 #{l.split(".")[0]}.wav`
+ end
+end
+```
diff --git a/deploy_template/mygame/metadata/game_metadata.txt b/deploy_template/mygame/metadata/game_metadata.txt
new file mode 100644
index 0000000..1b03500
--- /dev/null
+++ b/deploy_template/mygame/metadata/game_metadata.txt
@@ -0,0 +1,6 @@
+#devid=myname
+#devtitle=My Name
+#gameid=mygame
+#gametitle=My Game
+#version=0.1
+#icon=metadata/icon.png
diff --git a/deploy_template/mygame/metadata/icon.png b/deploy_template/mygame/metadata/icon.png
new file mode 100644
index 0000000..e20e8c2
--- /dev/null
+++ b/deploy_template/mygame/metadata/icon.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/circle-black.png b/deploy_template/mygame/sprites/circle-black.png
new file mode 100644
index 0000000..c98e23d
--- /dev/null
+++ b/deploy_template/mygame/sprites/circle-black.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/circle-blue.png b/deploy_template/mygame/sprites/circle-blue.png
new file mode 100644
index 0000000..1726d2a
--- /dev/null
+++ b/deploy_template/mygame/sprites/circle-blue.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/circle-gray.png b/deploy_template/mygame/sprites/circle-gray.png
new file mode 100644
index 0000000..960f191
--- /dev/null
+++ b/deploy_template/mygame/sprites/circle-gray.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/circle-green.png b/deploy_template/mygame/sprites/circle-green.png
new file mode 100644
index 0000000..43cf7ee
--- /dev/null
+++ b/deploy_template/mygame/sprites/circle-green.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/circle-indigo.png b/deploy_template/mygame/sprites/circle-indigo.png
new file mode 100644
index 0000000..598e240
--- /dev/null
+++ b/deploy_template/mygame/sprites/circle-indigo.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/circle-orange.png b/deploy_template/mygame/sprites/circle-orange.png
new file mode 100644
index 0000000..5604a42
--- /dev/null
+++ b/deploy_template/mygame/sprites/circle-orange.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/circle-red.png b/deploy_template/mygame/sprites/circle-red.png
new file mode 100644
index 0000000..7f17ca6
--- /dev/null
+++ b/deploy_template/mygame/sprites/circle-red.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/circle-violet.png b/deploy_template/mygame/sprites/circle-violet.png
new file mode 100644
index 0000000..681d210
--- /dev/null
+++ b/deploy_template/mygame/sprites/circle-violet.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/circle-white.png b/deploy_template/mygame/sprites/circle-white.png
new file mode 100644
index 0000000..bd32155
--- /dev/null
+++ b/deploy_template/mygame/sprites/circle-white.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/circle-yellow.png b/deploy_template/mygame/sprites/circle-yellow.png
new file mode 100644
index 0000000..94992eb
--- /dev/null
+++ b/deploy_template/mygame/sprites/circle-yellow.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/hexagon-black.png b/deploy_template/mygame/sprites/hexagon-black.png
new file mode 100644
index 0000000..f50c872
--- /dev/null
+++ b/deploy_template/mygame/sprites/hexagon-black.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/hexagon-blue.png b/deploy_template/mygame/sprites/hexagon-blue.png
new file mode 100644
index 0000000..1696bae
--- /dev/null
+++ b/deploy_template/mygame/sprites/hexagon-blue.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/hexagon-gray.png b/deploy_template/mygame/sprites/hexagon-gray.png
new file mode 100644
index 0000000..e8c4c5a
--- /dev/null
+++ b/deploy_template/mygame/sprites/hexagon-gray.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/hexagon-green.png b/deploy_template/mygame/sprites/hexagon-green.png
new file mode 100644
index 0000000..a700602
--- /dev/null
+++ b/deploy_template/mygame/sprites/hexagon-green.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/hexagon-indigo.png b/deploy_template/mygame/sprites/hexagon-indigo.png
new file mode 100644
index 0000000..15f6f4f
--- /dev/null
+++ b/deploy_template/mygame/sprites/hexagon-indigo.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/hexagon-orange.png b/deploy_template/mygame/sprites/hexagon-orange.png
new file mode 100644
index 0000000..1587173
--- /dev/null
+++ b/deploy_template/mygame/sprites/hexagon-orange.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/hexagon-red.png b/deploy_template/mygame/sprites/hexagon-red.png
new file mode 100644
index 0000000..d442f39
--- /dev/null
+++ b/deploy_template/mygame/sprites/hexagon-red.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/hexagon-violet.png b/deploy_template/mygame/sprites/hexagon-violet.png
new file mode 100644
index 0000000..3be5731
--- /dev/null
+++ b/deploy_template/mygame/sprites/hexagon-violet.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/hexagon-white.png b/deploy_template/mygame/sprites/hexagon-white.png
new file mode 100644
index 0000000..c1ad970
--- /dev/null
+++ b/deploy_template/mygame/sprites/hexagon-white.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/hexagon-yellow.png b/deploy_template/mygame/sprites/hexagon-yellow.png
new file mode 100644
index 0000000..63f5f34
--- /dev/null
+++ b/deploy_template/mygame/sprites/hexagon-yellow.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/isometric-black.png b/deploy_template/mygame/sprites/isometric-black.png
new file mode 100644
index 0000000..fa9e463
--- /dev/null
+++ b/deploy_template/mygame/sprites/isometric-black.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/isometric-blue.png b/deploy_template/mygame/sprites/isometric-blue.png
new file mode 100644
index 0000000..a3d8524
--- /dev/null
+++ b/deploy_template/mygame/sprites/isometric-blue.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/isometric-gray.png b/deploy_template/mygame/sprites/isometric-gray.png
new file mode 100644
index 0000000..85dcc1d
--- /dev/null
+++ b/deploy_template/mygame/sprites/isometric-gray.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/isometric-green.png b/deploy_template/mygame/sprites/isometric-green.png
new file mode 100644
index 0000000..ec2773e
--- /dev/null
+++ b/deploy_template/mygame/sprites/isometric-green.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/isometric-indigo.png b/deploy_template/mygame/sprites/isometric-indigo.png
new file mode 100644
index 0000000..e6be50c
--- /dev/null
+++ b/deploy_template/mygame/sprites/isometric-indigo.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/isometric-orange.png b/deploy_template/mygame/sprites/isometric-orange.png
new file mode 100644
index 0000000..154d81c
--- /dev/null
+++ b/deploy_template/mygame/sprites/isometric-orange.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/isometric-red.png b/deploy_template/mygame/sprites/isometric-red.png
new file mode 100644
index 0000000..3448c4d
--- /dev/null
+++ b/deploy_template/mygame/sprites/isometric-red.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/isometric-violet.png b/deploy_template/mygame/sprites/isometric-violet.png
new file mode 100644
index 0000000..f09bf21
--- /dev/null
+++ b/deploy_template/mygame/sprites/isometric-violet.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/isometric-white.png b/deploy_template/mygame/sprites/isometric-white.png
new file mode 100644
index 0000000..a45793d
--- /dev/null
+++ b/deploy_template/mygame/sprites/isometric-white.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/isometric-yellow.png b/deploy_template/mygame/sprites/isometric-yellow.png
new file mode 100644
index 0000000..9be20c7
--- /dev/null
+++ b/deploy_template/mygame/sprites/isometric-yellow.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/square-black.png b/deploy_template/mygame/sprites/square-black.png
new file mode 100644
index 0000000..cea7bd7
--- /dev/null
+++ b/deploy_template/mygame/sprites/square-black.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/square-blue.png b/deploy_template/mygame/sprites/square-blue.png
new file mode 100644
index 0000000..b840849
--- /dev/null
+++ b/deploy_template/mygame/sprites/square-blue.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/square-gray.png b/deploy_template/mygame/sprites/square-gray.png
new file mode 100644
index 0000000..2142b30
--- /dev/null
+++ b/deploy_template/mygame/sprites/square-gray.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/square-green.png b/deploy_template/mygame/sprites/square-green.png
new file mode 100644
index 0000000..5ef7f75
--- /dev/null
+++ b/deploy_template/mygame/sprites/square-green.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/square-indigo.png b/deploy_template/mygame/sprites/square-indigo.png
new file mode 100644
index 0000000..2384108
--- /dev/null
+++ b/deploy_template/mygame/sprites/square-indigo.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/square-orange.png b/deploy_template/mygame/sprites/square-orange.png
new file mode 100644
index 0000000..bb1eee7
--- /dev/null
+++ b/deploy_template/mygame/sprites/square-orange.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/square-red.png b/deploy_template/mygame/sprites/square-red.png
new file mode 100644
index 0000000..3ed5f13
--- /dev/null
+++ b/deploy_template/mygame/sprites/square-red.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/square-violet.png b/deploy_template/mygame/sprites/square-violet.png
new file mode 100644
index 0000000..333540c
--- /dev/null
+++ b/deploy_template/mygame/sprites/square-violet.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/square-white.png b/deploy_template/mygame/sprites/square-white.png
new file mode 100644
index 0000000..378c565
--- /dev/null
+++ b/deploy_template/mygame/sprites/square-white.png
Binary files differ
diff --git a/deploy_template/mygame/sprites/square-yellow.png b/deploy_template/mygame/sprites/square-yellow.png
new file mode 100644
index 0000000..0edeeec
--- /dev/null
+++ b/deploy_template/mygame/sprites/square-yellow.png
Binary files differ
diff --git a/deploy_template/open-source-licenses.txt b/deploy_template/open-source-licenses.txt
new file mode 100644
index 0000000..70abecd
--- /dev/null
+++ b/deploy_template/open-source-licenses.txt
@@ -0,0 +1,215 @@
+BORING LEGAL STUFF AND CREDIT WHERE CREDIT IS DUE:
+(if you don't read software licenses, you can skip this text file.)
+
+DragonRuby uses the following open source libraries!
+
+- mRuby: https://mruby.org/
+
+Copyright (c) 2019 mruby developers
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+
+- Simple Directmedia Layer: https://www.libsdl.org/
+
+Simple DirectMedia Layer
+Copyright (C) 1997-2019 Sam Lantinga <[email protected]>
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+
+
+- stb_vorbis, stb_image, stb_truetype: https://github.com/nothings/stb/
+
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+- lodepng: https://lodev.org/lodepng/
+
+Copyright (c) 2005-2018 Lode Vandevenne
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
+
+
+- miniz: https://github.com/richgel999/miniz
+
+Copyright 2013-2014 RAD Game Tools and Valve Software
+Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+- MojoAL: https://hg.icculus.org/icculus/mojoAL/
+
+ Copyright (c) 2018 Ryan C. Gordon and others.
+
+ This software is provided 'as-is', without any express or implied warranty.
+ In no event will the authors be held liable for any damages arising from
+ the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software in a
+ product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Ryan C. Gordon <[email protected]>
+
+
+- PhysicsFS: https://icculus.org/physfs/
+
+ Copyright (c) 2001-2019 Ryan C. Gordon and others.
+
+ This software is provided 'as-is', without any express or implied warranty.
+ In no event will the authors be held liable for any damages arising from
+ the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software in a
+ product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Ryan C. Gordon <[email protected]>
+
+- Yxml: https://dev.yorhel.nl/yxml
+
+Copyright (c) 2013-2014 Yoran Heling
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+- cJSON: https://github.com/DaveGamble/cJSON
+
+Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/dragon/args.rb b/dragon/args.rb
index d058b1d..487e843 100644
--- a/dragon/args.rb
+++ b/dragon/args.rb
@@ -4,147 +4,11 @@
# args.rb has been released under MIT (*only this file*).
module GTK
- class Grid
- include Serialize
- SCREEN_Y_DIRECTION = -1.0
-
- attr_accessor :bottom, :left, :right, :top,
- :rect, :origin_x, :origin_y, :center_x, :center_y,
- :name
-
- def initialize
- origin_bottom_left!
- end
-
- def __print_origin_help ascii_art
- log_once [:grid_ascii_art, @name], <<-S
-The origin has been set to :#{@name}.
-
-#{ascii_art}
-
-You can change the origin using any of
-the following methods:
-
- grid.origin_bottom_left!
- grid.origin_center!
-
-Example:
-
- def tick args
- args.grid.origin_bottom_left!
- end
-S
- end
-
- def transform_rect x, y, w, h
- new_x = transform_x x
- new_y = transform_y y
- new_w = w.to_f
- new_h = h * SCREEN_Y_DIRECTION
-
- if new_w < 0
- new_x = new_x + new_w
- new_w = new_w.abs
- end
-
- if new_h < 0
- new_y = new_y + new_h
- new_h = new_h.abs
- end
-
- [new_x, new_y, new_w, new_h]
- end
-
- def transform_x x
- @origin_x + x
- end
-
- def untransform_x x
- x - @origin_x
- end
-
- def untransform_y y
- @origin_y + y * SCREEN_Y_DIRECTION
- end
-
- def transform_y y
- @origin_y + y * SCREEN_Y_DIRECTION
- end
-
- def transform_angle angle
- (360 - angle).to_i
- end
-
- def origin_bottom_left!
- return if @name == :bottom_left
- @name = :bottom_left
- @origin_x = 0.0
- @origin_y = 720.0
- @left = 0.0
- @right = 1280.0
- @top = 720.0
- @bottom = 0.0
- @center_x = 640.0
- @center_y = 360.0
- @rect = [@left, @bottom, 1280.0, 720.0]
- __print_origin_help <<ASCII
-(0, 720) +-------------------+ (1280, 720)
- | |
- | (640, 360) |
- | + |
- | |
- | |
-(0, 0) +-------------------+ (1280, 0)
-ASCII
- end
-
- def origin_center!
- return if @name == :center
- @name = :center
- @origin_x = 640.0
- @origin_y = 360.0
- @left = -640.0
- @right = 640.0
- @top = 360.0
- @bottom = -360.0
- @center_x = 0.0
- @center_y = 0.0
- @rect = [@left, @bottom, 1280.0, 720.0]
- __print_origin_help <<ASCII
-(-640, 360) +-------------------+ ( 640, 360)
- | |
- | (0, 0) |
- | + |
- | |
- | |
-(-640, -360) +-------------------+ (-640, 360)
-ASCII
- end
-
- def w
- 1280.0
- end
-
- def w_half
- 640.0
- end
-
- def h
- 720.0
- end
-
- def h_half
- 360.0
- end
- end
-end
-
-module GTK
class Args
include ArgsDeprecated
attr_accessor :inputs, :outputs, :passes, :runtime,
- :grid, :recording
+ :grid, :recording, :geometry
def initialize runtime, recording
@inputs = Inputs.new
@@ -154,27 +18,28 @@ module GTK
@state.tick_count = -1
@runtime = runtime
@recording = recording
- @grid = Grid.new
+ @grid = Grid.new runtime.ffi_draw
@render_targets = {}
@all_tests = []
+ @geometry = GTK::Geometry
+ end
+
+ def tick_count
+ @state.tick_count
+ end
+
+ def tick_count= value
+ @state.tick_count = value
end
def gtk
@runtime
end
- # @return [OpenEntity] returns `OpenEntity` object that allows for storing state between ticks
- # @example Storing a value in a state
- # args.state.player_score = 0
- # args.state.current_time = Time.now
def state
@state
end
- # @param value [OpenEntity] the new state object to use
- # @return [OpenEntity] the new state object
- # @example Overwriting the state object
- # args.state = OpenEntity.new
def state= value
@state = value
end
@@ -206,7 +71,6 @@ module GTK
@render_targets[name]
end
- # @return [GTK::OutputsArray] the array of solids to render during current tick
def solids
@outputs.solids
end
@@ -215,7 +79,6 @@ module GTK
@outputs.static_solids
end
- # @return [GTK::OutputsArray] the array of sprites to render during current tick
def sprites
@outputs.sprites
end
@@ -224,7 +87,6 @@ module GTK
@outputs.static_sprites
end
- # @return [GTK::OutputsArray] the array of labels to render during current tick
def labels
@outputs.labels
end
@@ -233,7 +95,6 @@ module GTK
@outputs.static_labels
end
- # @return [GTK::OutputsArray] the array of lines to render during current tick
def lines
@outputs.lines
end
@@ -242,7 +103,6 @@ module GTK
@outputs.static_lines
end
- # @return [GTK::OutputsArray] the array of borders to render during current tick
def borders
@outputs.borders
end
@@ -272,7 +132,7 @@ module GTK
def click_at
return nil unless @inputs.mouse.click
- @inputs.mouse.click.created_at
+ @inpust.mouse.click.created_a
end
def mouse
diff --git a/dragon/assert.rb b/dragon/assert.rb
new file mode 100644
index 0000000..47d39ef
--- /dev/null
+++ b/dragon/assert.rb
@@ -0,0 +1,51 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# assert.rb has been released under MIT (*only this file*).
+
+module GTK
+ class Assert
+ attr :assertion_performed
+
+ def ok!
+ @assertion_performed = true
+ end
+
+ def true! value, message = nil
+ @assertion_performed = true
+ if !value
+ message = "#{value} was not truthy.\n#{message}"
+ raise "#{message}"
+ end
+ nil
+ end
+
+ def false! value, message = nil
+ @assertion_performed = true
+ if value
+ message = "#{value} was not falsey.\n#{message}"
+ raise message
+ end
+ nil
+ end
+
+ def equal! actual, expected, message = nil
+ @assertion_performed = true
+ if actual != expected
+ actual_string = "#{actual}#{actual.nil? ? " (nil) " : " " }".strip
+ message = "actual: #{actual_string} did not equal expected: #{expected}.\n#{message}"
+ raise message
+ end
+ nil
+ end
+
+ def nil! value, message = nil
+ @assertion_performed = true
+ if !value.nil?
+ message = "#{value} was supposed to be nil, but wasn't.\n#{message}"
+ raise message
+ end
+ nil
+ end
+ end
+end
diff --git a/dragon/attr_gtk.rb b/dragon/attr_gtk.rb
new file mode 100644
index 0000000..cf0b9f0
--- /dev/null
+++ b/dragon/attr_gtk.rb
@@ -0,0 +1,40 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# attr_gtk.rb has been released under MIT (*only this file*).
+
+module AttrGTK
+ attr_accessor :args
+
+ def keyboard
+ args.inputs.keyboard
+ end
+
+ def grid
+ args.grid
+ end
+
+ def state
+ args.state
+ end
+
+ def inputs
+ args.inputs
+ end
+
+ def outputs
+ args.outputs
+ end
+
+ def gtk
+ args.gtk
+ end
+
+ def passes
+ args.passes
+ end
+
+ def geometry
+ args.geometry
+ end
+end
diff --git a/dragon/console.rb b/dragon/console.rb
index 4008eb4..d58f507 100644
--- a/dragon/console.rb
+++ b/dragon/console.rb
@@ -202,7 +202,7 @@ S
addtext "* toast :#{id}"
puts "* TOAST: :#{id}"
messages.each do |message|
- lines = message.to_s.wrapped_lines(self.nconsole_text_width)
+ lines = message.to_s.wrapped_lines(self.console_text_width)
dwim_duration += lines.length.seconds
addtext "** #{message}"
puts "** #{message}"
@@ -262,6 +262,7 @@ S
end
def inputs_scroll_up_full? args
+ return false if @disabled
args.inputs.keyboard.key_down.pageup ||
(args.inputs.keyboard.key_up.b && args.inputs.keyboard.key_up.control)
end
@@ -274,6 +275,7 @@ S
end
def inputs_scroll_up_half? args
+ return false if @disabled
args.inputs.keyboard.ctrl_u
end
@@ -285,6 +287,7 @@ S
end
def inputs_scroll_down_full? args
+ return false if @disabled
args.inputs.keyboard.key_down.pagedown ||
(args.inputs.keyboard.key_up.f && args.inputs.keyboard.key_up.control)
end
@@ -297,10 +300,12 @@ S
end
def inputs_scroll_down_half? args
+ return false if @disabled
args.inputs.keyboard.ctrl_d
end
def inputs_clear_command? args
+ return false if @disabled
args.inputs.keyboard.escape || args.inputs.keyboard.ctrl_g
end
diff --git a/dragon/docs.rb b/dragon/docs.rb
new file mode 100644
index 0000000..b9d3dbf
--- /dev/null
+++ b/dragon/docs.rb
@@ -0,0 +1,47 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# docs.rb has been released under MIT (*only this file*).
+
+module GTK
+ class Docs
+ def map_with_ys
+ puts <<-S
+* Numeric#map_with_ys
+Numeric#map_with_ys is a helper method that is useful for working with coordinates
+or rows with columns. Here is an example usage.
+
+Assume you have a grid with 10 rows (xs) and 5 columns (ys). You can generate
+an array of hashes with the following form:
+
+#+begin_src
+[
+ { x: 0, y: 0, some_data: "A" },
+ { x: 0, y: 1, some_data: "A" },
+ { x: 0, y: 2, some_data: "A" },
+...
+ { x: 9, y: 4, some_data: "A" },
+]
+#+end_src
+
+Using the following code:
+
+#+begin_src ruby
+array_of_hashes = 10.map_with_ys 5 do |x, y|
+ { x: x, y: y, some_data: "A" }
+end
+
+Take a look at the "hexagon grid" sample app for a real world usage of
+this method.
+#+end_src
+S
+ end
+
+ def method_missing m, *args
+ puts <<-S
+* DOCUMENTATION MISSING:
+It looks like docs are missing for :#{m}. Let the @dragonborne know about it in the Discord channel: http://discord.dragonruby.org.
+S
+ end
+ end
+end
diff --git a/dragon/geometry.rb b/dragon/geometry.rb
new file mode 100644
index 0000000..77e07a3
--- /dev/null
+++ b/dragon/geometry.rb
@@ -0,0 +1,253 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# geometry.rb has been released under MIT (*only this file*).
+
+module GTK
+ module Geometry
+ def inside_rect? outer
+ Geometry.inside_rect? self, outer
+ end
+
+ def intersect_rect? other, tolerance = 0.1
+ Geometry.intersect_rect? self, other, tolerance
+ end
+
+ def intersects_rect? *args
+ Geometry.intersects_rect?(*args)
+ end
+
+ def scale_rect_extended percentage_x: percentage_x,
+ percentage_y: percentage_y,
+ anchor_x: anchor_x,
+ anchor_y: anchor_y
+
+ Geometry.scale_rect_extended self,
+ percentage_x: percentage_x,
+ percentage_y: percentage_y,
+ anchor_x: anchor_x,
+ anchor_y: anchor_y
+ end
+
+ def scale_rect percentage, *anchors
+ Geometry.scale_rect self, percentage, *anchors
+ end
+
+ def angle_to other_point
+ Geometry.angle_to self, other_point
+ end
+
+ def angle_from other_point
+ Geometry.angle_from self, other_point
+ end
+
+ def point_inside_circle? circle_center_point, radius
+ Geometry.point_inside_circle? self, circle_center_point, radius
+ end
+
+ def anchor_rect anchor_x, anchor_y
+ current_w = self.w
+ current_h = self.h
+ delta_x = -1 * (anchor_x * current_w)
+ delta_y = -1 * (anchor_y * current_h)
+ self.rect_shift(delta_x, delta_y)
+ end
+
+ def angle_given_point other_point
+ raise ":angle_given_point has been deprecated use :angle_from instead."
+ end
+
+ def self.shift_line line, x, y
+ if line.is_a?(Array) || line.is_a?(Hash)
+ new_line = line.dup
+ new_line.x += x
+ new_line.x2 += x
+ new_line.y += y
+ new_line.y2 += y
+ new_line
+ else
+ raise "shift_line for #{line} is not supported."
+ end
+ end
+
+ def self.intersects_rect? *args
+ raise <<-S
+intersects_rect? (with an \"s\") has been deprecated.
+Use intersect_rect? instead (remove the \"s\").
+
+* NOTE:
+Ruby's naming convention is to *never* include the \"s\" for
+interrogative method names (methods that end with a ?). It
+doesn't sound grammatically correct, but that has been the
+rule for a long time (and why intersects_rect? has been deprecated).
+
+S
+ end
+
+ def self.line_y_intercept line
+ line.y - line_slope(line) * line.x
+ end
+
+ def self.angle_between_lines line_one, line_two, replace_infinity: nil
+ m_line_one = line_slope line_one, replace_infinity: replace_infinity
+ m_line_two = line_slope line_two, replace_infinity: replace_infinity
+ Math.atan((m_line_one - m_line_two) / (1 + m_line_two * m_line_one)).to_degrees
+ end
+
+ def self.line_slope line, replace_infinity: nil
+ (line.y2 - line.y).fdiv(line.x2 - line.x)
+ .replace_infinity(replace_infinity)
+ end
+
+ def self.ray_test point, line
+ slope = (line.y2 - line.y).fdiv(line.x2 - line.x)
+
+ if line.x > line.x2
+ point_two, point_one = [point_one, point_two]
+ end
+
+ r = ((line.x2 - line.x) * (point.y - line.y) -
+ (point.x - line.x) * (line.y2 - line.y))
+
+ if r == 0
+ return :on
+ elsif r < 0
+ return :right if slope >= 0
+ return :left
+ elsif r > 0
+ return :left if slope >= 0
+ return :right
+ end
+ end
+
+ def self.line_rect line
+ if line.x > line.x2
+ x = line.x2
+ y = line.y2
+ x2 = line.x
+ y2 = line.y
+ else
+ x = line.x
+ y = line.y
+ x2 = line.x2
+ y2 = line.y2
+ end
+
+ w = x2 - x
+ h = y2 - y
+
+ { x: x, y: y, w: w, h: h }
+ end
+
+ def self.line_intersect line_one, line_two
+ m1 = line_slope(line_one)
+ m2 = line_slope(line_two)
+ b1 = line_y_intercept(line_one)
+ b2 = line_y_intercept(line_two)
+ x = (b1 - b2) / (m2 - m1)
+ y = (-b2.fdiv(m2) + b1.fdiv(m1)).fdiv(1.fdiv(m1) - 1.fdiv(m2))
+ [x, y]
+ end
+
+ 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 true
+ rescue Exception => e
+ raise e, ":intersect_rect? failed for rect_one: #{rect_one} rect_two: #{rect_two}."
+ end
+
+ def self.to_square size, x, y, anchor_x = 0.5, anchor_y = nil
+ anchor_y ||= anchor_x
+ x = x.shift_left(size * anchor_x)
+ 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}."
+ end
+
+ 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}."
+ end
+
+ def self.angle_from start_point, end_point
+ d_y = end_point.y - start_point.y
+ 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}."
+ end
+
+ 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}."
+ end
+
+ 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}"
+ end
+
+ def self.inside_rect? inner_rect, outer_rect
+ inner_rect.x >= outer_rect.x &&
+ inner_rect.right <= outer_rect.right &&
+ inner_rect.y >= outer_rect.y &&
+ inner_rect.top <= outer_rect.top
+ rescue Exception => e
+ raise e, ":inside_rect? failed for inner_rect: #{inner_rect} outer_rect: #{outer_rect}."
+ end
+
+ def self.scale_rect_extended rect,
+ percentage_x: percentage_x,
+ percentage_y: percentage_y,
+ anchor_x: anchor_x,
+ anchor_y: anchor_y
+ anchor_x ||= 0.0
+ anchor_y ||= 0.0
+ percentage_x ||= 1.0
+ percentage_y ||= 1.0
+ new_w = rect.w * percentage_x
+ new_h = rect.h * percentage_y
+ new_x = rect.x + (rect.w - new_w) * anchor_x
+ new_y = rect.y + (rect.h - new_h) * anchor_y
+ if rect.is_a? Array
+ return [
+ new_x,
+ new_y,
+ new_w,
+ new_h,
+ *rect[4..-1]
+ ]
+ elsif rect.is_a? Hash
+ return rect.merge(x: new_x, y: new_y, w: new_w, h: new_h)
+ else
+ rect.x = new_x
+ rect.y = new_y
+ rect.w = new_w
+ rect.h = new_h
+ 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}."
+ end
+
+ def self.scale_rect rect, percentage, *anchors
+ anchor_x, anchor_y = *anchors.flatten
+ anchor_x ||= 0
+ anchor_y ||= anchor_x
+ Geometry.scale_rect_extended rect,
+ percentage_x: percentage,
+ percentage_y: percentage,
+ 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)]."
+ end
+ end # module Geometry
+end # module GTK
diff --git a/dragon/help.rb b/dragon/help.rb
new file mode 100644
index 0000000..aee60d8
--- /dev/null
+++ b/dragon/help.rb
@@ -0,0 +1,72 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# help.rb has been released under MIT (*only this file*).
+
+module GTK
+ class Help
+ def self.primitive_contract primitive_name
+ if primitive_name == :label
+ label_contract
+ elsif primitive_name == :solid
+ solid_border_contract
+ elsif primitive_name == :border
+ solid_border_contract
+ elsif primitive_name == :sprite
+ sprite_contract
+ else
+ help_text = "No contract found for primitive #{primitive_name}. The supported primitives are :label, :solid, :border, :sprite."
+ end
+ end
+
+ def self.label_contract
+ <<-S
+* :label (if :primitive_marker returns :label)
+** :x, :y, :text
+** :size_enum
+default: 0
+negative value means smaller text
+positive value means larger text
+** :alignment_enum default: 0
+default: 0
+0: left aligned, 1: center aligned, 2: right aligned
+** :r, :g, :b, :a
+default: 0's for rgb and 255 for a
+** :font
+default nil
+path to ttf file
+S
+ end
+
+ def self.solid_border_contract
+ <<-S
+* :solid, :border (if :primitive_marker returns :solid or :border)
+** :x, :y, :w, :h, :r, :g, :b, :a
+S
+ end
+
+ def self.label_contract
+ <<-S
+* :line (if :primitive_marker returns :line)
+** :x, :y, :x2, :y2, :r, :g, :b, :a
+S
+ end
+
+ def self.sprite_contract
+ <<-S
+* :sprite (if :primitive_marker returns :sprite)
+** :x, :y, :w, :h
+** :angle, :angle_anchor_x, :angle_anchor_y
+default for angle: 0 (0 to 360 degress)
+default for angle_anchor_(x|y): 0 (decimal value between 0 and 1.0, 0.5 means center)
+** :r, :g, :b, :a
+** :tile_x, :tile_y
+default: 0, x, y offset for sprite to crop at
+** :tile_w, :tile_h
+default: -1, width and height of crop (-1 means full width and height)
+** :flip_horizontally, :flip_vertically
+default: falsey value
+S
+ end
+ end
+end
diff --git a/dragon/index.rb b/dragon/index.rb
index 8a1460c..5d4639d 100644
--- a/dragon/index.rb
+++ b/dragon/index.rb
@@ -1 +1,23 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# help.rb has been released under MIT (*only this file*).
+
require 'app/dragon/console.rb'
+require 'app/dragon/docs.rb'
+require 'app/dragon/help.rb'
+require 'app/dragon/log.rb'
+require 'app/dragon/geometry.rb'
+require 'app/dragon/attr_gtk.rb'
+require 'app/dragon/attr_sprite.rb'
+require 'app/dragon/string.rb'
+require 'app/dragon/numeric.rb'
+require 'app/dragon/directional_input_helper_methods.rb'
+require 'app/dragon/inputs.rb'
+require 'app/dragon/grid.rb'
+require 'app/dragon/args.rb'
+require 'app/dragon/console.rb'
+require 'app/dragon/assert.rb'
+require 'app/dragon/tests.rb'
+require 'app/dragon/trace.rb'
+require 'app/dragon/controller_config.rb'
diff --git a/dragon/inputs.rb b/dragon/inputs.rb
index 5d16091..07d1dc8 100644
--- a/dragon/inputs.rb
+++ b/dragon/inputs.rb
@@ -179,14 +179,14 @@ module GTK
end
def left_right
- return -1 if @left
- return 1 if @right
+ return -1 if self.left
+ return 1 if self.right
return 0
end
def up_down
- return 1 if @up
- return -1 if @down
+ return 1 if self.up
+ return -1 if self.down
return 0
end
@@ -273,8 +273,7 @@ S
end
def method_missing m, *args
- # determine if it's a ctrl+some_key combination
- if m.to_s.length != 1 && m.end_with_bang? # creation of args.intputs.SOME_KEY! (where the key is queried and then immediately cleared)
+ if m.to_s.length != 1 && m.end_with_bang? # creation of args.intputs.SOME_KEY! (where the key is queried and then immediately cleared)
begin
define_singleton_method(m) do
r = self.instance_variable_get("@#{m.without_ending_bang}".to_sym)
@@ -317,67 +316,20 @@ module GTK
@has_focus = false
end
- def left_right
- return -1 if left
- return 1 if right
- return 0
- end
-
- def up_down
- return 1 if up
- return -1 if down
- return 0
- end
-
def left
- @key_down.left || @key_held.left
+ @key_up.left || @key_held.left || a
end
def right
- @key_down.right || @key_held.right
+ @key_up.right || @key_held.right || d
end
def up
- @key_down.up || @key_held.up
+ @key_up.up || @key_held.up || w
end
def down
- @key_down.down || @key_held.down
- end
-
- def w
- @key_down.w || @key_held.w
- end
-
- def a
- @key_down.a || @key_held.a
- end
-
- def s
- @key_down.s || @key_held.s
- end
-
- def d
- @key_down.d || @key_held.d
- end
-
- def method_missing m, *args
- if m.to_s.start_with?("ctrl_")
- other_key = m.to_s.split("_").last
- define_singleton_method(m) do
- return @key_up.send(other_key.to_sym) && key_up.control
- end
-
- return send(m)
- elsif @key_down.respond_to? m
- define_singleton_method(m) do
- @key_down.send(m) || @key_held.send(m)
- end
-
- return send(m)
- end
-
- super
+ @key_up.down || @key_held.down || s
end
def clear
@@ -402,9 +354,12 @@ module GTK
def to_s
serialize.to_s
end
+
+ include DirectionalInputHelperMethods
end
end
+
module GTK
class ControllerKeys
include Serialize
@@ -481,14 +436,14 @@ module GTK
end
def left_right
- return -1 if @key_down.left || @key_held.left
- return 1 if @key_down.right || @key_held.right
+ return -1 if self.left
+ return 1 if self.right
return 0
end
def up_down
- return 1 if @key_down.up || @key_held.up
- return -1 if @key_down.down || @key_held.down
+ return 1 if self.up
+ return -1 if self.down
return 0
end
@@ -505,6 +460,24 @@ module GTK
@key_up.clear
@key_held.clear
end
+
+ def up
+ @key_up.up || @key_held.up
+ end
+
+ def down
+ @key_up.down || @key_held.down
+ end
+
+ def left
+ @key_up.left || @key_held.left
+ end
+
+ def right
+ @key_up.right || @key_held.right
+ end
+
+ include DirectionalInputHelperMethods
end
end
@@ -619,6 +592,43 @@ module GTK
@text = []
end
+ def up
+ keyboard.up ||
+ (controller_one && controller_one.up)
+ end
+
+ def down
+ keyboard.down ||
+ (controller_one && controller_one.down)
+ end
+
+ def left
+ keyboard.left ||
+ (controller_one && controller_one.left)
+ end
+
+ def right
+ keyboard.right ||
+ (controller_one && controller_one.right)
+ end
+
+ def directional_vector
+ keyboard.directional_vector ||
+ (controller_one && controller_one.directional_vector)
+ end
+
+ def left_right
+ return -1 if self.left
+ return 1 if self.right
+ return 0
+ end
+
+ def up_down
+ return 1 if self.up
+ return -1 if self.down
+ return 0
+ end
+
def click
return nil unless @mouse.click
return @mouse.click.point
diff --git a/dragon/log.rb b/dragon/log.rb
new file mode 100644
index 0000000..60246e6
--- /dev/null
+++ b/dragon/log.rb
@@ -0,0 +1,236 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# log.rb has been released under MIT (*only this file*).
+
+XTERM_COLOR = {
+ black: "\u001b[30m",
+ red: "\u001b[31m",
+ green: "\u001b[32m",
+ yellow: "\u001b[33m",
+ blue: "\u001b[34m",
+ magenta: "\u001b[35m",
+ cyan: "\u001b[36m",
+ white: "\u001b[37m",
+ bright_black: "\u001b[30;1m",
+ bright_red: "\u001b[31;1m",
+ bright_green: "\u001b[32;1m",
+ bright_yellow: "\u001b[33;1m",
+ bright_blue: "\u001b[34;1m",
+ bright_magenta: "\u001b[35;1m",
+ bright_cyan: "\u001b[36;1m",
+ bright_white: "\u001b[37;1m",
+ reset: "\u001b[0m",
+}
+
+module GTK
+ class Log
+ def self.write_to_log_and_puts *args
+ return if $gtk.production
+ $gtk.append_file 'logs/log.txt', args.join("\n") + "\n"
+ args.each { |obj| $gtk.log obj, self }
+ end
+
+ def self.write_to_log_and_print *args
+ return if $gtk.production
+ $gtk.append_file 'logs/log.txt', args.join("\n")
+ Object.print(*args)
+ end
+
+ def self.puts_important *args
+ return if $gtk.production
+ $gtk.append_file 'logs/log.txt', args.join("\n")
+ $gtk.notify! "Important notification occurred."
+ args.each { |obj| $gtk.log obj }
+ end
+
+ def self.puts *args
+ message_id, message = args
+ message ||= message_id
+ write_to_log_and_puts message
+ end
+
+ def self.multiline? *args
+ return true if args.length > 1
+ return !args[0].to_s.multiline?
+ end
+
+ def self.join_lines args
+ return "" if args.length == 0
+ return args if args.is_a? String
+ return args[0] if args.length == 1
+ return args.to_s.join("\n")
+ end
+
+ def self.headline name
+ @asterisk_count ||= 1
+ @asterisk_count = @asterisk_count.greater(1)
+ result_from_yield = join_lines yield
+ result_from_yield = result_from_yield.each_line.map { |l| " #{l}" }.join
+ r ="#{"*" * @asterisk_count} #{name}\n#{result_from_yield}"
+ @asterisk_count -= 1
+ @asterisk_count = @asterisk_count.greater(1)
+ r
+ end
+
+ def self.dynamic_block
+ "#+BEGIN:
+#{join_lines yield}
+#+END:
+
+"
+ end
+
+ def self.puts_info *args
+ args ||= []
+ title = args[0]
+ additional = args[1..-1] || []
+ additional = "" if additional.length == 0
+ if !title.multiline? && join_lines(additional).multiline?
+ message = headline "INFO: #{title}" do
+ dynamic_block do
+ additional
+ end
+ end
+ elsif title.multiline?
+ message = headline "INFO: " do
+ dynamic_block do
+ args
+ end
+ end
+ else
+ message = "* INFO: #{title} #{additional}".strip
+ end
+
+ self.puts message
+ end
+
+ def self.puts_once *ids, message
+ id = "#{ids}"
+ @once ||= {}
+ return if @once[id]
+ @once[id] = id
+ write_to_log_and_puts ""
+ write_to_log_and_puts "#{message.strip}"
+ write_to_log_and_puts ""
+ write_to_log_and_puts "[Message ID: #{id}]"
+ write_to_log_and_puts ""
+ return if $gtk.cli_arguments[:replay]
+ return if $gtk.cli_arguments[:record]
+ $gtk.notify!("One time notification occurred. [Message ID: #{id}] (Open console for more info.)")
+ end
+
+ def self.puts_once_info *ids, message
+ id = "#{ids}"
+ @once ||= {}
+ return if @once[id]
+ @once[id] = id
+ log_info message
+ end
+
+ def self.print *args
+ write_to_log_and_print(*args)
+ end
+ end
+end
+
+class Object
+ def log_print *args
+ GTK::Log.print(*args)
+ end
+
+ def log_important *args
+ GTK::Log.puts_important(*args)
+ end
+
+ def log *args
+ GTK::Log.puts(*args)
+ end
+
+ def log_with_color xterm_escape_code, *args
+ log_print xterm_escape_code
+ log(*args)
+ ensure
+ log_reset_color
+ end
+
+ def log_reset_color
+ log_print XTERM_COLOR[:reset]
+ end
+
+ def log_black *args
+ log_with_color XTERM_COLOR[:black], *args
+ end
+
+ def log_red *args
+ log_with_color XTERM_COLOR[:red], *args
+ end
+
+ def log_green *args
+ log_with_color XTERM_COLOR[:green], *args
+ end
+
+ def log_yellow *args
+ log_with_color XTERM_COLOR[:yellow], *args
+ end
+
+ def log_blue *args
+ log_with_color XTERM_COLOR[:blue], *args
+ end
+
+ def log_magenta *args
+ log_with_color XTERM_COLOR[:magenta], *args
+ end
+
+ def log_cyan *args
+ log_with_color XTERM_COLOR[:cyan], *args
+ end
+
+ def log_white *args
+ log_with_color XTERM_COLOR[:white], *args
+ end
+
+ def log_bright_black *args
+ log_with_color XTERM_COLOR[:bright_black], *args
+ end
+
+ def log_bright_red *args
+ log_with_color XTERM_COLOR[:bright_red], *args
+ end
+
+ def log_bright_green *args
+ log_with_color XTERM_COLOR[:bright_green], *args
+ end
+
+ def log_bright_yellow *args
+ log_with_color XTERM_COLOR[:bright_yellow], *args
+ end
+
+ def log_bright_blue *args
+ log_with_color XTERM_COLOR[:bright_blue], *args
+ end
+
+ def log_bright_magenta *args
+ log_with_color XTERM_COLOR[:bright_magenta], *args
+ end
+
+ def log_bright_cyan *args
+ log_with_color XTERM_COLOR[:bright_cyan], *args
+ end
+
+ def log_bright_white *args
+ log_with_color XTERM_COLOR[:bright_white], *args
+ end
+
+ def log_info *args
+ GTK::Log.puts_info(*args)
+ end
+
+ def log_once *ids, message
+ GTK::Log.puts_once(*ids, message)
+ end
+
+ def log_once_info *ids, message
+ GTK::Log.puts_once_info(*ids, message)
+ end
+end
diff --git a/dragon/numeric.rb b/dragon/numeric.rb
new file mode 100644
index 0000000..0ef606e
--- /dev/null
+++ b/dragon/numeric.rb
@@ -0,0 +1,527 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# numeric.rb has been released under MIT (*only this file*).
+
+class Numeric
+ include ValueType
+ include NumericDeprecated
+
+ alias_method :gte, :>=
+ alias_method :lte, :<=
+ alias_method :gt, :>
+ alias_method :lt, :<
+ alias_method(:original_eq_eq, :==) unless Numeric.instance_methods.include?(:original_eq_eq)
+
+ def seconds
+ self * 60
+ end
+
+ def half
+ return self / 2.0
+ end
+
+ def to_byte
+ return 0 if self < 0
+ return 255 if self > 255
+ return self.to_i
+ end
+
+ def elapsed_time tick_count_override = nil
+ (tick_count_override || Kernel.tick_count) - self
+ end
+
+ def elapsed_time_percent duration
+ elapsed_time.percentage_of duration
+ end
+
+ def new?
+ elapsed_time == 0
+ end
+
+ def elapsed? offset, tick_count_override = nil
+ (self + offset) < (tick_count_override || Kernel.tick_count)
+ end
+
+ def frame_index frame_count, hold_for, repeat, tick_count_override = nil
+ animation_frame_count = frame_count
+ animation_frame_hold_time = hold_for
+ animation_length = animation_frame_hold_time * animation_frame_count
+ if !repeat && self.+(animation_length) < (tick_count_override || Kernel.tick_count).-(1)
+ return nil
+ else
+ return self.elapsed_time.-(1).idiv(animation_frame_hold_time) % animation_frame_count
+ end
+ end
+
+ def zero
+ 0
+ end
+
+ def zero?
+ self == 0
+ end
+
+ def one
+ 1
+ end
+
+ def two
+ 2
+ end
+
+ def five
+ 5
+ end
+
+ def ten
+ 10
+ end
+
+ def above? v
+ self > v
+ end
+
+ def below? v
+ self < v
+ end
+
+ def left_of? v
+ self < v
+ end
+
+ def right_of? v
+ self > v
+ end
+
+ def shift_right i
+ self + i
+ end
+
+ def shift_left i
+ shift_right(i * -1)
+ rescue Exception => e
+ raise_immediately e, :shift_left, i
+ end
+
+ def shift_up i
+ self + i
+ rescue Exception => e
+ raise_immediately e, :shift_up, i
+ end
+
+ def shift_down i
+ shift_up(i * -1)
+ rescue Exception => e
+ raise_immediately e, :shift_down, i
+ end
+
+ def randomize *definitions
+ result = self
+
+ if definitions.include?(:sign)
+ result = rand_sign
+ end
+
+ if definitions.include?(:ratio)
+ result = rand * result
+ end
+
+ result
+ end
+
+ def rand_sign
+ return self * -1 if rand > 0.5
+ self
+ end
+
+ def rand_ratio
+ self * rand
+ end
+
+ def between? n, n2
+ self >= n && self <= n2 || self >= n2 && self <= n
+ end
+
+ def remainder_of_divide n
+ mod n
+ end
+
+ def ease_extended tick_count_override, duration, default_before, default_after, *definitions
+ GTK::Easing.exec_definitions(self,
+ tick_count_override,
+ self + duration,
+ default_before,
+ default_after,
+ *definitions)
+ end
+
+ def ease_initial_value *definitions
+ GTK::Easing.initial_value(*definitions)
+ end
+
+ def ease_final_value *definitions
+ GTK::Easing.final_value(*definitions)
+ end
+
+ def global_ease duration, *definitions
+ ease_extended Kernel.global_tick_count,
+ duration,
+ GTK::Easing.initial_value(*definitions),
+ GTK::Easing.final_value(*definitions),
+ *definitions
+ end
+
+ def ease duration, *definitions
+ ease_extended Kernel.tick_count,
+ duration,
+ GTK::Easing.initial_value(*definitions),
+ GTK::Easing.final_value(*definitions),
+ *definitions
+ end
+
+ def to_radians
+ self * Math::PI.fdiv(180)
+ end
+
+ def to_degrees
+ self / Math::PI.fdiv(180)
+ end
+
+ def to_square x, y, anchor_x = 0.5, anchor_y = nil
+ GTK::Geometry.to_square(self, x, y, anchor_x, anchor_y)
+ end
+
+ def vector max_value = 1
+ [vector_x(max_value), vector_y(max_value)]
+ end
+
+ def vector_y max_value = 1
+ max_value * Math.sin(self.to_radians)
+ end
+
+ def vector_x max_value = 1
+ max_value * Math.cos(self.to_radians)
+ end
+
+ def x_vector max_value = 1
+ vector_x max_value
+ end
+
+ def y_vector max_value = 1
+ vector_y max_value
+ end
+
+ def mod n
+ self % n
+ end
+
+ def mod_zero? *ns
+ ns.any? { |n| mod(n) == 0 }
+ end
+
+ def mult n
+ self * n
+ end
+
+ def fdiv n
+ self / n.to_f
+ end
+
+ def idiv n
+ (self / n.to_f).to_i
+ end
+
+ def towards target, magnitude
+ return self if self == target
+ delta = (self - target).abs
+ return target if delta < magnitude
+ return self - magnitude if self > target
+ return self + magnitude
+ end
+
+ def map_with_ys ys, &block
+ self.times.flat_map do |x|
+ ys.map_with_index do |y|
+ yield x, y
+ end
+ end
+ rescue Exception => e
+ raise_immediately e, :map_with_ys, [self, ys]
+ end
+
+ def combinations other_int
+ self.numbers.product(other_int.numbers)
+ end
+
+ def percentage_of n
+ (self / n.to_f).cap_min_max(0, 1)
+ end
+
+ def cap i
+ return i if self > i
+ self
+ end
+
+ def cap_min_max min, max
+ return min if self < min
+ return max if self > max
+ self
+ end
+
+ def lesser other
+ return other if other < self
+ self
+ end
+
+ def greater other
+ return other if other > self
+ self
+ end
+
+ def subtract i
+ self - i
+ end
+
+ def minus i
+ self - i
+ end
+
+ def add i
+ self + i
+ end
+
+ def plus i
+ self + i
+ end
+
+ def numbers
+ (0..self).to_a
+ end
+
+ def >= other
+ return false if !other
+ return gte other
+ end
+
+ def > other
+ return false if !other
+ return gt other
+ end
+
+ def <= other
+ return false if !other
+ return lte other
+ end
+
+ def < other
+ return false if !other
+ return gt other
+ end
+
+ def == other
+ return true if self.original_eq_eq(other)
+ if other.is_a?(OpenEntity)
+ return self.original_eq_eq(other.entity_id)
+ end
+ return self.original_eq_eq(other)
+ end
+
+ def map
+ unless block_given?
+ raise <<-S
+* ERROR:
+A block is required for Numeric#map.
+
+S
+ end
+
+ self.to_i.times.map do
+ yield
+ end
+ end
+
+ def map_with_index
+ unless block_given?
+ raise <<-S
+* ERROR:
+A block is required for Numeric#map.
+
+S
+ end
+
+ self.to_i.times.map do |i|
+ yield i
+ end
+ end
+
+ def check_numeric! sender, other
+ return if other.is_a? Numeric
+
+ raise <<-S
+* ERROR:
+Attempted to invoke :+ on #{self} with the right hand argument of:
+
+#{other}
+
+The object above is not a Numeric.
+
+S
+ end
+
+ def - other
+ return nil unless other
+ check_numeric! :-, other
+ super
+ end
+
+ def + other
+ return nil unless other
+ check_numeric! :+, other
+ super
+ end
+
+ def * other
+ return nil unless other
+ check_numeric! :*, other
+ super
+ end
+
+ def / other
+ return nil unless other
+ check_numeric! :/, other
+ super
+ end
+
+ def serialize
+ self
+ end
+end
+
+class Fixnum
+ include ValueType
+
+ alias_method(:original_eq_eq, :==) unless Fixnum.instance_methods.include?(:original_eq_eq)
+
+ def - other
+ return nil unless other
+ check_numeric! :-, other
+ super
+ end
+
+ def even?
+ return true if self % 2 == 1
+ return false
+ end
+
+ def odd?
+ return !even?
+ end
+
+ def + other
+ return nil unless other
+ check_numeric! :+, other
+ super
+ end
+
+ def * other
+ return nil unless other
+ check_numeric! :*, other
+ super
+ end
+
+ def / other
+ return nil unless other
+ check_numeric! :/, other
+ super
+ end
+
+ def == other
+ return true if self.original_eq_eq(other)
+ if other.is_a?(GTK::OpenEntity)
+ return self.original_eq_eq(other.entity_id)
+ end
+ return self.original_eq_eq(other)
+ end
+
+ def sign
+ return -1 if self < 0
+ return 1 if self > 0
+ return 0
+ end
+
+ def pos?
+ sign > 0
+ end
+
+ def neg?
+ sign < 0
+ end
+
+ def cos
+ Math.cos(self.to_radians)
+ end
+
+ def sin
+ Math.sin(self.to_radians)
+ end
+end
+
+class Float
+ include ValueType
+
+ def - other
+ return nil unless other
+ check_numeric! :-, other
+ super
+ end
+
+ def + other
+ return nil unless other
+ check_numeric! :+, other
+ super
+ end
+
+ def * other
+ return nil unless other
+ check_numeric! :*, other
+ super
+ end
+
+ def / other
+ return nil unless other
+ check_numeric! :/, other
+ super
+ end
+
+ def serialize
+ self
+ end
+
+ def clamp lower, higher
+ return lower if self < lower
+ return higher if self > higher
+ return self
+ end
+
+ def sign
+ return -1 if self < 0
+ return 1 if self > 0
+ return 0
+ end
+
+ def replace_infinity scalar
+ return self if !scalar
+ return self unless self.infinite?
+ return -scalar if self < 0
+ return scalar if self > 0
+ end
+
+ def pos?
+ sign > 0
+ end
+
+ def neg?
+ sign < 0
+ end
+end
diff --git a/dragon/string.rb b/dragon/string.rb
new file mode 100644
index 0000000..8d2d9ba
--- /dev/null
+++ b/dragon/string.rb
@@ -0,0 +1,98 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# string.rb has been released under MIT (*only this file*).
+
+class String
+ include ValueType
+
+ def wrapped_lines_recur word, rest, length, aggregate
+ if word.nil?
+ return aggregate
+ elsif rest[0].nil?
+ aggregate << word + "\n"
+ return aggregate
+ elsif (word + " " + rest[0]).length > length
+ aggregate << word + "\n"
+ return wrapped_lines_recur rest[0], rest[1..-1], length, aggregate
+ elsif (word + " " + rest[0]).length <= length
+ next_word = (word + " " + rest[0])
+ return wrapped_lines_recur next_word, rest[1..-1], length, aggregate
+ else
+ log <<-S
+WARNING:
+#{word} is too long to fit in length of #{length}.
+
+S
+ next_word = (word + " " + rest[0])
+ return wrapped_lines_recur next_word, rest[1..-1], length, aggregate
+ end
+ end
+
+ def end_with_bang?
+ self[-1] == "!"
+ end
+
+ def without_ending_bang
+ return self unless end_with_bang?
+ self[0..-2]
+ end
+
+ def wrapped_lines length
+ self.each_line.map do |l|
+ l = l.rstrip
+ if l.length < length
+ l + "\n"
+ else
+ words = l.split ' '
+ wrapped_lines_recur(words[0], words[1..-1], length, []).flatten
+ end
+ end.flatten
+ end
+
+ def wrap length
+ wrapped_lines(length).join.rstrip
+ end
+
+ def multiline?
+ include? "\n"
+ end
+
+ def indent_lines amount
+ self.each_line.each_with_index.map do |l, i|
+ if i == 0
+ l
+ else
+ " " * amount + l
+ end
+ end.join
+ end
+
+ def quote
+ "\"#{self}\""
+ end
+
+ def trim
+ strip
+ end
+
+ def trim!
+ strip!
+ end
+
+ def ltrim
+ lstrip
+ end
+
+ def ltrim!
+ lstrip!
+ end
+
+ def rtrim
+ rstrip
+ end
+
+ def rtrim!
+ rstrip!
+ end
+end
diff --git a/dragon/tests.rb b/dragon/tests.rb
new file mode 100644
index 0000000..fc6450e
--- /dev/null
+++ b/dragon/tests.rb
@@ -0,0 +1,136 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# tests.rb has been released under MIT (*only this file*).
+
+module GTK
+ class Tests
+ attr_accessor :failed, :passed, :inconclusive
+
+ def initialize
+ @failed = []
+ @passed = []
+ @inconclusive = []
+ end
+
+ def run_test m
+ args = Args.new $gtk, nil
+ assert = Assert.new
+ begin
+ log_test_running m
+ send(m, args, assert)
+ if !assert.assertion_performed
+ log_inconclusive m
+ else
+ log_passed m
+ end
+ rescue Exception => e
+ if test_signature_invalid_exception? e, m
+ log_test_signature_incorrect m
+ else
+ mark_test_failed m, e
+ end
+ end
+ end
+
+ def test_methods_focused
+ Object.methods.find_all { |m| m.start_with?( "focus_test_") }
+ end
+
+ def test_methods
+ Object.methods.find_all { |m| m.start_with? "test_" }
+ end
+
+ def start
+ log "* TEST: gtk.test.start has been invoked."
+ if test_methods_focused.length != 0
+ @is_running = true
+ test_methods_focused.each { |m| run_test m }
+ print_summary
+ @is_running = false
+ elsif test_methods.length == 0
+ log_no_tests_found
+ else
+ @is_running = true
+ test_methods.each { |m| run_test m }
+ print_summary
+ @is_running = false
+ end
+ end
+
+ def mark_test_failed m, e
+ message = "Failed."
+ self.failed << { m: m, e: e }
+ log message
+ end
+
+ def running?
+ @is_running
+ end
+
+ def log_inconclusive m
+ self.inconclusive << {m: m}
+ log "Inconclusive."
+ log_once :assertion_ok_note, <<-S
+NOTE FOR INCONCLUSIVE TESTS: No assertion was performed in the test.
+Add assert.ok! at the end of the test if you are using your own assertions.
+S
+ end
+
+ def log_passed m
+ self.passed << {m: m}
+ log "Passed."
+ end
+
+ def log_no_tests_found
+ log <<-S
+No tests were found. To create a test. Define a method
+that begins with test_. For example:
+#+begin_src
+def test_game_over args, assert
+
+end
+#+end_src
+S
+ end
+
+ def log_test_running m
+ log "** Running: #{m}"
+ end
+
+ def test_signature_invalid_exception? e, m
+ e.to_s.include?(m.to_s) && e.to_s.include?("wrong number of arguments")
+ end
+
+ def log_test_signature_incorrect m
+ log "TEST METHOD INVALID:", <<-S
+I found a test method called :#{m}. But it needs to have
+the following method signature:
+#+begin_src
+def #{m} args, assert
+
+end
+#+end_src
+Please update the method signature to match the code above. If you
+did not intend this to be a test method. Rename the method so it does
+not start with "test_".
+S
+ end
+
+ def print_summary
+ log "** Summary"
+ log "*** Passed"
+ log "#{self.passed.length} test(s) passed."
+ self.passed.each { |h| log "**** :#{h[:m]}" }
+ log "*** Inconclusive"
+ log "#{self.inconclusive.length} test(s) inconclusive."
+ self.inconclusive.each { |h| log "**** :#{h[:m]}" }
+ log "*** Failed"
+ 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}"
+ end
+ end
+ end
+end
diff --git a/dragon/trace.rb b/dragon/trace.rb
new file mode 100644
index 0000000..c3b4bbd
--- /dev/null
+++ b/dragon/trace.rb
@@ -0,0 +1,150 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# trace.rb has been released under MIT (*only this file*).
+
+module GTK
+ module Trace
+ IGNORED_METHODS = [
+ :define_singleton_method, :raise_immediately, :instance_of?,
+ :raise_with_caller, :initialize_copy, :class_defined?,
+ :instance_variable_get, :format, :purge_class, :instance_variable_defined?,
+ :metadata_object_id, :instance_variable_set, :__printstr__,
+ :instance_variables, :is_a?, :p, :kind_of?, :==, :log_once,
+ :protected_methods, :log_once_info, :private_methods, :open,
+ :!=, :initialize, :object_id, :Hash, :methods, :tick, :!,
+ :respond_to?, :yield_self, :send, :instance_eval, :then,
+ :__method__, :__send__, :log_print, :dig, :itself, :log_info,
+ :remove_instance_variable, :raise, :public_methods, :instance_exec,
+ :gets, :local_variables, :tap, :__id__, :class, :singleton_class,
+ :block_given?, :_inspect, :puts, :global_variables, :getc, :iterator?,
+ :hash, :to_enum, :printf, :frozen?, :print, :original_puts,
+ :srand, :freeze, :rand, :extend, :eql?, :equal?, :sprintf, :clone,
+ :dup, :to_s, :primitive_determined?, :inspect, :primitive?, :help,
+ :__object_methods__, :proc, :__custom_object_methods__, :Float, :enum_for,
+ :__supports_ivars__?, :nil?, :fast_rand, :or, :and,
+ :__caller_without_noise__, :__gtk_ruby_string_contains_source_file_path__?,
+ :__pretty_print_exception__, :__gtk_ruby_source_files__,
+ :String, :log, :Array, :putsc, :Integer, :===, :here,
+ :raise_error_with_kind_of_okay_message, :better_instance_information,
+ :lambda, :fail, :method_missing, :__case_eqq, :caller,
+ :raise_method_missing_better_error, :require, :singleton_methods,
+ :!~, :loop, :numeric_or_default, :`, :state, :inputs, :outputs, "args=".to_sym,
+ :grid, :gtk, :dragon, :args, :passes, :tick, :grep_source, :grep_source_file,
+ :numeric_or_default, :f_or_default, :s_or_default, :i_or_default,
+ :comment, :primitive_marker, :xrepl, :repl
+ ]
+
+ def self.traced_classes
+ @traced_classes ||= []
+ @traced_classes
+ end
+
+ def self.mark_class_as_traced! klass
+ @traced_classes << klass
+ end
+
+ def self.untrace_classes!
+ traced_classes.each do |klass|
+ klass.class_eval do
+ all_methods = klass.instance_methods false
+ if klass.instance_methods.respond_to?(:__trace_call_depth__)
+ undef_method :__trace_call_depth__
+ end
+
+ GTK::Trace.filter_methods_to_trace(all_methods).each do |m|
+ original_method_name = m
+ trace_method_name = GTK::Trace.trace_method_name_for m
+ if klass.instance_methods.include? trace_method_name
+ alias_method m, trace_method_name
+ end
+ end
+ end
+ end
+ $last_method_traced = nil
+ @traced_classes.clear
+ $trace_enabled = false
+ if !$gtk.production
+ $gtk.write_file 'logs/trace.txt', "Add trace!(SOMEOBJECT) to the top of `tick` and this file will be populated with invocation information.\n"
+ end
+ end
+
+ def self.trace_method_name_for m
+ "__trace_original_#{m}__".to_sym
+ end
+
+ def self.original_method_name_for m
+ return m unless m.to_s.start_with?("__trace_original_") && m.to_s.end_with?("__")
+ m[16..-3]
+ end
+
+ def self.filter_methods_to_trace methods
+ methods.reject { |m| m.start_with? "__trace_" }.reject { |m| IGNORED_METHODS.include? m }
+ end
+
+ def self.flush_trace pad_with_newline = false
+ $trace_puts ||= []
+ if $trace_puts.length > 0
+ text = $trace_puts.join("")
+ if pad_with_newline
+ $gtk.append_file 'logs/trace.txt', "\n" + text.strip
+ else
+ $gtk.append_file 'logs/trace.txt', text.strip
+ end
+ end
+ $trace_puts.clear
+ end
+
+ def self.trace! instance = nil
+ $trace_history ||= []
+ $trace_enabled = true
+ $trace_call_depth ||=0
+ flush_trace
+ instance = $top_level unless instance
+ return if Trace.traced_classes.include? instance.class
+ all_methods = instance.class.instance_methods false
+ instance.class.class_eval do
+ attr_accessor :__trace_call_depth__ unless instance.class.instance_methods.include?(:__trace_call_depth__)
+ GTK::Trace.filter_methods_to_trace(all_methods).each do |m|
+ original_method_name = m
+ trace_method_name = GTK::Trace.trace_method_name_for m
+ alias_method trace_method_name, m
+ $trace_puts << "Tracing #{m} on #{instance.class}.\n"
+ define_method(m) do |*args|
+ instance.__trace_call_depth__ ||= 0
+ tab_width = " " * (instance.__trace_call_depth__ * 8)
+ instance.__trace_call_depth__ += 1
+ $trace_call_depth = instance.__trace_call_depth__
+ parameters = "#{args}"[1..-2]
+ $trace_puts << "\n #{tab_width}#{m}(#{parameters})"
+ execution_time = Time.new.to_i
+ $last_method_traced = trace_method_name
+ $trace_history << [m, parameters]
+ result = send(trace_method_name, *args)
+ completion_time = Time.new.to_i
+ instance.__trace_call_depth__ -= 1
+ instance.__trace_call_depth__ = instance.__trace_call_depth__.greater 0
+ $trace_puts << "\n #{tab_width} success: #{m}"
+ if instance.__trace_call_depth__ == 0
+ $trace_puts << "\n"
+ $trace_history.clear
+ end
+ result
+ rescue Exception => e
+ instance.__trace_call_depth__ -= 1
+ instance.__trace_call_depth__ = instance.__trace_call_depth__.greater 0
+ $trace_puts << "\n #{tab_width} failed: #{m}"
+ if instance.__trace_call_depth__ == 0
+ $trace_puts << "\n #{tab_width} #{e}"
+ $trace_puts << "\n"
+ end
+ $trace_call_depth = 0
+ GTK::Trace.flush_trace true
+ raise e
+ end
+ end
+ end
+ mark_class_as_traced! instance.class
+ end
+ end
+end