Skip to content

Instantly share code, notes, and snippets.

@fowlmouth
Created April 23, 2013 00:33
Show Gist options
  • Save fowlmouth/5439848 to your computer and use it in GitHub Desktop.
Save fowlmouth/5439848 to your computer and use it in GitHub Desktop.
ruby mini component system
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