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

View File

@ -1,9 +1,9 @@
package component
package moving
import "github.com/kercylan98/minotaur/game"
// Moving2DEntity 2D移动对象接口定义
type Moving2DEntity interface {
// TwoDimensionalEntity 2D移动对象接口定义
type TwoDimensionalEntity interface {
game.Actor
game.Position2D
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 (
"fmt"
"github.com/kercylan98/minotaur/component"
"github.com/kercylan98/minotaur/component/components"
"github.com/kercylan98/minotaur/game/moving"
"sync"
"testing"
"time"
@ -41,30 +40,30 @@ func NewEntity(guid int64, speed float64) *MoveEntity {
}
}
func TestNewMoving2D(t *testing.T) {
moving := components.NewMoving2D()
func TestNewTwoDimensional(t *testing.T) {
m := moving.NewTwoDimensional()
defer func() {
moving.Release()
m.Release()
}()
}
func TestMoving2D_StopMove(t *testing.T) {
func TestTwoDimensional_StopMove(t *testing.T) {
var wait sync.WaitGroup
moving := components.NewMoving2D(components.WithMoving2DTimeUnit(time.Second))
m := moving.NewTwoDimensional(moving.WithTwoDimensionalTimeUnit(time.Second))
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()
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()))
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()))
wait.Done()
})
@ -72,13 +71,13 @@ func TestMoving2D_StopMove(t *testing.T) {
for i := 0; i < 10; i++ {
wait.Add(1)
entity := NewEntity(int64(i)+1, float64(10+i))
moving.MoveTo(entity, 50, 30)
m.MoveTo(entity, 50, 30)
}
time.Sleep(time.Second * 1)
for i := 0; i < 10; i++ {
moving.StopMove(int64(i) + 1)
m.StopMove(int64(i) + 1)
}
wait.Wait()