├── LICENSE ├── README.md └── addons └── godot-object-pool ├── icon.png └── pool.gd /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 rgrams 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # godot-object pool 2 | 3 | An object pool for Godot. 4 | 5 | # Usage example: 6 | 7 | PlayerController.gd 8 | 9 | ```gdscript 10 | const Pool = preload("res://addons/godot-object-pool/pool.gd") 11 | const GreenBullet = preload("res://com/example/bullets/green_bullet.tscn") 12 | 13 | const BULLET_POOL_SIZE = 60 14 | const BULLET_POOL_PREFIX = "bullet" 15 | 16 | onready var bullets = get_node("bullets") 17 | onready var player = get_node("player") 18 | onready var pool = Pool.new(BULLET_POOL_SIZE, BULLET_POOL_PREFIX, GreenBullet) 19 | 20 | func _ready(): 21 | # Attach pool of objects to the bullets node 22 | pool.add_to_node(bullets) 23 | 24 | # Attach the "on_pool_killed" method to the pool's "killed" signal 25 | pool.connect("killed", self, "_on_pool_killed") 26 | 27 | set_process_input(true) 28 | 29 | func _input(event): 30 | if event.is_action_pressed("ui_select"): 31 | var bullet = pool.get_first_dead() 32 | if bullet: bullet.shoot(player.get_node("weapon_position"), player) 33 | 34 | func _on_pool_killed(target): 35 | target.hide() 36 | print("Currently %d objects alive in pool" % pool.get_alive_count()) 37 | print("Currently %d objects dead in pool" % pool.get_dead_count()) 38 | ``` 39 | -------------------------------------------------------------------------------- /addons/godot-object-pool/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/godot-addons/godot-object-pool/f56435f119754367b06cfeaea99d557d9b2c63d9/addons/godot-object-pool/icon.png -------------------------------------------------------------------------------- /addons/godot-object-pool/pool.gd: -------------------------------------------------------------------------------- 1 | # 2 | # The design/intent of this object pool is to be as immutable as possible from the outside. 3 | # With this in mind, I've attempted to not expose many internal to keep things as simple as possible, 4 | # knowing that nothing actually prevents you from modifying the object. 5 | # 6 | # See README.md for example usage 7 | # 8 | 9 | # Signal emitted when an object managed by the pool is "killed". 10 | # This is called after the pool has handled the killed signal from the object. 11 | signal killed(target) 12 | 13 | # Prefix to use when adding objects to the scene (becomes "undefined_1, undefined_2, etc") 14 | var prefix setget , get_prefix 15 | 16 | # Pool size on initialization 17 | var size setget , get_size 18 | 19 | # Preloaded scene resource 20 | var scene setget , get_scene 21 | 22 | # Dictionary of "alive" objects currently in-use. 23 | # Using a dictionary for fast lookup/deletion 24 | var alive = {} 25 | 26 | # Array of "dead" objects currently available for use 27 | var dead = [] 28 | 29 | # Constructor accepting pool size, prefix and scene 30 | func _init(size_, prefix_, scene_): 31 | size = int(size_) 32 | prefix = str(prefix_) 33 | scene = scene_ 34 | init() 35 | 36 | # Expand the total pool size by the number of size objects. 37 | # For example, if passed 2, we will instantiate 2 new objects and add to the dead pool. 38 | func init(): 39 | # If scene has not been set, just return 40 | if scene == null: 41 | return 42 | 43 | for i in range(size): 44 | var s = scene.instance() 45 | s.set_name(prefix + "_" + str(i)) 46 | s.connect("killed", self, "_on_killed") 47 | dead.push_back(s) 48 | 49 | func get_prefix(): 50 | return prefix 51 | 52 | func get_size(): 53 | return size 54 | 55 | func get_scene(): 56 | return scene 57 | 58 | func get_alive_size(): 59 | return alive.size() 60 | 61 | func get_dead_size(): 62 | return dead.size() 63 | 64 | # Get the first dead object and make it alive, adding the object to the alive pool and removing from dead pool 65 | func get_first_dead(): 66 | var ds = dead.size() 67 | if ds > 0: 68 | var o = dead[ds - 1] 69 | if !o.dead: return null 70 | 71 | var n = o.get_name() 72 | alive[n] = o 73 | dead.pop_back() 74 | o.dead = false 75 | o.set_pause_mode(0) 76 | return o 77 | 78 | return null 79 | 80 | # Get the first alive object. Does not affect / change the object's dead value 81 | func get_first_alive(): 82 | if alive.size() > 0: 83 | return alive.values()[0] 84 | 85 | return null 86 | 87 | # Convenience method to kill all ALIVE objects managed by the pool 88 | func kill_all(): 89 | for i in alive.values(): 90 | i.kill() 91 | 92 | # Attach all objects managed by the pool to the node passed 93 | func add_to_node(node): 94 | for i in alive.values(): 95 | node.add_child(i) 96 | 97 | for i in dead: 98 | node.add_child(i) 99 | 100 | # Convenience method to show all objects managed by the pool 101 | func show(): 102 | for i in alive.values(): 103 | i.show() 104 | 105 | for i in dead: 106 | i.show() 107 | 108 | # Convenience method to hide all objects managed by the pool 109 | func hide(): 110 | for i in alive.values(): 111 | i.hide() 112 | 113 | for i in dead: 114 | i.hide() 115 | 116 | # Event that all objects should emit so that the pool can manage dead/alive pools 117 | func _on_killed(target): 118 | # Get the name of the target object that was killed 119 | var name = target.get_name() 120 | 121 | # Remove the killed object from the alive pool 122 | alive.erase(name) 123 | 124 | # Add the killed object to the dead pool, now available for use 125 | dead.push_back(target) 126 | 127 | target.set_pause_mode(1) 128 | 129 | emit_signal("killed", target) 130 | --------------------------------------------------------------------------------