Created
April 23, 2013 00:33
-
-
Save fowlmouth/5439848 to your computer and use it in GitHub Desktop.
ruby mini component system
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require'gosu';include Gosu | |
class Component | |
class << self | |
# @field should be set for each base class, | |
# entities that include this component or a derivative | |
# respond to this as a message | |
def field() @field or superclass.field end | |
def iface() (@interface or []) + (superclass.iface rescue []) end | |
def interface method, &b | |
(@interface ||= []) << method | |
define_method method, &b | |
end | |
end | |
end | |
class Pos < Component | |
@field = :pos | |
attr_accessor :x,:y | |
def initialize x,y | |
self.x,self.y = x,y | |
end | |
def * b | |
self.class.new(x * b, y * b) | |
end | |
end | |
class Velocity < Pos | |
@field = :vel | |
interface :update do |ent, dt| | |
ent.pos.x += x * dt | |
ent.pos.y += y * dt | |
end | |
end | |
class Friction < Component | |
@field = :fric | |
attr_accessor :f | |
def initialize f = 0.93 | |
self.f = f | |
end | |
interface :update do |ent, dt| | |
ent.vel *= f ** dt | |
end | |
end | |
class Renderable < Component | |
@field = :rendr | |
interface :draw do |entity, window| end | |
end | |
class Circle < Renderable | |
attr_accessor :radius | |
def initialize radius; self.radius = radius end | |
def draw entity, window | |
window.draw_circle entity.pos.x, entity.pos.y, radius, | |
Gosu::Color::GREEN, 0 | |
#require'pry';binding.pry | |
end | |
end | |
def Entity(*components, &b) | |
## make a new struct with the required fields | |
c = Struct.new(*components.map{|c| c.field}.compact) | |
c.class_eval( | |
components.each_with_object({}){ |co, h| | |
unless (i = co.iface).empty? | |
i.each do |func| | |
(h[func] ||= []) << co.field | |
end | |
end | |
}.map { |m, fields| | |
"def #{m}(*args) \n #{ | |
fields.map { |f| "#{f}.#{m} self, *args" }.join("\n ") | |
}\nend\n" | |
}.join#.tap{|x| puts x} | |
) | |
c.send :define_method, :initialize, &b if b | |
c | |
end | |
class Gosu::Window | |
def draw_circle cx, cy, radius, color, z, step = 30 | |
(0 .. 360).step(step) do |a| | |
a2 = a + step | |
draw_line \ | |
cx + Gosu::offset_x(a, radius), | |
cy + Gosu::offset_y(a, radius), | |
color, | |
cx + Gosu::offset_x(a2, radius), | |
cy + Gosu::offset_y(a2, radius), | |
color, | |
z | |
end | |
end | |
end | |
Bob = Entity(Pos, Renderable, Friction, Velocity) do |x, y, r| | |
#should write something to automate this | |
self.pos = Pos.new(x,y) | |
self.vel = Velocity.new(0, 30) | |
self.rendr = Circle.new(r) | |
self.fric = Friction.new(0.95) | |
end | |
class GameWindow < Window | |
def initialize | |
super 640,480,false | |
self.caption = "foo" | |
@last = Gosu::milliseconds | |
@ents = [] | |
@ents << Bob.new(100,100,3.0) | |
end | |
def button_down id | |
close if id == Gosu::KbEscape | |
end | |
def update | |
cur = Gosu::milliseconds | |
dt, @last = (cur - @last)/1000.0, cur | |
@ents.each do |e| e.update dt end | |
end | |
def draw | |
@ents.each do |e| e.draw self end | |
end | |
end | |
GameWindow.new.show |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment