GithubHelp home page GithubHelp logo

sedyh / mizu Goto Github PK

View Code? Open in Web Editor NEW
81.0 1.0 3.0 360 KB

Entity Component System framework for Ebitengine

License: Other

Go 100.00%
engine game-engine game-development entity-component-system ecs ebiten go golang gamedev ebitengine

mizu's Introduction

mizu Mizu

Mizu is Entity Component System framework for Ebitengine.

Mizu is based on ento, which is made by wfranczyk.

The name is short for Mizutaki, a japenese dish, where chicken pieces and vegetables stewed in a simple stock, and eaten with dipping sauce such as ponzu.

Contents

Features

  • Very low boilerplate in exchange for a certain amount of reflection.
  • Scene management.
  • Compile defined components and entities.

Examples

To check all examples, visit this page.

Installation

Mizu uses Go 1.20 at the current moment.

Getting the latest version reflection API:

go get -u github.com/sedyh/mizu

Getting the latest version generics API:

go get -u github.com/sedyh/mizu@experimental

Usage

Import this package

import "github.com/sedyh/mizu/pkg/engine"

Define components, attributes of your game objects.

// Position for any entity, if it needs
type Pos struct {
    X, Y float64 // Just a 2D point
}

// Velocity for any entity, if it needs
type Vel struct {
    L, M float64 // Also, 2D point
}

// Radius for any entity, if it needs
type Rad struct {
    Value float64 // Width value
}

Define entities, your game objects.

// Your game object
type Ball struct {
    Pos // Ball position
    Vel // Ball velocity
    Rad // Ball radius
}

Define systems, your game mechanics that will work for a specific set of components.

// You can go through all entities that have a certain set of 
// components specifying the requirements in the fields of the system
type Velocity struct {
    *Pos // Current entity position
    *Vel // Current entity velocity
}

// Apply velocity for each entity that has Pos and Vel
func (v *Velocity) Update(w engine.World) {
    // If they are registered components, they will not be nil
    v.Pos.X += v.Vel.L
    v.Pos.Y += v.Vel.M
}

// When you need many sets of components
// in one system, you can use the views
type Render struct {}

// Render one frame
func (r *Render) Draw(w engine.World, screen *ebiten.Image) {
    // But choose the right entities yourself
    view := w.View(Pos{}, Rad{})
    view.Each(func(entity engine.Entity) {
        var pos *Pos
        var rad *Rad
        entity.Get(&pos, &rad)
        
        ebitenutil.DrawRect(
            screen,
            pos.X-rad.Value/2, pos.Y-rad.Value/2,
            rad.Value, rad.Value,
            colornames.Aliceblue,
        )
    })
}

Define scenes, where will all this live.

type Game struct{}

// Main scene, you can use that for settings or main menu
func (g *Game) Setup(w engine.World) {
    w.AddComponents(Pos{}, Vel{}, Rad{})
    w.AddEntities(&Ball{Pos{0, 0}, Vel{4, 4}, Rad{10}})
    w.AddSystems(&Velocity{}, &Render{})
}

Run the game.

// Provides its own ebiten.Game implementation
g := engine.NewGame(&Game{})
if err := ebiten.RunGame(g); err != nil {
	log.Fatal(err)
}

Wiki

Please visit our wiki for a helpful articles and best practices about Mizu.

mizu's People

Contributors

sedyh 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

Watchers

 avatar

mizu's Issues

How can I use a custom Layout method?

In mizu,struct world implements the method "Layout" from ebiten.Game interface,But I want overwrite the method,or my ebiten app draw text with chinese would be fuzzy。

if I use ebiten directly,use the code below,the text display very clear,

func (g Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
	s := ebiten.DeviceScaleFactor()
	return outsideWidth * int(s), outsideHeight * int(s)
}

But if I use mizu, I didnt overwrite the method named Layout, So How do I do?

System constructor is not checking if component exist

Problem

When adding systems, there is no check for unregistered components.

func makeSystem(world *world, s interface{}) *system {
    ...
    componentId, found := world.componentIds[componentType.Elem()]
    if !found {
        continue // system pointer field is not component bound
    }
    ...
}

Solution

Setting a panic at this point will solve the problem, but may affect the ability to correctly compare entities by mask, as well as the ability to get optional components.
It's also worth noting that fixing issue #1 might fix this issue as well, as before initialization of systems, there will be an initialization of entities in which this check is already present.

Help: How can i use imgui with mizu?

I want: run ebiten-imgui 's Usage ( https://github.com/gabstv/ebiten-imgui)

problem: black screen

mod:

module github.com/cdhon/ebiten1

go 1.18

require (
	github.com/gabstv/ebiten-imgui v0.5.0
	github.com/hajimehoshi/ebiten/v2 v2.3.4
	github.com/inkyblackness/imgui-go/v4 v4.4.0
	github.com/sedyh/mizu v1.0.4
)

require (
	github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220320163800-277f93cfa958 // indirect
	github.com/gofrs/flock v0.8.1 // indirect
	github.com/jezek/xgb v1.0.0 // indirect
	golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
	golang.org/x/image v0.0.0-20220321031419-a8550c1d254a // indirect
	golang.org/x/mobile v0.0.0-20220518205345-8578da9835fd // indirect
	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
	golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
)

code:

package main

