GithubHelp home page GithubHelp logo

octod / godot-gameplay-systems Goto Github PK

View Code? Open in Web Editor NEW
429.0 13.0 41.0 4.7 MB

⚔️ A plugin for Godot to create your gameplay systems in a Godot way.

License: MIT License

GDScript 100.00%
godot godot-engine godot-editor gameplay attributes rpg godot-addon gameplay-attributes

godot-gameplay-systems's Introduction

Warning

A full rewrite is going on (using gdextension). Some old api will change and be aware that all hard references (like extends res://) in your custom classes will stop working with the approach of 1.0.0

⚔️ GGS ⚔️

Godot Gameplay Systems (formerly godot gameplay attributes) is a set of nodes and resources which speed up development your gameplay systems.

Install

Clone this repo, copy the addons folder content inside your project's addons directory.

Enable this plugin by going to project settings/plugins.

Important: reload the project after activating the plugin

Enjoy!

How does it work?

You can check some tutorials/doc/examples here

I am making also small "demos" to demonstrate how things work. You can check them out opening this repository using godot 4.x (stable), pressing the play button and choosing one.

Esc key will always return you to the main menu.

Networking and multiplayer

Did not test too much, but abilities, effects and attributes could be replicated using the MultiplayerSynchronizer node provided by godot4.x.

The same should apply to Inventory and Equipment.

Contribution

Every contribution is really welcome, feel free to contribute!

You can open PR, issues or you can suggest features. Have a good day you wonderful Godot people!

Licence

MIT licence

godot-gameplay-systems's People

Contributors

andreaterenz avatar danielbernard avatar mark-rafter avatar octod avatar sergwest585 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

godot-gameplay-systems's Issues

Comments and actual code is different

## Return [code]true[/code] if the ability can be ended, [code]false[/code] otherwise.
## [br]Always return: [code]true[/code] if [member Ability.tags_end_blocking] is empty.
func can_end(activation_event: ActivationEvent) -> bool:
if tags_end_blocking.size() > 0:
return has_all_tags(tags_end_blocking, activation_event.tags)
return false

Comments says Always return: true if Ability.tags_end_blocking is empty, but this function returns false.
can_cancel, can_block return false too.

Is comment wrong or code wrong?

PS. this wonderful library saved my life. thx! XP

🐛 [bug] Interactions doesn't work in Sot-like example

Describe the bug
Can't interact with anything in Sot-like example.

To Reproduce
Steps to reproduce the behavior:

  1. Go to sot_game.tscn
  2. Run the scene
  3. Try to interact with Crate or Sails (using F button)

Expected behavior
Crate is dragged using Interact button.

Desktop (please complete the following information):

  • OS: Windows 10
  • Godot version 4.2.2

Additional context
Just cloned repo and tried to test interaction system in the Sot-like example, I really like this project and willing to learn how's everything implemented!

🐛 [bug] Ability Container fails to initialize if preloaded with multiple Abilities

Description

AbilityContainer removes entries during initialization while granting, causing it to lose abilities.

To Reproduce

Create an AbilityContainer, add multiple Ability entries in the editor, run the scene and observe what abilities remain in the abilities Array.

Details

I added a few unique abilities to an Ability Container manually in the editor, and upon running, I was receiving index errors.
Out of bounds get index '2' (on base: 'Array[Ability]')
I observed two possible issues in the code:

First, this section of the _ready function

for i in abilities.size():
var ability = abilities[i - 1]
grant(ability)

the for i in abilities.size() will return [0 ... n] rather than [1 ... n], so there's no need to subtract 1. This leads to accessing the last element of the array first.
Removing the -1 or replacing this with the following should let it process in order.:

 for ability in abilities:
 	grant(ability) 

Note that replacing the index iteration with objects allows the code to execute without errors, but the ability array is still missing entries even if the array changes shape (as occurs in the grant function).

Digging into the indexing error, I found that you get odd behavior when the grant(ability) call is performed; since it will remove the first instance of an ability in the AbilityContainer, it removes the entry currently being granted. This causes the original array shape to change, and the loop in the _ready function to get confused and skip entries.

# Removes from abilities array if it's there. This avoids duplication which could lead to bugs.
var ability_index = abilities.find(ability)
if ability_index >= 0:
abilities.remove_at(ability_index)

🐛 [bug] Resurrect in the demo fires a fireball

Describe the bug
Pressing the R button for resurrect also fires a fireball in the demo

To Reproduce
Steps to reproduce the behavior:

  1. Open the project
  2. Run the project
  3. Grab the fireball
  4. Die somehow
  5. Press R to resurrect
  6. Keep pressing R, notice the debug messages

Expected behavior
Abilities shouldn't activate each other

Screenshots
No screenshot needed.

Desktop (please complete the following information):

  • OS: Windows 11
  • Godot version : 4.0.2

Additional context
100% reproducable

🐛 [bug] Pickable_item_3d can not add if inventory is assigned to collider node(player)

Describe the bug
Player has Inventory and Equipment. Added Pickable_Area_3d with item and auto_pickup. When player collides the following error is thrown:

Invalid type in function 'can_add' in base 'Node (Inventory)'. The Object-derived class of argument 1 (Node (Inventory)) is not a subclass of the expected argument class.

This appears to happen because in lines 53-56 as shown below, it's passing the 'by' node to it's self, which fails as inventory.can_add() is expecting the argument to be of type Item:

func pick(by: Node) -> void:
	assert(item != null, "item should not be null")

	if by is Inventory:
		if by.can_add(by):
			by.add_item(by)
			queue_free()
	elif by is Equipment:
		## Adds tags because it "picked" the item.
		by.add_tags(item.tags_added_on_add)
func can_add(item: Item) -> bool:
	if item.tags_required_to_add.size() == 0:
		return true

	for tag in item.tags_required_to_add:
		if not tags.has(tag):
			return false

	return true

To Reproduce
Steps to reproduce the behavior:

  1. Open Doom-Like Demo player.
  2. Add Inventory to player.
  3. Play game and select Doom-Like Demo.
  4. Run over weapon, it should throw the reported error.

Expected behavior
Item gets added to the inventory.

Screenshots
N/A

Desktop (please complete the following information):

  • OS: WIN11
  • Godot version 4.0.3

Additional context
N/A

UE5-like advanced tag system.

Is your feature request related to a problem? Please describe.
Useful when filting items, players or effects, such you want to get all enemies that have buff, just query "buff", not "buff.a", "buff.b"...

Describe the solution you'd like
Define all tags as a tree, and each tag is a path in the tree, and tags always match their descendants tags.

Describe alternatives you've considered
Godot built-in group system, but it is more compatible with editor, and doesn't provide much useful features.

Additional context
UE5 gameplay system has a well-intergrated tag system, post here as a reference, https://docs.unrealengine.com/5.3/en-US/using-gameplay-tags-in-unreal-engine/.

🐛 [bug] GameplayAttributeMap Bugs

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

Add A GameplayAttributeMap
Look at the inspector for it.
You will see only Attributes Variable, and it uses the type Attribute Table LOL.
the attribute table doesn't show up.
also assigning attribute table resource to it, doesn't allow me to add a health or something (I following your tutorial).

I changed this section

## Is the array of Attribute resources generated by the inspector plugin.
@export var attributes: Array[AttributeResource] 

## Is the AttributeTable selected resource.
@export var table: AttributeTable 

To

## Is the array of Attribute resources generated by the inspector plugin.
@export var Attributes: Array[AttributeResource] 

## Is the AttributeTable selected resource.
@export var Table: AttributeTable 

and it show them seperately
image

but as seen it doesn't create a resource attribute manually, I need to do it myself :
image

Expected behavior
Working Out Of The Box, lol :)

