From 5f480b596890bbee2b453edd3320ed3739349e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20K=C3=BCbler?= Date: Wed, 1 Nov 2023 05:58:33 +0100 Subject: [PATCH] Add a transform.ChangeParent(child, parent, keepWorldPosition) Function (#111) * add change parent * fix tests * fix children test --- features/hierarchy/example_test.go | 43 ++++++++++++++++++++++++++++ features/hierarchy/parent.go | 33 +++++++++++++++++++++ features/transform/transform.go | 34 ++++++++++++++++++++++ features/transform/transform_test.go | 16 +++++++++++ 4 files changed, 126 insertions(+) diff --git a/features/hierarchy/example_test.go b/features/hierarchy/example_test.go index c02ca2c..d799983 100644 --- a/features/hierarchy/example_test.go +++ b/features/hierarchy/example_test.go @@ -172,6 +172,49 @@ func TestFindChildren(t *testing.T) { } } +func TestChangeParent(t *testing.T) { + w := donburi.NewWorld() + + parent1 := donburi.NewTag().SetName("parent1") + parent2 := donburi.NewTag().SetName("parent2") + child := donburi.NewTag().SetName("child") + + p1e := w.Entry(w.Create(parent1)) + p2e := w.Entry(w.Create(parent2)) + ce := w.Entry(w.Create(child)) + + // no parent exists + ChangeParent(ce, p1e) + testChildren(t, []childrenTest{ + { + Parent: p1e, + Children: []*donburi.Entry{ce}, + }, + }) + + // change to same parent + ChangeParent(ce, p1e) + testChildren(t, []childrenTest{ + { + Parent: p1e, + Children: []*donburi.Entry{ce}, + }, + }) + + // change parent + ChangeParent(ce, p2e) + testChildren(t, []childrenTest{ + { + Parent: p1e, + Children: []*donburi.Entry{}, + }, + { + Parent: p2e, + Children: []*donburi.Entry{ce}, + }, + }) +} + type childrenTest struct { Parent *donburi.Entry Children []*donburi.Entry diff --git a/features/hierarchy/parent.go b/features/hierarchy/parent.go index 802c556..1246baa 100644 --- a/features/hierarchy/parent.go +++ b/features/hierarchy/parent.go @@ -89,6 +89,39 @@ func HasParent(entry *donburi.Entry) bool { return entry.HasComponent(parentComponent) } +// ChangeParent changes a parent of the entry. +func ChangeParent(child *donburi.Entry, newParent *donburi.Entry) { + if !newParent.Valid() { + panic("newParent is not valid") + } + if !child.Valid() { + panic("child is not valid") + } + if !newParent.HasComponent(childrenComponent) { + newParent.AddComponent(childrenComponent) + } + + if oldParent, ok := GetParent(child); ok { + if oldParent == newParent { + return + } + + if oldParent.Valid() { + oldChildren := donburi.Get[childrenData](oldParent, childrenComponent) + for i, c := range oldChildren.Children { + if c == child { + oldChildren.Children = append(oldChildren.Children[:i], oldChildren.Children[i+1:]...) + break + } + } + } + + child.RemoveComponent(parentComponent) + } + + SetParent(child, newParent) +} + func getParentData(entry *donburi.Entry) (*parentData, bool) { if HasParent(entry) { p := donburi.Get[parentData](entry, parentComponent) diff --git a/features/transform/transform.go b/features/transform/transform.go index 26fca9d..6d9d785 100644 --- a/features/transform/transform.go +++ b/features/transform/transform.go @@ -41,6 +41,16 @@ func AppendChild(parent, child *donburi.Entry, keepWorldPosition bool) { SetParent(child, parent, keepWorldPosition) } +// ChangeParent changes parent of the entry. +func ChangeParent(child, parent *donburi.Entry, keepWorldPosition bool) { + if !child.HasComponent(Transform) { + panic("entry does not have transform component") + } + RemoveParent(child, keepWorldPosition) + hierarchy.ChangeParent(child, parent) + SetParent(child, parent, keepWorldPosition) +} + // SetParent sets parent to the entry. func SetParent(entry, parent *donburi.Entry, keepWorldPosition bool) { if !entry.HasComponent(Transform) { @@ -73,6 +83,30 @@ func GetParent(entry *donburi.Entry) (*donburi.Entry, bool) { return hierarchy.GetParent(entry) } +// RemoveParent removes parent of the entry. +func RemoveParent(entry *donburi.Entry, keepWorldPosition bool) { + d := GetTransform(entry) + if !d.hasParent { + return + } + parent, _ := GetParent(entry) + d.hasParent = false + if keepWorldPosition { + parentPos := WorldPosition(parent) + + d.LocalPosition = d.LocalPosition.Add(parentPos) + d.LocalRotation += WorldRotation(parent) + + ws := WorldScale(parent) + if ws.X != 0 { + d.LocalScale.X = d.LocalScale.X * ws.X + } + if ws.Y != 0 { + d.LocalScale.Y = d.LocalScale.Y * ws.Y + } + } +} + // GetChildren returns children of the entry. func GetChildren(entry *donburi.Entry) ([]*donburi.Entry, bool) { return hierarchy.GetChildren(entry) diff --git a/features/transform/transform_test.go b/features/transform/transform_test.go index a1edf37..d9fe2c2 100644 --- a/features/transform/transform_test.go +++ b/features/transform/transform_test.go @@ -39,6 +39,14 @@ func TestTransform(t *testing.T) { Rotation: 180, Scale: dmath.Vec2{X: 2, Y: 3}, }) + + transform.RemoveParent(parent, false) + + testWorldTransform(t, child, &testTransform{ + Position: dmath.Vec2{X: 1, Y: 2}, + Rotation: 180, + Scale: dmath.Vec2{X: 2, Y: 3}, + }) } func TestTransformKeepWorldPosition(t *testing.T) { @@ -64,6 +72,14 @@ func TestTransformKeepWorldPosition(t *testing.T) { Rotation: 90, Scale: dmath.Vec2{X: 1.5, Y: 1.5}, }) + + transform.RemoveParent(parent, true) + + testWorldTransform(t, child, &testTransform{ + Position: dmath.Vec2{X: 1, Y: 2}, + Rotation: 90, + Scale: dmath.Vec2{X: 1.5, Y: 1.5}, + }) } func TestTransformDefaultValue(t *testing.T) {