import (
	"fmt"
	"image/color"
	"log"

	"github.com/gabstv/ebiten-imgui/renderer"
	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/ebitenutil"
	"github.com/inkyblackness/imgui-go/v4"
	"github.com/sedyh/mizu/pkg/engine"
)

type UIComponent struct {
	mgr *renderer.Manager
	// demo members:
	clearColor [3]float32
	floatVal   float32
	counter    int
	name       string
}

type UIEntity struct {
	UIComponent
}

type UISystem struct {
	*UIComponent
}

func (ui *UISystem) Update(w engine.World) {
	ui.mgr.Update(1.0 / 60.0)
	ui.mgr.BeginFrame()
	{
		imgui.Text("ภาษาไทย测试조선말")  // To display these, you'll need to register a compatible font
		imgui.Text("Hello, world!") // Display some text

		imgui.SliderFloat("float", &ui.floatVal, 0.0, 1.0) // Edit 1 float using a slider from 0.0f to 1.0f
		imgui.ColorEdit3("clear color", &ui.clearColor)    // Edit 3 floats representing a color

		if imgui.Button("Button") { // Buttons return true when clicked (most widgets return true when edited/activated)
			ui.counter++
		}
		imgui.SameLine()
		imgui.Text(fmt.Sprintf("counter = %d", ui.counter))

		imgui.InputText("Name", &ui.name)
	}
	ui.mgr.EndFrame()
}

func (ui *UISystem) Draw(screen *ebiten.Image) {
	screen.Fill(color.RGBA{uint8(ui.clearColor[0] * 255), uint8(ui.clearColor[1] * 255), uint8(ui.clearColor[2] * 255), 255})
	ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %.2f", ebiten.CurrentTPS()))
	ui.mgr.Draw(screen)
}

type Game struct{}

func (g *Game) Setup(w engine.World) {
	mgr := renderer.New(nil)
	ui :=&UIEntity{UIComponent: UIComponent{mgr: mgr}}
	ui.mgr.SetDisplaySize(float32(800), float32(600))
	w.AddComponents(UIComponent{})
	w.AddEntities(ui)
	w.AddSystems(&UISystem{})
}

func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
	return 800, 600
}

func main() {
	ebiten.SetWindowSize(800, 600)
	if err := ebiten.RunGame(engine.NewGame(&Game{})); err != nil {
		log.Fatal(err)
	}
}

error:

level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:5:2: could not import image/color (-: could not load export data: cannot import \"image/color\" (unknown iexport format version 2), export data is newer version - update tool)"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:56:34: undeclared name: ebiten"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:39:3: undeclared name: imgui"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:40:3: undeclared name: imgui"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:42:3: undeclared name: imgui"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:43:3: undeclared name: imgui"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:45:6: undeclared name: imgui"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:48:3: undeclared name: imgui"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:49:3: undeclared name: imgui"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:51:3: undeclared name: imgui"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:58:57: undeclared name: ebiten"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:80:2: undeclared name: ebiten"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:81:12: undeclared name: ebiten"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:9:2: \"github.com/hajimehoshi/ebiten/v2\" imported but not used"
level=error msg="[linters context] typechecking error: c:\\PF\\go\\ebiten\\ebiten1\\main.go:11:2: \"github.com/inkyblackness/imgui-go/v4\" imported but not used"
level=warning msg="[runner] Can't run linter goanalysis_metalinter: buildir: failed to load package goarch: could not load export data: cannot import \"internal/goarch\" (unknown iexport format version 2), export data is newer version - update tool"

Enable runtime component modification

Problem

The library code now contains methods for modifying components at runtime, but they are not yet tested and turned off.

Solution

It is necessary to enable and test their work, and it will also be determined whether it is worth creating all entities at runtime or limited to only modifying components.

Filtering entities with external slice reuse

Problem

We need an alternative to Filter, which will allow you to use your own list (for example, for sorting), but at the same time, it will not do the allocation once again.

Solution

You can make an analogue of append, but for entities.

func (v *view) AppendEntities(entities []Entity) {
    for _, en := range v.w.entities {
        if en.mask.contains(v.mask) {
            entities = append(entities, en)
        }
    }
}

type System struct {
    entities []Entity
    balls engine.View
}

func (s *System) Update(w engine.World) {
    // Clear balls
    s.entities = s.entities[:0]
    ...
    // Add balls
    balls.AppendEntities(s.entities)
}

The scene must be initialized in a certain order

Problem

At the moment, scene initialization should always go in the order: components > systems > entities. Otherwise, they will not find each other.

type Game struct{}

func (g *Game) Setup(w engine.World) {
    w.AddComponents()
    w.AddSystems()
    w.AddEntities()
}

Solution

It is necessary to correct this behavior by replacing the functions of adding all parts with a builder that will automatically initialize at the very end of the scene creation.

func (w *world) AddComponents(components ...interface{}) {
	w.futureComponents = append(w.futureComponents, components...)
}
func (w *world) AddSystems(systems ...interface{}) {
	w.futureSystems = append(w.futureSystems, components...)
}
func (w *world) AddEntities(entities ...interface{}) {
	w.futureEntities = append(w.futureEntities, components...)
}
func (w *world) ChangeScene(next Scene) {
	next.Setup(w)
        w.buildScene()
}

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.