Skip to content

Commit

Permalink
Bump to v1.2, support rendering on sub-viewports and canvas layers
Browse files Browse the repository at this point in the history
  • Loading branch information
samdze committed Sep 1, 2022
1 parent fe22f85 commit 474eb66
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 16 deletions.
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ Not compatible with Godot 4.x.

Pre-built binaries are provided for:

- Windows x86-64 (v1.1.1)
- Windows x86-64 (v1.2)
- Linux x86-64 (v1.1)
- macOS Universal (x86-64 + arm64, v1.1.2)
- macOS Universal (x86-64 + arm64, v1.2)

## Features

Expand All @@ -25,7 +25,8 @@ Pre-built binaries are provided for:
5. Configure bullets with a collision shape, layer and mask of your choice.
6. Toggle collision detection on or off for each type of bullet.
7. Set the pool size and z index for every bullet type.
8. Extend the plugin using C++.
8. Choose the target viewport or canvas layer.
9. Extend the plugin using C++.

## Step by step

Expand Down Expand Up @@ -71,6 +72,7 @@ The BulletsEnvironment node has to be configured to choose which kinds of bullet
Here, drag & drop the BulletKit resource you created earlier to let the node know that you'll want to spawn the bullet described in it!
4. Choose the maximum amount of bullets setting the `pool_size` property and the their `z_index`.
3000 and 1 will be ok.
Leave the `parent_hint` property empty, it will make the bullets spawn in the nearest Viewport or CanvasLayer up in the scene tree.

<p align="center">
<img src="https://user-images.githubusercontent.com/19392104/140386914-287dc3bb-9926-4f89-b4c1-f60a878406e3.png" />
Expand Down Expand Up @@ -353,6 +355,11 @@ Bullets spawned by a FollowingDynamicBulletKit have those properties:
The BulletsEnvironment node is responsible for defining which bullets will be spawned in the current scene.
It can be configured through the editor setting which kinds of bullets will be used, the pool sizes and the z indices.

The `parent_hint` property indicates which node to use as a starting point to search for the first available Viewport or CanvasLayer up in the scene tree.
The resulting node will then be used to render the bullets.

Note: any change to a BulletsEnvironment node at runtime needs the node to be reloaded to take effect.

#### Signals

