1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-29 10:35:23 +00:00
1 ECS: Development Guide
gravestench edited this page 2020-12-15 22:18:06 -08:00

This page is still WIP!

About

This page serves as a rubric for development on our ECS branch. Be aware that as the ECS branch is under active development, the information on this page may be out of date or in need of revision.

What is ECS?

ECS is an architectural pattern, you can read about it on wikipedia.

Why do we want ECS in OpenDiablo2?

As of writing, much of our engine code is tightly coupled. It makes writing tests or re-using code fairly difficult. An ECS implementation will resolve this issue because systems in an ECS architecture are decoupled via the components they use.

What ECS framework are we using?

We have developed our own called Akara.

Please read the akara README for the most up-to-date info regarding basic usage.

Development Guide

Everything in this section needs to be adhered to. PR's will not be merged if they violate anything described herein.

Systems will contain a d2util.Logger and a unique logger prefix

const (
	logPrefixExample = "Example System"
)

type ExampleSystem struct {
	akara.BaseSystem
	*d2util.Logger
}

func (u *ExampleSystem) Init(world *akara.World) {
	u.World = world

	u.setupLogger()

	if u.World == nil {
		u.SetActive(false)
	}

	u.Debug("initializing")
}

func (u *ExampleSystem) setupLogger() {
	u.Logger = d2util.NewLogger()
	u.SetPrefix(logPrefixExample)
}

Graphical systems must be implemented as a Scene system

Please read about scene systems here.

Every component should also declare a concrete component factory

This is important because it reduces noise in our code by keeping us from constantly casting akara.Component to the concrete component implementation.

here is an example Color component:

// Color is a flag component that is used to denote a "dirty" state
type Color struct {
	color.Color
}

// New creates a new Color. By default, IsColor is false.
func (*Color) New() akara.Component {
	return &Color{
		color.Transparent,
	}
}

And here is the concrete component factory for this component

// ColorFactory is a wrapper for the generic component factory that returns Color component instances.
// This can be embedded inside of a system to give them the methods for adding, retrieving, and removing a Color.
type ColorFactory struct {
	*akara.ComponentFactory
}

// Add adds a Color component to the given entity and returns it
func (m *ColorFactory) Add(id akara.EID) *Color {
	return m.ComponentFactory.Add(id).(*Color)
}

// Get returns the Color component for the given entity, and a bool for whether or not it exists
func (m *ColorFactory) Get(id akara.EID) (*Color, bool) {
	component, found := m.ComponentFactory.Get(id)
	if !found {
		return nil, found
	}

	return component.(*Color), found
}

File locations

At the time of writing:

  • all systems belong in d2core/d2systems/
  • all components and component factories belong in d2core/d2components/