Screenshots
image

Desktop (please complete the following information):

  • OS: Linux
  • Godot version 4.2.dev4

Additional context
N/A

🐛 [bug] plugin fail to load scripts and icons after 4.2 relocatability change

Describe the bug
Loading plugin from AssetLib fails to load on 4.2, indicating that load'ed scripts and files failed.

To Reproduce

  1. Create empty project
  2. Add GGS from AssetLib
  3. Enable plugin and relaunch editor or reload project
  4. See error:
  Attempt to open script 'res://./nodes/camera_shake.gd' resulted in error 'File not found'.
  Failed loading resource: res://./nodes/camera_shake.gd. Make sure resources have been imported by opening the project in the editor at least once.
  It's not a reference to a valid Script object.
  Attempt to open script 'res://./nodes/2d/point_and_click_2d.gd' resulted in error 'File not found'.
  Failed loading resource: res://./nodes/2d/point_and_click_2d.gd. Make sure resources have been imported by opening the project in the editor at least once.
  It's not a reference to a valid Script object.
  Attempt to open script 'res://./nodes/3d/point_and_click_3d.gd' resulted in error 'File not found'.
  Failed loading resource: res://./nodes/3d/point_and_click_3d.gd. Make sure resources have been imported by opening the project in the editor at least once.
  It's not a reference to a valid Script object.
  Attempt to open script 'res://./nodes/2d/interactable_area_2d.gd' resulted in error 'File not found'.
  Failed loading resource: res://./nodes/2d/interactable_area_2d.gd. Make sure resources have been imported by opening the project in the editor at least once.
  Resource file not found: res://./assets/InteractableArea2D.png (expected type: )
  It's not a reference to a valid Script object.
  Attempt to open script 'res://./nodes/3d/interactable_area_3d.gd' resulted in error 'File not found'.
  Failed loading resource: res://./nodes/3d/interactable_area_3d.gd. Make sure resources have been imported by opening the project in the editor at least once.
  Resource file not found: res://./assets/InteractableArea2D.png (expected type: )
  It's not a reference to a valid Script object.
  Attempt to open script 'res://./nodes/2d/interaction_raycast_2d.gd' resulted in error 'File not found'.
  Failed loading resource: res://./nodes/2d/interaction_raycast_2d.gd. Make sure resources have been imported by opening the project in the editor at least once.
  Resource file not found: res://./assets/InteractionRayCast2DIcon.png (expected type: )
  It's not a reference to a valid Script object.
  Attempt to open script 'res://./nodes/3d/interaction_raycast_3d.gd' resulted in error 'File not found'.
  Failed loading resource: res://./nodes/3d/interaction_raycast_3d.gd. Make sure resources have been imported by opening the project in the editor at least once.
  Resource file not found: res://./assets/InteractionRayCast3DIcon.png (expected type: )
  It's not a reference to a valid Script object.
  Attempt to open script 'res://./nodes/interaction_manager.gd' resulted in error 'File not found'.
  Failed loading resource: res://./nodes/interaction_manager.gd. Make sure resources have been imported by opening the project in the editor at least once.
  Resource file not found: res://./assets/InteractionIcon.png (expected type: )
  It's not a reference to a valid Script object.
  Attempt to open script 'res://./resources/interaction.gd' resulted in error 'File not found'.
  Failed loading resource: res://./resources/interaction.gd. Make sure resources have been imported by opening the project in the editor at least once.
  Resource file not found: res://./assets/InteractionIcon.png (expected type: )
  It's not a reference to a valid Script object.

