{"id":16140196,"url":"https://github.com/kobewi/sapphire","last_synced_at":"2025-03-18T17:30:25.336Z","repository":{"id":6256221,"uuid":"7488906","full_name":"KoBeWi/Sapphire","owner":"KoBeWi","description":"The ultimate Ruby game programming for Windows","archived":false,"fork":false,"pushed_at":"2018-06-03T23:59:04.000Z","size":53207,"stargazers_count":7,"open_issues_count":1,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-28T10:53:56.915Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KoBeWi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-01-07T20:03:52.000Z","updated_at":"2025-01-01T08:35:08.000Z","dependencies_parsed_at":"2022-09-12T23:41:34.940Z","dependency_job_id":null,"html_url":"https://github.com/KoBeWi/Sapphire","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KoBeWi%2FSapphire","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KoBeWi%2FSapphire/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KoBeWi%2FSapphire/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KoBeWi%2FSapphire/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KoBeWi","download_url":"https://codeload.github.com/KoBeWi/Sapphire/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243940138,"owners_count":20372047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-09T23:51:07.219Z","updated_at":"2025-03-18T17:30:23.723Z","avatar_url":"https://github.com/KoBeWi.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"Sapphire (source version) \n\nThe 'source' includes:\n- source code (with Template files)\n- exe\n- icon file\n- batch compiler for Windows/Ocra (pretty useless)\n- SciTe (Windows)\n- examples directory\n- examples zip\n- this file\n\nSapphire is:\n- stand-alone Ruby for Windows, including gems for making games\n- template maker to start developing games with Ruby/Gosu easier\n\n\nIf you are Windows, you can use the exe. If not, you need Ruby and run/compile Sapphire.rb to have same functionality.\nAnd having Ruby installed, the only interesting thing you can do is the !template command (see below). Just run Sapphire.rb\nThis file describes mainly the Template features.\n\n\nSpecjal commands:\n!scite - opens text editor (Windows only)\n!examles - crates zip of examples how to use template\n!template - creates template for game\n  You can specify title by typing it after space (!template My_Title)\n\nTemplate is an empty game project with useful classes to help developing.\n__________________________________________________________________________________________________________\n\nTemplate documentation:\n\nUpon creating, template includes (Title).rb file and 'data' directory.\nInside data, there are few more directories:\nscripts - here is code of your project ; all files placed here will be loaded automatically\ncore - contains system image files and some others ; modify your GUI graphics here\ngfx - default directory for all graphics ; any loaded image will be first looked for in this directory (and sub-folders if you specify path), but you can place images anywhere in 'data' directory\nsfx - default for sound samples\nmusic - default for music\nfades - all fading effects are stored here (see: somewhere below)\n\n\nGlobal variables used:\n- $state - current state of game, which is being updated and drawn ; $state= for changing game states\n- $screen - window instance ; useful when you need mouse position etc.\n- $time- global frame counter ; non-moldifable, use it like Gosu.milliseconds\n- $enable_gui - set true to enable GUI\n- $premusic - used by music intro, not you\n\n\nCode files: (number is for class index below)\n- (Title).rb  // 1\n    Game's core, which loads scripts and has Window's class\n\n- specjal.rb  // 2,3,4,5,6\n    Major file with helper classes. Manages resources, buttons etc.\n    Stop_Music - method that stops any song playing\n\n- game.rb  // 7\n    File for main game's state. Manages entities etc.\n\n- utility\u0026fx.rb  // 8,9,10,11,12,13,14,15,16,17,18,19,20,21,22\n    Tools for easy advanced entity control and classes taking care of simple effects, like particles etc. Also some collision classes\n    \n  objects.rb // 23\n    You can put your objects here\n\n- GUI\n    Contains GUI module\n\n\nClasse index (note that not every single variable is described as they are repeating ; there are also some references to files you should look with specific lines/methods ; all classes are explained in examples)\n1.Main\nWindow class responsible for updating and drawing game states and reading input.\n\n def button_down/up(id)\n Checks if specified key is pressed/released. Needs to be placed in state class to work\n \n def fade_out(effect, speed, solid=:auto)\n Fades out screen and disables further drawing. Used: $screen.fade_out\n effect - name of effect in 'data/fades'. Images should be grayscale gradient/pattern/whatever, where colors with greater luminance (brighter) will fade out first\n speed - speed of fading, 1000 meaning instant and 1 is about 15 seconds\n solid - true or false ; defines if fading effect should be completely opaque (solid) or fade smoothly ; when nothing is given, it will use default value\n \n def fade_in(effect, speed, solid=:auto)\n Same as fade out, but fades in and brighter colors appear last ; also, continues the drawing loop\n \n def unfade\n Continue the drawing loop without fading in\n \n def fade_mode\n Default value for 'solid' argument\n\n2.Keypress\nUsed for input checking, allows to bind keys to symbols\n\n  def Keypress.[](id,repeat)\n  id - Gosu::Button or symbol\n  repeat - when false, key is triggered once until releasing it\n  Symbol will be used as key for control hash, defined with methods below\n\n  def Keypress.Any\n  Returns key pressed in current frame (button_down(id))\n  \n  def Keypress.Define(keys)\n  Defines controls (used in main.rb). keys must be a {:symbol=\u003eGosu::Button} hash\n  \n  def Keypress.Set(key,new)\n  Binds one key, where 'key' is :symbol of key and 'new' is Button to be stored\n\n3.Img \\ Snd \\ Msc\nLoads specified resoure and saves in memory for re-use\n\n  def .[](name,/tileable/,/pre/)\n  Use: Img['space'] so it will load 'space.png' from 'data/gfx' etc.\n  name - path to resource\n  tileable - used only for Img, true if image has to be tileable\n  pre - apply intro to music. It will be played at the beginning and then the actual music is looped. Intro must be separate file named '(music_name)-pre'. Using :auto will seek automatically if there's intro available\n  Images need to be .png , music and sound .ogg\n  \nfor Msc\n\n  def Msc.Stop\n  Stops any music playing making sure you won't cause an exception\n  \n  def Msc.Pause\n  Pauses any music\n  \n  def Msc.Resume\n  Resumes paused music, taking care of any intros, so it will loop right\n\n4.Tls\nLoads tiles from image\n\n  def Tls.[](name,width, height=width, tileable=false)\n  width/height - size per tile, lower than 0 splits image into width/height tiles ; ommiting width will make square tiles\n\n5.Fnt\nLoads fonts\n\n  def Fnt.[](name,size)\n  name - path to font or name of .ttf file from system's fonts ; if specified as Tls array, makes a BitmapFont (see below)\n  size - height of the font or array with order of characters for BitmapFont (see below)\n\n6.BitmapFont\nSpecjal class for custom fonts\nsee: specjal.rb 154 for some customization\n\n  def initialize(name,characters)\n  name - array of images (use Tls method here)\n  characters - array of characters as they are ordered in font's image. There's no difference in upcase or downcase chars\n\n  def draw(x,y,z,args)\n  args - hash arguments:\n    :scalex/scaley - scale of characters\n    :xspacing/yspacing - space between letters, defaultly is letter's size\n    :max - maximal width of text in one line\n    :align - :right or :center, no support for multiline text (yet?)\n    :color - works best for greyscale images. Gosu::Color or hex 0xaarrggbb\n\n6.Entity\nMain class for game objects. Every object you make should inherit from Entity to provide these methods\nsee: specjal.rb 184 to define entity groups\n\n  @x,@y - they are accessors by default\n  @stop (accessor) - prevents entity update\n  @invisible (accessor) - skips entity in drawing\n  @removed (reader) - entity was removed (see below)\n  @spawn_time (reader) - $time value when object was initialized. May be used for counters etc. ($time-@spawn_time is a lifetime value)\n\n  def init(types)\n  Pushes entity to game's entity array, so it's being updated. Use types arrray for grouping entities for easier managing\n  Entity initialized again will have @removed variable set to nil\n\n  def remove\n  Deletes entity from game's entity array and all group arrays ; note that entity will vanish at the end of update cycle. Calling this sets @removed variatble to true on first ; entity can be initialized again if still stored somewhere\n\n  def gravity(width,height,gravity)\n  Method for simple falling physics\n  width/height - size of object. When no height is give, it will take width value\n\n7.Game\nDefault state class for handling game action. Manages in-game objects, provides useful methods. Just copy it when you need more states like this (for menu maybe)\nsee: game.rb 5 to customize effects\nuse intialize update and draw methods as comments say, so you can add your logic\n\n  @lighting_enabled - if true, screen will darken out and Lights will be enabled (see: 20.Light class)\n\n  def solid?\n  Method to check if current coordinates are solid. Needs to be manually defined\n\n  def reset\n  Deletes all in-game entities\n  \n  def missing?(entity)\n  Checks if entity is removed\n  \n  def find(group) {block}\n  Searchs entitiy passing specified block. If no group is given, it will process through all entities\n\n  def flash(color,speed,starting)\n  Makes simple flash effect\n    color - color of effect\n    speed - how fast effect proceeds (255 means instant)\n    starting - when true, screen is faded gradually, false means instant clear and then fade out of flash\n\n  def shake(max,time,num)\n  Makes simple shake effect ; shakes current state's Camera ; creates black frame if shaking beyond boundaries\n    max - amplitude of oscillation\n    time - number of frames between changing position\n    num - number of shakes\n    \n  def set_camera(camera)\n  Changes game's camera to given object (instance of Camera class)\n  \n  def set_default_camera(camera)\n  Changes game's default camera to given one\n  \n  def default_camera\n  Changes current camera to the default one\n  \n  def play(sample, x, y, volume)\n  Plays sample somewhere, so it's volume and panning depends on disance from camera\n  sample - name of sample\n  x/y - coordinates of source\n  volume - maximal radius at which the sample is heard\n\n8.Counter\nObject used for countdowns\n\n  @finished (reader) - true if time reaches 0\n  @time (reader) - current time\n\n  def initialize(time)\n  time - number of frames (ticks) to count\n\n  def image(h,m,s,hs)\n  Returns string which converts time into hours, minutes, seconds and hundreth of seconds (use variables to specify display)\n\n9.Mover\nBasic object to move group of entities together\n\n  def initialize(entities, speed_x, speed_y)\n  entities - array of entities\n  speed_x/y - speed of moving\n\n10.Flasher\nToggles entities' @invisible variable to make them flash effect\n\n  def initialize(entities,time1,time2)\n  time1/time2 - how often variable is toggling\n\n11.Delayer\nSlows entities' update for certain ammount of frames making a lag/slow motion effect\n\n  def initialize(entities, time)\n  time - lenght of lag in frames\n\n12.Particle\nSimple falling object, may be use eg. for crashing glass\n\n  def initialize(x,y,z,img,vx,vy,args)\n  img - name/path to image or array for tile values ([\"imagename\" ,w ,h , id] instead of Tls method)\n  vx/vy - initial speed\n  args - hash arguments:\n    :angle - initial angle of image (default: 0)\n    :rotate - speed of image's rotating\n    :scalex/:scaley - objects scale\n    :color - color for image\n\n13.Trail\nSingle animation sequence, which disappears after finishing\n\n  def initialize(x,y,z,tiles,sequence,time,args)\n  tiles - not Tls, but simple array (see: Particle)\n  time - frame length of each frame\n  args - :scalex, :scaley, :color\n    :sequence - array of numbers, corresponding for frames in spriteset. Used for custom animation order\n    :repeat - number of times to repeat sequence\n\n14.Trace\nSingle image, which fades out particular time\n\n  def initialize(x,y,img,speed,args={})\n  img - see: Particle\n  speed - speed of fading (max 255)\n  args - :angle,:scalex,:scaley\n    :color (MUST be Gosu::Color)\n    :inverted - fades in instead of out\n\n15.Combo\nUsed for reading key sequences\n\n  @trigger (reader) - changes to true when combo is successful ; lasts for 1 frame (tick)\n\n  def initialize(timeout,sequence)\n  timeout - number of frames before combo cancels\n  sequence - array of buttons or defined key symbols\n  \n\nNote: Collision classes are not inherits of Entity and they provide only readers for @x and @y\n16.Collision_Box\nFor bounding box collision detection ; attach it to object with the note that it's position is centered\n\n  @vectors (reader) - array of positions of edges in order: [x1, y1, x2, y2, x3, y3, x4, y4]\n  @w,@h (writer/reader) - size of box\n  \n  def initialize(x,y,w,h,a)\n  x,y - coordinates of the center\n  w,h - width and height of box\n  a - angle of box, around center\n  \n  def collides?(col)\n  Returns true if box intersects with col (col is either Collision_Box, Collision_Ball or Collission_Group)\n  \n  def set(x,y,a)\n  Binds new values for x,y and angle ; use it to follow object box is attached\n  \n  def move(x,y,a)\n  Adds given values to x,y and angle\n  \n17.Collision_Ball\nFor bounding sphere (circle) collision detection ; attach it to object\n\n  @r (writer/reader) - radius of ball\n  \n  def initialize(x,y,r)\n  x,y - coordinates of the center\n  r - radius\n  \n  def collides?(col)\n  \n  def set(x,y)\n  Binds new values for x,y ; use it to follow object box is attached ; trying to set angle like in box, does nothing\n  \n  def move(x,y)\n  Adds given values to x,y\n  \n18.Collision_Group\nGroup of balls and boxes ; they will move relatively to group position\n\n  @c (reader) - array of colliders attached\n  \n  def initialize(x,y,a,*c)\n  x,y - coordinates of group\n  a - angle\n  c - array of colliders\n  \n  def collides?(col)\n  Checks if any of attached colliders intersect with col\n  \n  def set(x,y,a)\n  Binds new values for x,y and angle ; children colliders will move accordingly also taking care of angle\n  \n  def move(x,y,a)\n  Adds given values to x,y and angle of children colliders, also moving them accordingly\n  \n19.Camera\nClass dedicated to screen control in Game class ; see: 7.Game class to see how to set camera\n\n  def initialize(x, y)\n  Screen will be centered around x,y (so the camera is in the middle of screen)\n  \n  def follow(entity, smooth)\n  entity - camera will follow entity given\n  smooth - integer, makes camera follow entity with given speed instead of instantly\n  \n  def move(x,y,speed)\n  Camera will move to given position with given speed\n  \n  def scroll(vx,vy)\n  Camera will move constantly with given speeds\n  \n  def boundary(min_x, min_y, max_x, max_y)\n  Sets the boundary to the camera so top of the screen will never cross min_y etc.\n  \n  def offset(x, y)\n  Sets the x and y offsets of camera, so will not center around given object etc.\n  \n  def pos_x/pos_y\n  Returns position of left/top corner of the screen\n  \n  def shader(shader)\n  Sets camera shader to given Ashton::Shader ; nil will disable\n  \n20.Light\nTo use with game's lighting effects ; creates light on its position with given properties\n\n  @radius (accessor) - radius of light\n  @color (accessor) - color of light\n  @luminance (accessor) - strength of light from 1 to 8 ; 8 is solid\n\n  def intialize(x,y,radius,color,luminance)\n  \n21.Sequence\nsee: utility\u0026fx.rb 497 to customize and add own actions\nClass used to perform scheduled actions. Each next action will take place only if previous one was finished.\n\n  def initialize(sequence)\n  sequence - array of actions ; each action is an hash, each requires :type key. The types and their arguments (additional keys) are following:\n    :wait - waits given time before next action\n      :time (REQUIRED) - number of frames (ticks) to wait\n    \n    :camera_move - moves camera to given positions\n      :target (REQUIRED) - 3 element array: [target_x, target_y, speed]\n      \n    :camera_follow - follows target\n      :target (REQUIRED) - this entity will be followed\n      :smooth - if following should be smooth\n      \n    :flash - makes flash effect\n      :values (REQUIRED) - arguments to effect (see: 7.Game.flash)\n      \n    :shake - makes shake effect\n      :values (REQUIRED) - arguments to effect (see: 7.Game.shake\n      \n    :trail - crates Trail Entity\n      :values (REQUIRED) - arguments to constructor (see: 13.Trail)\n      \n    :trace/:particle - same as :trail\n    \n    :sample - plays a sound\n      :name (REQUIRED) - path/name of the sample\n      \n    :entity - creates entity of given class\n      :class (REQUIRED) - symbol representing name of the class to create\n      :values (REQUIRED) - arguments to constructor, depending on class you chose\n      \n    :fade_in/:fade_out - makes a fade effect\n      :effect (REQUIRED) - name of the effect\n      :speed (REQUIRED) -speed of the effect\n      :mode  - solid mode (see: 7.Game.fade_in/out)\n      \n  \n22.Projectile\nsee: objects.rb to customize\nTemplate class for projetiles. Includes functions like moving, homing, falling etc. but you have to define yourself how does this interact with other objects\n\n@time - a variable that counts frame lifetime of projectile\n\ndef initialize(x,y,type,img,args={})\nimg - see: Trail\ntype - :trail, :bullet or :arrow  ;  Defines projectile logic. Types take different hash arguments, some of which are even required\n  - :trail - Static animation, useful for explosions ; Takes arguments:\n  :animation - array [number of frames, ticks per frame], uses images from img, trails without defined animation will be single-image\n  :sequence - define order of frames in animation\n  :repeat - number of times to repeat animation or lifetime of single-image\n  :movex,:movey - makes trail moving with given speed\n  \n  - :bullet - Straigh projectile, good for bullets, missiles etc.\n  :dir (REQUIRED) - direction of bullet\n  :speed - speed of bullet (default is 1)\n  :folllow - array [target entity, target offset x, target offset y, bullet offset x, bullet offset y], target will be followed by bullet so (bullets position + offset of bullet) will turn to (target's position + offset of target) ; offset is optional\n  :accuracy - ability to turn while following, default is 1\n  :limit - limit of following time\n  :pointing - bullet image angle will follow dir, pointing is integer which also defines offset of angle\n  \n  - :arrow - Falling projectile, like arrow or grenade. Make it bouncing yourself\n  :vx,:vy (REQUIRED) - starting velocity of arrow\n  OR\n  :power,:dir (REQUIRED) - used instead of :vx,:vy, just automatically calculates them\n  :gravity - default is 1\n  :pointing - arrow image angle will follow velocity direction, pointing is integer which also defines offset of angle\n  \n  type-independent args:\n  :angle - angle of projectile's image\n  :rotate - angle of projectile changes by this value per frame\n  :animation,:sequence - may be used for non-trail projectiles, they won't dissappear like trail\n  :z - z-order if different than default\n  :scalex,:scaley - scale of image\n  :color - color of image\n  \n  \n__________________________________________________________________________________________________________\n\nHow to use GUI\n- GUI is feature included in game template\n- First you need to enable it, by calling  $enable_gui=true\n- Then just initialize some GUI objects to use them. It's better to place them in GUI's window. To initialize objects use GUI::ObjName.new\n- GUI graphics can be customized in data/GUI. Use only four colors from GUI palette for compatibility\n\nWindow\n- GUI::Window.new(x,y,width,height,title,customization)\nx,y - position of window\nwidth,height - window size\ntitle - window caption\ncustomization - array for options\n  example:\n  [[:separator,[10,10,50,50]] , [:object,[:button_1,Button.new(20,20,\"Press me\"]] , [:nox]]\n  \n  Above you can see 3 types of customization. Each customization is double array: name in symbol and then an array for options.\n  - Layout\n  You can add texts and separators to your window.\n      :separator - [x1, y1, x2, y2]\n      :text - [text, x, y]\n      \n  - Objects\n  Add GUI elements. The first option for objects is its name referenced by window, second is new objects insance. They are listed below. Note that objects position is relative to window's\n  \n  - Additional options\n  Window settings, they take no arguments\n  :nox - window will have no X for closing\n  :disabled - window is invisible at start\n  :dock - window is unmovable\n  \nWindows can be closed and moved. You can only use actve window (the one with foreground border) and to activate window, just click its header, what will automatically move it to top\nWindows has also instance variables that can be changed anytime: @nox, @docked, @disabled\nYou can also retrieve and set values of window's objects by Window.value(object name) and Window.set_value(objects name, value)\n\nGUI Objects\nEvery objects has its  :value  accessor so values can be easily read and written\nThey have a   :changed   reader, that returns true if value was changed last frame\nThey also have a variable  @disabled  that makes them invisible\n\nButton - a bassic button. Read value to check if it's pressed\nArguments: (x, y, text)\n\nZip - a zip bar with numeric value\nArguments: (x, y, max value, unit)\n-unit - pixel distance between values\n\nCheck - a simple checkbox\nArguments: (x, y, negateable)\n-negateable - check normally takes true or nil, but negateable enables additionally false\n\nRadio - radio-type choice\nArguments: (x, y, choices)\n-choices - it's an array of available selections ; it can be modified dynamically\n\nDropdown - dropdown-box-type choice\nArguments: (x, y, choices)\n-choices - it can be modified dynamically\n\nTextbox - a monospaced line of text input\nArguments: (x, y, max)\n-max - maximal number of characters\n\nNumber - numeric input with textbox\nArguments: (x, y, minimal value, maximal value)\nmin and max can be modified dynamically\n\nRadio and Dropdown have a   value2   method that returns currently selected text rather than choice id","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkobewi%2Fsapphire","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkobewi%2Fsapphire","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkobewi%2Fsapphire/lists"}