Implement avatar animations
This commit is contained in:
parent
d1fb2daa41
commit
208b7c3743
12
body.html
12
body.html
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
71
index.js
71
index.js
|
@ -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) => {
|
||||||
|
|
Loading…
Reference in a new issue