Спрайты Pixi.js "дрожат", когда вращается другой спрайт

Я работаю над игрой Pixi.js в Coffeescript, которая в основном фокусируется на вращении гексов. Все в вращении работает правильно с точки зрения анимации вращения и базового состояния платы, распознающего вращение. Тем не менее, для определенных гексов на доске (не для всех) вращение их приводит к "встряхиванию" других (не всех) спрайтов на сцене. Они на мгновение сдвигаются в сторону, а затем снова сдвигаются назад, когда вращение заканчивается. Я пытался найти проблему во всем; единственный результат, который я нашел, был кем-то с подобной проблемой на другом сайте, но не имел ответов: здесь.

Я не уверен, с чего начать в плане диагностики ошибки самостоятельно. Если это проблема с холстом, я мог бы посмотреть там, но это может быть и проблема Pixi. Вот гиф проблемы. Когда я нажимаю на первый гекс (справа), многие линии дрожат. Когда я нажимаю на второй гекс (слева), они не делают.

Проект довольно большой на данный момент с точки зрения кода. Вот функция анимации и вспомогательные методы:

## The frame count the window is on ##
@count = 0

### Moves the connector to the correct lit layer ###
@toLit = (connector) ->
  try
    @colorContainers[connector.color].unlit.removeChild(connector.panel)
  catch
  if @typeIsArray connector.color
    if connector.color.length > 0
      c = connector.color[0].toUpperCase()
    else
      c = Color.asString(Color.NONE).toUpperCase()
  else
    c = connector.color.toUpperCase()
  if c is Color.asString(Color.NONE).toUpperCase()
    @toUnlit(connector) ## Prevent lighting of color.NONE
  else
    @colorContainers[c.toUpperCase()].lit.addChild(connector.panel)
    connector.linked = true
  return

### Moves the connector to the correct unlit layer ###
@toUnlit = (connector) ->
  try
    @colorContainers[connector.color].lit.removeChild(connector.panel)
  catch
  if @typeIsArray connector.color
    if connector.color.length > 0
      c = connector.color[0]
    else
      c = Color.asString(Color.NONE)
  else
    c = connector.color
  if connector.hex? and connector.hex instanceof Crystal  
    @colorContainers[Color.asString(Color.NONE).toUpperCase()].unlit.addChild(connector.panel)
  else
    @colorContainers[c.toUpperCase()].unlit.addChild(connector.panel)
  connector.linked = false
  return

### Creates a frame offset for the each color ###
@colorOffset = {}
for c in Color.values()
  if not isNaN(c)
    c = Color.fromString(c).toUpperCase()
  else
    c = c.toUpperCase()
  @colorOffset[c] = Math.random() + 0.5

### Updates the pulse filter that controls lighting effects ###
@calcPulseFilter = (count) ->
  for col, val of @colorContainers
    pulse = val.lit.filters[0]
    cont = (count + val.lit.pulseOffset)/val.lit.pulseLength
    m = pulse.matrix
    m[0] = Math.abs(Math.sin(cont * 2 * Math.PI)) * 0.5 + 0.5
    m[5] = Math.abs(Math.sin(cont * 2 * Math.PI)) * 0.5 + 0.5
    m[10] = Math.abs(Math.sin(cont * 2 * Math.PI)) * 0.5 + 0.5
    m[15] = Math.abs(Math.sin(cont * 2 * Math.PI)) * 0.25 + 0.75
    pulse.matrix = m
  for cont in @goalContainer.children
    if cont.children.length >= 2 and cont.filters.length >= 2
      pulse = cont.filters[1]
      correspondCont = @colorContainers[cont.children[0].color.toUpperCase()].lit
      c = (count + correspondCont.pulseOffset)/correspondCont.pulseLength
      m = pulse.matrix
      if parseInt(cont.children[1].text.substring(0, 1)) >= parseInt(cont.children[1].text.substring(2))
        m[0] = Math.abs(Math.sin(c * 2 * Math.PI)) * 0.5 + 0.5
        m[5] = Math.abs(Math.sin(c * 2 * Math.PI)) * 0.5 + 0.5
        m[10] = Math.abs(Math.sin(c * 2 * Math.PI)) * 0.5 + 0.5
        m[15] = Math.abs(Math.sin(c * 2 * Math.PI)) * 0.25 + 0.75
      else
        m[0] = 1
        m[5] = 1
        m[10] = 1
        m[15] = 1
      pulse.matrix = m
  return

