GameplayKit - confusion in sending messages between components

I immerse myself in GameplayKit with Spritekit and from what I collect, you subclass GKEntity , and then start adding GKComponents to this object. An object will be more or less just a bag of components that fill some functions.

The part I'm confused with is the connection between the components. How do you keep them untied. For example, suppose I have a HealthComponent class, and I add this component to PlayerEntity and EnemyEntity . I also have a HealthBarComponent , but I want the health bar to appear above the player . When a player takes damage, this information must be updated in the HealthBarComponent .

So how to send this information? I see that in the documentation there is a class called GKComponentSystem . I am not 100% on how to use it.

Another question: when a player’s health reaches zero, he must recover until the enemy remains dead. When a player runs out of life, the game ends.

The health system for the enemy and the player will be approximately the same, but the events around death will be completely different for everyone. I don’t understand how to use the component system while preserving the unique behavior of each object.

some pseudo code will be big

+5
source share
3 answers

It seems that this infrastructure works slightly different than the others that I have seen, since these systems work only with one type of component, and not with objects with groups of component types.

In the GamePlay-Kit shell, you can either scroll and update your entities manually (which updates each entity component in turn), or create a class that inherits from GKComponentSystem. Then, when you update the system, it updates all the components that you added to it , if their class type matches the type that you initialized the system with

To deal with the problem of your bar, I would say by creating a HealthBarComponent , which during its update retrieves the HealthComponent from its owner object, reads the health value and displays each frame. But you only add a HealthBarComponent to your game object.

You can get the owner object from the component and vice versa (see GKComponent.entity and GKEntity.components ) so that you can update your health panel as follows:

 /*Note: I'm not an ios developer, this is pseudocode*/ HealthBarComponent.update(){ int healthValue = self.entity.components.get(HealthComponent).value; //Now render your health bar accordingly or hold onto this for later } 

To deal with the issue of player death, I would think that it would be best to have two different types of health components (PlayerHealth and EnemyHealth) with two different respective systems. This is or is one component of health, but two separate components of "Death." Yes, this seems superfluous, but it’s hard for me to think of a better way within this structure. In my experience, you either spend your time worrying about keeping everything completely untied and reusable, or you are building a game :)

+5
source

Components can access their objects through the self.entity property. From there, you can request other components to pass data through the entity componentForClass property:

 guard let moveComponent = entity?.componentForClass(MoveComponent.self) else { fatalError("A MovementComponent entity must have a MoveComponent") } 

In iOS Games by Tutorials , the book has an excellent tutorial on GameplayKit objects and components.

+3
source

Notifications are good for this kind of problem. There is no direct connection between objects at all, and it is very expandable if more than one object needs to be known (for example, your health component, a higher-level game object that determines the game, even an opponent / ally's AI can behave differently when health is low).

You may have a notification called playerHealthChanged, and your health bar component and other objects will be registered independently to respond to this event. (You probably need to tell the HealthComponent instance whether it should publish this notification, so only the player should publish - maybe it can use isKind (of :) on its essence, or just have a bool field to enable the publication, which is set to true for player instance).

I usually put all the definitions of notification names in one module so that any class can access them:

 let kPlayerHealthChangedNotification = Notification.Name("playerHealthChanged") 

Here's the way the component will post a notification (you can optionally pass an object other than self):

 NotificationCenter.default.post(name: kPlayerHealthChangedNotification, object:self) 

Then objects that take care of changes in the player’s health can be registered in the same way as in the initialization code - create a handler function, and then add yourself as an observer for notification:

 @objc func onPlayerHealthChanged(_ notification:Notification) { // do whatever is needed; notification.object // has the object from the post } // put this in a setup method - init or similar: NotificationCenter.default.addObserver(self, selector: #selector(onPlayerHealthChanged(_:)), name: kPlayerHealthChangedNotification object:nil) 

Here is the documentation: https://developer.apple.com/documentation/foundation/notifications

0
source

All Articles