summaryrefslogtreecommitdiffhomepage
path: root/README.mdown
blob: 01dab799b859907ce823905aa1c00d3860f145af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

![FelFlame](https://filestorage.catgirls.rodeo/images/felflame-logo-full.png)

[![Maintainability](https://api.codeclimate.com/v1/badges/56d425d9078e98efb74b/maintainability)](https://codeclimate.com/github/realtradam/FelFlame/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/56d425d9078e98efb74b/test_coverage)](https://codeclimate.com/github/realtradam/FelFlame/test_coverage)
[![Documentation Coverage](https://img.shields.io/badge/Documentation-100%25-br)](https://felflame.tradam.fyi)

# What is this?

This is a Ruby ECS Framework for developing games. It is still a work in progress in the early stages, is not fit for use, and does not work.
It is designed to be platform agnostic, this means it should be able to work by plugging it into any ruby game engine/library/toolkit with minimal modifications.  

I wanted a reusable framework so I could quickly and effectively develop games. I also want it to be more complete, as opposed to barebones or boilerplate.
I plan to eventually add functionality outside of just ECS such as loading tilesets, a camera system, etc. that are built into the framework to work seamlessly.


# What is currently implemented?

Entities and Components are mostly implemented, with only a few non-critical functions missing.

Systems, Scenes, and the Stage still needs to be implemented

You can view the [Documentation here](https://felflame.tradam.fyi)


# Specification

Below are the specifications I have imagined for this framework and have been written out. They are subject to change as FelFlame is developed and used.

## Aliases:
```ruby
FF = FelFlame
FF::Ent = FelFlame::Entities
FF::Cmp = FelFlame::Components
FF::Sys = FelFlame::Systems
FF::Sce = FelFlame::Scenes
FF::Stg = FelFlame::Stage
```
## Classes:

### FF::Entities
```ruby
FF::Ent.new(@component1, @component2)
@entity = FF::Ent.get(entity_id)
FF::Ent.delete(entity_id)
@entity.id # => unique entity id

@entity.add @component
@entity.remove @component
@entity.dump # => [:id, :scenes, :components]
FF::Ent.load @entity_dump
```

### FF::Components
```ruby
FF::Cmp.new('Name', 'param1', param2: 'default')
FF::Cmp::Name.new(param1: value1)
@component = FF::Cmp::Name.get(component_id)
FF::Cmp::Name.get_by_entity(entity_id) # gets array of components
@component.set(param2: 'not default')
@component.param2 = 'different not default'
FF::Cmp::Name.detach(entity_id: ent_id, component_id: cmp_id)
FF::Cmp::Name.remove_entity(entity_id) # Removes entity from any components
FF::Cmp::Name.delete_component(component_id) # deletes component and removes from all relevant entities
@component.dump # returns hash of all variables!(and the id)
FF::Cmp::Name.load @component_dump

FF::Cmp::Health.added # => returns values for sys to setup
FF::Cmp::Health.removed # => returns values for sys to setup
FF::Cmp::Health.is_set('var') # => returns values for sys to setup
```

### FF::Systems
```ruby
FF::Sys.new(name: 'Render', position: 5, frame: 1) do
	@component.each do
		# functionality
	end
end
FF::Sys::Render.trigger_when FF::Cmp::Health.added
FF::Sys::Render.trigger_when FF::Cmp::Health.removed
FF::Sys::Render.trigger_when FF::Cmp::Health.is_set('var')
```

### FF::Scenes
```ruby
FF::Scn.new(name: 'Scene1', position: 1)
FF::Scn::Scene1.add @entity
FF::Scn::Scene1.add FF::Sys::Render
FF::Scn::Scene1.entities # => [id_1, id_7, etc]
FF::Scn::Scene1.systems # => [:Render, :Damage, etc]
FF::Scn::Scene1.dump # => [:name, :entities, :systems]
FF::Scn::Scene1.load @scene_dump
```

### FF::Stage
```ruby
FF::Stg.add FF::Scn::Scene1
FF::Stg.remove FF::Scn::Scene1
FF::Stg.scene # => [:Scene1, :Scene2, etc]
FF::Stg.dump # => [:Scene1, :Scene2, etc]
FF::Stg.load @stage_dump
FF::Stg.clear
```

### FelFlame
```ruby
FF.dump # => all data
FF.load @felflame_dump
```
---
![blank](https://filestorage.catgirls.rodeo/images/whitespace.png)  
![blank](https://filestorage.catgirls.rodeo/images/whitespace.png)  
![blank](https://filestorage.catgirls.rodeo/images/whitespace.png)  
---
# Ramblings:
Was my originally written up specs. Rewrote it as what is written above to be more clear.
The below are more verbose but not as helpful for me for implementation. Once the framework is
complete I will use a more verbose explanation as below to help users of the framework.

---

Creating Entities:

```ruby
# Plain:
@my_entity = FF:Ent.new

# With components:
FF::Ent.new(FF::Cmp::Position.new(var1: 'val', var3: 'change_default'),
	    FF::Cmp::Health.new(hp: 20),
	    FF::Cmp::Poison.new(dps: 3),
	    FF::Cmp::Poison.new(dps: 2), # This entity has 2 of the same component in it!
	    FF::Cmp::Selection.get(component_id)) # Components can belong to multiple entities, this component already existed elsewhere!
```

Adding and Removing Components from Entities:
```ruby
@my_entity = FF::Ent.get(entity_id)

@my_entity.remove(component_id)
# Remove the specific component with that id

@my_entity.remove(FF::Cmp::Poison)
# Removes all components of that type

@my_entity.add(FF::Cmp::Selection.new)
# Adds a new Component
```

Creating Component Class:

```ruby
# Creating a component 'factory':
FF::Cmp.new('Name', 'var1', 'var2',  var3: 'default') # Name, *no_default, **with_default
```

And then using those components:
```ruby
@new_cmp = FF::Cmp::Name.new(var1: 'oke') # var3 will be 'default', var2 will be nil
@new_cmp.var2 = 3 # now var2 is set
@new_cmp.set(var1: 'nope', var3: 'different') # var1 and var3 are now changed!
@new_cmp.to_hash # returns the hash of all variables!
```

Referencing Components:
```ruby
FF::Cmp::Name.get(component_id) # gets component by their unique id
FF::Cmp::Name.get_by_entity(entity_id) # gets component that is attached to the entitry
# will return array of components if there is multiple of same component
# if it returns array, see the `dump` section. Need to add custom method to the array
```

Creating Systems:
```ruby
FF::Sys.new(name: 'Render', position: 5, frame: 1) do 
# position is the order in which systems get executed, can be overlapping but then order is unexpected between same positions
# frame is on which frame the system will be called. 0 is never, 1 is on each frame, 2 is every other frame, etc
	FF::Cmp::Position.each do
		#render your sprite
	end
end
```

Enabling Systems:
```ruby
# By default systems are not enabled. You need to add them to a scene
FF::Scn::Scene1.add FF::Sys::Render

# They can also be disabled by removing them
FF::Scn::Scene1.remove FF::Sys::Render
```

Custom Hooks:
```ruby
# Systems can be configured to be called whenever a certain component is added, removed or set
FF::Sys::Damage.trigger_when FF::Cmp::Health.added
FF::Sys::Revive.trigger_when FF::Cmp::Health.removed
FF::Sys::Healup.trigger_when FF::Cmp::Health.is_set
		
# Systems can also be manually called so you can code custom hooks!
FF::Sys::Restore.run
```

Scenes contain Entities and Systems
```ruby
FF::Scn.new(name: 'Scene1', position: 1)
# Multiple scenes could be ran at once, if they do then they will run according
# to their positions as explained above

FF::Scn::Scene1.add FF::Entity.get(entity_id)
# You can also just pass the id on its own => FF::Scn::Scene1.add entity_id
FF::Scn::Scene1.add FF::Entity.new

FF::Scn::Scene1.add FF::Sys::Render
```

To List Systems and Enties
```ruby
FF::Scn::Scene1.get_entities # => [id_1, id_7, etc]
FF::Scn::Scene1.get_systems  # => [:Render, :Damage, etc]
```

To run a Scene it must be added to the Stage
```ruby
FF::Stg.add FF::Scn::Scene1
```

Or remove it:
```ruby
FF::Stg.remove FF::Scn::Scene1
```

Show all Scenes on the Stage:
```ruby
FF::Stg.scenes # => [:Scene1, :Scene2, etc]
```

Remove all Scenes from the Stage:
```ruby
FF::Stg.clear
```

You can save the current game state:
```ruby
@json_save_data = FF.dump
```

You can also specifically choose what you want to save:
```ruby
@hash_entity = FF::Ent.get(entity_id).dump
# to save all components related to a player

@hash_component_single = FF::Cmp::Health.get(component_id).dump
# save all data in the single component(needs to handle arrays of components)

@hash_component = FF::Cmp::Health.dump
# save all components of a certain component type

@hash_components_all = FF::Cmp.dump
# save all components

@hash_scene = FF::Scn::Scene1.dump
# save all entities, components, and activated systems in a given scene
```

And then they can be loaded back in:
```ruby
FF::Ent.load(@hash_entity)
FF::Cmp::Health.load(@hash_component)
FF::Cmp.load(@hash_component)
FF::Cmp.load(@hash_components_all)
FF::Scn.load(@Hash_scene)
```

### To Do List(old)

---

* [ ] Some level of hierarchical support?
* [ ] One Component to many entities.
* [ ] Multiple of same component to one entity
* [ ] State Machine?
* [ ] Systems execute code on an event
	* [ ] Adding/removing/setting component is event
	* [ ] Frame is an event
* [ ] System Execution Order
* [ ] Save Dump/Load