kiwi-ecs 0.0.3 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/arch_store.rb +7 -0
- data/lib/archetype.rb +84 -80
- data/lib/bitmap.rb +6 -0
- data/lib/entity.rb +6 -0
- data/lib/kiwi-ecs.rb +2 -2
- data/lib/query.rb +10 -0
- data/lib/world.rb +50 -48
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c92559b41133eb2dc4efeb25ae91bce5ddc356eed0b4164cbc284b5c8ca4eac
|
4
|
+
data.tar.gz: b213c479a15483424f08617bf5fb7c5b0895c8866804f4adaa0912068e6d1819
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23611a5577855aa6f67245e195942009d08535c82d4bfb5d737bc3d8c9ff9914a09cdc66c5ff920e90cbdc02038b221d8fabdc5111fd20c60bb1e94a4a185d86
|
7
|
+
data.tar.gz: 2adf271c5166619053826369b1458abd4b44d679f02f394f1e6da6cfef86dcb82db67f03d841e7747bd55942fd26b4e64aefa07b7f9f5de2ab30ea030f062aff
|
data/README.md
CHANGED
data/lib/arch_store.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
require_relative 'archetype'
|
2
2
|
|
3
|
+
module Kiwi
|
4
|
+
# Internal methods not meant for outside use
|
5
|
+
module Internal
|
6
|
+
|
3
7
|
class ArchStore
|
4
8
|
# [[Integer]:Integer]
|
5
9
|
attr_accessor :compMap
|
@@ -28,3 +32,6 @@ class ArchStore
|
|
28
32
|
end
|
29
33
|
end
|
30
34
|
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/archetype.rb
CHANGED
@@ -1,93 +1,97 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
def new_arch_row_id(entityId)
|
16
|
-
id = @availableEntityRows.pop
|
17
|
-
if id != nil
|
18
|
-
@entities[id] = entityId
|
19
|
-
return id
|
20
|
-
else
|
21
|
-
id = @entities.size
|
22
|
-
@entities.push entityId
|
23
|
-
return id
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def set_component(archRowId, component)
|
28
|
-
compCol = @components[component.class.object_id]
|
29
|
-
if compCol.components.size <= archRowId
|
30
|
-
compCol.components.push component
|
31
|
-
else
|
32
|
-
compCol.components[archRowId] = component
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def get_component(archRowId, componentId)
|
37
|
-
return @components[componentId].components[archRowId]
|
38
|
-
end
|
39
|
-
|
40
|
-
def has_component(componentId)
|
41
|
-
return @components[componentId] != nil
|
42
|
-
end
|
1
|
+
module Kiwi
|
2
|
+
module Internal
|
3
|
+
ComponentColumn = Struct.new(:components)
|
4
|
+
|
5
|
+
class Archetype
|
6
|
+
# @params [Array<Integer>] componentIds
|
7
|
+
def initialize(componentIds)
|
8
|
+
# [Integer(componentId): ComponentColumn]
|
9
|
+
@components = componentIds.map do |compId|
|
10
|
+
[compId, ComponentColumn.new([])]
|
11
|
+
end.to_h
|
12
|
+
@availableEntityRows = []
|
13
|
+
@entities = []
|
14
|
+
end
|
43
15
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
16
|
+
# @return [int]
|
17
|
+
def new_arch_row_id(entityId)
|
18
|
+
id = @availableEntityRows.pop
|
19
|
+
if id != nil
|
20
|
+
@entities[id] = entityId
|
21
|
+
return id
|
22
|
+
else
|
23
|
+
id = @entities.size
|
24
|
+
@entities.push entityId
|
25
|
+
return id
|
26
|
+
end
|
27
|
+
end
|
48
28
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
@components[compId].components
|
29
|
+
def set_component(archRowId, component)
|
30
|
+
compCol = @components[component.class.object_id]
|
31
|
+
if compCol.components.size <= archRowId
|
32
|
+
compCol.components.push component
|
33
|
+
else
|
34
|
+
compCol.components[archRowId] = component
|
35
|
+
end
|
57
36
|
end
|
58
|
-
compCount = componentIds.size
|
59
37
|
|
60
|
-
|
61
|
-
|
62
|
-
.filter do |entId, _|
|
63
|
-
entId != nil
|
38
|
+
def get_component(archRowId, componentId)
|
39
|
+
return @components[componentId].components[archRowId]
|
64
40
|
end
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
41
|
+
|
42
|
+
def has_component(componentId)
|
43
|
+
return @components[componentId] != nil
|
69
44
|
end
|
70
|
-
end
|
71
45
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
# ...
|
76
|
-
components = componentIds
|
77
|
-
.map do |compId|
|
78
|
-
@components[compId].components
|
46
|
+
def remove_entity(archRowId)
|
47
|
+
@availableEntityRows.push(archRowId)
|
48
|
+
@entities[archRowId] = nil
|
79
49
|
end
|
80
|
-
compCount = componentIds.size
|
81
50
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
51
|
+
# @return [[Component, EntityId]]
|
52
|
+
def active_components(componentIds)
|
53
|
+
# [comp1a, comp1b]
|
54
|
+
# [comp2a, comp2b]
|
55
|
+
# ...
|
56
|
+
components = componentIds
|
57
|
+
.map do |compId|
|
58
|
+
@components[compId].components
|
59
|
+
end
|
60
|
+
compCount = componentIds.size
|
61
|
+
|
62
|
+
@entities
|
63
|
+
.each_with_index
|
64
|
+
.filter do |entId, _|
|
65
|
+
entId != nil
|
66
|
+
end
|
67
|
+
.map do |_, rowIdx|
|
68
|
+
(0...compCount).map do |compRowId|
|
69
|
+
components[compRowId][rowIdx]
|
70
|
+
end
|
71
|
+
end
|
86
72
|
end
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
73
|
+
|
74
|
+
def components_and_ids(componentIds)
|
75
|
+
# [comp1a, comp1b]
|
76
|
+
# [comp2a, comp2b]
|
77
|
+
# ...
|
78
|
+
components = componentIds
|
79
|
+
.map do |compId|
|
80
|
+
@components[compId].components
|
81
|
+
end
|
82
|
+
compCount = componentIds.size
|
83
|
+
|
84
|
+
@entities
|
85
|
+
.each_with_index
|
86
|
+
.filter do |entId, _|
|
87
|
+
entId != nil
|
88
|
+
end
|
89
|
+
.map do |entId, rowIdx|
|
90
|
+
[entId, *(0...compCount).map do |compRowId|
|
91
|
+
components[compRowId][rowIdx]
|
92
|
+
end]
|
93
|
+
end
|
91
94
|
end
|
95
|
+
end
|
92
96
|
end
|
93
97
|
end
|
data/lib/bitmap.rb
CHANGED
data/lib/entity.rb
CHANGED
data/lib/kiwi-ecs.rb
CHANGED
@@ -5,14 +5,14 @@
|
|
5
5
|
# Copyright (C) 2023 Jonas Everaert
|
6
6
|
#
|
7
7
|
# This program is free software: you can redistribute it and/or modify
|
8
|
-
# it under the terms of the GNU General Public License as published by
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
9
9
|
# the Free Software Foundation, either version 3 of the License, or
|
10
10
|
# (at your option) any later version.
|
11
11
|
#
|
12
12
|
# This program is distributed in the hope that it will be useful,
|
13
13
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
14
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
# GNU General Public License for more details.
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
16
|
#
|
17
17
|
# You should have received a copy of the GNU General Public License
|
18
18
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
data/lib/query.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
module Kiwi
|
2
|
+
module Internal
|
1
3
|
module Query
|
2
4
|
# @return [enumerator<Integer>]
|
3
5
|
def query_ids
|
@@ -23,6 +25,12 @@ module Query
|
|
23
25
|
.active_components(componentIds)
|
24
26
|
end
|
25
27
|
|
28
|
+
if componentType.size == 1
|
29
|
+
result = result.map do |c|
|
30
|
+
c[0]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
26
34
|
if block_given?
|
27
35
|
result.each do |a|
|
28
36
|
yield a
|
@@ -54,3 +62,5 @@ module Query
|
|
54
62
|
end
|
55
63
|
end
|
56
64
|
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/world.rb
CHANGED
@@ -2,63 +2,65 @@ require_relative 'entity'
|
|
2
2
|
require_relative 'arch_store'
|
3
3
|
require_relative 'query'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
module Kiwi
|
6
|
+
class World
|
7
|
+
def initialize
|
8
|
+
@entityStore = Kiwi::Internal::EntityStore.new
|
9
|
+
@archStore = Kiwi::Internal::ArchStore.new
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
def spawn(*components)
|
13
|
+
compIds = components.map { |c| c.class.object_id }.sort
|
14
|
+
archId = @archStore.get_archetype_id(compIds)
|
15
|
+
entId = @entityStore.new_id
|
16
|
+
archetype = @archStore.get(archId)
|
17
|
+
archRowId = archetype.new_arch_row_id(entId)
|
18
|
+
@entityStore.spawn(entId, archId, archRowId)
|
19
|
+
for component in components
|
20
|
+
archetype.set_component(archRowId, component)
|
21
|
+
end
|
22
|
+
return entId
|
20
23
|
end
|
21
|
-
return entId
|
22
|
-
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
def get_component(entityId, componentType)
|
26
|
+
entity = @entityStore.get(entityId)
|
27
|
+
archetype = @archStore.get(entity.archId)
|
28
|
+
archetype.get_component(entity.archRow, componentType.object_id)
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
def kill(entityId)
|
32
|
+
entity = @entityStore.get entityId
|
33
|
+
@entityStore.kill(entityId)
|
34
|
+
archetype = @archStore.get(entity.archId)
|
35
|
+
archetype.remove_entity(entity.archRow)
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
def entity_count
|
39
|
+
return @entityStore.entity_count
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
def has_component(entityId, componentType)
|
43
|
+
entity = @entityStore.get(entityId)
|
44
|
+
archetype = @archStore.get(entity.archId)
|
45
|
+
return archetype.has_component(componentType.object_id)
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
def has_flag(entityId, flagId)
|
49
|
+
return @entityStore.has_flag entityId, flagId
|
50
|
+
end
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
def has_flags(entityId, *flagIds)
|
53
|
+
return flagIds.filter { |flagId| !@entityStore.has_flag entityId, flagId }.count == 0
|
54
|
+
end
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
56
|
+
def set_flag(entityId, flagId)
|
57
|
+
@entityStore.set_flag(entityId, flagId)
|
58
|
+
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
60
|
+
def remove_flag(entityId, flagId)
|
61
|
+
@entityStore.remove_flag(entityId, flagId)
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
+
include Kiwi::Internal::Query
|
65
|
+
end
|
64
66
|
end
|
metadata
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kiwi-ecs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonas Everaert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-08-
|
11
|
+
date: 2023-08-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
14
|
-
|
13
|
+
description: |-
|
14
|
+
== Description
|
15
|
+
|
16
|
+
["Kiwi is a versatile entity component system focussing on fast iteration and a nice api.\n", "\n", "To get started, read the [usage guide](#usage) below.\n", "\n", "[](https://github.com/Jomy10/kiwi-ecs-ruby/actions/workflows/tests.yml)\n", "\n", "## Installation\n", "\n", "The library is available from [ruby gems](https://rubygems.org/gems/kiwi-ecs):\n", "\n", "```sh\n", "gem install kiwi-ecs\n", "```\n", "\n", "To use it in your ruby source files:\n", "\n", "```ruby\n", "require 'kiwi-ecs'\n", "```\n", "\n", "## Usage\n", "\n", "### The world\n", "\n", "The world is the main object that controls the ecs.\n", "\n", "```ruby\n", "world = Kiwi::World.new\n", "```\n", "\n", "### Components\n", "\n", "Creating a component is as simple as declaring a struct:\n", "\n", "```ruby\n", "Position = Struct.new :x, :y\n", "```\n", "\n", "Classes can also be used instead of structs\n", "\n", "```ruby\n", "class Velocity\n", " attr_accessor :x\n", " attr_accessor :y\n", "end\n", "```\n", "\n", "### Entities\n", "\n", "An entity is spawned with a set of components:\n", "\n", "```ruby\n", "entityId = world.spawn(Position.new(10, 10))\n", "\n", "world.spawn(Position.new(3, 5), Velocity.new(1.5, 0.0))\n", "```\n", "\n", "The `world.spawn(*components)` function will return the id of the spawned entity.\n", "\n", "Killing an entity can be done using `world.kill(entityId)`:\n", "\n", "```ruby\n", "world.kill(entityId)\n", "```\n", "\n", "### Systems\n", "\n", "#### Queries\n", "\n", "Queries can be constructed as follows:\n", "\n", "```ruby\n", "# Query all position componentss\n", "world.query(Position) do |pos|\n", " puts pos\n", "end\n", "\n", "# Query all entities having a position and a velocity component, and their entity ids\n", "world.query_with_ids(Position, Velocity) do |id, pos, vel|\n", " # ...\n", "end\n", "```\n", "\n", "### Flags\n", "\n", "Entities can be tagged using flags\n", "\n", "#### Defining flags\n", "\n", "A flag is an integer\n", "\n", "```ruby\n", "module Flags\n", " Player = 0\n", " Enemy = 1\n", "end\n", "```\n", "\n", "#### Setting flags\n", "\n", "```ruby\n", "id = world.spawn\n", "\n", "world.set_flag(id, Flags::Player)\n", "```\n", "\n", "#### Removing a flag\n", "\n", "```ruby\n", "world.remove_flag(id, Flags::Player)\n", "```\n", "\n", "#### Checking wether an entity has a flag\n", "\n", "```ruby\n", "world.has_flag(id, Flags::Player)\n", "```\n", "\n", "#### Filtering queries with flags\n", "\n", "```ruby\n", "world.query_with_ids(Pos)\n", " .filter do |id, pos|\n", " world.has_flag(id, Flags::Player)\n", " end\n", " .each do |id, pos|\n", " # Do something with the filtered query\n", " end\n", "```\n", "\n", "The `hasFlags` function is also available for when you want to check multiple flags.\n", "\n", "## Road map\n", "\n", "- [ ] System groups\n", "\n", "## Contributing\n", "\n", "Contributors are welcome to open an issue requesting new features or fixes or opening a pull request for them.\n", "\n", "## License\n", "\n", "The library is licensed under LGPLv3.\n"]
|
15
17
|
email:
|
16
18
|
executables: []
|
17
19
|
extensions: []
|