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 line-height:1.2
} }
</style> </style>
<script src="index.js?v=1"></script> <script src="index.js?v=2"></script>
</head> </head>
<body> <body>
<h1 id="filename"></h1> <h1 id="filename"></h1>
<div id="actions">
<h2>Actions</h2>
</div>
<div id="limbs"> <div id="limbs">
<h2>Limbs</h2> <h2>Limbs</h2>
</div> </div>
@ -63,6 +66,13 @@
labelLimb(limbContainer, ilimb) labelLimb(limbContainer, ilimb)
showAnimations(limb, limbContainer, LimbImpl) 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) { } catch (e) {
showError(e, filename) showError(e, filename)

View file

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

View file

@ -501,7 +501,7 @@ const decodeLimb = (data, limb) => {
} }
const choreographyActions = [ 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", "bend_back", "point", "throw", "get_shot", "jump", "punch", "wave",
"frown", "stand_back", "walk_front", "walk_back", "stand_front", "frown", "stand_back", "walk_front", "walk_back", "stand_front",
"unpocket", "gimme", "knife", "arm_get", "hand_out", "operate", "unpocket", "gimme", "knife", "arm_get", "hand_out", "operate",
@ -543,7 +543,13 @@ const decodeBody = (data) => {
body.choreography.push(choreography) body.choreography.push(choreography)
for (;; tableIndex ++) { for (;; tableIndex ++) {
const state = data.getUint8(choreographyTableOff + 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) { if ((state & 0x80) != 0) {
break break
} }
@ -629,11 +635,6 @@ const PropImpl = {
celsForAnimationState: (prop, istate) => celsFromMask(prop, prop.celmasks[istate]), celsForAnimationState: (prop, istate) => celsFromMask(prop, prop.celmasks[istate]),
} }
const BodyImpl = {
decode: decodeBody,
detailHref: (filename) => `body.html?f=${filename}`
}
const LimbImpl = { const LimbImpl = {
celsForAnimationState: (limb, istate) => { celsForAnimationState: (limb, istate) => {
const iframe = limb.frames[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) => { const linkDetail = (element, filename, impl) => {
return impl && impl.detailHref ? wrapLink(element, impl.detailHref(filename)) : element return impl && impl.detailHref ? wrapLink(element, impl.detailHref(filename)) : element
} }
const createAnimation = (animation, value, impl) => { const createAnimation = (animation, value, impl) => {
const frames = [] const frames = []
if (impl.generateFrames) {
impl.generateFrames(animation, value, frames)
} else {
for (let istate = animation.startState; istate <= animation.endState; istate ++) { for (let istate = animation.startState; istate <= animation.endState; istate ++) {
const frame = compositeCels(impl.celsForAnimationState(value, istate)) const frame = compositeCels(impl.celsForAnimationState(value, istate))
if (frame != null) { if (frame != null) {
frames.push(frame) frames.push(frame)
} }
} }
}
if (frames.length == 0) { if (frames.length == 0) {
return textNode("") return textNode("")
} else if (frames.length == 1) { } else if (frames.length == 1) {
@ -765,9 +818,7 @@ PropImpl.display = (prop, container) => {
} }
BodyImpl.display = (body, container) => { BodyImpl.display = (body, container) => {
for (const limb of body.limbs) { container.appendChild(linkDetail(createAnimation("walk", body, BodyImpl), body.filename, BodyImpl))
showCels(limb, container)
}
} }
const displayList = async (indexFile, containerId, impl) => { const displayList = async (indexFile, containerId, impl) => {