You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
3.0 KiB
129 lines
3.0 KiB
package gohan |
|
|
|
import ( |
|
"fmt" |
|
"log" |
|
"os" |
|
"strings" |
|
"time" |
|
|
|
"github.com/hajimehoshi/ebiten/v2" |
|
) |
|
|
|
var ( |
|
gameComponents = make(map[EntityID]map[ComponentID]interface{}) |
|
|
|
gameSystems []System |
|
gameSystemEntities [][]EntityID // Slice of entities matching each system. |
|
|
|
gameSystemReceivesUpdate []bool |
|
gameSystemReceivesDraw []bool |
|
|
|
debug bool |
|
) |
|
|
|
func init() { |
|
debugEnv := os.Getenv("GOHAN_DEBUG") |
|
debugEnv = strings.TrimSpace(debugEnv) |
|
debugEnv = strings.ToLower(debugEnv) |
|
|
|
debug = debugEnv == "1" || debugEnv == "t" || debugEnv == "y" || debugEnv == "on" || debugEnv == "yes" || debugEnv == "true" |
|
} |
|
|
|
// print prints debug information (when enabled). |
|
func print(s string) { |
|
if !debug { |
|
return |
|
} |
|
|
|
log.Println(s) |
|
} |
|
|
|
func attachEntitiesToSystem(system System) { |
|
// This function is always called on a newly added system. |
|
systemID := len(gameSystemEntities) - 1 |
|
|
|
for entity := EntityID(0); entity < nextEntityID; entity++ { |
|
if system.Matches(entity) { |
|
gameSystemEntities[systemID] = append(gameSystemEntities[systemID], entity) |
|
|
|
print(fmt.Sprintf("Attached entity %d to system %d.", entity, systemID)) |
|
} |
|
} |
|
} |
|
|
|
// RegisterSystem registers a system to start receiving Update and Draw calls. |
|
func RegisterSystem(system System) { |
|
gameSystems = append(gameSystems, system) |
|
gameSystemReceivesUpdate = append(gameSystemReceivesUpdate, true) |
|
gameSystemReceivesDraw = append(gameSystemReceivesDraw, true) |
|
gameSystemEntities = append(gameSystemEntities, nil) |
|
|
|
attachEntitiesToSystem(system) |
|
} |
|
|
|
func updateSystem(i int) (int, error) { |
|
updated := 0 |
|
for _, entity := range gameSystemEntities[i] { |
|
err := gameSystems[i].Update(entity) |
|
if err != nil { |
|
if err == ErrSystemWithoutUpdate { |
|
// Unregister system from Update events. |
|
gameSystemReceivesUpdate[i] = false |
|
return 0, nil |
|
} |
|
return 0, fmt.Errorf("failed to update system %d for entity %d: %s", i, entity, err) |
|
} |
|
updated++ |
|
} |
|
return updated, nil |
|
} |
|
|
|
// Update updates the game state. |
|
func Update() error { |
|
var t time.Time |
|
if debug { |
|
t = time.Now() |
|
} |
|
var systems int |
|
for i, registered := range gameSystemReceivesUpdate { |
|
if !registered { |
|
continue |
|
} |
|
|
|
updated, err := updateSystem(i) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
print(fmt.Sprintf("System %d: updated %d entities.", i, updated)) |
|
systems++ |
|
} |
|
if debug { |
|
print(fmt.Sprintf("Finished updating %d systems in %.2fms.", systems, float64(time.Since(t).Microseconds())/1000)) |
|
} |
|
return nil |
|
} |
|
|
|
// Draw draws the game on to the screen. |
|
func Draw(screen *ebiten.Image) error { |
|
DRAWSYSTEMS: |
|
for i, registered := range gameSystemReceivesDraw { |
|
if !registered { |
|
continue |
|
} |
|
|
|
for _, entity := range gameSystemEntities[i] { |
|
err := gameSystems[i].Draw(entity, screen) |
|
if err != nil { |
|
if err == ErrSystemWithoutDraw { |
|
// Unregister system from Draw events. |
|
gameSystemReceivesDraw[i] = false |
|
continue DRAWSYSTEMS |
|
} |
|
return fmt.Errorf("failed to draw system %d for entity %d: %s", i, entity, err) |
|
} |
|
} |
|
} |
|
return nil |
|
}
|
|
|