Expected behavior
Plugin should load normally without error.

Desktop (please complete the following information):

  • OS: Windows 11
  • Godot version: 4.2 rc2

Reproducible project
Happens even on a clone of this repository

Proposed fix
I was able to remedy this by adjusting the load calls in the _enter_tree() functions within the plugin.gd files.
Addressed in subsequent pull request.

Multiple instances of the same Node share tags during activation [bug]

Describe the bug
While using GGS, I created a Scene for a enemy entity with a ShootBullet Ability. This requires two tags to start ('alive' and 'triple_shoot') and is blocked if the tag 'triple_shooting' is present, which is given on activation. This works fine when there's only 1 of these enemies, however when multiple are added to the scene, only one of them seems to performing the ability.
I noticed that the tag 'triple_shooting' is added to all entities of the same type when the Ability, instead of that specific entity. This happens within the AbilityContainer function "_handle_ability_activated".

Currently I wrote the following quick fix to avoid to add the tag to all instances by confronting who that tag is for. Probably it would be cool if the function gets called only on the target object.

immagine

Here's the ability configuration, for reference (in the chance I set something wrong):

immagine

Desktop:

  • OS: Windows 10
  • Godot version [e.g. 4.0.3]

🐛 [bug] 4.2 absolute path is no more

Describe the bug
In 4.2 devs can install an addon wherever they want, hence the absolute paths for loading scripts will be broken badly.

