Last active
March 13, 2019 10:56
-
-
Save mbuffa/b11518fd6b5b82edf1ade168b30255e0 to your computer and use it in GitHub Desktop.
An attempt at creating an Entity-Component-System architecture, in Ruby
This file contains 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 'securerandom' | |
Entity = Struct.new(:uuid) | |
class Component | |
attr_accessor :entity_uuid | |
def initialize(entity_uuid) | |
@entity_uuid = entity_uuid | |
ComponentsStore.register_component(self) | |
end | |
end | |
class System | |
class << self | |
def update(payload = nil) | |
SystemsStore.all.each do |systems| | |
systems.each do |sistem| | |
sistem.update(payload) | |
end | |
end | |
end | |
end | |
def initialize(*component_types) | |
@component_types = component_types | |
SystemsStore.register_system(self, @component_types) | |
end | |
def update(payload = nil) | |
raise 'You must implement this method!' | |
end | |
end | |
class SystemsStore | |
class << self | |
def all | |
instance.systems.values | |
end | |
def register_system(sistem, component_types) | |
instance.systems[component_types] ||= [] | |
instance.systems[component_types] << sistem | |
self | |
end | |
private | |
def instance | |
@instance ||= new | |
end | |
end | |
attr_reader :systems | |
private | |
def initialize | |
@systems = {} | |
end | |
end | |
class ComponentsStore | |
class << self | |
def fetch_by_types(types) | |
Array(types).map do |type| | |
instance.components[type] | |
end.flatten | |
end | |
def register_component(component) | |
instance.components[component.class] ||= [] | |
instance.components[component.class] << component | |
self | |
end | |
private | |
def instance | |
@instance ||= new | |
end | |
end | |
attr_reader :components | |
private | |
def initialize | |
@components = {} | |
end | |
end | |
RSpec.describe 'Ruby Entity-Component-System architecture' do | |
class YoloComponent < Component | |
end | |
class YoloSystem < System | |
def initialize | |
super(YoloComponent) | |
end | |
def update(payload = nil) | |
ComponentsStore.fetch_by_types(*@component_types).each do |component| | |
puts "#{component.class} says: Yolo!" | |
end | |
end | |
end | |
before do | |
@yolo_entity = Entity.new(SecureRandom.uuid) | |
@yolo_component = YoloComponent.new(@yolo_entity.uuid) | |
@yolo_system = YoloSystem.new | |
end | |
describe System do | |
it "doesn't crash" do | |
expect { described_class.update }.not_to raise_error | |
end | |
it 'sends updates to all systems' do | |
allow(@yolo_system).to receive(:update) | |
described_class.update | |
expect(@yolo_system).to have_received(:update).exactly(1).times | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment