ecs

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 13, 2020 License: MIT Imports: 1 Imported by: 0

README

GoEcs

An implementation of the ECS paradigm in Go.

Usage

package main

import (
	"fmt"

	ecs "github.com/x-hgg-x/goecs"
)

func main() {
	// List of component data types
	type Shape struct{ shape string }
	type Color struct{ color string }
	type Name struct{ name string }

	// Structure for storing components
	components := struct {
		Shape *ecs.Component
		Color *ecs.Component
		Name  *ecs.Component
		Value *ecs.Component
	}{}

	// Initialize a new manager
	manager := ecs.NewManager()

	// Create components
	components.Shape = manager.NewComponent()
	components.Color = manager.NewComponent()
	components.Name = manager.NewComponent()
	components.Value = manager.NewComponent()

	// Create entities
	manager.NewEntity().AddComponent(components.Shape, &Shape{"square"}).AddComponent(components.Color, &Color{"red"})
	manager.NewEntity().AddComponent(components.Shape, &Shape{"circle"}).AddComponent(components.Name, &Name{"tom"})
	manager.NewEntity().AddComponent(components.Color, &Color{"blue"}).AddComponent(components.Name, &Name{"john"})

	manager.NewEntity().
		AddComponent(components.Shape, &Shape{"triangle"}).
		AddComponent(components.Color, &Color{"green"}).
		AddComponent(components.Name, &Name{"paul"})

	// Loop on entities which have specified components
	// The Join() method gives a bit.Set tag containing integers which can be converted to entities,
	// and we use the bit.Set.Visit() method to loop through the set.
	// The decorator ecs.Visit() is used when we want to iterate through all elements of the set.
	// It converts each set element to an entity.
	manager.Join(components.Shape, components.Name).Visit(ecs.Visit(func(entity ecs.Entity) {
		shape := components.Shape.Get(entity).(*Shape)
		name := components.Name.Get(entity).(*Name)
		fmt.Printf("Entity has the shape '%s' and the name '%s'\n", shape.shape, name.name)
	}))
	fmt.Println()

	// If we want to break the loop when some condition is met, we use the Visit() method directly
	aborted := manager.Join(components.Shape).Visit(func(index int) (skip bool) {
		shape := components.Shape.Get(ecs.Entity(index)).(*Shape)
		fmt.Printf("Entity has the shape '%s'\n", shape.shape)
		if shape.shape == "circle" {
			shape.shape = "CIRCLE"
			fmt.Printf("Entity has now the shape '%s'\n", shape.shape)
			return true
		}
		return false
	})
	fmt.Printf("Loop aborted: %v\n\n", aborted)

	// The helper function ecs.GetFirst() is useful if we want only the first entity matching a tag
	if firstEntity := ecs.GetFirst(manager.Join(components.Shape, components.Color, components.Name)); firstEntity != nil {
		shape := components.Shape.Get(*firstEntity).(*Shape)
		color := components.Color.Get(*firstEntity).(*Color)
		name := components.Name.Get(*firstEntity).(*Name)
		fmt.Printf("First matching entity has the shape '%s', the color '%s' and the name '%s'\n", shape.shape, color.color, name.name)
	}
	fmt.Println()

	// The Not() method is used when we want to exclude a particular component
	manager.Join(components.Shape.Not()).Visit(ecs.Visit(func(entity ecs.Entity) {
		fmt.Printf("Entity components: ")
		if entity.HasComponent(components.Color) {
			fmt.Printf("Color: '%s', ", components.Color.Get(entity).(*Color).color)
		}
		if entity.HasComponent(components.Name) {
			fmt.Printf("Name: '%s'", components.Name.Get(entity).(*Name).name)
		}
		fmt.Println()
	}))
	fmt.Println()

	// To iterate through all entities with at least one component, we use the Join() method without any argument
	manager.Join().Visit(ecs.Visit(func(entity ecs.Entity) {
		fmt.Printf("Entity components: ")
		if entity.HasComponent(components.Shape) {
			fmt.Printf("Shape: '%s', ", components.Shape.Get(entity).(*Shape).shape)
		}
		if entity.HasComponent(components.Color) {
			fmt.Printf("Color: '%s', ", components.Color.Get(entity).(*Color).color)
		}
		if entity.HasComponent(components.Name) {
			fmt.Printf("Name: '%s'", components.Name.Get(entity).(*Name).name)
		}
		fmt.Println()
	}))
	fmt.Println()

	// If the component data is not a pointer, we can use the Set() method to change its value
	manager.NewEntity().AddComponent(components.Value, 3)
	firstEntity := *ecs.GetFirst(manager.Join(components.Value))
	fmt.Println("Old value:", components.Value.Get(firstEntity).(int))
	components.Value.Set(firstEntity, 4)
	fmt.Println("New value:", components.Value.Get(firstEntity).(int))
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Visit

func Visit(f func(entity Entity)) func(index int) bool

Visit is a decorator function for bit.Set.Visit() method

Types

type AntiComponent

type AntiComponent struct {
	// contains filtered or unexported fields
}

AntiComponent is an inverted component used for filtering entities that don't have a component

type Component

type Component struct {
	// contains filtered or unexported fields
}

Component is a data storage

func (*Component) Get

func (c *Component) Get(entity Entity) interface{}

Get returns data corresponding to entity

func (*Component) Not

func (c *Component) Not() *AntiComponent

Not returns an inverted component used for filtering entities that don't have the component

func (*Component) Set

func (c *Component) Set(entity Entity, data interface{})

Set sets data corresponding to entity, or does nothing if the entity does not have the component

type Entity

type Entity int

Entity is an index

func GetFirst

func GetFirst(tag *bit.Set) *Entity

GetFirst returns a reference to the first entity matching a tag or nil if there are none

func (Entity) AddComponent

func (entity Entity) AddComponent(component *Component, data interface{}) Entity

AddComponent adds entity for component

func (Entity) HasComponent

func (entity Entity) HasComponent(component *Component) bool

HasComponent checks if component has entity

func (Entity) RemoveComponent

func (entity Entity) RemoveComponent(component *Component) Entity

RemoveComponent removes entity for component

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager manages components and entities

func NewManager added in v1.1.0

func NewManager() *Manager

NewManager creates a new manager

func (*Manager) DeleteAllEntities

func (manager *Manager) DeleteAllEntities()

DeleteAllEntities removes all entities for all components and reset current entity index

func (*Manager) DeleteEntities

func (manager *Manager) DeleteEntities(entities ...Entity)

DeleteEntities removes entities for all associated components

func (*Manager) DeleteEntity

func (manager *Manager) DeleteEntity(entity Entity)

DeleteEntity removes entity for all associated components

func (*Manager) Join

func (manager *Manager) Join(components ...component) *bit.Set

Join returns tag describing intersection of components

func (*Manager) NewComponent

func (manager *Manager) NewComponent() *Component

NewComponent creates a new component

func (*Manager) NewEntity

func (manager *Manager) NewEntity() Entity

NewEntity creates a new entity

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL