非静态物体碰撞解决中的奇怪问题

时间:2017-12-27 18:39:20

标签: go collision-detection game-engine game-physics

我在引擎开发方面有点初学者,所以我决定从头开始编写自己的引擎,这样我就可以了解更多关于在所有事情下发生的事情。

我的进展相当不错,除了物理引擎方面让我有点头疼。

这是我的意思的gif:

Weird collision issue

基本上,只要玩家没有从上方或从右到左与另一个非静态身体发生碰撞,引擎就可以正常工作。

这是我用以下代码编写的碰撞解决方案代码:

package resources

import (
  "game/pidgeot-socket/ecs"

  "github.com/bxcodec/saint"
)

type PhysicsSystem struct {
  Hub *Hub
}

func (system PhysicsSystem) Loop() {
  entities, err := system.Hub.World.AllEntitiesWithComponent(ecs.CollisionComponent)
  if err != nil { return }

  for e, _ := range entities {
    // apply impulse
    c_p, _ := system.Hub.World.GetComponent(e, ecs.CollisionComponent)
    c := (*c_p).(*ecs.Collision)

    p_p, _ := system.Hub.World.GetComponent(e, ecs.PositionComponent)
    p := (*p_p).(*ecs.Position)

    if c.WithGravity {
      // Add gravity
      c.ImpulseY = saint.Min(c.ImpulseY + 1, c.MaxSpeedY)
    }

    // apply impulse
    p.NextY = p.Y + c.ImpulseY
    p.NextX = p.X + c.ImpulseX
  }

  // resolving collisions
  for e1, _ := range entities {
    c1_p, _ := system.Hub.World.GetComponent(e1, ecs.CollisionComponent)
    c1 := (*c1_p).(*ecs.Collision)

    if c1.IsStatic { continue }

    for e2, _ := range entities {
      if e1 == e2 { continue }

      system.ResolveCollision(entities, e1, e2)
    }
  }

  // moving entities
  for e, _ := range entities {
    p_p, _ := system.Hub.World.GetComponent(e, ecs.PositionComponent)
    p := (*p_p).(*ecs.Position)

    if (p.X != p.NextX || p.Y != p.NextY) {
      p.X = p.NextX
      p.Y = p.NextY

      system.Hub.broadcast <- system.Hub.World.GetComponentMessage(e, p_p)
    }
  }
}

func (system PhysicsSystem) ResolveCollision(entities map[ecs.EID]*ecs.Component, e1 ecs.EID, e2 ecs.EID) {
  c1_p, _ := system.Hub.World.GetComponent(e1, ecs.CollisionComponent)
  p1_p, _ := system.Hub.World.GetComponent(e1, ecs.PositionComponent)
  c1 := (*c1_p).(*ecs.Collision)
  p1 := (*p1_p).(*ecs.Position)

  c2_p, _ := system.Hub.World.GetComponent(e2, ecs.CollisionComponent)
  p2_p, _ := system.Hub.World.GetComponent(e2, ecs.PositionComponent)
  c2 := (*c2_p).(*ecs.Collision)
  p2 := (*p2_p).(*ecs.Position)

  // resolve y-axis
  collidingX := IsOverlapping(p1.X, p1.X + c1.W, p2.X, p2.X + c2.W)
  collidingY := IsOverlapping(p1.NextY, p1.NextY + c1.H, p2.NextY, p2.NextY + c2.H)
  colliding := collidingX && collidingY

  if colliding {
    direction := func (impulse int) int {if impulse < 0 { return 1 } else { return -1 }}(c1.ImpulseY)
    overlap := CalculateOverlap(p1.NextY, p1.NextY + c1.H, p2.NextY, p2.NextY + c2.H)

    p1.NextY += (direction * overlap)
    c1.ImpulseY = 0
    c1.IsJumping = false
  }

  // resolve x-axis
  collidingX = IsOverlapping(p1.NextX, p1.NextX + c1.W, p2.NextX, p2.NextX + c2.W)
  collidingY = IsOverlapping(p1.Y, p1.Y + c1.H, p2.Y, p2.Y + c2.H)
  colliding = collidingX && collidingY

  if colliding {
    direction := func (impulse int) int {if impulse < 0 { return 1 } else { return -1 }}(c1.ImpulseX)
    overlap := CalculateOverlap(p1.NextX, p1.NextX + c1.W, p2.NextX, p2.NextX + c2.W)

    p1.NextX += (direction * overlap)
  }

  for e3, _ := range entities {
    if e1 == e3 { continue }

    c3_p, _ := system.Hub.World.GetComponent(e3, ecs.CollisionComponent)
    p3_p, _ := system.Hub.World.GetComponent(e3, ecs.PositionComponent)
    c3 := (*c3_p).(*ecs.Collision)
    p3 := (*p3_p).(*ecs.Position)

    collidingX = IsOverlapping(p1.NextX, p1.NextX + c1.W, p3.NextX, p3.NextX + c3.W)
    collidingY = IsOverlapping(p1.NextY, p1.NextY + c1.H, p3.NextY, p3.NextY + c3.H)
    colliding = collidingX && collidingY

    if colliding { system.ResolveCollision(entities, e1, e3) }
  }
}

我能做些什么来解决这个问题?

0 个答案:

没有答案