golang基于原型的实体组件系统(ECS)框架插件Ark的使用
Golang基于原型的实体组件系统(ECS)框架插件Ark的使用
Ark是一个基于原型的Go语言实体组件系统(ECS)框架,它是Arche框架的继任者。
特性
- 为高性能设计并高度优化
- 文档完善,类型安全的API,以及全面的用户指南
- 实体关系作为一等特性
- 快速的批量操作进行大规模操作
- 没有系统,只有查询。使用你自己的结构
- 通过ark-serde实现世界序列化和反序列化
安装
要在Go项目中使用Ark,运行:
go get github.com/mlange-42/ark
使用
下面是一个经典的Position/Velocity示例,展示了Ark的基本用法。
package main
import (
"math/rand/v2"
"github.com/mlange-42/ark/ecs"
)
// Position 组件
type Position struct {
X float64
Y float64
}
// Velocity 组件
type Velocity struct {
X float64
Y float64
}
func main() {
// 创建一个新的World
world := ecs.NewWorld()
// 创建一个组件映射器
// 永久保存映射器并重复使用以获得最佳性能
mapper := ecs.NewMap2[Position, Velocity](&world)
// 创建实体
for range 1000 {
// 创建一个带有组件的新实体
_ = mapper.NewEntity(
&Position{X: rand.Float64() * 100, Y: rand.Float64() * 100},
&Velocity{X: rand.NormFloat64(), Y: rand.NormFloat64()},
)
}
// 创建一个过滤器
// 永久保存过滤器并重复使用以获得最佳性能
f
更多关于golang基于原型的实体组件系统(ECS)框架插件Ark的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang基于原型的实体组件系统(ECS)框架插件Ark的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Ark - Golang基于原型的ECS框架插件使用指南
Ark是一个基于原型的实体组件系统(ECS)框架插件,专为Golang设计。ECS是一种游戏开发架构模式,将实体(Entity)、组件(Component)和系统(System)分离,提供高度灵活性和性能优化。
基本概念
- 实体(Entity): 游戏中的对象,由多个组件组成
- 组件(Component): 纯数据结构,描述实体的某方面特性
- 系统(System): 处理具有特定组件组合的实体的逻辑
安装Ark
go get github.com/bytearena/ark
基本用法
1. 定义组件
type Position struct {
X, Y float64
}
type Velocity struct {
X, Y float64
}
type Renderable struct {
SpriteID string
Width, Height float64
}
2. 创建世界和原型
import "github.com/bytearena/ark"
func main() {
// 创建世界
world := ark.NewWorld()
// 注册组件
world.RegisterComponent(Position{})
world.RegisterComponent(Velocity{})
world.RegisterComponent(Renderable{})
// 定义玩家原型
playerProto := world.NewPrototype("player").
AddComponent(Position{X: 0, Y: 0}).
AddComponent(Velocity{X: 0, Y: 0}).
AddComponent(Renderable{
SpriteID: "player_sprite",
Width: 32,
Height: 32,
})
// 从原型创建实体
player := playerProto.Spawn()
// 运行世界
world.Run()
}
3. 创建系统
type MovementSystem struct {
*ark.System
}
func NewMovementSystem() *MovementSystem {
return &MovementSystem{
System: ark.NewSystemWithRequirements(
ark.ComponentRequirement(Position{}),
ark.ComponentRequirement(Velocity{}),
),
}
}
func (s *MovementSystem) Update(dt float64) {
s.IterateEntities(func(entity ark.EntityID, components ...interface{}) {
pos := components[0].(*Position)
vel := components[1].(*Velocity)
pos.X += vel.X * dt
pos.Y += vel.Y * dt
})
}
// 注册系统
world.AddSystem(NewMovementSystem())
4. 查询实体
// 查询所有有Position和Renderable组件的实体
query := world.NewQuery().
WithComponent(Position{}).
WithComponent(Renderable{})
query.Each(func(entity ark.EntityID, components ...interface{}) {
pos := components[0].(*Position)
render := components[1].(*Renderable)
fmt.Printf("Entity %d at (%.2f, %.2f) with sprite %s\n",
entity, pos.X, pos.Y, render.SpriteID)
})
高级特性
1. 事件系统
// 定义事件
type CollisionEvent struct {
Entity1, Entity2 ark.EntityID
}
// 发送事件
world.Emit(CollisionEvent{
Entity1: player1,
Entity2: player2,
})
// 监听事件
world.AddListener(func(evt CollisionEvent) {
fmt.Printf("Collision between %d and %d\n", evt.Entity1, evt.Entity2)
})
2. 原型继承
// 基础敌人原型
enemyProto := world.NewPrototype("enemy").
AddComponent(Position{}).
AddComponent(Velocity{X: 0.5, Y: 0}).
AddComponent(Health{Value: 100})
// 特殊敌人继承基础敌人
bossProto := world.NewPrototype("boss", "enemy").
OverrideComponent(Health{Value: 500}).
AddComponent(BossAI{})
3. 系统优先级
// 设置系统执行顺序
world.AddSystem(NewInputSystem(), ark.WithPriority(10)) // 最先执行
world.AddSystem(NewMovementSystem(), ark.WithPriority(20))
world.AddSystem(NewRenderSystem(), ark.WithPriority(100)) // 最后执行
性能优化技巧
- 批量处理: 在系统中使用IterateEntities而不是单独处理每个实体
- 组件布局: 将经常一起访问的组件放在相邻内存位置
- 查询缓存: 复用查询对象而不是每次都创建新的
- 适当的系统粒度: 不要在一个系统中做太多事情
完整示例
package main
import (
"fmt"
"github.com/bytearena/ark"
)
// 定义组件
type Position struct{ X, Y float64 }
type Velocity struct{ X, Y float64 }
type Renderable struct{ SpriteID string }
// 移动系统
type MovementSystem struct{ *ark.System }
func NewMovementSystem() *MovementSystem {
return &MovementSystem{
System: ark.NewSystemWithRequirements(
ark.ComponentRequirement(Position{}),
ark.ComponentRequirement(Velocity{}),
),
}
}
func (s *MovementSystem) Update(dt float64) {
s.IterateEntities(func(entity ark.EntityID, components ...interface{}) {
pos := components[0].(*Position)
vel := components[1].(*Velocity)
pos.X += vel.X * dt
pos.Y += vel.Y * dt
fmt.Printf("Entity %d moved to (%.2f, %.2f)\n", entity, pos.X, pos.Y)
})
}
// 渲染系统
type RenderSystem struct{ *ark.System }
func NewRenderSystem() *RenderSystem {
return &RenderSystem{
System: ark.NewSystemWithRequirements(
ark.ComponentRequirement(Position{}),
ark.ComponentRequirement(Renderable{}),
),
}
}
func (s *RenderSystem) Update(dt float64) {
s.IterateEntities(func(entity ark.EntityID, components ...interface{}) {
pos := components[0].(*Position)
render := components[1].(*Renderable)
fmt.Printf("Rendering %s at (%.2f, %.2f)\n", render.SpriteID, pos.X, pos.Y)
})
}
func main() {
world := ark.NewWorld()
// 注册组件
world.RegisterComponent(Position{})
world.RegisterComponent(Velocity{})
world.RegisterComponent(Renderable{})
// 创建玩家原型
playerProto := world.NewPrototype("player").
AddComponent(Position{X: 0, Y: 0}).
AddComponent(Velocity{X: 1, Y: 0.5}).
AddComponent(Renderable{SpriteID: "player_sprite"})
// 创建敌人原型
enemyProto := world.NewPrototype("enemy").
AddComponent(Position{X: 10, Y: 10}).
AddComponent(Velocity{X: -0.5, Y: -0.2}).
AddComponent(Renderable{SpriteID: "enemy_sprite"})
// 生成实体
playerProto.Spawn()
enemyProto.Spawn()
// 添加系统
world.AddSystem(NewMovementSystem())
world.AddSystem(NewRenderSystem())
// 模拟游戏循环
for i := 0; i < 5; i++ {
fmt.Printf("\n--- Frame %d ---\n", i+1)
world.Update(1.0) // dt = 1.0
}
}
Ark框架提供了简洁而强大的ECS实现,特别适合需要高性能和灵活架构的游戏或模拟应用。通过原型系统,可以轻松创建和管理大量相似实体,而组件-系统架构则确保了代码的良好组织和可维护性。