Chingu
OpenGL accelerated 2D game framework for Ruby
Install / Use
/learn @ippa/ChinguREADME
= CHINGU http://github.com/ippa/chingu/tree/master
DOCUMENTATION: http://rdoc.info/projects/ippa/chingu
Ruby 1.9.2 is recommended. Should also work with 1.8.7+. Chingu development is mostly conducted using Win7 / Ruby 1.9.2.
== DESCRIPTION OpenGL accelerated 2D game framework for Ruby. Builds on the awesome Gosu (Ruby/C++) which provides all the core functionality. It adds simple yet powerful game states, pretty input handling, deployment safe asset-handling, a basic re-usable game object and automation of common task.
== INSTALL gem install chingu
== QUICK START (TRY OUT THE EXAMPLES) Chingu comes with 25+ examples demonstrating various parts of Chingu. Please browse the examples-directory in the Chingu root directory. The examples start out very simple. Watch out for instructions in the windows titlebar. Could be how to move the onscreen player or how to move the example forward. Usually it's arrowkeys and space. There's also more complex examples, like a clone of Conways game of life (http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) game_of_life.rb and example21_sidescroller_with_edit.rb where You can switch between playing and editing the level itself.
== PROJECTS USING CHINGU Links to some of the projects using/depending on Chingu:
- https://github.com/Spooner/wrath (pixely 2-player action adventure in development)
- http://ippa.se/games/unexpected_outcome.zip (LD#19 game compo entry by ippa)
- https://bitbucket.org/philomory/ld19/ (LD#19 game compo entry by philomory)
- https://github.com/Spooner/fidgit (GUI-lib )
- https://github.com/Spooner/sidney (Sleep Is Death remake in ruby)
- https://github.com/ippa/the_light_at_the_end_of_the_tunnel (LD#16 game compo entry)
- https://github.com/ippa/gnorf (LD#18 game compo entry. Decent minigame with online highscores.)
- https://github.com/ippa/holiday_droid (Work in progess platformer)
- https://github.com/ippa/pixel_pang (Work in progress remake of the classic Pang)
- https://github.com/ippa/whygone (An odd little platformer-puzzle-game for _why day)
- https://github.com/erisdiscord/gosu-tmx (a TMX map loader)
- https://github.com/rkachowski/tmxtilemap (Another TMX-class)
- https://github.com/erisdiscord/gosu-ring (Secret of Mana-style ring menu for chingu/gosu)
- https://github.com/deps/Berzerk (remake of the classic game. comes with robots.)
- https://github.com/rkachowski/tigjamuk10 ("sillyness from tigjamuk - CB2 bistro in Cambridge, January 2010")
- https://github.com/zukunftsalick/ruby-raid (Remake of Ataris river raid, unsure of status)
- https://github.com/edward/spacewar (a small game, unsure of status)
- https://github.com/jstorimer/zig-zag (2D scrolling game, unsure of status)
... miss your Chingu project? Msg me on github and I'll add it to the list!
== THE STORY The last years I've dabbled around a lot with game development. I've developed games in both Rubygame and Gosu. I've looked at gamebox. Rubygame is a very capable framework with a lot of functionality (collision detection, very good event system etc). Gosu is way more minimalistic but also faster with OpenGL -acceleration. Gosu isn't likely to get much more complex since it does what it should do very well and fast.
After 10+ game prototypes and some finished smaller games I started to see patterns each time I started a new game. Making classes with x/y/image/other-parameters that I called update/draw on in the main loop. This became the basic Chingu::GameObject which encapsulates Gosus "Image.draw_rot" and enables automatic updating/drawing through "game_objects".
There was always a huge big chunk of checking keyboard-events in the main loop. Borrowing ideas from Rubygame this has now become @player.keyboard(:left => :move_left, :space => :fire ... etc.
== CORE OVERVIEW Chingu consists of the following core classes / concepts:
=== Chingu::Window The main window, use it at you use Gosu::Window now. Calculates the framerate, takes care of states, handles chingu-formated input, updates and draws BasicGameObject / GameObjects automatically. Available throughout your source as $window (Yes, that's the only global Chingu has). You can also set various global settings. For example, self.factor=3, will make all fortcomming GameObjects scale 3 times.
=== Chingu::GameObject Use this for all your in game objects. The player, the enemies, the bullets, the powerups, the loot laying around. It's very reusable and doesn't contain any game-logic (that's up to you!). Only stuff to put it on screen a certain way. If you do GameObject.create() instead of new() Chingu will keep save the object in the "game_object"-list for automatic updates/draws. GameObjects also have the nicer Chingu input-mapping: @player.input = { :left => :move_left, :right => :move_right, :space => :fire} Has either Chingu::Window or a Chingu::GameState as "parent".
=== Chingu::BasicGameObject For those who think GameObject is a too little fat, there's BasicGameObject (GameObject inherits from BasicGameObject). BasicGameObject is just an empty frame (no x,y,image accessors or draw-logic) for you to build on. It can be extended with Chingus trait-system though. The new() vs create() behavior of GameObject comes from BasicGameObject. BasicGameObject#parent points to either $window or a game state and is automatically set on creation time.
=== Chingu::GameStateManager Keeps track of the game states. Implements a stack-based system with push_game_state and pop_game_state.
=== Chingu::GameState A "standalone game loop" that can be activated and deactivated to control game flow. A game state is very much like a main gosu window. You define update() and draw() in a gamestate. It comes with 2 extras that main window doesn't have. #setup (called when activated) and #finalize (called when deactivated)
If using game states, the flow of draw/update/button_up/button_down is: Chingu::Window --> Chingu::GameStateManager --> Chingu::GameState. For example, inside game state Menu you call push_game_state(Level). When Level exists, it will go back to Menu.
=== Traits Traits are extensions (or plugins if you so will) to BasicGameObjects included on the class-level. The aim is so encapsulate common behavior into modules for easy inclusion in your game classes. Making a trait is easy, just an ordinary module with the methods setup_trait(), update_trait() and/or draw_trait(). It currently has to be namespaced to Chingu::Traits for "traits" to work inside GameObject-classes.
== OTHER CLASSES / HELPERS
=== Chingu::Text Makes use of Image#from_text more rubyish and powerful. In it's core, another Chingu::GameObject + image genning with Image#from_text.
=== Chingu::Animation Load and interact with tile-based animations. loop, bounce and access invidual frame(s) easily. An "@image = @animation.next" in your Player#update is usually enough to get you started!
=== Chingu::Parallax A class for easy parallaxscrolling. Add layers with different damping, move the camera to generate a new snapshot. See example3.rb for more. NOTE: Doing Parallax.create when using a trait viewport will give bad results. If you need parallax together with viewport do Parallax.new and then manually doing parallax.update/draw.
=== Chingu::HighScoreList A class to keep track of high scores, limit the list, automatic sorting on score, save/load to disc. See example13.rb for more.
=== Chingu::OnlineHighScoreList A class to keep/sync online highscores to http://gamercv.com/. A lot more fun competing with others for positions then a local list.
=== Various Helpers Both $window and game states gets some new graphical helpers, currently only 3, but quite useful:
fill() # Fills whole window with color 'color'. fill_rect() # Fills a given Rect 'rect' with Color 'color' fill_gradient() # Fills window or a given rect with a gradient between two colors. draw_circle() # Draws a circle draw_rect() # Draws a rect
If you base your models on GameObject (or BasicGameObject) you get: Enemy.all # Returns an Array of all Enemy-instances Enemy.size # Returns the amount of Enemy-instances Enemy.destroy_all # Destroys all Enemy-instances Enemy.destroy_if(&block) # Destroy all objects for which &block returns true
== BASICS / EXAMPLES
=== Chingu::Window With Gosu the main window inherits from Gosu::Window. In Chingu we use Chingu::Window. It's a basic Gosu::Window with extra cheese on top of it. keyboard handling, automatic update/draw calls to all gameobjects, fps counting etc.
You're probably familiar with this very common Gosu pattern:
ROOT_PATH = File.dirname(File.expand_path(FILE)) class Game < Gosu::Window def initialize @player = Player.new end
def update
if button_down? Button::KbLeft
@player.left
elsif button_down? Button::KbRight
@player.right
end
@player.update
end
def draw
@player.draw
end
end
class Player attr_accessor :x,:y,:image def initialize(options) @x = options[:x] @y = options[:y] @image = Image.new(File.join(ROOT_PATH, "media", "player.png")) end
def move_left
@x -= 1
end
def move_right
@x += 1
end
def draw
@image.draw(@x,@y,100)
end
end
Game.new.show # Start the Game update/draw loop!
Chingu doesn't change the fundamental concept/flow of Gosu, but it will make the above code shorter:
We use Chingu::Window instead of Gosu::Window
class Game < Chingu::Window def initialize super # This is always needed if you override Window#initialize # # Player will automatically be updated and drawn since it's a Chingu::GameObject # You'll need your own Chingu::Window#update and Chingu::Window#draw after a while, but just put #super there and Chingu can do its thing. # @player = Player.create
