✨ Interactable object!
This commit is contained in:
		| @@ -5,6 +5,8 @@ import "github.com/veandco/go-sdl2/sdl" | |||||||
| type Object interface { | type Object interface { | ||||||
| 	Create() | 	Create() | ||||||
| 	Update() | 	Update() | ||||||
|  | 	AddChild(child Object) | ||||||
|  | 	GetChildren() []Object | ||||||
| } | } | ||||||
|  |  | ||||||
| type DrawableObject interface { | type DrawableObject interface { | ||||||
| @@ -27,3 +29,7 @@ func (p *BaseObject) Update() { | |||||||
| func (p *BaseObject) AddChild(child Object) { | func (p *BaseObject) AddChild(child Object) { | ||||||
| 	p.Children = append(p.Children, child) | 	p.Children = append(p.Children, child) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (p *BaseObject) GetChildren() []Object { | ||||||
|  | 	return p.Children | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,5 +1,15 @@ | |||||||
| package land | package land | ||||||
|  |  | ||||||
|  | type PositionedObject interface { | ||||||
|  | 	GetPosition() Vector2D | ||||||
|  | 	GetSize() Vector2D | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IsOverlapWithPoint(obj PositionedObject, point Vector2D) bool { | ||||||
|  | 	return point.X >= obj.GetPosition().X && point.X <= obj.GetPosition().X+obj.GetSize().X && | ||||||
|  | 		point.Y >= obj.GetPosition().Y && point.Y <= obj.GetPosition().Y+obj.GetSize().Y | ||||||
|  | } | ||||||
|  |  | ||||||
| type CollidableObject interface { | type CollidableObject interface { | ||||||
| 	GetPosition() Vector2D | 	GetPosition() Vector2D | ||||||
| 	GetSize() Vector2D | 	GetSize() Vector2D | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								pkg/internal/land/object_interactable.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								pkg/internal/land/object_interactable.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | package land | ||||||
|  |  | ||||||
|  | type InteractableObject interface { | ||||||
|  | 	GetPosition() Vector2D | ||||||
|  | 	GetSize() Vector2D | ||||||
|  | 	OnClick(mousePos Vector2D) | ||||||
|  | } | ||||||
| @@ -35,26 +35,60 @@ func (p *RootObject) RunEventLoop(tickDuration time.Duration) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (p *RootObject) ForEachChildren(cb func(child Object)) { | ||||||
|  | 	var caller func(current Object) | ||||||
|  |  | ||||||
|  | 	caller = func(current Object) { | ||||||
|  | 		cb(current) | ||||||
|  | 		for _, child := range current.GetChildren() { | ||||||
|  | 			caller(child) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	caller(p) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *RootObject) HandleUserEvent(event sdl.Event) { | ||||||
|  | 	switch event := event.(type) { | ||||||
|  | 	case *sdl.MouseButtonEvent: | ||||||
|  | 		if event.Type == sdl.MOUSEBUTTONDOWN { | ||||||
|  | 			x, y := float64(event.X), float64(event.Y) | ||||||
|  | 			vec := Vector2D{x, y} | ||||||
|  | 			p.ForEachChildren(func(child Object) { | ||||||
|  | 				if interChild, ok := child.(InteractableObject); ok { | ||||||
|  | 					isOverlap := IsOverlapWithPoint(child.(PositionedObject), vec) | ||||||
|  | 					if isOverlap { | ||||||
|  | 						interChild.OnClick(vec) | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func (p *RootObject) Update() { | func (p *RootObject) Update() { | ||||||
| 	p.BaseObject.Update() | 	p.BaseObject.Update() | ||||||
|  |  | ||||||
| 	// Check collision | 	// Check collision | ||||||
| 	for _, child := range p.Children { | 	p.ForEachChildren(func(child Object) { | ||||||
| 		for _, other := range p.Children { | 		p.ForEachChildren(func(other Object) { | ||||||
|  | 			if child == other { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
| 			collidableChild, ok := child.(CollidableObject) | 			collidableChild, ok := child.(CollidableObject) | ||||||
| 			if !ok { | 			if !ok { | ||||||
| 				continue | 				return | ||||||
| 			} | 			} | ||||||
| 			collidableOther, ok := other.(CollidableObject) | 			collidableOther, ok := other.(CollidableObject) | ||||||
| 			if !ok { | 			if !ok { | ||||||
| 				continue | 				return | ||||||
| 			} | 			} | ||||||
| 			if child != other && checkCollisionBetweenObject(collidableChild, collidableOther) { | 			if checkCollisionBetweenObject(collidableChild, collidableOther) { | ||||||
| 				collidableChild.OnCollide(collidableOther) | 				collidableChild.OnCollide(collidableOther) | ||||||
| 				collidableOther.OnCollide(collidableChild) | 				collidableOther.OnCollide(collidableChild) | ||||||
| 			} | 			} | ||||||
| 		} | 		}) | ||||||
| 	} | 	}) | ||||||
|  |  | ||||||
| 	p.Analyzer.Tick() | 	p.Analyzer.Tick() | ||||||
| } | } | ||||||
| @@ -65,11 +99,15 @@ func (p *RootObject) Draw(pen *sdl.Renderer) { | |||||||
| 	pen.Clear() | 	pen.Clear() | ||||||
|  |  | ||||||
| 	// Render each child | 	// Render each child | ||||||
| 	for _, child := range p.Children { | 	p.ForEachChildren(func(child Object) { | ||||||
|  | 		if child == p { | ||||||
|  | 			// Skip the current to prevent infinite drawing | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
| 		if drawableChild, ok := child.(DrawableObject); ok { | 		if drawableChild, ok := child.(DrawableObject); ok { | ||||||
| 			drawableChild.Draw(pen) | 			drawableChild.Draw(pen) | ||||||
| 		} | 		} | ||||||
| 	} | 	}) | ||||||
|  |  | ||||||
| 	p.Analyzer.Draw() | 	p.Analyzer.Draw() | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,9 +1,15 @@ | |||||||
| package land | package land | ||||||
|  |  | ||||||
|  | import "fmt" | ||||||
|  |  | ||||||
| type Vector2D struct { | type Vector2D struct { | ||||||
| 	X, Y float64 | 	X, Y float64 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (p Vector2D) String() string { | ||||||
|  | 	return fmt.Sprintf("(%.2f, %.2f)", p.X, p.Y) | ||||||
|  | } | ||||||
|  |  | ||||||
| func (p Vector2D) IsZero() bool { | func (p Vector2D) IsZero() bool { | ||||||
| 	return p.X == 0 && p.Y == 0 | 	return p.X == 0 && p.Y == 0 | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ package tiles | |||||||
| import ( | import ( | ||||||
| 	"git.solsynth.dev/highland/codingland/pkg/internal/land" | 	"git.solsynth.dev/highland/codingland/pkg/internal/land" | ||||||
| 	"github.com/veandco/go-sdl2/sdl" | 	"github.com/veandco/go-sdl2/sdl" | ||||||
|  | 	"log" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Tile struct { | type Tile struct { | ||||||
| @@ -38,3 +39,7 @@ func (p *Tile) GetSize() land.Vector2D { | |||||||
|  |  | ||||||
| func (p *Tile) OnCollide(other land.CollidableObject) { | func (p *Tile) OnCollide(other land.CollidableObject) { | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (p *Tile) OnClick(mousePos land.Vector2D) { | ||||||
|  | 	log.Printf("user clicked tile: %s", mousePos.String()) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -44,7 +44,7 @@ func main() { | |||||||
| 		Size:     land.Vector2D{X: 50, Y: 50}, | 		Size:     land.Vector2D{X: 50, Y: 50}, | ||||||
| 	}) | 	}) | ||||||
| 	root.AddChild(&tiles.Tile{ | 	root.AddChild(&tiles.Tile{ | ||||||
| 		Position: land.Vector2D{X: 25, Y: 25}, | 		Position: land.Vector2D{X: 50, Y: 50}, | ||||||
| 		Size:     land.Vector2D{X: 50, Y: 50}, | 		Size:     land.Vector2D{X: 50, Y: 50}, | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| @@ -57,6 +57,8 @@ func main() { | |||||||
| 			switch event.(type) { | 			switch event.(type) { | ||||||
| 			case *sdl.QuitEvent: | 			case *sdl.QuitEvent: | ||||||
| 				running = false | 				running = false | ||||||
|  | 			case *sdl.MouseButtonEvent: | ||||||
|  | 				root.HandleUserEvent(event) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user