refactor: moving2d 移动到 game 包中

This commit is contained in:
kercylan98 2023-08-01 15:33:11 +08:00
parent b9d953338f
commit e3224d010b
9 changed files with 153 additions and 172 deletions

View File

@ -1,72 +0,0 @@
package components_test
import (
"fmt"
"github.com/kercylan98/minotaur/component"
"github.com/kercylan98/minotaur/component/components"
"sync"
"time"
)
func ExampleNewMoving2D() {
moving := components.NewMoving2D()
defer func() {
moving.Release()
}()
fmt.Println(moving != nil)
// Output:
// true
}
func ExampleMoving2D_MoveTo() {
moving := components.NewMoving2D(components.WithMoving2DTimeUnit(time.Second))
defer func() {
moving.Release()
}()
var wait sync.WaitGroup
moving.RegPosition2DDestinationEvent(func(moving component.Moving2D, entity component.Moving2DEntity) {
fmt.Println("done")
wait.Done()
})
wait.Add(1)
entity := NewEntity(1, 100)
moving.MoveTo(entity, 50, 30)
wait.Wait()
// Output:
// done
}
func ExampleMoving2D_StopMove() {
moving := components.NewMoving2D(components.WithMoving2DTimeUnit(time.Second))
defer func() {
moving.Release()
}()
var wait sync.WaitGroup
moving.RegPosition2DChangeEvent(func(moving component.Moving2D, entity component.Moving2DEntity, oldX, oldY float64) {
fmt.Println("move")
})
moving.RegPosition2DStopMoveEvent(func(moving component.Moving2D, entity component.Moving2DEntity) {
fmt.Println("stop")
wait.Done()
})
moving.RegPosition2DDestinationEvent(func(moving component.Moving2D, entity component.Moving2DEntity) {
fmt.Println("done")
wait.Done()
})
wait.Add(1)
entity := NewEntity(1, 100)
moving.MoveTo(entity, 50, 300)
moving.StopMove(1)
wait.Wait()
// Output:
// stop
}

View File

@ -1,34 +0,0 @@
package components
import (
"errors"
"time"
)
type Moving2DOption func(moving *Moving2D)
// WithMoving2DTimeUnit 通过特定时间单位创建
// - 默认单位为1毫秒最小单位也为1毫秒
func WithMoving2DTimeUnit(duration time.Duration) Moving2DOption {
return func(moving *Moving2D) {
if duration < time.Millisecond {
panic(errors.New("time unit milliseconds minimum"))
}
moving.timeUnit = float64(duration)
}
}
// WithMoving2DIdleWaitTime 通过特定的空闲等待时间创建
// - 默认情况下在没有新的移动计划时将限制 100毫秒 + 移动间隔事件(默认100毫秒)
func WithMoving2DIdleWaitTime(duration time.Duration) Moving2DOption {
return func(moving *Moving2D) {
moving.idle = duration
}
}
// WithMoving2DInterval 通过特定的移动间隔时间创建
func WithMoving2DInterval(duration time.Duration) Moving2DOption {
return func(moving *Moving2D) {
moving.interval = duration
}
}

View File

@ -1,23 +0,0 @@
package component
// Moving2D 2D移动功能接口定义
type Moving2D interface {
// MoveTo 设置对象移动至特定位置
MoveTo(entity Moving2DEntity, x float64, y float64)
// StopMove 终止特定对象的移动
StopMove(guid int64)
// RegPosition2DChangeEvent 对象位置改变时将立即执行被注册的事件处理函数
RegPosition2DChangeEvent(handle Position2DChangeEventHandle)
OnPosition2DChangeEvent(entity Moving2DEntity, oldX, oldY float64)
// RegPosition2DDestinationEvent 对象抵达终点时将立即执行被注册的事件处理函数
RegPosition2DDestinationEvent(handle Position2DDestinationEventHandle)
OnPosition2DDestinationEvent(entity Moving2DEntity)
}
type (
Position2DChangeEventHandle func(moving Moving2D, entity Moving2DEntity, oldX, oldY float64)
Position2DDestinationEventHandle func(moving Moving2D, entity Moving2DEntity)
Position2DStopMoveEventHandle func(moving Moving2D, entity Moving2DEntity)
)

