Skip to content

Swift experiment with composition based components.

License

apparata/Componentized

Repository files navigation

Componentized

An experimental Swift framework for implementing component-based architecture in your applications. Componentized provides a simple yet powerful way to add, retrieve, and manage components on any object that conforms to the ComponentBased protocol.

Features

  • Type-safe component storage: Store and retrieve components using Swift's type system
  • Qualified components: Support for multiple components of the same type using qualifiers
  • Protocol-based design: Clean separation of concerns through the ComponentBased protocol
  • Cross-platform support: Works on iOS 16+, macOS 14+, tvOS 16+, and visionOS 1+
  • Zero dependencies: Lightweight framework with no external dependencies

Usage

Basic Implementation

To use Componentized, make your class conform to the ComponentBased protocol:

import Componentized

class GameObject: ComponentBased {
    let componentStore = ComponentStore()
}

Adding Components

Add components to your object:

let gameObject = GameObject()

// Add a simple component
gameObject.componentStore.addComponent(HealthComponent(health: 100))

// Add components with qualifiers to distinguish between similar types
gameObject.componentStore.addComponent("Primary Weapon", qualifier: "weapon1")
gameObject.componentStore.addComponent("Secondary Weapon", qualifier: "weapon2")

Retrieving Components

Retrieve components using the convenient methods provided by the ComponentBased protocol:

// Get an optional component
if let health: HealthComponent = gameObject.component() {
    print("Current health: \(health.value)")
}

// Get a component with explicit type
let health = gameObject.component(HealthComponent.self)

// Get a component with qualifier
let primaryWeapon: String? = gameObject.component(qualifier: "weapon1")

// Get a required component (crashes if not found)
let requiredHealth: HealthComponent = gameObject.requiredComponent()

Component Store Methods

The ComponentStore class provides the core functionality:

let store = ComponentStore()

// Adding components
store.addComponent(MyComponent())
store.addComponent(AnotherComponent(), qualifier: "special")

// Retrieving components
let component: MyComponent? = store.component()
let qualifiedComponent: AnotherComponent? = store.component(qualifier: "special")
let requiredComponent: MyComponent = store.requiredComponent()

Example

Here's a complete example of a game entity using the component system:

import Componentized

// Define your components
struct HealthComponent {
    var maxHealth: Int
    var currentHealth: Int
}

struct PositionComponent {
    var x: Float
    var y: Float
}

// Create a componentized entity
class GameEntity: ComponentBased {
    let componentStore = ComponentStore()
    
    init() {
        // Add initial components
        componentStore.addComponent(HealthComponent(maxHealth: 100, currentHealth: 100))
        componentStore.addComponent(PositionComponent(x: 0, y: 0))
    }
    
    func takeDamage(_ amount: Int) {
        guard var health: HealthComponent = component() else { return }
        health.currentHealth = max(0, health.currentHealth - amount)
        componentStore.addComponent(health) // Update the component
    }
    
    func move(to x: Float, y: Float) {
        var position: PositionComponent = requiredComponent()
        position.x = x
        position.y = y
        componentStore.addComponent(position) // Update the component
    }
}

// Usage
let entity = GameEntity()
entity.takeDamage(25)
entity.move(to: 10.0, y: 20.0)

if let health: HealthComponent = entity.component() {
    print("Entity health: \(health.currentHealth)/\(health.maxHealth)")
}

Requirements

  • iOS 16.0+
  • macOS 14.0+
  • tvOS 16.0+
  • visionOS 1.0+

License

See the LICENSE file for licensing information.

About

Swift experiment with composition based components.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages