{"id":27014273,"url":"https://github.com/samdze/godot-native-bullets-plugin","last_synced_at":"2025-04-04T13:30:00.255Z","repository":{"id":180473169,"uuid":"419818453","full_name":"samdze/godot-native-bullets-plugin","owner":"samdze","description":"Efficiently spawn and move high amounts of objects like bullets for bullet hells, particles and more.","archived":false,"fork":false,"pushed_at":"2023-12-07T16:34:05.000Z","size":38623,"stargazers_count":152,"open_issues_count":5,"forks_count":13,"subscribers_count":8,"default_branch":"main","last_synced_at":"2023-12-07T17:45:11.953Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/samdze.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-10-21T17:32:35.000Z","updated_at":"2023-11-30T21:18:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"30630beb-251b-4ab9-b7d6-9db099c9ff77","html_url":"https://github.com/samdze/godot-native-bullets-plugin","commit_stats":null,"previous_names":["samdze/godot-native-bullets-plugin"],"tags_count":2,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samdze%2Fgodot-native-bullets-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samdze%2Fgodot-native-bullets-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samdze%2Fgodot-native-bullets-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samdze%2Fgodot-native-bullets-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/samdze","download_url":"https://codeload.github.com/samdze/godot-native-bullets-plugin/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247184708,"owners_count":20897827,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-04T13:29:59.607Z","updated_at":"2025-04-04T13:30:00.242Z","avatar_url":"https://github.com/samdze.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Godot Native Bullets\n\nEfficiently spawn and move high amounts of objects like bullets for bullet hells, particles and more.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/19392104/138730996-4ae0c6c0-6283-44df-ba44-b1f261c9035c.gif\" width=\"360\" /\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/19392104/138732303-21ab282f-3f00-417f-ba47-d6e1713648ea.gif\" width=\"360\" /\u003e\n\u003c/p\u003e\n\nThis is a **GDNative plugin**, compatible with Godot 3.4.x and up.\u003cbr\u003e\nNot compatible with Godot 4.x.\n\nThe versions of the pre-built binaries are as follows:\n\n- Windows x86-64 (v1.2.1)\n- Linux x86-64 (v1.2.1)\n- macOS Universal (x86-64 + arm64, v1.2.1)\n\n**Notice**: to make sure you have the latest binary version you can build from source.\u003cbr\u003e\nSee [Compiling and extending the plugin](#compiling-and-extending-the-plugin).\n\n## Features\n\n1. Spawn and move high amounts of bullets.\n2. Configure multiple types of bullets, each with its own behaviour.\n3. Set custom properties to categories of bullets or to any single bullet.\n4. Customize bullets using shaders.\n5. Configure bullets with a collision shape, layer and mask of your choice.\n6. Toggle collision detection on or off for each type of bullet.\n7. Set the pool size and z index for every bullet type.\n8. Choose the target viewport or canvas layer.\n9. Extend the plugin using C++.\n\n## Step by step\n\n### Installation\n\n1. Copy the addons/native_bullets folder in your addons folder.\n2. Navigate to Project -\u003e Project Settings -\u003e Plugin and enable the Native Bullets plugin.\n\nFor best performance, toggle `use_bvh` off in Project Settings -\u003e Physics -\u003e 2d.\n\n### BulletKit creation\n\nThe first thing to do is create a BulletKit resource and choose how bullets will appear and behave tweaking its properties.\n\n1. Create a new empty resource and assign one of the scripts you can find in the `addons/native_bullets/kits` folder to it.\n   In this example, we'll assign the `basic_bullet_kit.gdns` script.\n   New properties will appear in the resource inspector.\n2. To get started, fill the `texture` property with any texture you have.\n3. As the `material`, you can use a new material resource using the `animated_shader.gdshader` you can find in the utils folder.\n   This shader takes care of animating your bullets if you specify more than 1 frame in its parameters.\n\n4. For now, turn off `collisions_enabled`, turn `use_viewport_as_active_rect` on, turn `rotate` off and set `unique_modulate_component` to `None`.\n   See the [Reference](#reference) section to learn more.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/19392104/140386739-dc06ddbe-1943-45b0-a4c7-ac5e6a494783.png\" /\u003e\n\u003c/p\u003e\n\nThis BulletKit resource is now ready to be used!\n\n### BulletsEnvironment node\n\nIn order to spawn bullets in the scene, a BulletsEnvironment node is needed.\nThis is the node that will define which kinds of bullets will be available during its lifetime.\nOnly one BulletsEnvironment node can be active at the same time and if you add another one to the scene tree its configuration will replace the previous one.\n\nThe BulletsEnvironment node has to be configured to choose which kinds of bullets will be able to spawn, their maximum amount and their z indices.\n\n1. Create a new BulletsEnvironment node.\n2. Choose how many types of bullets this node will be able to spawn. Increase `bullet_types_amount` to 1 for now.\n\n3. A new section of the inspector will appear below. Unfold the `Bullet Type 0` entry.\n   Here, drag \u0026 drop the BulletKit resource you created earlier to let the node know that you'll want to spawn the bullet described in it!\n4. Choose the maximum amount of bullets setting the `pool_size` property and the their `z_index`.\n   3000 and 1 will be ok.\n   Leave the `parent_hint` property empty, it will make the bullets spawn in the nearest Viewport or CanvasLayer up in the scene tree.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/19392104/140386914-287dc3bb-9926-4f89-b4c1-f60a878406e3.png\" /\u003e\n\u003c/p\u003e\n\nNice! Now the bullets are ready.\n\n### Spawn bullets\n\nThe last step is to spawn a lot of those bullets.\u003cbr\u003e\nYou can use the utilities provided by the plugin to spawn bullets in a variety of ways, but let's do it manually for now.\u003cbr\u003e\nCreate a script.\n\n```gdscript\n# Assign a valid BulletKit via the inspector.\nexport(Resource) var bullet_kit\n\n\nfunc _process(delta):\n\tif Input.is_key_pressed(KEY_SPACE):\n\t\tshoot()\n\tif Input.is_key_pressed(KEY_RIGHT):\n\t\trotation += PI * delta\n\tif Input.is_key_pressed(KEY_LEFT):\n\t\trotation -= PI * delta\n\n\nfunc shoot():\n\tvar bullet_velocity = Vector2(cos(global_rotation), sin(global_rotation)) * 30.0\n\n\t# Define which properties will be set to the newly spawned bullet.\n\t# The bullet will be spawned in the same position as this node,\n\t# travelling in the direction defined by its rotation.\n\tvar properties = {\n\t\t\"transform\": Transform2D(global_rotation, global_position),\n\t\t\"velocity\": bullet_velocity\n\t}\n\t# Spawn a bullet using the selected BulletKit and setting the properties defined above.\n\t# Bullets is an autoload.\n\tBullets.spawn_bullet(bullet_kit, properties)\n```\n\nHere you go!\nNow attach this script to one of your 2D nodes, start the game, press space to shoot and right/left to change the bullets direction!\n\n## More examples\n\nThe repository contains an `examples` folder containing a few pre-configured scenes, ready to be played in the editor.\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/19392104/140408897-00f6de24-e826-4463-a95e-15f7152ead5b.gif\" width=\"580\" /\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/19392104/140408824-e8008e68-5282-46b8-ab83-6dba3d96e41f.gif\" width=\"580\" /\u003e\n\u003c/p\u003e\n\nBelow are reported some of the most common things you can do.\n\n### Bullets spawning\n\nSpawn bullets.\n\n```gdscript\nexport(float) var bullets_speed = 50.0\n\n\nfunc shoot():\n\tvar bullet_kit = preload(\"res://path/to/following_bullet_kit.tres\")\n\n\t# The bullet will be spawned in the same position as this node,\n\t# travelling in the direction defined by its rotation.\n\tvar bullet_velocity = Vector2(cos(global_rotation), sin(global_rotation)) * bullets_speed\n\t# Follow the first node inside the Player group.\n\tvar target_node = get_tree().get_nodes_in_group(\"Player\")[0]\n\n\t# Define which properties will be set to the newly spawned bullet.\n\tvar properties = {\n\t\t\"target_node\": target_node,\n\t\t\"transform\": Transform2D(global_rotation, global_position),\n\t\t\"velocity\": bullet_velocity\n\t}\n\t# Spawn a bullet using the selected BulletKit and setting the properties defined above.\n\tBullets.spawn_bullet(bullet_kit, properties)\n```\n\n### Bullets handling\n\nYou can manipulate and set properties of bullets even after you spawned them.\n\n```gdscript\nexport(float) var bullets_speed = 50.0\n\n\nfunc shoot():\n\tvar bullet_kit = preload(\"res://path/to/basic_bullet_kit.tres\")\n\n\t# Use `obtain_bullet` to receive an opaque BulletID object.\n\tvar bullet_id = Bullets.obtain_bullet(bullet_kit)\n\n\t# You can then use `bullet_id' to set and get properties.\n\tBullets.set_bullet_property(bullet_id, \"transform\", Transform2D(global_rotation, global_position))\n\tBullets.set_bullet_property(bullet_id, \"velocity\", Vector2(cos(global_rotation), sin(global_rotation)) * bullets_speed)\n```\n\n### Collision detection\n\nWhen a bullet collides with a body or an area, the best way to get the data of the colliding bullet is to connect to the `area_shape_entered` signal.\n\n```gdscript\nfunc _on_area_shape_entered(area_id, _area, area_shape, _local_shape):\n\tif not Bullets.is_bullet_existing(area_id, area_shape):\n\t\t# The colliding area is not a bullet, returning.\n\t\treturn\n\n\t# Get a BulletID from the area_shape passed in by the engine.\n\tvar bullet_id = Bullets.get_bullet_from_shape(area_id, area_shape)\n\n\t# Get bullet properties, transform, velocity, lifetime etc.\n\tvar bullet_transform = Bullets.get_bullet_property(bullet_id, \"transform\")\n\t# If you previously set a custom Dictionary containing the `damage` key as the data property, you can retrieve it.\n\tvar bullet_damage = Bullet.get_bullet_property(bullet_id, \"data\").damage\n\n\t# You can also retrieve the BulletKit that generated the bullet and get/set its properties.\n\tvar kit_collision_shape = Bullets.get_kit_from_bullet(bullet_id).collision_shape\n\n\t# Remove the bullet, call_deferred is necessary because the Physics2DServer is in its flushing state during callbacks.\n\tBullets.call_deferred(\"release_bullet\", bullet_id)\n```\n\n## Reference\n\nThe plugin has a few main components, explained below:\n\n### @ BulletKit\n\nThis is the resource used to configure each type of bullet.\u003cbr\u003e\nEvery BulletKit spawns its own bullet instances that support different kinds of properties.\u003cbr\u003e\n\nThe plugin comes with 4 base variants that can be customized via the editor:\n\n\u003cdetails\u003e\n\u003csummary\u003eBasicBulletKit\u003c/summary\u003e\n\u003cbr\u003e\nThis is the most basic BulletKit, makes bullets move, generally at constant speed.\u003cbr\u003e\nIt's configurable with:\n\n- `texture`: controls what texture is sent to the bullet material.\n- `material`: the material used to render each bullet.\n- `collisions_enabled`: enables or disables collision detection, turning it off increases performance.\n- `collision_layer`: the collision layer to use during collision detection. Visible only if `collisions_enabled` is on.\n- `collision_mask`: the collision mask to use during collision detection. Visible only if `collisions_enabled` is on.\n- `collision_shape`: the CollisionShape to use during collision detection. Visible only if `collisions_enabled` is on.\n- `use_viewport_as_active_rect`: if enabled, uses the current viewport to detect whether a bullet should be deleted.\n- `active_rect`: the rect outside of which the bullets get deleted. Visible only if `use_viewport_as_active_rect` if off.\n- `rotate`: controls whether the bullets automatically rotate based on their direction of travel.\n- `unique_modulate_component`: controls which modulate component in the material will be used as a unique value for each bullet instance. This can be used to offset bullets animation frames by unique amounts inside shaders and it's needed due to Godot not supporting material instance properties in 3.x.\n- `data`: custom data you can assign to the BulletKit.\n\nBullets spawned by a BasicBulletKit have those properties:\n\n- `item_rid`: the bullet canvas item RID, used internally. Read-only.\n- `cycle`: the number of times the bullet was recycled, used internally. Read-only.\n- `shape_index`: the index of the collision shape used by this bullet, used internally. Read-only.\n- `transform`: the Transform2D used to position and rotate the bullet.\n- `velocity`: the Vector2 that will be used to update the bullet position.\n- `lifetime`: how much time the bullet has been alive.\n- `data`: custom data you can assign to any bullet.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eFollowingBulletKit\u003c/summary\u003e\n\u003cbr\u003e\nThis BulletKit lets you define a target node for each bullet and a turning speed used to chase it around.\u003cbr\u003e\nIt's configurable with:\n\n- `texture`: controls what texture is sent to the bullet material.\n- `bullets_turning_speed`: the turning speed with which the bullets will rotate towards the target node.\n- `material`: the material used to render each bullet.\n- `collisions_enabled`: enables or disables collision detection, turning it off increases performance.\n- `collision_layer`: the collision layer to use during collision detection. Visible only if `collisions_enabled` is on.\n- `collision_mask`: the collision mask to use during collision detection. Visible only if `collisions_enabled` is on.\n- `collision_shape`: the CollisionShape to use during collision detection. Visible only if `collisions_enabled` is on.\n- `use_viewport_as_active_rect`: if enabled, uses the current viewport to detect whether a bullet should be deleted.\n- `active_rect`: the rect outside of which the bullets get deleted. Visible only if `use_viewport_as_active_rect` if off.\n- `rotate`: controls whether the bullets automatically rotate based on their direction of travel.\n- `unique_modulate_component`: controls which modulate component in the material will be used as a unique value for each bullet instance. This can be used to offset bullets animation frames by unique amounts inside shaders and it's needed due to Godot not supporting material instance properties in 3.x.\n- `data`: custom data you can assign to the BulletKit.\n\nBullets spawned by a FollowingBulletKit have those properties:\n\n- `target_node`: the Node2D the bullet will chase.\n- `item_rid`: the bullet canvas item RID, used internally. Read-only.\n- `cycle`: the number of times the bullet was recycled, used internally. Read-only.\n- `shape_index`: the index of the collision shape used by this bullet, used internally. Read-only.\n- `transform`: the Transform2D used to position and rotate the bullet.\n- `velocity`: the Vector2 that will be used to update the bullet position.\n- `lifetime`: how much time the bullet has been alive.\n- `data`: custom data you can assign to any bullet.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eDynamicBulletKit\u003c/summary\u003e\n\u003cbr\u003e\nLets you define bullets that change their behaviour based on their lifetime.\u003cbr\u003e\nIt's configurable with:\n\n- `texture`: controls what texture is sent to the bullet material.\n- `lifetime_curves_span`: the reference lifespan used by the curves to determine their current value.\n- `lifetime_curves_loop`: controls whether the curves will loop around when `lifetime` goes past `lifetime_curves_span`.\n- `speed_multiplier_over_lifetime`: controls the bullet speed multiplying its velocity magnitude by the value defined in this curve, based on the bullet lifetime.\n- `rotation_offset_over_lifetime`: controls the bullet rotation offsetting its initial rotation by the value in radians defined in this curve, based on the bullet lifetime.\n- `material`: the material used to render each bullet.\n- `collisions_enabled`: enables or disables collision detection, turning it off increases performance.\n- `collision_layer`: the collision layer to use during collision detection. Visible only if `collisions_enabled` is on.\n- `collision_mask`: the collision mask to use during collision detection. Visible only if `collisions_enabled` is on.\n- `collision_shape`: the CollisionShape to use during collision detection. Visible only if `collisions_enabled` is on.\n- `use_viewport_as_active_rect`: if enabled, uses the current viewport to detect whether a bullet should be deleted.\n- `active_rect`: the rect outside of which the bullets get deleted. Visible only if `use_viewport_as_active_rect` if off.\n- `rotate`: controls whether the bullets automatically rotate based on their direction of travel.\n- `unique_modulate_component`: controls which modulate component in the material will be used as a unique value for each bullet instance. This can be used to offset bullets animation frames by unique amounts inside shaders and it's needed due to Godot not supporting material instance properties in 3.x.\n- `data`: custom data you can assign to the BulletKit.\n\nBullets spawned by a DynamicBulletKit have those properties:\n\n- `transform`: the Transform2D used to position and rotate the bullet.\n- `starting_transform`: the baseline Transform2D, curves will apply their changes based on this transform. This is automatically set when you manually edit `transform`.\n- `velocity`: the Vector2 that will be used to update the bullet position.\n- `starting_speed`: the baseline speed, curves will apply their changes based on this speed value. This is automatically set when you manually edit `velocity`.\n- `item_rid`: the bullet canvas item RID, used internally. Read-only.\n- `cycle`: the number of times the bullet was recycled, used internally. Read-only.\n- `shape_index`: the index of the collision shape used by this bullet, used internally. Read-only.\n- `lifetime`: how much time the bullet has been alive.\n- `data`: custom data you can assign to any bullet.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eFollowingDynamicBulletKit\u003c/summary\u003e\n\u003cbr\u003e\nLets you define bullets that change their chasing behaviour based on their lifetime, their distance to the target, or their angle to the target.\u003cbr\u003e\nIt's configurable with:\n\n- `texture`: controls what texture is sent to the bullet material.\n- `lifetime_curves_span`: the reference lifespan used by the curves to determine their current value. Only used when mode `Based On Lifetime` is selected on a curve.\n- `distance_curves_span`: the reference max distance used by the curves to determine their current value. Only used when mode `Based On Target Distance` is selected on a curve.\n- `lifetime_curves_loop`: controls whether the curves will loop around when `lifetime` goes past `lifetime_curves_span`. Only used when mode `Based On Lifetime` is selected on a curve.\n- `speed_control_mode`: specifies the mode the speed multiplier curve will determine its value:\n  - `Based On Lifetime`: the curve x axis will map to the lifetime of the bullet, from 0 to `lifetime_curves_span`.\n  - `Based On Target Distance`: the curve x axis will map to the distance to the target, from 0 to `distance_curves_span`.\n  - `Based on Angle To Target`: the curve x axis will map to the angle between the bullet `velocity` Vector2 and the Vector2 pointing from the bullet to the target node, from 0 to PI.\n- `speed_multiplier`: controls the bullet speed multiplying its velocity magnitude by the value defined in this curve, based on whatever is set in `speed_control_mode`.\n- `turning_speed_control_mode`: specifies the mode the turning speed curve will determine its value:\n  - `Based On Lifetime`: the curve x axis will map to the lifetime of the bullet, from 0 to `lifetime_curves_span`.\n  - `Based On Target Distance`: the curve x axis will map to the distance to the target, from 0 to `distance_curves_span`.\n  - `Based on Angle To Target`: the curve x axis will map to the angle between the bullet `velocity` Vector2 and the Vector2 pointing from the bullet to the target node, from 0 to PI.\n- `turning_speed`: controls the bullet turning speed towards the target node, based on whathever is set in `turning_speed_control_mode`.\n- `material`: the material used to render each bullet.\n- `collisions_enabled`: enables or disables collision detection, turning it off increases performance.\n- `collision_layer`: the collision layer to use during collision detection. Visible only if `collisions_enabled` is on.\n- `collision_mask`: the collision mask to use during collision detection. Visible only if `collisions_enabled` is on.\n- `collision_shape`: the CollisionShape to use during collision detection. Visible only if `collisions_enabled` is on.\n- `use_viewport_as_active_rect`: if enabled, uses the current viewport to detect whether a bullet should be deleted.\n- `active_rect`: the rect outside of which the bullets get deleted. Visible only if `use_viewport_as_active_rect` is off.\n- `rotate`: controls whether the bullets automatically rotate based on their direction of travel.\n- `unique_modulate_component`: controls which modulate component in the material will be used as a unique value for each bullet instance. This can be used to offset bullets animation frames by unique amounts inside shaders and it's needed due to Godot not supporting material instance properties in 3.x.\n- `data`: custom data you can assign to the BulletKit.\n\nBullets spawned by a FollowingDynamicBulletKit have those properties:\n\n- `target_node`: the Node2D the bullet will chase.\n- `velocity`: the Vector2 that will be used to update the bullet position.\n- `starting_speed`: the baseline speed, curves will apply their changes based on this speed value. This is automatically set when you manually edit `velocity`.\n- `item_rid`: the bullet canvas item RID, used internally. Read-only.\n- `cycle`: the number of times the bullet was recycled, used internally. Read-only.\n- `shape_index`: the index of the collision shape used by this bullet, used internally. Read-only.\n- `transform`: the Transform2D used to position and rotate the bullet.\n- `lifetime`: how much time the bullet has been alive.\n- `data`: custom data you can assign to any bullet.\n\u003c/details\u003e\n\n### @ BulletsEnvironment\n\nThe BulletsEnvironment node is responsible for defining which bullets will be spawned in the current scene.\nIt can be configured through the editor setting which kinds of bullets will be used, the pool sizes and the z indices.\n\nThe `parent_hint` property indicates which node to use as the starting point to search for the first available Viewport or CanvasLayer up in the scene tree.\nThe resulting node will then be used to render the bullets.\n\nNote: any change to a BulletsEnvironment node at runtime needs the node to be reloaded to take effect.\n\n#### Signals\n\n```gdscript\n# Emitted when the BulletsEnvironment is about to commit itself to configure which kind of bullets will be available.\n# Can be used to customize the node configuration before applying it.\nsignal tree_entering(node : BulletsEnvironment)\n```\n\n#### Methods\n\n```gdscript\n# Forces the reloading of this BulletsEnvironment, making it the active one.\nreload() -\u003e void\n```\n\n### @ Bullets\n\nBullets is the autoload used to spawn bullets into the scene.\nIt can spawn bullets only if a BulletsEnvironment has been configured and added to the scene.\n\n#### Methods\n\n```gdscript\n# Sets the currently active BulletsEnvironment and allocates the bullets it contains.\n# If a BulletsEnvironment is already active, it will be disabled.\nmount(bullets_environment : BulletsEnvironment) -\u003e void\n\n# Disables and deallocates the bullets contained in `bullets_environment` if it's the currently active BulletsEnvironment.\nunmount(bullets_environment : BulletsEnvironment) -\u003e void\n\n# Returns the currently active BulletsEnvironment node.\nget_bullets_environment() -\u003e BulletsEnvironment\n\n# Spawns a bullet using the passed BulletKit and setting the properties contained in the `properties` dictionary.\n# Returns whether a bullet has been spawned successfully.\nspawn_bullet(bullet_kit : BulletKit, properties : Dictionary) -\u003e bool\n\n# Spawns and returns an opaque ID of a bullet using the passed BulletKit.\nobtain_bullet(bullet_kit : BulletKit) -\u003e BulletID\n\n# Attempts to delete the bullet referenced by the passed `bullet_id`. Returns whether the removal was successful.\nrelease_bullet(bullet_id : BulletID) -\u003e bool\n\n# Returns whether the bullet referenced by `bullet_id` is still alive and valid.\nis_bullet_valid(bullet_id : BulletID) -\u003e bool\n\n# Returns whether `kit` has been configured and is ready to be used in this Bullets instance.\nis_kit_valid(kit : BulletKit) -\u003e bool\n\n# Returns the number of currently available bullets for the `kit` BulletKit.\nget_available_bullets(kit : BulletKit) -\u003e int\n\n# Returns the number of currently active bullets for the `kit` BulletKit.\nget_active_bullets(kit : BulletKit) -\u003e int\n\n# Returns the number of pooled bullets for the `kit` BulletKit.\nget_pool_size(kit : BulletKit) -\u003e int\n\n# Returns the z index of the bulltes generated by the `kit` BulletKit.\nget_z_index(kit : BulletKit) -\u003e int\n\n# Returns the total number of currently available bullets.\nget_total_available_bullets() -\u003e int\n\n# Returns the total number of currently active bullets.\nget_total_active_bullets() -\u003e int\n\n# Returns whether `area_rid` and `area_shape` represent a valid and active bullet.\nis_bullet_existing(area_rid : RID, area_shape : int) -\u003e BulletID\n\n# Returns the opaque ID of a bullet based on its area RID and its shape index.\nget_bullet_from_shape(area_rid : RID, area_shape : int) -\u003e BulletID\n\n# Returns the BulletKit that defined the bullet referenced by the passed `bullet_id`.\nget_kit_from_bullet(bullet_id : BulletID) -\u003e BulletKit\n\n# Sets the indicated property of the bullet referenced by `bullet_id`.\nset_bullet_property(bullet_id : BulletID, property : String, value : Variant) -\u003e void\n\n# Returns the indicated property of the bullet referenced by `bullet_id`.\nget_bullet_property(bullet_id : BulletID, property : String) -\u003e Variant\n```\n\n### @ TimedRotator\n\nA node that defines and sets the rotation of itself over time based on a curve.\n\n#### Properties\n\n```gdscript\n# Enables or disables the rotating behaviour.\nvar enabled : bool\n\n# The time span the curve acts on.\nvar duration : float\n\n# The curve that defines the node rotation over time in degrees.\n# 1 in the curve X axis represents `duration` seconds passed.\nvar orientation_over_time : Curve\n\n# The time scale, used to speed up or slow down the node rotation.\nvar time_scale : float\n\n# Time offset used to calculate the current node rotation.\nvar time_offset : float\n\n# Rotation offset in degrees applied to calculate the current node rotation.\nvar orientation_degrees_offset : float\n\n# Enables the mirroring of the curve resulting rotation.\nvar mirror_enabled : bool\n\n# If `mirror_enabled` is on, defines the reference degrees used to mirror the rotation applied by the curve.\nvar mirror_reference_degrees : bool\n```\n\n### @ TimedEvents\n\nA node that defines and fires an amount of events per second over time based on a curve.\n\n#### Signals\n\n```gdscript\n# Emitted when an event should be fired.\nsignal event()\n\n# Emitted when an event should be fired.\n# `leftover` is how much time, in seconds, the event is late. It is never above the delta time of a physics step.\nsignal event_with_leftover(leftover : float)\n```\n\n#### Properties\n\n```gdscript\n# Enables or disables the event firing behaviour.\nvar enabled : bool\n\n# If defined, this TimedEvents node will try to connect to `connect_to_children` and its children.\n# The `on_timed_events_request` function of 'connect_to_children` node and its children will be called, if defined.\n# The actual connection is their resposibility.\nvar connect_to_children : NodePath\n\n# The time span the curve acts on.\nvar duration : float\n\n# The curve that defines the fire rate of events over time.\n# 1 in the curve X axis represents `duration` seconds passed.\nvar events_per_second_over_time : Curve\n\n# Multiplier used to calculate the events per second.\nvar events_per_second_multiplier : float\n\n# Time offset used to calculate the events fire rate over time.\nvar time_offset : float\n\n# Defines whether the curve will loop starting from the beginning if the time passed exceeds `duration`.\nvar loop : bool\n```\n\n#### Methods\n\n```gdscript\n# Resets the time passed to 0.\nreset() -\u003e void\n```\n\n### @ BulletsSpawner\n\nA simple bullets spawner that uses child nodes as spawning points.\nIt sets bullets velocity, position and rotation.\n\n#### Properties\n\n```gdscript\n# Enables or disables shooting.\nvar enabled : bool\n\n# The BulletKit to use to spawn bullets.\nvar bullet_kit : BulletKit\n\n# The spawned bullets speed.\nvar bullets_speed : float\n\n# The distance from the original spawn point at which the bullets will be spawned.\nvar bullets_spawn_distance : float\n```\n\n#### Methods\n\n```gdscript\n# Shoots bullets based on how many children the node has.\n# Every child is a spawn point and can have its own position and rotation.\n# `recover_seconds` indicates how many seconds the bullet has to recover ahead of time,\n# e.g. when spawning a bullet in the middle of two physics steps.\nshoot(recover_seconds : float) -\u003e void\n\n# Called by TimedEvents nodes when they wish to automatically connect to this node.\non_timed_events_request(timed_events : TimedEvents) -\u003e void\n```\n\n## Compiling and extending the plugin\n[Prerequisites](https://docs.godotengine.org/en/3.6/tutorials/scripting/gdnative/gdnative_c_example.html#prerequisites)\n\nThe plugin can be extended with new BulletKits that are more suitable to your specific use cases.\u003cbr\u003e\nTo do so, you have to download the entire repository together with submodules, write some C++ code and recompile the plugin.\n\n```\ngit clone --recursive https://github.com/samdze/godot-native-bullets-plugin\n```\n\nNew BulletKits can be added creating a new header file inside the src/kits directory.\nHere's an example.\n\n```c++\n// src/kits/custom_following_bullet_kit.h\n\n#ifndef CUSTOM_FOLLOWING_BULLET_KIT_H\n#define CUSTOM_FOLLOWING_BULLET_KIT_H\n\n#include \u003cTexture.hpp\u003e\n#include \u003cPackedScene.hpp\u003e\n#include \u003cNode2D.hpp\u003e\n#include \u003cSceneTree.hpp\u003e\n#include \u003ccmath\u003e\n\n#include \"../bullet_kit.h\"\n\nusing namespace godot;\n\n\n// Bullet definition.\n// This is necessary only if your BulletKit needs custom efficiently accessible bullet properties.\nclass CustomFollowingBullet : public Bullet {\n\t// Godot requires you to add this macro to make this class work properly.\n\tGODOT_CLASS(CustomFollowingBullet, Bullet)\npublic:\n\tNode2D* target_node = nullptr;\n\n\t// the _init method must be defined.\n\tvoid _init() {}\n\n\t// Custom setter and getter, not needed.\n\tvoid set_target_node(Node2D* node) {\n\t\ttarget_node = node;\n\t}\n\n\tNode2D* get_target_node() {\n\t\treturn target_node;\n\t}\n\n\tstatic void _register_methods() {\n\t\t// Registering an Object reference property with GODOT_PROPERTY_HINT_RESOURCE_TYPE and hint_string is just\n\t\t// a way to tell the editor plugin the type of the property, so that it can be viewed in the BulletKit inspector.\n\t\tregister_property\u003cCustomFollowingBullet, Node2D*\u003e(\"target_node\",\n\t\t\t\u0026CustomFollowingBullet::set_target_node,\n\t\t\t\u0026CustomFollowingBullet::get_target_node, nullptr,\n\t\t\tGODOT_METHOD_RPC_MODE_DISABLED, GODOT_PROPERTY_USAGE_NO_INSTANCE_STATE, GODOT_PROPERTY_HINT_RESOURCE_TYPE, \"Node2D\");\n\t}\n};\n\n// Bullet kit definition.\n// Add your own properties, methods and exports.\nclass CustomFollowingBulletKit : public BulletKit {\n\t// Godot requires you to add this macro to make this class work properly.\n\tGODOT_CLASS(CustomFollowingBulletKit, BulletKit)\npublic:\n\t// Use this macro to configure this bullet kit.\n\t// Pass the BulletsPool type that will be used as the argument.\n\tBULLET_KIT(CustomFollowingBulletsPool)\n\n\tRef\u003cTexture\u003e texture;\n\tfloat bullets_turning_speed = 1.0f;\n\n\tstatic void _register_methods() {\n\t\tregister_property\u003cCustomFollowingBulletKit, Ref\u003cTexture\u003e\u003e(\"texture\", \u0026CustomFollowingBulletKit::texture, Ref\u003cTexture\u003e(),\n\t\t\tGODOT_METHOD_RPC_MODE_DISABLED, GODOT_PROPERTY_USAGE_DEFAULT, GODOT_PROPERTY_HINT_RESOURCE_TYPE, \"Texture\");\n\t\tregister_property\u003cCustomFollowingBulletKit, float\u003e(\"bullets_turning_speed\", \u0026CustomFollowingBulletKit::bullets_turning_speed, 1.0f,\n\t\t\tGODOT_METHOD_RPC_MODE_DISABLED, GODOT_PROPERTY_USAGE_DEFAULT, GODOT_PROPERTY_HINT_RANGE, \"0.0,128.0\");\n\n\t\t// Add this macro at the end of the _register_methods() method.\n\t\t// Pass this BulletKit type and the used Bullet type as arguments.\n\t\tBULLET_KIT_REGISTRATION(CustomFollowingBulletKit, CustomFollowingBullet)\n\t}\n};\n\n// Bullets pool definition.\n// This is the class that will handle the logic linked to your custom BulletKit.\n// It must extend AbstractBulletsPool.\nclass CustomFollowingBulletsPool : public AbstractBulletsPool\u003cCustomFollowingBulletKit, CustomFollowingBullet\u003e {\n\n\tvoid _init_bullet(CustomFollowingBullet* bullet) {\n\t\t// Initialize your bullet however you like.\n\t}\n\n\tvoid _enable_bullet(CustomFollowingBullet* bullet) {\n\t\t// Runs when a bullet is obtained from the pool and is being enabled.\n\n\t\t// Reset the bullet lifetime.\n\t\tbullet-\u003elifetime = 0.0f;\n\t\tRect2 texture_rect = Rect2(-kit-\u003etexture-\u003eget_size() / 2.0f, kit-\u003etexture-\u003eget_size());\n\t\tRID texture_rid = kit-\u003etexture-\u003eget_rid();\n\n\t\t// Configure the bullet to draw the kit texture each frame.\n\t\tVisualServer::get_singleton()-\u003ecanvas_item_add_texture_rect(bullet-\u003eitem_rid,\n\t\t\ttexture_rect,\n\t\t\ttexture_rid);\n\t}\n\n\tvoid _disable_bullet(CustomFollowingBullet* bullet) {\n\t\t// Runs when a bullet is being removed from the scene.\n\t}\n\n\tbool _process_bullet(CustomFollowingBullet* bullet, float delta) {\n\t\t// Runs each frame for each bullet, here goes your update logic.\n\t\tif(bullet-\u003etarget_node != nullptr) {\n\t\t\t// Find the rotation to the target node.\n\t\t\tVector2 to_target = bullet-\u003etarget_node-\u003eget_global_position() - bullet-\u003etransform.get_origin();\n\t\t\tfloat rotation_to_target = bullet-\u003evelocity.angle_to(to_target);\n\t\t\tfloat rotation_value = Math::min(kit-\u003ebullets_turning_speed * delta, std::abs(rotation_to_target));\n\n\t\t\t// Apply the rotation, capped to the max turning speed.\n\t\t\tbullet-\u003evelocity = bullet-\u003evelocity.rotated(Math::sign(rotation_to_target) * rotation_value);\n\t\t}\n\t\t// Apply velocity.\n\t\tbullet-\u003etransform.set_origin(bullet-\u003etransform.get_origin() + bullet-\u003evelocity * delta);\n\n\t\tif(!active_rect.has_point(bullet-\u003etransform.get_origin())) {\n\t\t\t// Return true if the bullet should be deleted.\n\t\t\treturn true;\n\t\t}\n\t\t// Rotate the bullet based on its velocity if \"rotate\" is enabled.\n\t\tif(kit-\u003erotate) {\n\t\t\tbullet-\u003etransform.set_rotation(bullet-\u003evelocity.angle());\n\t\t}\n\t\t// Bullet is still alive, increase its lifetime.\n\t\tbullet-\u003elifetime += delta;\n\t\t// Return false if the bullet should not be deleted yet.\n\t\treturn false;\n\t}\n};\n\n// Add this macro at the end of the file to automatically implement a few needed utilities.\n// Pass the BulletKit type and the BulletsPool type as arguments.\nBULLET_KIT_IMPLEMENTATION(CustomFollowingBulletKit, CustomFollowingBulletsPool)\n\n#endif\n```\n\nNext, register you Godot classes inside the `gdlibrary.cpp` file.\n\n```c++\n// src/gdlibrary.cpp\n\n#include \"bullets.h\"\n...\n...\n\n#include \"kits/custom_following_bullet_kit.h\"\n\n...\n...\n\nextern \"C\" void GDN_EXPORT godot_nativescript_init(void *handle) {\n\t...\n\t...\n\n\t// Custom Bullet Kits.\n\tgodot::register_class\u003cCustomFollowingBullet\u003e();\n\tgodot::register_class\u003cCustomFollowingBulletKit\u003e();\n}\n```\n\nCompile the bindings and the plugin for your selected platform.\n\n```\ncd addons/native_bullets/godot-cpp\nscons platform=windows target=release generate_bindings=yes -j4\n\ncd ..\nscons platform=windows target=release\n```\n\nFinally, create a NativeScript resource setting `bullets.gdnlib` as its library and `CustomFollowingBulletKit` as its class name.\u003cbr\u003e\nNow you can attach this script to your BulletKit resources and use it.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamdze%2Fgodot-native-bullets-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsamdze%2Fgodot-native-bullets-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamdze%2Fgodot-native-bullets-plugin/lists"}