```gdscript
Expand Down
Binary file modified addons/native_bullets/bin/macos/libbullets.dylib
Binary file not shown.
Binary file modified addons/native_bullets/bin/win64/bullets.dll
Binary file not shown.
25 changes: 25 additions & 0 deletions addons/native_bullets/bullets_environment.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ signal tree_entering(node)
export(bool) var current = true setget _set_current
export(Array, Resource) var bullet_kits: Array
export(Array, int) var pools_sizes: Array
export(Array, NodePath) var parents_hints: Array
export(Array, int) var z_indices: Array

var properties_regex : RegEx
Expand All @@ -22,6 +23,18 @@ func _enter_tree():
if Engine.editor_hint:
return
emit_signal("tree_entering", self)


func _ready():
if Engine.editor_hint:
return
# var i = 0
# for parent_path in parents:
# if parent_path != null:
# parents[i] = get_node(parent_path)
# else:
# parents[i] = null
# i += 1
if current and is_instance_valid(Bullets):
Bullets.mount(self)

Expand Down Expand Up @@ -64,6 +77,8 @@ func _get(property: String):
return bullet_kits[prop_index]
elif strings[1] == "pool_size":
return pools_sizes[prop_index]
elif strings[1] == "parent_hint":
return parents_hints[prop_index]
elif strings[1] == "z_index":
return z_indices[prop_index]
return null
Expand All @@ -73,6 +88,7 @@ func _set(property: String, value):
if property == "bullet_types_amount":
bullet_kits.resize(value)
pools_sizes.resize(value)
parents_hints.resize(value)
z_indices.resize(value)
property_list_changed_notify()
return true
Expand All @@ -88,6 +104,9 @@ func _set(property: String, value):
elif strings[1] == "pool_size":
pools_sizes[prop_index] = value
return true
elif strings[1] == "parent_hint":
parents_hints[prop_index] = value
return true
elif strings[1] == "z_index":
z_indices[prop_index] = value
return true
Expand Down Expand Up @@ -122,6 +141,12 @@ func _get_property_list():
"hint": PROPERTY_HINT_RANGE,
"hint_string": "1,65536"
})
properties.append({
"name": "bullet_type_{0}/parent_hint".format(format_array),
"type": TYPE_NODE_PATH,
"usage": PROPERTY_USAGE_DEFAULT,
"hint": PROPERTY_HINT_NONE
})
properties.append({
"name": "bullet_type_{0}/z_index".format(format_array),
"type": TYPE_INT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func can_handle(object):


func parse_property(object, type, path, hint, hint_text, usage):
if path == "bullet_kits" or path == "pools_sizes" or path == "z_indices":
if path == "bullet_kits" or path == "pools_sizes" or path == "parents_hints" or path == "z_indices":
return true

var result = properties_regex.search(path)
Expand Down
2 changes: 1 addition & 1 deletion addons/native_bullets/plugin.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
name="Native Bullets"
description="Efficiently spawn and move high amounts of objects like bullets for bullet hells, particles and more."
author="Samuele Zolfanelli"
version="1.1.2"
version="1.2"
script="plugin.gd"
29 changes: 28 additions & 1 deletion addons/native_bullets/src/bullets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ void Bullets::mount(Node* bullets_environment) {

Array bullet_kits = bullets_environment->get("bullet_kits");
Array pools_sizes = bullets_environment->get("pools_sizes");
Array parents_paths = bullets_environment->get("parents_hints");
Array z_indices = bullets_environment->get("z_indices");

pool_sets.clear();
Expand All @@ -122,6 +123,9 @@ void Bullets::mount(Node* bullets_environment) {
active_bullets = 0;

Dictionary collision_layers_masks_to_kits;

Viewport* default_viewport = bullets_environment->get_viewport();
RID default_parent_canvas = default_viewport->find_world_2d()->get_canvas();

for(int32_t i = 0; i < bullet_kits.size(); i++) {
Ref<BulletKit> kit = bullet_kits[i];
Expand Down Expand Up @@ -180,12 +184,35 @@ void Bullets::mount(Node* bullets_environment) {
int32_t kit_index_in_node = bullet_kits.find(kit);
int32_t pool_size = pools_sizes[kit_index_in_node];

Node* parent_node_hint = nullptr;
//RID actual_parent_canvas = default_parent_canvas;

NodePath parent_path = parents_paths[0];//[kit_index_in_node];
Godot::print("Parent hint path is {0}", parent_path);
if (!parent_path.is_empty()) {
Godot::print("Parent hint path is not empty");
parent_node_hint = bullets_environment->get_node(parent_path);
Godot::print("Viewport node is {0}", parent_node_hint);
// if (viewport_node != nullptr) {
// actual_viewport = viewport_node;
// CanvasItem* parent_canvas = Object::cast_to<CanvasItem>(parent_node);
// if (parent_canvas != nullptr) {
// actual_parent_canvas = parent_canvas->get_canvas_item();
// } else {
// actual_parent_canvas = actual_viewport->find_world_2d()->get_canvas();
// }
// }
}
if (parent_node_hint == nullptr) {
parent_node_hint = bullets_environment;
}

pool_sets[i].pools[j].pool = kit->_create_pool();
pool_sets[i].pools[j].bullet_kit = kit;
pool_sets[i].pools[j].size = pool_size;
pool_sets[i].pools[j].z_index = z_indices[kit_index_in_node];

pool_sets[i].pools[j].pool->_init(this, shared_area, pool_set_available_bullets,
pool_sets[i].pools[j].pool->_init(/*actual_parent_canvas, */parent_node_hint, shared_area, pool_set_available_bullets,
i, kit, pool_size, z_indices[kit_index_in_node]);

pool_set_available_bullets += pool_size;
Expand Down
9 changes: 6 additions & 3 deletions addons/native_bullets/src/bullets_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define BULLETS_POOL_H

#include <Godot.hpp>
#include <CanvasLayer.hpp>
#include <CanvasItem.hpp>
#include <AtlasTexture.hpp>
#include <Material.hpp>
Expand All @@ -22,7 +23,9 @@ class BulletsPool {
int32_t bullets_to_handle = 0;
bool collisions_enabled;

CanvasItem* canvas_parent;
CanvasLayer* canvas_layer;
Viewport* viewport;
RID canvas_parent;
RID canvas_item;
RID shared_area;
int32_t starting_shape_index;
Expand All @@ -43,7 +46,7 @@ class BulletsPool {
BulletsPool();
virtual ~BulletsPool();

virtual void _init(CanvasItem* canvas_parent, RID shared_area, int32_t starting_shape_index,
virtual void _init(/*RID canvas_parent, Viewport* viewport, */Node* parent_hint, RID shared_area, int32_t starting_shape_index,
int32_t set_index, Ref<BulletKit> kit, int32_t pool_size, int32_t z_index) = 0;

int32_t get_available_bullets();
Expand Down Expand Up @@ -81,7 +84,7 @@ class AbstractBulletsPool : public BulletsPool {
AbstractBulletsPool() {}
virtual ~AbstractBulletsPool();

virtual void _init(CanvasItem* canvas_parent, RID shared_area, int32_t starting_shape_index,
virtual void _init(/*RID canvas_parent, Viewport* viewport, */Node* parent_hint, RID shared_area, int32_t starting_shape_index,
int32_t set_index, Ref<BulletKit> kit, int32_t pool_size, int32_t z_index) override;

virtual int32_t _process(float delta) override;
Expand Down
42 changes: 38 additions & 4 deletions addons/native_bullets/src/bullets_pool.inl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <Godot.hpp>
#include <VisualServer.hpp>
#include <World2D.hpp>
#include <Physics2DServer.hpp>
#include <Viewport.hpp>
#include <Font.hpp>
Expand Down Expand Up @@ -59,28 +60,49 @@ AbstractBulletsPool<Kit, BulletType>::~AbstractBulletsPool() {
}

template <class Kit, class BulletType>
void AbstractBulletsPool<Kit, BulletType>::_init(CanvasItem* canvas_parent, RID shared_area, int32_t starting_shape_index,
void AbstractBulletsPool<Kit, BulletType>::_init(Node* parent_hint, RID shared_area, int32_t starting_shape_index,
int32_t set_index, Ref<BulletKit> kit, int32_t pool_size, int32_t z_index) {

// Check if collisions are enabled and if layer or mask are != 0,
// otherwise the bullets would not collide with anything anyways.
this->collisions_enabled = kit->collisions_enabled && kit->collision_shape.is_valid() &&
((int64_t)kit->collision_layer + (int64_t)kit->collision_mask) != 0;
this->canvas_parent = canvas_parent;
// this->viewport = viewport;
this->shared_area = shared_area;
this->starting_shape_index = starting_shape_index;
this->kit = kit;
this->pool_size = pool_size;
this->set_index = set_index;

this->viewport = nullptr;
this->canvas_layer = nullptr;

Node* n = parent_hint;
while (n) {
if (!this->canvas_layer) {
this->canvas_layer = Object::cast_to<CanvasLayer>(n);
}
this->viewport = Object::cast_to<Viewport>(n);
if (this->viewport) {
break;
}

n = n->get_parent();
}
if (this->canvas_layer) {
this->canvas_parent = canvas_layer->get_canvas();
} else {
this->canvas_parent = viewport->find_world_2d()->get_canvas();
}

available_bullets = pool_size;
active_bullets = 0;

bullets = new BulletType*[pool_size];
shapes_to_indices = new int32_t[pool_size];

canvas_item = VisualServer::get_singleton()->canvas_item_create();
VisualServer::get_singleton()->canvas_item_set_parent(canvas_item, canvas_parent->get_canvas_item());
VisualServer::get_singleton()->canvas_item_set_parent(canvas_item, canvas_parent);
VisualServer::get_singleton()->canvas_item_set_z_index(canvas_item, z_index);

for(int32_t i = 0; i < pool_size; i++) {
Expand Down Expand Up @@ -125,7 +147,19 @@ void AbstractBulletsPool<Kit, BulletType>::_init(CanvasItem* canvas_parent, RID
template <class Kit, class BulletType>
int32_t AbstractBulletsPool<Kit, BulletType>::_process(float delta) {
if(kit->use_viewport_as_active_rect) {
active_rect = canvas_parent->get_viewport()->get_visible_rect();
Rect2 viewport_rect = viewport->get_visible_rect();
Transform2D viewport_inv_transform = canvas_layer ? canvas_layer->get_transform().affine_inverse() : viewport->get_canvas_transform().affine_inverse();
Vector2 top_left_point = viewport_inv_transform.xform(Vector2::ZERO);
Vector2 top_right_point = viewport_inv_transform.xform(Vector2(viewport_rect.size.x, 0));
Vector2 bot_right_point = viewport_inv_transform.xform(viewport_rect.size);
Vector2 bot_left_point = viewport_inv_transform.xform(Vector2(0, viewport_rect.size.y));

Vector2 origin = Vector2(Math::min(top_left_point.x, Math::min(top_right_point.x, Math::min(bot_right_point.x, bot_left_point.x))),
Math::min(top_left_point.y, Math::min(top_right_point.y, Math::min(bot_right_point.y, bot_left_point.y))));
Vector2 edge = Vector2(Math::max(top_left_point.x, Math::max(top_right_point.x, Math::max(bot_right_point.x, bot_left_point.x))),
Math::max(top_left_point.y, Math::max(top_right_point.y, Math::max(bot_right_point.y, bot_left_point.y))));

active_rect = Rect2(origin, edge - origin);
} else {
active_rect = kit->active_rect;
}
Expand Down
2 changes: 2 additions & 0 deletions examples/example_01.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,12 @@ __meta__ = {
script = ExtResource( 3 )
bullet_kits = [ ExtResource( 2 ) ]
pools_sizes = [ 3000 ]
parents_hints = [ null ]
z_indices = [ 1 ]
bullet_types_amount = 1
bullet_type_0/bullet_kit = ExtResource( 2 )
bullet_type_0/pool_size = 3000
bullet_type_0/parent_hint = null
bullet_type_0/z_index = 1

[node name="UI" type="CanvasLayer" parent="."]
Expand Down
5 changes: 2 additions & 3 deletions examples/example_02.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ _data = [ Vector2( 0, -4 ), 0.0, 16.0773, 0, 1, Vector2( 0.497596, 4 ), 16.0773,
[node name="Example01" type="CenterContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false
}

[node name="Center" type="Control" parent="."]
margin_left = 512.0
Expand Down Expand Up @@ -131,10 +128,12 @@ bullets_active_rect_grow = 20.0
script = ExtResource( 3 )
bullet_kits = [ ExtResource( 4 ) ]
pools_sizes = [ 3000 ]
parents_hints = [ null ]
z_indices = [ 1 ]
bullet_types_amount = 1
bullet_type_0/bullet_kit = ExtResource( 4 )
bullet_type_0/pool_size = 3000
bullet_type_0/parent_hint = null
bullet_type_0/z_index = 1

[node name="UI" type="CanvasLayer" parent="."]
Expand Down

0 comments on commit 474eb66

Please sign in to comment.