View File

@ -1,15 +1,14 @@
package components package moving
import ( import (
"github.com/kercylan98/minotaur/component"
"github.com/kercylan98/minotaur/utils/geometry" "github.com/kercylan98/minotaur/utils/geometry"
"sync" "sync"
"time" "time"
) )
// NewMoving2D 创建一个用于2D对象移动的实例(Moving2D) // NewTwoDimensional 创建一个用于2D对象移动的实例(TwoDimensional)
func NewMoving2D(options ...Moving2DOption) *Moving2D { func NewTwoDimensional(options ...TwoDimensionalOption) *TwoDimensional {
moving2D := &Moving2D{ moving2D := &TwoDimensional{
entities: map[int64]*moving2DTarget{}, entities: map[int64]*moving2DTarget{},
timeUnit: float64(time.Millisecond), timeUnit: float64(time.Millisecond),
idle: time.Millisecond * 100, idle: time.Millisecond * 100,
@ -22,11 +21,11 @@ func NewMoving2D(options ...Moving2DOption) *Moving2D {
return moving2D return moving2D
} }
// Moving2D 用于2D对象移动的数据结构 // TwoDimensional 用于2D对象移动的数据结构
// - 通过对象调用 MoveTo 方法后将开始执行该对象的移动 // - 通过对象调用 MoveTo 方法后将开始执行该对象的移动
// - 移动将在根据设置的每次移动间隔时间(WithMoving2DInterval)进行移动,当无对象移动需要移动时将会进入短暂的休眠 // - 移动将在根据设置的每次移动间隔时间(WithTwoDimensionalInterval)进行移动,当无对象移动需要移动时将会进入短暂的休眠
// - 当对象移动速度永久为0时将会导致永久无法完成的移动 // - 当对象移动速度永久为0时将会导致永久无法完成的移动
type Moving2D struct { type TwoDimensional struct {
rw sync.RWMutex rw sync.RWMutex
entities map[int64]*moving2DTarget entities map[int64]*moving2DTarget
timeUnit float64 timeUnit float64
@ -34,13 +33,13 @@ type Moving2D struct {
interval time.Duration interval time.Duration
close bool close bool
position2DChangeEventHandles []component.Position2DChangeEventHandle position2DChangeEventHandles []Position2DChangeEventHandle
position2DDestinationEventHandles []component.Position2DDestinationEventHandle position2DDestinationEventHandles []Position2DDestinationEventHandle
position2DStopMoveEventHandles []component.Position2DStopMoveEventHandle position2DStopMoveEventHandles []Position2DStopMoveEventHandle
} }
// MoveTo 设置对象移动到特定位置 // MoveTo 设置对象移动到特定位置
func (slf *Moving2D) MoveTo(entity component.Moving2DEntity, x float64, y float64) { func (slf *TwoDimensional) MoveTo(entity TwoDimensionalEntity, x float64, y float64) {
guid := entity.GetGuid() guid := entity.GetGuid()
current := time.Now().UnixMilli() current := time.Now().UnixMilli()
slf.rw.Lock() slf.rw.Lock()
@ -51,10 +50,10 @@ func (slf *Moving2D) MoveTo(entity component.Moving2DEntity, x float64, y float6
entityTarget, exist := slf.entities[guid] entityTarget, exist := slf.entities[guid]
if !exist { if !exist {
entityTarget = &moving2DTarget{ entityTarget = &moving2DTarget{
Moving2DEntity: entity, TwoDimensionalEntity: entity,
x: x, x: x,
y: y, y: y,
lastMoveTime: current, lastMoveTime: current,
} }
slf.entities[guid] = entityTarget slf.entities[guid] = entityTarget
return return
@ -65,7 +64,7 @@ func (slf *Moving2D) MoveTo(entity component.Moving2DEntity, x float64, y float6
} }
// StopMove 停止特定对象的移动 // StopMove 停止特定对象的移动
func (slf *Moving2D) StopMove(guid int64) { func (slf *TwoDimensional) StopMove(guid int64) {
slf.rw.Lock() slf.rw.Lock()
defer slf.rw.Unlock() defer slf.rw.Unlock()
entity, exist := slf.entities[guid] entity, exist := slf.entities[guid]
@ -76,52 +75,52 @@ func (slf *Moving2D) StopMove(guid int64) {
} }
// RegPosition2DChangeEvent 在对象位置改变时将执行注册的事件处理函数 // RegPosition2DChangeEvent 在对象位置改变时将执行注册的事件处理函数
func (slf *Moving2D) RegPosition2DChangeEvent(handle component.Position2DChangeEventHandle) { func (slf *TwoDimensional) RegPosition2DChangeEvent(handle Position2DChangeEventHandle) {
slf.position2DChangeEventHandles = append(slf.position2DChangeEventHandles, handle) slf.position2DChangeEventHandles = append(slf.position2DChangeEventHandles, handle)
} }
func (slf *Moving2D) OnPosition2DChangeEvent(entity component.Moving2DEntity, oldX, oldY float64) { func (slf *TwoDimensional) OnPosition2DChangeEvent(entity TwoDimensionalEntity, oldX, oldY float64) {
for _, handle := range slf.position2DChangeEventHandles { for _, handle := range slf.position2DChangeEventHandles {
handle(slf, entity, oldX, oldY) handle(slf, entity, oldX, oldY)
} }
} }
// RegPosition2DDestinationEvent 在对象到达终点时将执行被注册的事件处理函数 // RegPosition2DDestinationEvent 在对象到达终点时将执行被注册的事件处理函数
func (slf *Moving2D) RegPosition2DDestinationEvent(handle component.Position2DDestinationEventHandle) { func (slf *TwoDimensional) RegPosition2DDestinationEvent(handle Position2DDestinationEventHandle) {
slf.position2DDestinationEventHandles = append(slf.position2DDestinationEventHandles, handle) slf.position2DDestinationEventHandles = append(slf.position2DDestinationEventHandles, handle)
} }
func (slf *Moving2D) OnPosition2DDestinationEvent(entity component.Moving2DEntity) { func (slf *TwoDimensional) OnPosition2DDestinationEvent(entity TwoDimensionalEntity) {
for _, handle := range slf.position2DDestinationEventHandles { for _, handle := range slf.position2DDestinationEventHandles {
handle(slf, entity) handle(slf, entity)
} }
} }
// RegPosition2DStopMoveEvent 在对象停止移动时将执行被注册的事件处理函数 // RegPosition2DStopMoveEvent 在对象停止移动时将执行被注册的事件处理函数
func (slf *Moving2D) RegPosition2DStopMoveEvent(handle component.Position2DStopMoveEventHandle) { func (slf *TwoDimensional) RegPosition2DStopMoveEvent(handle Position2DStopMoveEventHandle) {
slf.position2DStopMoveEventHandles = append(slf.position2DStopMoveEventHandles, handle) slf.position2DStopMoveEventHandles = append(slf.position2DStopMoveEventHandles, handle)
} }
func (slf *Moving2D) OnPosition2DStopMoveEvent(entity component.Moving2DEntity) { func (slf *TwoDimensional) OnPosition2DStopMoveEvent(entity TwoDimensionalEntity) {
for _, handle := range slf.position2DStopMoveEventHandles { for _, handle := range slf.position2DStopMoveEventHandles {
handle(slf, entity) handle(slf, entity)
} }
} }
type moving2DTarget struct { type moving2DTarget struct {
component.Moving2DEntity TwoDimensionalEntity
x, y float64 x, y float64
lastMoveTime int64 lastMoveTime int64
} }
// Release 释放对象移动对象所占用的资源 // Release 释放对象移动对象所占用的资源
func (slf *Moving2D) Release() { func (slf *TwoDimensional) Release() {
slf.rw.Lock() slf.rw.Lock()
defer slf.rw.Unlock() defer slf.rw.Unlock()
slf.close = true slf.close = true
} }
func (slf *Moving2D) handle() { func (slf *TwoDimensional) handle() {
for { for {
slf.rw.Lock() slf.rw.Lock()
if slf.close { if slf.close {

View File

@ -1,9 +1,9 @@
package component package moving
import "github.com/kercylan98/minotaur/game" import "github.com/kercylan98/minotaur/game"
// Moving2DEntity 2D移动对象接口定义 // TwoDimensionalEntity 2D移动对象接口定义
type Moving2DEntity interface { type TwoDimensionalEntity interface {
game.Actor game.Actor
game.Position2D game.Position2D
game.Position2DSet game.Position2DSet

7
game/moving/2d_events.go Normal file
View File

@ -0,0 +1,7 @@
package moving
type (
Position2DChangeEventHandle func(moving *TwoDimensional, entity TwoDimensionalEntity, oldX, oldY float64)
Position2DDestinationEventHandle func(moving *TwoDimensional, entity TwoDimensionalEntity)
Position2DStopMoveEventHandle func(moving *TwoDimensional, entity TwoDimensionalEntity)
)

View File

@ -0,0 +1,71 @@
package moving_test
import (
"fmt"
"github.com/kercylan98/minotaur/game/moving"
"sync"
"time"
)
func ExampleNewTwoDimensional() {
m := moving.NewTwoDimensional()
defer func() {
m.Release()
}()
fmt.Println(m != nil)
// Output:
// true
}
func ExampleTwoDimensional_MoveTo() {
m := moving.NewTwoDimensional(moving.WithTwoDimensionalTimeUnit(time.Second))
defer func() {
m.Release()
}()
var wait sync.WaitGroup
m.RegPosition2DDestinationEvent(func(moving *moving.TwoDimensional, entity moving.TwoDimensionalEntity) {
fmt.Println("done")
wait.Done()
})
wait.Add(1)
entity := NewEntity(1, 100)
m.MoveTo(entity, 50, 30)
wait.Wait()
// Output:
// done
}
func ExampleTwoDimensional_StopMove() {
m := moving.NewTwoDimensional(moving.WithTwoDimensionalTimeUnit(time.Second))
defer func() {
m.Release()
}()
var wait sync.WaitGroup
m.RegPosition2DChangeEvent(func(moving *moving.TwoDimensional, entity moving.TwoDimensionalEntity, oldX, oldY float64) {
fmt.Println("move")
})
m.RegPosition2DStopMoveEvent(func(moving *moving.TwoDimensional, entity moving.TwoDimensionalEntity) {
fmt.Println("stop")
wait.Done()
})
m.RegPosition2DDestinationEvent(func(moving *moving.TwoDimensional, entity moving.TwoDimensionalEntity) {
fmt.Println("done")
wait.Done()
})
wait.Add(1)
entity := NewEntity(1, 100)
m.MoveTo(entity, 50, 300)
m.StopMove(1)
wait.Wait()
// Output:
// stop
}

34
game/moving/2d_options.go Normal file
View File

@ -0,0 +1,34 @@
package moving
import (
"errors"
"time"
)
type TwoDimensionalOption func(moving *TwoDimensional)
// WithTwoDimensionalTimeUnit 通过特定时间单位创建
// - 默认单位为1毫秒最小单位也为1毫秒
func WithTwoDimensionalTimeUnit(duration time.Duration) TwoDimensionalOption {
return func(moving *TwoDimensional) {
if duration < time.Millisecond {
panic(errors.New("time unit milliseconds minimum"))
}
moving.timeUnit = float64(duration)
}
}
// WithTwoDimensionalIdleWaitTime 通过特定的空闲等待时间创建
// - 默认情况下在没有新的移动计划时将限制 100毫秒 + 移动间隔事件(默认100毫秒)
func WithTwoDimensionalIdleWaitTime(duration time.Duration) TwoDimensionalOption {
return func(moving *TwoDimensional) {
moving.idle = duration
}
}
// WithTwoDimensionalInterval 通过特定的移动间隔时间创建
func WithTwoDimensionalInterval(duration time.Duration) TwoDimensionalOption {
return func(moving *TwoDimensional) {
moving.interval = duration
}
}

View File

@ -1,9 +1,8 @@
package components_test package moving_test
import ( import (
"fmt" "fmt"
"github.com/kercylan98/minotaur/component" "github.com/kercylan98/minotaur/game/moving"
"github.com/kercylan98/minotaur/component/components"
"sync" "sync"
"testing" "testing"
"time" "time"
@ -41,30 +40,30 @@ func NewEntity(guid int64, speed float64) *MoveEntity {
} }
} }
func TestNewMoving2D(t *testing.T) { func TestNewTwoDimensional(t *testing.T) {
moving := components.NewMoving2D() m := moving.NewTwoDimensional()
defer func() { defer func() {
moving.Release() m.Release()
}() }()
} }
func TestMoving2D_StopMove(t *testing.T) { func TestTwoDimensional_StopMove(t *testing.T) {
var wait sync.WaitGroup var wait sync.WaitGroup
moving := components.NewMoving2D(components.WithMoving2DTimeUnit(time.Second)) m := moving.NewTwoDimensional(moving.WithTwoDimensionalTimeUnit(time.Second))
defer func() { defer func() {
moving.Release() m.Release()
}() }()
moving.RegPosition2DChangeEvent(func(moving component.Moving2D, entity component.Moving2DEntity, oldX, oldY float64) { m.RegPosition2DChangeEvent(func(moving *moving.TwoDimensional, entity moving.TwoDimensionalEntity, oldX, oldY float64) {
x, y := entity.GetPosition() x, y := entity.GetPosition()
fmt.Println(fmt.Sprintf("%d : %d | %f, %f > %f, %f", entity.GetGuid(), time.Now().UnixMilli(), oldX, oldY, x, y)) fmt.Println(fmt.Sprintf("%d : %d | %f, %f > %f, %f", entity.GetGuid(), time.Now().UnixMilli(), oldX, oldY, x, y))
}) })
moving.RegPosition2DDestinationEvent(func(moving component.Moving2D, entity component.Moving2DEntity) { m.RegPosition2DDestinationEvent(func(moving *moving.TwoDimensional, entity moving.TwoDimensionalEntity) {
fmt.Println(fmt.Sprintf("%d : %d | destination", entity.GetGuid(), time.Now().UnixMilli())) fmt.Println(fmt.Sprintf("%d : %d | destination", entity.GetGuid(), time.Now().UnixMilli()))
wait.Done() wait.Done()
}) })
moving.RegPosition2DStopMoveEvent(func(moving component.Moving2D, entity component.Moving2DEntity) { m.RegPosition2DStopMoveEvent(func(moving *moving.TwoDimensional, entity moving.TwoDimensionalEntity) {
fmt.Println(fmt.Sprintf("%d : %d | stop", entity.GetGuid(), time.Now().UnixMilli())) fmt.Println(fmt.Sprintf("%d : %d | stop", entity.GetGuid(), time.Now().UnixMilli()))
wait.Done() wait.Done()
}) })
@ -72,13 +71,13 @@ func TestMoving2D_StopMove(t *testing.T) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
wait.Add(1) wait.Add(1)
entity := NewEntity(int64(i)+1, float64(10+i)) entity := NewEntity(int64(i)+1, float64(10+i))
moving.MoveTo(entity, 50, 30) m.MoveTo(entity, 50, 30)
} }
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
moving.StopMove(int64(i) + 1) m.StopMove(int64(i) + 1)
} }
wait.Wait() wait.Wait()