Skip to content
This repository was archived by the owner on Mar 22, 2026. It is now read-only.

Commit 432f52a

Browse files
committed
重做动画系统
1 parent 07e2ffa commit 432f52a

File tree

25 files changed

+526
-396
lines changed

25 files changed

+526
-396
lines changed
Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package top.fifthlight.blazerod.model.animation
22

3-
data class Animation(
4-
val name: String? = null,
5-
val channels: List<AnimationChannel<*, *>>,
6-
)
3+
interface Animation {
4+
val name: String?
5+
val channels: List<AnimationChannel<*, *>>
6+
7+
val duration: Float?
8+
get() = null
9+
10+
fun createState(context: AnimationContext): AnimationState
11+
}

blazerod/model/model-base/src/main/kotlin/top/fifthlight/blazerod/model/animation/AnimationChannel.kt

Lines changed: 2 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -53,121 +53,6 @@ interface AnimationChannel<T : Any, D> : AnimationChannelComponentContainer {
5353
}
5454

5555
val type: Type<T, D>
56-
val data: D
57-
val duration: Float
58-
val interpolation: AnimationInterpolation
59-
val interpolator: AnimationInterpolator<T>
60-
fun getKeyFrameData(time: Float, result: T)
56+
val typeData: D
57+
fun getData(context: AnimationContext, state: AnimationState, result: T)
6158
}
62-
63-
data class SimpleAnimationChannel<T : Any, D>(
64-
override val type: AnimationChannel.Type<T, D>,
65-
override val data: D,
66-
private val components: List<AnimationChannelComponent<*, *>> = listOf(),
67-
val indexer: AnimationKeyFrameIndexer,
68-
override val interpolator: AnimationInterpolator<T>,
69-
val keyframeData: AnimationKeyFrameData<T>,
70-
override val interpolation: AnimationInterpolation,
71-
val defaultValue: () -> T,
72-
) : AnimationChannel<T, D> {
73-
init {
74-
require(interpolation.elements == keyframeData.elements) { "Bad elements of keyframe data: ${keyframeData.elements}" }
75-
}
76-
77-
override val duration: Float
78-
get() = indexer.lastTime
79-
80-
private val indexResult = AnimationKeyFrameIndexer.FindResult()
81-
private val startValues = List(interpolation.elements) { defaultValue() }
82-
private val endValues = List(interpolation.elements) { defaultValue() }
83-
84-
private val componentOfTypes = components.associateBy { it.type }
85-
86-
init {
87-
for (component in componentOfTypes.values) {
88-
component.onAttachToChannel(this)
89-
}
90-
}
91-
92-
@Suppress("UNCHECKED_CAST")
93-
override fun <T : AnimationChannelComponent.Type<C, T>, C> getComponent(type: T): C? =
94-
componentOfTypes[type] as C?
95-
96-
override fun getKeyFrameData(time: Float, result: T) {
97-
indexer.findKeyFrames(time, indexResult)
98-
if (indexResult.startFrame == indexResult.endFrame || indexResult.startTime > time || indexResult.endTime < time) {
99-
keyframeData.get(indexResult.startFrame, startValues)
100-
interpolator.set(startValues, result)
101-
return
102-
}
103-
val delta = (time - indexResult.startTime) / (indexResult.endTime - indexResult.startTime)
104-
keyframeData.get(indexResult.startFrame, startValues)
105-
keyframeData.get(indexResult.endFrame, endValues)
106-
interpolator.interpolate(
107-
delta = delta,
108-
startFrame = indexResult.startFrame,
109-
endFrame = indexResult.endFrame,
110-
type = interpolation,
111-
startValue = startValues,
112-
endValue = endValues,
113-
result = result,
114-
)
115-
}
116-
}
117-
118-
@JvmName("Vector3fSimpleAnimationChannel")
119-
fun <D> SimpleAnimationChannel(
120-
type: AnimationChannel.Type<Vector3f, D>,
121-
data: D,
122-
components: List<AnimationChannelComponent<*, *>> = listOf(),
123-
indexer: AnimationKeyFrameIndexer,
124-
keyframeData: AnimationKeyFrameData<Vector3f>,
125-
interpolation: AnimationInterpolation,
126-
): SimpleAnimationChannel<Vector3f, D> = SimpleAnimationChannel(
127-
type = type,
128-
data = data,
129-
components = components,
130-
indexer = indexer,
131-
interpolator = Vector3AnimationInterpolator,
132-
keyframeData = keyframeData,
133-
interpolation = interpolation,
134-
defaultValue = ::Vector3f,
135-
)
136-
137-
@JvmName("QuaternionfSimpleAnimationChannel")
138-
fun <D> SimpleAnimationChannel(
139-
type: AnimationChannel.Type<Quaternionf, D>,
140-
data: D,
141-
components: List<AnimationChannelComponent<*, *>> = listOf(),
142-
indexer: AnimationKeyFrameIndexer,
143-
keyframeData: AnimationKeyFrameData<Quaternionf>,
144-
interpolation: AnimationInterpolation,
145-
): SimpleAnimationChannel<Quaternionf, D> = SimpleAnimationChannel(
146-
type = type,
147-
data = data,
148-
components = components,
149-
indexer = indexer,
150-
interpolator = QuaternionAnimationInterpolator,
151-
keyframeData = keyframeData,
152-
interpolation = interpolation,
153-
defaultValue = ::Quaternionf,
154-
)
155-
156-
@JvmName("FloatSimpleAnimationChannel")
157-
fun <D> SimpleAnimationChannel(
158-
type: AnimationChannel.Type<MutableFloat, D>,
159-
data: D,
160-
components: List<AnimationChannelComponent<*, *>> = listOf(),
161-
indexer: AnimationKeyFrameIndexer,
162-
keyframeData: AnimationKeyFrameData<MutableFloat>,
163-
interpolation: AnimationInterpolation,
164-
): SimpleAnimationChannel<MutableFloat, D> = SimpleAnimationChannel(
165-
type = type,
166-
data = data,
167-
components = components,
168-
indexer = indexer,
169-
interpolator = FloatAnimationInterpolator,
170-
keyframeData = keyframeData,
171-
interpolation = interpolation,
172-
defaultValue = ::MutableFloat,
173-
)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package top.fifthlight.blazerod.model.animation
2+
3+
import top.fifthlight.blazerod.model.util.FloatWrapper
4+
import top.fifthlight.blazerod.model.util.IntWrapper
5+
6+
interface AnimationContext {
7+
companion object {
8+
const val SECONDS_PER_TICK = 1f / 20f
9+
}
10+
11+
interface Property<T> {
12+
object GameTick: Property<IntWrapper>
13+
object DeltaTick: Property<FloatWrapper>
14+
}
15+
16+
// game ticks
17+
fun getGameTick(): Long
18+
// 0 ~ 1
19+
fun getDeltaTick(): Float
20+
21+
fun <T> getProperty(type: Property<T>): T?
22+
23+
fun getPropertyTypes(): List<Property<*>>
24+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package top.fifthlight.blazerod.model.animation
2+
3+
interface AnimationState {
4+
fun updateTime(context: AnimationContext)
5+
6+
fun getTime(): Float
7+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package top.fifthlight.blazerod.model.animation
2+
3+
import org.joml.Quaternionf
4+
import org.joml.Vector3f
5+
import top.fifthlight.blazerod.model.util.MutableFloat
6+
7+
data class KeyFrameAnimationChannel<T : Any, D>(
8+
override val type: AnimationChannel.Type<T, D>,
9+
override val typeData: D,
10+
private val components: List<AnimationChannelComponent<*, *>> = listOf(),
11+
val indexer: AnimationKeyFrameIndexer,
12+
val interpolator: AnimationInterpolator<T>,
13+
val keyframeData: AnimationKeyFrameData<T>,
14+
val interpolation: AnimationInterpolation,
15+
val defaultValue: () -> T,
16+
) : AnimationChannel<T, D> {
17+
init {
18+
require(interpolation.elements == keyframeData.elements) { "Bad elements of keyframe data: ${keyframeData.elements}" }
19+
}
20+
21+
val duration: Float
22+
get() = indexer.lastTime
23+
24+
private val indexResult = AnimationKeyFrameIndexer.FindResult()
25+
private val startValues = List(interpolation.elements) { defaultValue() }
26+
private val endValues = List(interpolation.elements) { defaultValue() }
27+
28+
private val componentOfTypes = components.associateBy { it.type }
29+
30+
init {
31+
for (component in componentOfTypes.values) {
32+
component.onAttachToChannel(this)
33+
}
34+
}
35+
36+
@Suppress("UNCHECKED_CAST")
37+
override fun <T : AnimationChannelComponent.Type<C, T>, C> getComponent(type: T): C? =
38+
componentOfTypes[type] as C?
39+
40+
override fun getData(context: AnimationContext, state: AnimationState, result: T) {
41+
val time = state.getTime()
42+
indexer.findKeyFrames(time, indexResult)
43+
if (indexResult.startFrame == indexResult.endFrame || indexResult.startTime > time || indexResult.endTime < time) {
44+
keyframeData.get(indexResult.startFrame, startValues)
45+
interpolator.set(startValues, result)
46+
return
47+
}
48+
val delta = (time - indexResult.startTime) / (indexResult.endTime - indexResult.startTime)
49+
keyframeData.get(indexResult.startFrame, startValues)
50+
keyframeData.get(indexResult.endFrame, endValues)
51+
interpolator.interpolate(
52+
delta = delta,
53+
startFrame = indexResult.startFrame,
54+
endFrame = indexResult.endFrame,
55+
type = interpolation,
56+
startValue = startValues,
57+
endValue = endValues,
58+
result = result,
59+
)
60+
}
61+
}
62+
63+
@JvmName("Vector3fKeyFrameAnimationChannel")
64+
fun <D> KeyFrameAnimationChannel(
65+
type: AnimationChannel.Type<Vector3f, D>,
66+
data: D,
67+
components: List<AnimationChannelComponent<*, *>> = listOf(),
68+
indexer: AnimationKeyFrameIndexer,
69+
keyframeData: AnimationKeyFrameData<Vector3f>,
70+
interpolation: AnimationInterpolation,
71+
): KeyFrameAnimationChannel<Vector3f, D> = KeyFrameAnimationChannel(
72+
type = type,
73+
typeData = data,
74+
components = components,
75+
indexer = indexer,
76+
interpolator = Vector3AnimationInterpolator,
77+
keyframeData = keyframeData,
78+
interpolation = interpolation,
79+
defaultValue = ::Vector3f,
80+
)
81+
82+
@JvmName("QuaternionfKeyFrameAnimationChannel")
83+
fun <D> KeyFrameAnimationChannel(
84+
type: AnimationChannel.Type<Quaternionf, D>,
85+
data: D,
86+
components: List<AnimationChannelComponent<*, *>> = listOf(),
87+
indexer: AnimationKeyFrameIndexer,
88+
keyframeData: AnimationKeyFrameData<Quaternionf>,
89+
interpolation: AnimationInterpolation,
90+
): KeyFrameAnimationChannel<Quaternionf, D> = KeyFrameAnimationChannel(
91+
type = type,
92+
typeData = data,
93+
components = components,
94+
indexer = indexer,
95+
interpolator = QuaternionAnimationInterpolator,
96+
keyframeData = keyframeData,
97+
interpolation = interpolation,
98+
defaultValue = ::Quaternionf,
99+
)
100+
101+
@JvmName("FloatKeyFrameAnimationChannel")
102+
fun <D> KeyFrameAnimationChannel(
103+
type: AnimationChannel.Type<MutableFloat, D>,
104+
data: D,
105+
components: List<AnimationChannelComponent<*, *>> = listOf(),
106+
indexer: AnimationKeyFrameIndexer,
107+
keyframeData: AnimationKeyFrameData<MutableFloat>,
108+
interpolation: AnimationInterpolation,
109+
): KeyFrameAnimationChannel<MutableFloat, D> = KeyFrameAnimationChannel(
110+
type = type,
111+
typeData = data,
112+
components = components,
113+
indexer = indexer,
114+
interpolator = FloatAnimationInterpolator,
115+
keyframeData = keyframeData,
116+
interpolation = interpolation,
117+
defaultValue = ::MutableFloat,
118+
)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package top.fifthlight.blazerod.model.animation
2+
3+
data class SimpleAnimation(
4+
override val name: String? = null,
5+
override val channels: List<KeyFrameAnimationChannel<*, *>>,
6+
) : Animation {
7+
override val duration = channels.maxOf { it.duration }
8+
9+
override fun createState(context: AnimationContext) = SimpleAnimationState(context, duration)
10+
}

0 commit comments

Comments
 (0)