电话
400 9058 355
本文介绍如何在 go 中避免继承式设计,使用接口和组合(而非类型断言嵌入结构)实现灵活、可维护的碰撞检测系统,强调 `collider` 接口 + `collisionshape()` 方法的推荐模式。
在 Go 中,试图通过嵌入结构(如 Circle)并依赖运行时类型断言(如 value.(type) == Circle)来实现“多态碰撞逻辑”,本质上是将面向对象的继承思维强行套用到 Go 的组合范式中——这不仅违背 Go 的设计哲学,还会导致代码僵化、难以扩展且类型安全缺失。
正确的做法是:分离“可碰撞实体”与“碰撞几何形状”,通过明确的接口契约解耦行为与实现。

// collision/collision.go
package collision
type Shaper interface {
BoundingBox() (x, y, w, h float64)
FastCollisionCheck(other Shaper) bool
DoesCollide(other Shaper) bool
}
type Collider interface {
CollisionShape() Shaper // 统一入口:获取用于碰撞计算的几何形状
}所有参与碰撞的对象(如 Rock、Spaceship、Asteroid)只需实现 CollisionShape(),返回其底层几何体(如 *Circle、*Rectangle),无需暴露内部结构:
// game/objects.go
package game
import "yourproject/collision"
type Rock struct {
PositionX, PositionY float64
shape *collision.Circle // 显式持有,语义清晰
Mass float64
}
func (r *Rock) CollisionShape() collision.Shaper {
return r.shape // 直接返回,零开销
}
// 可随时切换实现而不影响外部调用:
// func (r *Rock) CollisionShape() collision.Shaper {
// return &collision.Rectangle{X: r.PositionX-1, Y: r.PositionY-1, W: 2, H: 2}
// }碰撞判定逻辑完全封装在 collision 包内,与业务对象解耦:
// collision/collision.go
func Collide(c1, c2 Collider) bool {
s1, s2 := c1.CollisionShape(), c2.CollisionShape()
if !s1.FastCollisionCheck(s2) {
return false
}
return s1.DoesCollide(s2)
}
// 使用示例(业务层)
func (g *Game) handleCollisions() {
for _, obj1 := range g.objects {
for _, obj2 := range g.objects {
if obj1 != obj2 && collision.Collide(obj1, obj2) {
obj1.OnCollide(obj2) // 由具体类型实现响应逻辑
}
}
}
}原始问题中尝试的写法:
type Rock struct {
collision.Circle // 匿名嵌入
}
func (c *Circle) DoesCollide(other Collidable) bool {
switch v := other.(type) {
case Circle: // ❌ Rock 不是 Circle 类型,断言失败
}
}问题在于:
若追求极致性能(如高频物理模拟),可考虑嵌入几何体以避免指针间接访问:
type Rock struct {
collision.Circle // 匿名嵌入
Mass float64
}
func (r *Rock) CollisionShape() collision.Shaper {
return &r.Circle // 返回嵌入字段地址
}但需注意:
| 原则 | 说明 |
|---|---|
| 组合优于继承 | 用 CollisionShape() 方法委托行为,而非让 Rock “是” Circle |
| 接口小而专注 | Collider 只声明 CollisionShape();Shaper 封装几何计算,职责单一 |
| 实现可替换 | Rock 内部可自由切换 Circle/Polygon/Capsule,只要 CollisionShape() 返回 Shaper 即可 |
| 包边界清晰 | 碰撞算法(collision 包)不依赖游戏逻辑(game 包),利于单元测试与复用 |
最终,collision.Collide(rock, spaceship) 调用简洁、类型安全、易于扩展——这才是 Go 的惯用之道。
邮箱:8955556@qq.com
Q Q:8955556
本文详解如何将Go官方present工具(用于生成HTML5...
PySNMP在不同版本中对SNMP错误状态(errorSta...
time.Sleep仅阻塞当前goroutine,其他gor...
PHPfopen()创建含特殊符号的文件名失败主因是操作系统...
WooCommerce中通过代码为分组产品动态聚合子商品的属...
io.ReadFull返回io.ErrUnexpectedE...
本文详解Yii2中控制器向视图传递ActiveRecord数...
本文详解为何通过wp_set_object_terms()为...
Pytest中使用@mock.patch类装饰器会导致补丁泄...
带缓冲的channel是并发安全的FIFO队列;make(c...