Спрайты 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(), он вызывает изменение размера родительского контейнера. Он продолжает изменять размеры на протяжении вращения, так как спрайт, который определяет угол, движется. Изменение размера контейнера вызывает его смещение относительно его братьев и сестер.
Исправление заключается в добавлении невидимого статического спрайта в контейнер, в котором вы вращаете вещи, которые немного больше, чем контейнер, в противном случае. Таким образом, вы гарантируете, что вращающийся спрайт не является одним из ребер и, следовательно, не приведет к изменению размера контейнера.