Fix cel positioning in avatar drawing / animation

This commit is contained in:
Jeremy Penner 2023-12-29 14:48:28 -05:00
parent 208b7c3743
commit 5ee1d45f83
3 changed files with 43 additions and 20 deletions

View file

@ -15,7 +15,7 @@
line-height:1.2 line-height:1.2
} }
</style> </style>
<script src="index.js?v=2"></script> <script src="index.js?v=3"></script>
</head> </head>
<body> <body>
<h1 id="filename"></h1> <h1 id="filename"></h1>

View file

@ -15,7 +15,7 @@
line-height:1.2 line-height:1.2
} }
</style> </style>
<script src="index.js?v=2"></script> <script src="index.js?v=3"></script>
<script> <script>
function showErrors() { function showErrors() {
document.getElementById('errors').style.display = 'block' document.getElementById('errors').style.display = 'block'

View file

@ -571,7 +571,7 @@ const celsFromMask = (prop, celMask) => {
return cels return cels
} }
const compositeCels = (cels) => { const compositeCels = (cels, paintOrder = null) => {
if (cels.length == 0) { if (cels.length == 0) {
return null return null
} }
@ -581,13 +581,29 @@ const compositeCels = (cels) => {
let maxY = Number.NEGATIVE_INFINITY let maxY = Number.NEGATIVE_INFINITY
let xRel = 0 let xRel = 0
let yRel = 0 let yRel = 0
let layers = []
for (let cel of cels) { for (let cel of cels) {
minX = Math.min(minX, cel.xOffset + xRel) if (cel) {
minY = Math.min(minY, -(cel.yOffset + yRel)) const x = cel.xOffset + xRel
maxX = Math.max(maxX, cel.width + cel.xOffset + xRel) const y = -(cel.yOffset + yRel)
maxY = Math.max(maxY, cel.height - (cel.yOffset + yRel)) minX = Math.min(minX, x)
xRel += cel.xRel minY = Math.min(minY, y)
yRel += cel.yRel maxX = Math.max(maxX, cel.width + x)
maxY = Math.max(maxY, cel.height + y)
layers.push({ cel, x, y })
xRel += cel.xRel
yRel += cel.yRel
} else {
layers.push(null)
}
}
if (paintOrder) {
const reordered = []
for (const ilayer of paintOrder) {
reordered.push(layers[ilayer])
}
layers = reordered
} }
const w = (maxX - minX) * 8 const w = (maxX - minX) * 8
@ -595,14 +611,10 @@ const compositeCels = (cels) => {
const canvas = makeCanvas(w, h) const canvas = makeCanvas(w, h)
const ctx = canvas.getContext("2d") const ctx = canvas.getContext("2d")
xRel = 0 for (const layer of layers) {
yRel = 0 if (layer && layer.cel.canvas) {
for (let cel of cels) { ctx.drawImage(layer.cel.canvas, (layer.x - minX) * 8, layer.y - minY)
if (cel.canvas) {
ctx.drawImage(cel.canvas, (cel.xOffset + xRel - minX) * 8, -(cel.yOffset + yRel) - minY)
} }
xRel += cel.xRel
yRel += cel.yRel
} }
return { canvas: canvas, xOffset: minX * 8, yOffset: minY, w: w, h: h } return { canvas: canvas, xOffset: minX * 8, yOffset: minY, w: w, h: h }
} }
@ -646,13 +658,23 @@ const LimbImpl = {
} }
} }
const actionOrientations = {
"stand_back": "back",
"walk_front": "front",
"walk_back": "back",
"stand_front": "front",
"sit_front": "front"
}
const BodyImpl = { const BodyImpl = {
decode: decodeBody, decode: decodeBody,
detailHref: (filename) => `body.html?f=${filename}`, detailHref: (filename) => `body.html?f=${filename}`,
generateFrames: (action, body, frames) => { generateFrames: (action, body, frames) => {
const chore = body.choreography[body.actions[action]] const chore = body.choreography[body.actions[action]]
const animations = [] const animations = []
const limbOrder = action.includes("_back") ? body.backFacingLimbOrder : body.frontFacingLimbOrder const orientation = actionOrientations[action] ?? "side"
const limbOrder = orientation == "front" ? body.frontFacingLimbOrder :
orientation == "back" ? body.backFacingLimbOrder :
null // side animations are always displayed in standard limb order
for (const limb of body.limbs) { for (const limb of body.limbs) {
if (limb.animations.length > 0) { if (limb.animations.length > 0) {
animations.push({ ...limb.animations[0] }) animations.push({ ...limb.animations[0] })
@ -669,9 +691,8 @@ const BodyImpl = {
while (true) { while (true) {
const cels = [] const cels = []
let restartedCount = 0 let restartedCount = 0
for (const ilimb of limbOrder) { for (const [ilimb, limb] of body.limbs.entries()) {
const animation = animations[ilimb] const animation = animations[ilimb]
const limb = body.limbs[ilimb]
if (animation.current == undefined) { if (animation.current == undefined) {
animation.current = animation.startState animation.current = animation.startState
} else { } else {
@ -684,12 +705,14 @@ const BodyImpl = {
const istate = limb.frames[animation.current] const istate = limb.frames[animation.current]
if (istate >= 0) { if (istate >= 0) {
cels.push(limb.cels[istate]) cels.push(limb.cels[istate])
} else {
cels.push(null)
} }
} }
if (restartedCount == animations.length) { if (restartedCount == animations.length) {
break break
} }
frames.push(compositeCels(cels)) frames.push(compositeCels(cels, limbOrder))
} }
} }
} }