### The animation function. Called by pixi and requests to be recalled ###
@animate = () ->
    ## Color animation
    window.count += 1;  ## Frame count
    @calcPulseFilter(window.count)
    rotSpeed = 1/5
    tolerance = 0.000001 ## For floating point errors - difference below this is considered 'equal'
    radTo60Degree = 1.04719755 ## 1 radian * this coefficient = 60 degrees
    if (@BOARD?)
      ## Update text on goal
      curLit = @BOARD.crystalLitCount()
      goalContainer = @menu.children[@goalContainerIndex]
      isWin = true ## True if this user has won - every goal set.
      for pan in goalContainer.children
        for spr in pan.children
          if spr instanceof PIXI.Text and spr.color.toUpperCase() of curLit
            spr.setText(curLit[spr.color.toUpperCase()] + spr.text.substring(1))
            if curLit[spr.color.toUpperCase()] < parseInt(spr.text.substring(2))
              isWin = false

      if isWin and (not @winContainer?) and @showWinContainer
        @gameOn = false
        @makeWinGameContainer()

      for h in @BOARD.allHexes()
        ##Update lighting of all hexes
        if h.isLit().length > 0 and not h.backPanel.children[0].lit
          h.backPanel.children[0].lit = true
          if not (h instanceof Prism)
            @toLit(h.backPanel.spr)
        if h.isLit().length is 0 and h.backPanel.children[0].lit
          h.backPanel.children[0].lit = false
          if not (h instanceof Prism)
            @toUnlit(h.backPanel.spr)

        hLit = h.isLit()
        if h instanceof Prism
          ## Adjust opacity of cores
          for col, core of h.cores
            if col.toLowerCase() not in hLit and core.alpha > 0
              core.alpha = 0
            else if col.toLowerCase() in hLit and core.alpha is 0
              core.alpha = 0.75

        nS = h.getNeighborsWithBlanks()
        ## Fixing lighting of connectors 
        for panel in h.colorPanels
          col = panel.color.toLowerCase()
          for connector in panel.children
            for side in connector.sides
              n = nS[side]

              if n? and col in hLit and n.colorOfSide(n.indexLinked(h)) is col and not connector.linked
                @toLit(connector)
                for nPanel in n.colorPanels
                  for nConnector in nPanel.children
                    for nSide in nConnector.sides
                      if nSide is n.indexLinked(h) and not nConnector.linked
                        @toLit(nConnector)
              else if connector.linked and col not in hLit
                @toUnlit(connector)
                if n?
                  for nPanel in n.colorPanels
                    for nConnector in nPanel.children
                      for nSide in nConnector.sides
                        if nSide is n.indexLinked(h) and not nConnector.linked
                          @toUnlit(nConnector)

        ### Rotation of a prism - finds a prism that wants to rotate and rotates it a bit. ###
        ### If this is the first notification that this prism wants to rotate, stops providing light. ###
        ### If the prism is now done rotating, starts providing light again ###
        if h instanceof Prism and h.currentRotation isnt h.targetRotation
          if h.canLight
            h.canLight = false
            h.light()
          inc = 
            if (h.targetRotation - h.prevRotation) >= 0 
              rotSpeed
            else
              -rotSpeed
          h.backPanel.rotation += inc * radTo60Degree
          h.currentRotation += inc 
          for value in h.colorPanels
            value.rotation += inc * radTo60Degree
          if Math.abs(h.targetRotation - h.currentRotation) < tolerance
            inc = (h.targetRotation - h.currentRotation)
            h.backPanel.rotation += inc * radTo60Degree
            h.currentRotation += inc
            for value in h.colorPanels
              value.rotation += inc * radTo60Degree
              ## Update side index of each sprite
              for spr in value.children
                newSides = []
                for side in spr.sides
                  newSides.push((side + (h.currentRotation - h.prevRotation)) %% Hex.SIDES)
                spr.sides = newSides
            h.prevRotation = h.currentRotation
            h.canLight = true
            h.light()

        ### Spark and crystal color changing ###
        if (h instanceof Spark or h instanceof Crystal) and h.toColor isnt ""
          col = if (not isNaN(h.toColor)) 
                  Color.asString(h.toColor).toUpperCase() 
                else 
                  h.toColor.toUpperCase()
          h.backPanel.spr.color = col
          @toLit(h.backPanel.spr)
          h.toColor = ""
    requestAnimFrame(animate )
    @renderer.render(@stage)
    return

Если есть какие-то другие части кода, которые, по вашему мнению, имеют отношение к ошибке, дайте мне знать, и я опубликую эти части. Любая помощь или предложения будут действительно хороши!

1 ответ

Решение

Наткнулся на решение по прихоти - когда вы поворачиваете спрайт, который в данный момент находится на границе его родительского DisplayObjectContainer(), он вызывает изменение размера родительского контейнера. Он продолжает изменять размеры на протяжении вращения, так как спрайт, который определяет угол, движется. Изменение размера контейнера вызывает его смещение относительно его братьев и сестер.

Исправление заключается в добавлении невидимого статического спрайта в контейнер, в котором вы вращаете вещи, которые немного больше, чем контейнер, в противном случае. Таким образом, вы гарантируете, что вращающийся спрайт не является одним из ребер и, следовательно, не приведет к изменению размера контейнера.

Другие вопросы по тегам