Implement avatar animations

This commit is contained in:
Jeremy Penner 2023-12-28 16:57:39 -05:00
parent d1fb2daa41
commit 208b7c3743
3 changed files with 78 additions and 17 deletions

View file

@ -15,10 +15,13 @@
line-height:1.2
}
</style>
<script src="index.js?v=1"></script>
<script src="index.js?v=2"></script>
</head>
<body>
<h1 id="filename"></h1>
<div id="actions">
<h2>Actions</h2>
</div>
<div id="limbs">
<h2>Limbs</h2>
</div>
@ -63,6 +66,13 @@
labelLimb(limbContainer, ilimb)
showAnimations(limb, limbContainer, LimbImpl)
}
const actionContainer = document.getElementById("actions")
for (const action of choreographyActions) {
if (action == "stand" || body.actions[action] != body.actions["stand"]) {
actionContainer.appendChild(textNode(action, "div"))
actionContainer.appendChild(createAnimation(action, body, BodyImpl))
}
}
}
} catch (e) {
showError(e, filename)

View file

@ -15,7 +15,7 @@
line-height:1.2
}
</style>
<script src="index.js?v=1"></script>
<script src="index.js?v=2"></script>
<script>
function showErrors() {
document.getElementById('errors').style.display = 'block'
@ -50,7 +50,7 @@
Some of these objects were never actually included in any released version of Habitat.
</p>
<div id="bodies">
<h3>Bodies</h3>
<h3>Avatars</h3>
</div>
<div id="heads">
<h3>The Hall Of Heads</h3>

View file

@ -501,7 +501,7 @@ const decodeLimb = (data, limb) => {
}
const choreographyActions = [
"init", "stand", "walk", "hand_back", "sit_floor", "bend_over",
"init", "stand", "walk", "hand_back", "sit_floor", "sit_chair", "bend_over",
"bend_back", "point", "throw", "get_shot", "jump", "punch", "wave",
"frown", "stand_back", "walk_front", "walk_back", "stand_front",
"unpocket", "gimme", "knife", "arm_get", "hand_out", "operate",
@ -543,7 +543,13 @@ const decodeBody = (data) => {
body.choreography.push(choreography)
for (;; tableIndex ++) {
const state = data.getUint8(choreographyTableOff + tableIndex)
choreography.push(state & 0x7f)
let limb = (state & 0x70) >> 4
let animation = state & 0x0f
if (limb == 6) {
limb = 5
animation += 0x10
}
choreography.push({ limb, animation })
if ((state & 0x80) != 0) {
break
}
@ -629,11 +635,6 @@ const PropImpl = {
celsForAnimationState: (prop, istate) => celsFromMask(prop, prop.celmasks[istate]),
}
const BodyImpl = {
decode: decodeBody,
detailHref: (filename) => `body.html?f=${filename}`
}
const LimbImpl = {
celsForAnimationState: (limb, istate) => {
const iframe = limb.frames[istate]
@ -645,18 +646,70 @@ const LimbImpl = {
}
}
const BodyImpl = {
decode: decodeBody,
detailHref: (filename) => `body.html?f=${filename}`,
generateFrames: (action, body, frames) => {
const chore = body.choreography[body.actions[action]]
const animations = []
const limbOrder = action.includes("_back") ? body.backFacingLimbOrder : body.frontFacingLimbOrder
for (const limb of body.limbs) {
if (limb.animations.length > 0) {
animations.push({ ...limb.animations[0] })
} else {
animations.push({ startState: 0, endState: 0 })
}
}
for (const override of chore) {
const ilimb = override.limb
const newAnim = body.limbs[ilimb].animations[override.animation]
animations[ilimb].startState = newAnim.startState
animations[ilimb].endState = newAnim.endState
}
while (true) {
const cels = []
let restartedCount = 0
for (const ilimb of limbOrder) {
const animation = animations[ilimb]
const limb = body.limbs[ilimb]
if (animation.current == undefined) {
animation.current = animation.startState
} else {
animation.current ++
if (animation.current > animation.endState) {
animation.current = animation.startState
restartedCount ++
}
}
const istate = limb.frames[animation.current]
if (istate >= 0) {
cels.push(limb.cels[istate])
}
}
if (restartedCount == animations.length) {
break
}
frames.push(compositeCels(cels))
}
}
}
const linkDetail = (element, filename, impl) => {
return impl && impl.detailHref ? wrapLink(element, impl.detailHref(filename)) : element
}
const createAnimation = (animation, value, impl) => {
const frames = []
if (impl.generateFrames) {
impl.generateFrames(animation, value, frames)
} else {
for (let istate = animation.startState; istate <= animation.endState; istate ++) {
const frame = compositeCels(impl.celsForAnimationState(value, istate))
if (frame != null) {
frames.push(frame)
}
}
}
if (frames.length == 0) {
return textNode("")
} else if (frames.length == 1) {
@ -765,9 +818,7 @@ PropImpl.display = (prop, container) => {
}
BodyImpl.display = (body, container) => {
for (const limb of body.limbs) {
showCels(limb, container)
}
container.appendChild(linkDetail(createAnimation("walk", body, BodyImpl), body.filename, BodyImpl))
}
const displayList = async (indexFile, containerId, impl) => {