To Reproduce

  • Install 4.2
  • Add the addon on a directory different from addons
  • Boom

Expected behavior
Installing the addon in a specific folder should not break everything.

Additional context
Sigh

🐛 [bug]

Describe the bug
User cannot use the has_tag function from an Ability Container because ability_container.gd doesn't have that function. It throws a runtime error when attempting to use it.

To Reproduce

  1. Add an Ability Container to a CharacterBody2D or CharacterBody3D.
  2. Add some tags to the Ability Container.
  3. Open the script attached to the character.
  4. Take a reference from the ability container: @onready var ability_container: AbilityContainer = $AbilityContainer
  5. Try to use the function has_tag from the Ability Container --> if not ability_container.has_tag("dead"):

Expected behavior
The has_tag function should return true or false if the tag is contained in the tags of the specified Ability in the Ability Container.

Screenshots
image

image

Desktop (please complete the following information):

  • OS: Windows 11
  • Godot 4.0.2

Additional context
Thank you for developing the addon :)
I found this issue following the tutorial. I don't know if the has_tag function should be added to the ability_container.gd file or if I should use the has_some_tags function from ability.gd.

🐛 [bug] The attribute of "Gameplayattributemap"

Describe the bug
I read the document and it said:

This node accepts an AttributeTable resource as value. This resource specifies which attributes the entity has.
Next is:

Once specified a table, the inspector will show you these attributes, where you can set a:

minimum value: which usually is zero
maximum value: if you set it to zero, there will be not a maximum
current value: the starting value for the entity

But in fact, I found that "Attributes" has "Minimum Value" entries. Is this a document error?

Godot4.1.1 Stable.

Multiplayer Support

Is your feature request related to a problem? Please describe.
Multiplayer Support Out Of The Box

Describe the solution you'd like
I am going to add this awesome system (thank you for it) to my multiplayer game.
so I am going to add multiplayer system to it.
I am offering to do a PR after I finish the integeration in my game.

in my game I always pack my Nodes that needs to be synced in a Seperate Scene, and add Multiplayer Sync to it, and choose properties that needs to be synced.

or we can use RPC beside its code (I would like to avoid that to not bloat the code for non multiplayer users)

Describe alternatives you've considered
Maybe I just document my way of getting it for multiplayer and add it to the WIKI, instead of having it built-in.

Additional context
N/A

🐛 [bug] Ability Container Array[Ability] Order is Reversed

Describe the bug
When creating new abilities and putting them into the Ability Container's Ability Array, the resulting order seems to be reversed. The UI below indicates an array with the following order:

  1. "Regenerate"
  2. "Sacrifice"
  3. Ability with ui_name "fake_pos2"
  4. Ability with ui_name "fake_pos3".

The latter two abilities are dummies which have ui_names indicating the expected position in the array. You can see this ordering reflecting in the following screenshot.

Screenshot 2023-12-17 at 3 08 22 PM

However, when I attempt to active Regenerate using the following code

var ability = ability_container.granted_abilities[0]
ability_container.activate_one(ability)

