2D Game Engine

Fizyka (PhysicsManager)

Phaser Arcade Physics — ciała, prędkości, collidery, overlap i granice świata. Bez własnego silnika fizyki.

Arcade, nie własny silnik#

PhysicsManager to cienka warstwa nad Phaser Arcade Physics. Świadoma decyzja: prosta fizyka AABB wystarcza dla gier 2D, a własny silnik to tysiące linii do utrzymania.

API#

ts
attach(port); detach(); isAttached()
setWorldBounds(x, y, w, h)
attachBody(object); detachBody(object); readPosition(object)
setVelocity(object, vx, vy); getVelocity(object)
setImmovable(object, bool); setCollideWorldBounds(object, bool)
addCollider(a, b, handler?): ColliderHandle
addOverlap(a, b, handler): ColliderHandle
clear(): void

ColliderPair to jeden obiekt albo tablica obiektów — np. findByTag('wall').

Ciało obiektu#

ts
const player = this.createSprite('hero', { x: 100, y: 200 })

this.getPhysics().attachBody(player)
this.getPhysics().setCollideWorldBounds(player, true)
this.getPhysics().setVelocity(player, 0, 0)

Albo przez deskryptor przy tworzeniu:

ts
const wall = this.createRect(280, 24, { x: 520, y: 420, fill: '#3a4256' })
this.getPhysics().attachBody(wall)
this.getPhysics().setImmovable(wall, true)

Granice świata#

ts
this.getPhysics().setWorldBounds(0, 0, 2000, 1400)

Kolizje i overlap#

Collider — fizyczne zderzenie (ciała się odbijają/zatrzymują):

ts
const walls = this.findByTag('wall')
this.getPhysics().addCollider(player, walls)

Overlap — wykrycie przecięcia bez reakcji fizycznej (pickupy, strefy):

ts
const coins = this.findByTag('coin')
this.getPhysics().addOverlap(player, coins, (playerObj, coinObj) => {
  this.score += 1
  this.playSound('pickup', { channel: 'sfx' })
  this.destroyObject(coinObj)
})

Przykład: platformer z fixedUpdate#

ts
class PlatformerScene extends Scene {
  private player!: GameObject
  private walls: GameObject[] = []

  create() {
    this.getPhysics().setWorldBounds(0, 0, 2000, 1400)

    this.player = this.createSprite('hero', { x: 100, y: 300 })
    this.getPhysics().attachBody(this.player)
    this.getPhysics().setCollideWorldBounds(this.player, true)

    for (const spec of WALLS) {
      const wall = this.createRect(spec.width, spec.height, { x: spec.x, y: spec.y })
      this.getPhysics().attachBody(wall)
      this.getPhysics().setImmovable(wall, true)
      this.walls.push(wall)
    }

    this.getPhysics().addCollider(this.player, this.walls)
  }

  fixedUpdate() {
    const input = this.getInput()
    const vx = input.isActionDown('move-right') ? 240 : input.isActionDown('move-left') ? -240 : 0
    this.getPhysics().setVelocity(this.player, vx, 0)
  }
}

Fizyka w fixedUpdate

Ustawianie prędkości rób w fixedUpdate, nie w update — inaczej przy spadku FPS fizyka stanie się niedeterministyczna. Render może zostać w update z interpolacją przez fixedAlpha.

Sprzątanie#

ts
this.getPhysics().clear()

Przy shutdown() sceny ciała i collidery są usuwane razem z obiektami. clear() przydaje się przy przebudowie poziomu bez zmiany sceny.