it instead activates the "fake_pos3" ability (or it would if it weren't a placeholder). When we print the array using the following code:

for idx in len(ability_container.granted_abilities):
	print(idx,ability_container.granted_abilities[idx].ui_name)

We would expect to see the index printed along the ability ui_name associated with the index. Instead we see the following screenshot:

Screenshot 2023-12-17 at 3 08 31 PM

In the screenshot, the order is reversed relative to the expectation.

To Reproduce
Steps to reproduce the behavior:

  1. Initialize a character and add a GameplayAttributes with a GameplayEffect as its child. Also add an AbilityContainer. My tree looks like this:
Screenshot 2023-12-17 at 3 09 25 PM 2. Add at least two Abilities to the AbilityContainer. I chose to add 4 to verify the behavior. 3. Attach a script to the player and retrieve the AbilityContainer and AttributeMap. 4. In the script, identify the contents of the AbilityContainer's granted_abilities[Ability] array. I used the following code: ```

func _input(event):
if event.is_action_pressed("ability_q"):
for idx in len(ability_container.granted_abilities):
print(idx,ability_container.granted_abilities[idx].ui_name)

In my case, this yields output of 
0Fake_pos3
1fake_pos2
2Sacrifice
3Regenerate


**Expected behavior**
I would expect the output instead to be:
0Regenerate
1Sacrifice
2fake_pos2
3Fake_pos3

**Screenshots**
Included inline

**Desktop (please complete the following information):**
 - OS: MacOS Sonoma 14.1
 - Godot version 4.1.3

**Additional context**
I've found a fairly simple fix for my case. In ability_container.gd, add `granted_abilities.reverse()` to the function after granting the abilities, i.e.

func _ready() -> void:
gameplay_attribute_map = get_node(gameplay_attribute_map_path)
grant_all_abilities()
granted_abilities.reverse()


However, this may not fix the issue when abilities are appended to the array as a part of the game, i.e. not a runtime. I suspect the issue lies in grant() or in grant_all_abilities(), but I'm still a bit new to Godot and am not 100% sure where the issue is arising. My best guess is that in grant_all_abilities(), when iterating through the abilities it grants them in reverse order because cursor is set to -1. When I add print statements to the function

```func grant_all_abilities() -> int:
	var granted = 0
	var cursor = -1

	for i in abilities.size():

		var ability = abilities[cursor]
		for ab in abilities:
			print(ab.ui_name)
		print(i,cursor,ability.ui_name)
		if grant(ability):
			granted += 1
		else:
			cursor -= 1

	return granted

It yields the following:

Regenerate
Sacrifice
fake_pos2
Fake_pos3
0-1Fake_pos3
Regenerate
Sacrifice
fake_pos2
1-1fake_pos2
Regenerate
Sacrifice
2-1Sacrifice
Regenerate
3-1Regenerate

It seems to grant from the back of the abilities array first when granting, making it so Regenerate is added last despite being listed first. It might be that iterating in a different way would correct the ordering, but it may be that you have a reason for iterating in this way and I'm still new enough to Godot that I'm unsure the proper way.

Reproducible project
Here's the link to my project. The relevant files are archetype_base.gd in the root directory and the ability_container.gd script found in the addons folder.

🐛 [bug]EquippedItem3D tags_to_be_displayed not being used?

Describe the bug
I don't believe that tags_to_be_displayed is in use. Or at least I'm not certain how it's being used. I've checked the Doom demo, it had right.hand but I don't see any tags on the SMG or Shotgun that resemble right.hand and I don't see them in code anywhere.

To Reproduce
Add tag to EquippedItem3D and equip-item, should still equip.

Expected behavior
If the tags do not match it should not show the item.

Screenshots
N/A

Desktop (please complete the following information):

  • OS: Win11
  • Godot version 4.0.3

Additional context
I've added the following to the lambda function(I think thats what they're called):

From:

	equipment.equipped.connect(func (item: Item, _slot: EquipmentSlot):
		if item.scene and item.scene.can_instantiate():
			current = item.scene.instantiate()
			add_child(current)
	)

To:

	equipment.equipped.connect(func (item: Item, _slot: EquipmentSlot):
		if item.scene and item.scene.can_instantiate():
			if item.tags.has(tags_to_display[0]):
				current = item.scene.instantiate()
				add_child(current)
	)

My above check does work, but it's very specific to the first tag for my testing so it should probably be written differently to check all the tags and make sure they match or a grouping of them or something more modular/intelligent than my hard coded first entry of the tags_to_display array.

🐛 [bug] Installation is not working as expected

Describe the bug
The installation process you mention on the README doesn't work as expected due to folder organization

To Reproduce
Steps to reproduce the behavior:

  1. Clone the repository in your addons folder
  2. Try to enable it

Expected behavior
I'd like to clone the repository inside the folder and be able to enable the plugin without errors

Screenshots
image

This is gonna fail because if you clone the repo on your addons your path is the following:
addons\godot_gameplay_systems\addons\godot_gameplay_systems

I can create a fork and change this but I think is worth to mention since it's not a big change and it's blocking the usage of the plugin in a straight-forward way.

Desktop (please complete the following information):

  • OS: Windows 11
  • Godot version: 4.0.2

Additional context
Thanks for your time!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.