minecraft-renderer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/README.md +297 -0
  2. package/dist/index.html +83 -0
  3. package/dist/static/image/arrow.6f27b59f.png +0 -0
  4. package/dist/static/image/blocksAtlasLatest.7850afa3.png +0 -0
  5. package/dist/static/image/blocksAtlasLegacy.5c76823d.png +0 -0
  6. package/dist/static/image/itemsAtlasLatest.36036f95.png +0 -0
  7. package/dist/static/image/itemsAtlasLegacy.dcb1b58d.png +0 -0
  8. package/dist/static/image/tipped_arrow.6f27b59f.png +0 -0
  9. package/dist/static/js/365.f05233ab.js +8462 -0
  10. package/dist/static/js/365.f05233ab.js.LICENSE.txt +52 -0
  11. package/dist/static/js/async/738.efa27644.js +1 -0
  12. package/dist/static/js/index.092ec5be.js +56 -0
  13. package/dist/static/js/lib-polyfill.98986ac5.js +1 -0
  14. package/dist/static/js/lib-react.5c9129e0.js +2 -0
  15. package/dist/static/js/lib-react.5c9129e0.js.LICENSE.txt +39 -0
  16. package/package.json +104 -0
  17. package/src/assets/destroy_stage_0.png +0 -0
  18. package/src/assets/destroy_stage_1.png +0 -0
  19. package/src/assets/destroy_stage_2.png +0 -0
  20. package/src/assets/destroy_stage_3.png +0 -0
  21. package/src/assets/destroy_stage_4.png +0 -0
  22. package/src/assets/destroy_stage_5.png +0 -0
  23. package/src/assets/destroy_stage_6.png +0 -0
  24. package/src/assets/destroy_stage_7.png +0 -0
  25. package/src/assets/destroy_stage_8.png +0 -0
  26. package/src/assets/destroy_stage_9.png +0 -0
  27. package/src/examples/README.md +146 -0
  28. package/src/examples/appViewerExample.ts +205 -0
  29. package/src/examples/initialMenuStart.ts +161 -0
  30. package/src/graphicsBackend/appViewer.ts +297 -0
  31. package/src/graphicsBackend/config.ts +119 -0
  32. package/src/graphicsBackend/index.ts +10 -0
  33. package/src/graphicsBackend/playerState.ts +61 -0
  34. package/src/graphicsBackend/types.ts +143 -0
  35. package/src/index.ts +97 -0
  36. package/src/lib/DebugGui.ts +190 -0
  37. package/src/lib/animationController.ts +85 -0
  38. package/src/lib/buildSharedConfig.mjs +1 -0
  39. package/src/lib/cameraBobbing.ts +94 -0
  40. package/src/lib/canvas2DOverlay.example.ts +361 -0
  41. package/src/lib/canvas2DOverlay.quickstart.ts +242 -0
  42. package/src/lib/canvas2DOverlay.ts +381 -0
  43. package/src/lib/cleanupDecorator.ts +29 -0
  44. package/src/lib/createPlayerObject.ts +55 -0
  45. package/src/lib/frameTimingCollector.ts +164 -0
  46. package/src/lib/guiRenderer.ts +283 -0
  47. package/src/lib/items.ts +140 -0
  48. package/src/lib/mesherlogReader.ts +131 -0
  49. package/src/lib/moreBlockDataGenerated.json +714 -0
  50. package/src/lib/preflatMap.json +1741 -0
  51. package/src/lib/simpleUtils.ts +40 -0
  52. package/src/lib/smoothSwitcher.ts +168 -0
  53. package/src/lib/spiral.ts +29 -0
  54. package/src/lib/ui/newStats.ts +120 -0
  55. package/src/lib/utils/proxy.ts +23 -0
  56. package/src/lib/utils/skins.ts +63 -0
  57. package/src/lib/utils.ts +76 -0
  58. package/src/lib/workerProxy.ts +342 -0
  59. package/src/lib/worldrendererCommon.ts +1088 -0
  60. package/src/mesher/mesher.ts +253 -0
  61. package/src/mesher/models.ts +769 -0
  62. package/src/mesher/modelsGeometryCommon.ts +142 -0
  63. package/src/mesher/shared.ts +80 -0
  64. package/src/mesher/standaloneRenderer.ts +270 -0
  65. package/src/mesher/test/a.ts +3 -0
  66. package/src/mesher/test/mesherTester.ts +76 -0
  67. package/src/mesher/test/playground.ts +19 -0
  68. package/src/mesher/test/test-perf.ts +74 -0
  69. package/src/mesher/test/tests.test.ts +56 -0
  70. package/src/mesher/world.ts +294 -0
  71. package/src/mesher/worldConstants.ts +1 -0
  72. package/src/modules/index.ts +11 -0
  73. package/src/modules/starfield.ts +313 -0
  74. package/src/modules/types.ts +110 -0
  75. package/src/playerState/playerState.ts +78 -0
  76. package/src/playerState/types.ts +36 -0
  77. package/src/playground/allEntitiesDebug.ts +170 -0
  78. package/src/playground/baseScene.ts +587 -0
  79. package/src/playground/mobileControls.tsx +268 -0
  80. package/src/playground/playground.html +83 -0
  81. package/src/playground/playground.ts +11 -0
  82. package/src/playground/playgroundUi.tsx +140 -0
  83. package/src/playground/reactUtils.ts +71 -0
  84. package/src/playground/scenes/allEntities.ts +13 -0
  85. package/src/playground/scenes/entities.ts +37 -0
  86. package/src/playground/scenes/floorRandom.ts +33 -0
  87. package/src/playground/scenes/frequentUpdates.ts +148 -0
  88. package/src/playground/scenes/geometryExport.ts +142 -0
  89. package/src/playground/scenes/index.ts +12 -0
  90. package/src/playground/scenes/lightingStarfield.ts +40 -0
  91. package/src/playground/scenes/main.ts +313 -0
  92. package/src/playground/scenes/railsCobweb.ts +14 -0
  93. package/src/playground/scenes/rotationIssue.ts +7 -0
  94. package/src/playground/scenes/slabsOptimization.ts +16 -0
  95. package/src/playground/scenes/transparencyIssue.ts +11 -0
  96. package/src/playground/shared.ts +79 -0
  97. package/src/resourcesManager/index.ts +5 -0
  98. package/src/resourcesManager/resourcesManager.ts +314 -0
  99. package/src/shims/minecraftData.ts +41 -0
  100. package/src/sign-renderer/index.html +21 -0
  101. package/src/sign-renderer/index.ts +216 -0
  102. package/src/sign-renderer/noop.js +1 -0
  103. package/src/sign-renderer/playground.ts +38 -0
  104. package/src/sign-renderer/tests.test.ts +69 -0
  105. package/src/sign-renderer/vite.config.ts +10 -0
  106. package/src/three/appShared.ts +75 -0
  107. package/src/three/bannerRenderer.ts +275 -0
  108. package/src/three/cameraShake.ts +120 -0
  109. package/src/three/cinimaticScript.ts +350 -0
  110. package/src/three/documentRenderer.ts +491 -0
  111. package/src/three/entities.ts +1580 -0
  112. package/src/three/entity/EntityMesh.ts +707 -0
  113. package/src/three/entity/animations.js +171 -0
  114. package/src/three/entity/armorModels.json +204 -0
  115. package/src/three/entity/armorModels.ts +36 -0
  116. package/src/three/entity/entities.json +6230 -0
  117. package/src/three/entity/exportedModels.js +38 -0
  118. package/src/three/entity/externalTextures.json +1 -0
  119. package/src/three/entity/models/allay.obj +325 -0
  120. package/src/three/entity/models/arrow.obj +60 -0
  121. package/src/three/entity/models/axolotl.obj +509 -0
  122. package/src/three/entity/models/blaze.obj +601 -0
  123. package/src/three/entity/models/boat.obj +417 -0
  124. package/src/three/entity/models/camel.obj +1061 -0
  125. package/src/three/entity/models/cat.obj +509 -0
  126. package/src/three/entity/models/chicken.obj +371 -0
  127. package/src/three/entity/models/cod.obj +371 -0
  128. package/src/three/entity/models/creeper.obj +279 -0
  129. package/src/three/entity/models/dolphin.obj +371 -0
  130. package/src/three/entity/models/ender_dragon.obj +2993 -0
  131. package/src/three/entity/models/enderman.obj +325 -0
  132. package/src/three/entity/models/endermite.obj +187 -0
  133. package/src/three/entity/models/fox.obj +463 -0
  134. package/src/three/entity/models/frog.obj +739 -0
  135. package/src/three/entity/models/ghast.obj +463 -0
  136. package/src/three/entity/models/goat.obj +601 -0
  137. package/src/three/entity/models/guardian.obj +1015 -0
  138. package/src/three/entity/models/horse.obj +1061 -0
  139. package/src/three/entity/models/llama.obj +509 -0
  140. package/src/three/entity/models/minecart.obj +233 -0
  141. package/src/three/entity/models/parrot.obj +509 -0
  142. package/src/three/entity/models/piglin.obj +739 -0
  143. package/src/three/entity/models/pillager.obj +371 -0
  144. package/src/three/entity/models/rabbit.obj +555 -0
  145. package/src/three/entity/models/sheep.obj +555 -0
  146. package/src/three/entity/models/shulker.obj +141 -0
  147. package/src/three/entity/models/sniffer.obj +693 -0
  148. package/src/three/entity/models/spider.obj +509 -0
  149. package/src/three/entity/models/tadpole.obj +95 -0
  150. package/src/three/entity/models/turtle.obj +371 -0
  151. package/src/three/entity/models/vex.obj +325 -0
  152. package/src/three/entity/models/villager.obj +509 -0
  153. package/src/three/entity/models/warden.obj +463 -0
  154. package/src/three/entity/models/witch.obj +647 -0
  155. package/src/three/entity/models/wolf.obj +509 -0
  156. package/src/three/entity/models/zombie_villager.obj +463 -0
  157. package/src/three/entity/objModels.js +1 -0
  158. package/src/three/fireworks.ts +661 -0
  159. package/src/three/fireworksRenderer.ts +434 -0
  160. package/src/three/globals.d.ts +7 -0
  161. package/src/three/graphicsBackend.ts +274 -0
  162. package/src/three/graphicsBackendOffThread.ts +107 -0
  163. package/src/three/hand.ts +89 -0
  164. package/src/three/holdingBlock.ts +926 -0
  165. package/src/three/index.ts +20 -0
  166. package/src/three/itemMesh.ts +427 -0
  167. package/src/three/modules.d.ts +14 -0
  168. package/src/three/panorama.ts +308 -0
  169. package/src/three/panoramaShared.ts +1 -0
  170. package/src/three/renderSlot.ts +82 -0
  171. package/src/three/skyboxRenderer.ts +406 -0
  172. package/src/three/starField.ts +13 -0
  173. package/src/three/threeJsMedia.ts +731 -0
  174. package/src/three/threeJsMethods.ts +15 -0
  175. package/src/three/threeJsParticles.ts +160 -0
  176. package/src/three/threeJsSound.ts +95 -0
  177. package/src/three/threeJsUtils.ts +90 -0
  178. package/src/three/waypointSprite.ts +435 -0
  179. package/src/three/waypoints.ts +163 -0
  180. package/src/three/world/cursorBlock.ts +172 -0
  181. package/src/three/world/vr.ts +257 -0
  182. package/src/three/worldGeometryExport.ts +259 -0
  183. package/src/three/worldGeometryHandler.ts +279 -0
  184. package/src/three/worldRendererThree.ts +1381 -0
  185. package/src/worldView/index.ts +6 -0
  186. package/src/worldView/types.ts +66 -0
  187. package/src/worldView/worldView.ts +424 -0
package/src/index.ts ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Minecraft Renderer
3
+ *
4
+ * A modular Minecraft world renderer with Three.js WebGL backend.
5
+ *
6
+ * ## Quick Start
7
+ *
8
+ * ```typescript
9
+ * import { AppViewer, createGraphicsBackend } from 'minecraft-renderer'
10
+ * import { WorldView } from 'minecraft-renderer'
11
+ *
12
+ * // Create viewer
13
+ * const viewer = new AppViewer()
14
+ *
15
+ * // Load backend
16
+ * await viewer.loadBackend(createGraphicsBackend)
17
+ *
18
+ * // Start world
19
+ * await viewer.startWorld(world, renderDistance)
20
+ * ```
21
+ *
22
+ * ## Architecture
23
+ *
24
+ * The renderer is split into several modules:
25
+ *
26
+ * - **Core**: Types, configuration, player state, world view
27
+ * - **Three.js Backend**: WebGL rendering using Three.js
28
+ * - **Playground**: Testing and development environment
29
+ */
30
+
31
+ // ============================================================================
32
+ // Graphics Backend (Core)
33
+ // ============================================================================
34
+ export * from './graphicsBackend'
35
+
36
+ // ============================================================================
37
+ // World View
38
+ // ============================================================================
39
+ export {
40
+ WorldView,
41
+ WorldViewWorker,
42
+ chunkPos,
43
+ sectionPos,
44
+ generateSpiralMatrix,
45
+ delayedIterator
46
+ } from './worldView'
47
+ export type { WorldProvider } from './worldView'
48
+
49
+ // ============================================================================
50
+ // Player State
51
+ // ============================================================================
52
+ export {
53
+ getInitialPlayerState,
54
+ getPlayerStateUtils,
55
+ getInitialPlayerStateRenderer
56
+ } from './playerState/playerState'
57
+
58
+ // ============================================================================
59
+ // Resource Manager
60
+ // ============================================================================
61
+ export {
62
+ ResourcesManager,
63
+ LoadedResourcesTransferrable
64
+ } from './resourcesManager'
65
+
66
+ // ============================================================================
67
+ // Modules System
68
+ // ============================================================================
69
+ export * from './modules'
70
+
71
+ // ============================================================================
72
+ // Three.js Backend (re-exported for convenience)
73
+ // ============================================================================
74
+ export {
75
+ createGraphicsBackend,
76
+ createGraphicsBackendBase
77
+ } from './three/graphicsBackend'
78
+
79
+ export {
80
+ DocumentRenderer,
81
+ addCanvasForWorker,
82
+ isWebWorker
83
+ } from './three/documentRenderer'
84
+
85
+ // export {
86
+ // WorldGeometryHandler,
87
+ // estimateGeometryMemoryUsage,
88
+ // disposeObject
89
+ // } from './three/worldGeometryHandler'
90
+
91
+ export { StarField } from './three/starField'
92
+
93
+ // ============================================================================
94
+ // Examples (for reference and testing)
95
+ // ============================================================================
96
+ export { AppViewerExample, runExample } from './examples/appViewerExample'
97
+ export { appViewer, initialMenuStart, initialize } from './examples/initialMenuStart'
@@ -0,0 +1,190 @@
1
+ // eslint-disable-next-line import/no-named-as-default
2
+ import GUI from 'lil-gui'
3
+ import { isWebWorker } from '../three/documentRenderer'
4
+
5
+ export interface ParamMeta {
6
+ min?: number
7
+ max?: number
8
+ step?: number
9
+ }
10
+
11
+ export class DebugGui {
12
+ private gui: GUI | null = null
13
+ private readonly storageKey: string = ''
14
+ private target: any
15
+ private readonly params: string[] = []
16
+ private readonly paramsMeta: Record<string, ParamMeta> = {}
17
+ private _visible = false // Default to not visible
18
+ private readonly initialValues: Record<string, any> = {} // Store initial values
19
+ private initialized = false
20
+
21
+ constructor (id: string, target: any, params?: string[], paramsMeta?: Record<string, ParamMeta>) {
22
+ // If in web worker, don't initialize anything
23
+ if (isWebWorker) return
24
+
25
+ this.gui = new GUI()
26
+ this.storageKey = `debug_params_${id}`
27
+ this.target = target
28
+ this.paramsMeta = paramsMeta ?? {}
29
+ this.params = params ?? Object.keys(target)
30
+
31
+ // Store initial values
32
+ for (const param of this.params) {
33
+ this.initialValues[param] = target[param]
34
+ }
35
+
36
+ // Hide by default
37
+ this.gui.domElement.style.display = 'none'
38
+ }
39
+
40
+ // Initialize and show the GUI
41
+ activate () {
42
+ if (isWebWorker) return this
43
+
44
+ if (!this.initialized && this.gui) {
45
+ this.loadSavedValues()
46
+ this.setupControls()
47
+ this.initialized = true
48
+ }
49
+ this.show()
50
+ return this
51
+ }
52
+
53
+ // Getter for visibility
54
+ get visible (): boolean {
55
+ if (isWebWorker) return false
56
+ return this._visible
57
+ }
58
+
59
+ // Setter for visibility
60
+ set visible (value: boolean) {
61
+ if (isWebWorker || !this.gui) return
62
+ this._visible = value
63
+ this.gui.domElement.style.display = value ? 'block' : 'none'
64
+ this.saveVisibility()
65
+ }
66
+
67
+ private loadSavedValues () {
68
+ if (isWebWorker) return
69
+ try {
70
+ const saved = localStorage.getItem(this.storageKey)
71
+ if (saved) {
72
+ const values = JSON.parse(saved)
73
+ // Apply saved values to target
74
+ for (const param of this.params) {
75
+ if (param in values) {
76
+ const value = values[param]
77
+ if (value !== null) {
78
+ this.target[param] = value
79
+ }
80
+ }
81
+ }
82
+ }
83
+ } catch (e) {
84
+ console.warn('Failed to load debug values:', e)
85
+ }
86
+ }
87
+
88
+ private saveValues (deleteKey = false) {
89
+ if (isWebWorker) return
90
+ try {
91
+ const values = {}
92
+ for (const param of this.params) {
93
+ values[param] = this.target[param]
94
+ }
95
+ if (deleteKey) {
96
+ localStorage.removeItem(this.storageKey)
97
+ } else {
98
+ localStorage.setItem(this.storageKey, JSON.stringify(values))
99
+ }
100
+ } catch (e) {
101
+ console.warn('Failed to save debug values:', e)
102
+ }
103
+ }
104
+
105
+ private saveVisibility () {
106
+ if (isWebWorker) return
107
+ try {
108
+ localStorage.setItem(`${this.storageKey}_visible`, this._visible.toString())
109
+ } catch (e) {
110
+ console.warn('Failed to save debug visibility:', e)
111
+ }
112
+ }
113
+
114
+ private setupControls () {
115
+ if (isWebWorker || !this.gui) return
116
+
117
+ // Add visibility toggle at the top
118
+ this.gui.add(this, 'visible').name('Show Controls')
119
+ this.gui.add({ resetAll: () => {
120
+ if (!this.gui) return
121
+ for (const param of this.params) {
122
+ this.target[param] = this.initialValues[param]
123
+ }
124
+ this.saveValues(true)
125
+ this.gui.destroy()
126
+ this.gui = new GUI()
127
+ this.setupControls()
128
+ } }, 'resetAll').name('Reset All Parameters')
129
+
130
+ for (const param of this.params) {
131
+ const value = this.target[param]
132
+ const meta = this.paramsMeta[param] ?? {}
133
+
134
+ if (typeof value === 'number') {
135
+ // For numbers, use meta values or calculate reasonable defaults
136
+ const min = meta.min ?? value - Math.abs(value * 2)
137
+ const max = meta.max ?? value + Math.abs(value * 2)
138
+ const step = meta.step ?? Math.abs(value) / 100
139
+
140
+ this.gui.add(this.target, param, min, max, step)
141
+ .onChange(() => this.saveValues())
142
+ } else if (typeof value === 'boolean') {
143
+ // For booleans, create a checkbox
144
+ this.gui.add(this.target, param)
145
+ .onChange(() => this.saveValues())
146
+ } else if (typeof value === 'string' && ['x', 'y', 'z'].includes(param)) {
147
+ // Special case for xyz coordinates
148
+ const min = meta.min ?? -10
149
+ const max = meta.max ?? 10
150
+ const step = meta.step ?? 0.1
151
+
152
+ this.gui.add(this.target, param, min, max, step)
153
+ .onChange(() => this.saveValues())
154
+ } else if (Array.isArray(value)) {
155
+ // For arrays, create a dropdown
156
+ this.gui.add(this.target, param, value)
157
+ .onChange(() => this.saveValues())
158
+ }
159
+ }
160
+ }
161
+
162
+ // Method to manually trigger save
163
+ save () {
164
+ if (isWebWorker) return
165
+ this.saveValues()
166
+ this.saveVisibility()
167
+ }
168
+
169
+ // Method to destroy the GUI and clean up
170
+ destroy () {
171
+ if (isWebWorker || !this.gui) return
172
+ this.saveVisibility()
173
+ this.gui.destroy()
174
+ }
175
+
176
+ // Toggle visibility
177
+ toggle () {
178
+ this.visible = !this.visible
179
+ }
180
+
181
+ // Show the GUI
182
+ show () {
183
+ this.visible = true
184
+ }
185
+
186
+ // Hide the GUI
187
+ hide () {
188
+ this.visible = false
189
+ }
190
+ }
@@ -0,0 +1,85 @@
1
+ import * as tweenJs from '@tweenjs/tween.js'
2
+
3
+ export class AnimationController {
4
+ private currentAnimation: tweenJs.Group | null = null
5
+ private isAnimating = false
6
+ private cancelRequested = false
7
+ private completionCallbacks: Array<() => void> = []
8
+ private currentCancelCallback: (() => void) | null = null
9
+
10
+ /** Main method */
11
+ async startAnimation (createAnimation: () => tweenJs.Group, onCancelled?: () => void): Promise<void> {
12
+ if (this.isAnimating) {
13
+ await this.cancelCurrentAnimation()
14
+ }
15
+
16
+ return new Promise((resolve) => {
17
+ this.isAnimating = true
18
+ this.cancelRequested = false
19
+ this.currentCancelCallback = onCancelled ?? null
20
+ this.currentAnimation = createAnimation()
21
+
22
+ this.completionCallbacks.push(() => {
23
+ this.isAnimating = false
24
+ this.currentAnimation = null
25
+ resolve()
26
+ })
27
+ })
28
+ }
29
+
30
+ /** Main method */
31
+ async cancelCurrentAnimation (): Promise<void> {
32
+ if (!this.isAnimating) return
33
+
34
+ if (this.currentCancelCallback) {
35
+ const callback = this.currentCancelCallback
36
+ this.currentCancelCallback = null
37
+ callback()
38
+ }
39
+
40
+ return new Promise((resolve) => {
41
+ this.cancelRequested = true
42
+ this.completionCallbacks.push(() => {
43
+ resolve()
44
+ })
45
+ })
46
+ }
47
+
48
+ animationCycleFinish () {
49
+ if (this.cancelRequested) this.forceFinish()
50
+ }
51
+
52
+ forceFinish (callComplete = true) {
53
+ if (!this.isAnimating) return
54
+
55
+ if (this.currentAnimation) {
56
+ for (const tween of this.currentAnimation.getAll()) tween.stop()
57
+ this.currentAnimation.removeAll()
58
+ this.currentAnimation = null
59
+ }
60
+
61
+ this.isAnimating = false
62
+ this.cancelRequested = false
63
+
64
+ const callbacks = [...this.completionCallbacks]
65
+ this.completionCallbacks = []
66
+ if (callComplete) {
67
+ for (const cb of callbacks) cb()
68
+ }
69
+ }
70
+
71
+ /** Required method */
72
+ update () {
73
+ if (this.currentAnimation) {
74
+ this.currentAnimation.update()
75
+ }
76
+ }
77
+
78
+ get isActive () {
79
+ return this.isAnimating
80
+ }
81
+
82
+ get shouldCancel () {
83
+ return this.cancelRequested
84
+ }
85
+ }
@@ -0,0 +1 @@
1
+ export const dynamicMcDataFiles = ['blocks', 'blockCollisionShapes', 'biomes', 'version']
@@ -0,0 +1,94 @@
1
+ export class CameraBobbing {
2
+ private walkDistance = 0
3
+ private prevWalkDistance = 0
4
+ private bobAmount = 0
5
+ private prevBobAmount = 0
6
+ private readonly gameTimer = new GameTimer()
7
+
8
+ // eslint-disable-next-line max-params
9
+ constructor (
10
+ private readonly BOB_FREQUENCY: number = Math.PI, // How fast the bob cycles
11
+ private readonly BOB_BASE_AMPLITUDE: number = 0.5, // Base amplitude of the bob
12
+ private readonly VERTICAL_MULTIPLIER: number = 1, // Vertical movement multiplier
13
+ private readonly ROTATION_MULTIPLIER_Z: number = 3, // Roll rotation multiplier
14
+ private readonly ROTATION_MULTIPLIER_X: number = 5 // Pitch rotation multiplier
15
+ ) {}
16
+
17
+ // Call this when player is moving
18
+ public updateWalkDistance (distance: number): void {
19
+ this.prevWalkDistance = this.walkDistance
20
+ this.walkDistance = distance
21
+ }
22
+
23
+ // Call this when player is moving to update bob amount
24
+ public updateBobAmount (isMoving: boolean): void {
25
+ const targetBob = isMoving ? 1 : 0
26
+ this.prevBobAmount = this.bobAmount
27
+
28
+ // Update timing
29
+ const ticks = this.gameTimer.update()
30
+ const deltaTime = ticks / 20 // Convert ticks to seconds assuming 20 TPS
31
+
32
+ // Smooth transition for bob amount
33
+ const bobDelta = (targetBob - this.bobAmount) * Math.min(1, deltaTime * 10)
34
+ this.bobAmount += bobDelta
35
+ }
36
+
37
+ // Call this in your render/animation loop
38
+ public getBobbing (): { position: { x: number, y: number }, rotation: { x: number, z: number } } {
39
+ // Interpolate walk distance
40
+ const walkDist = this.prevWalkDistance +
41
+ (this.walkDistance - this.prevWalkDistance) * this.gameTimer.partialTick
42
+
43
+ // Interpolate bob amount
44
+ const bob = this.prevBobAmount +
45
+ (this.bobAmount - this.prevBobAmount) * this.gameTimer.partialTick
46
+
47
+ // Calculate total distance for bob cycle
48
+ const totalDist = -(walkDist * this.BOB_FREQUENCY)
49
+
50
+ // Calculate offsets
51
+ const xOffset = Math.sin(totalDist) * bob * this.BOB_BASE_AMPLITUDE
52
+ const yOffset = -Math.abs(Math.cos(totalDist) * bob) * this.VERTICAL_MULTIPLIER
53
+
54
+ // Calculate rotations (in radians)
55
+ const zRot = (Math.sin(totalDist) * bob * this.ROTATION_MULTIPLIER_Z) * (Math.PI / 180)
56
+ const xRot = (Math.abs(Math.cos(totalDist - 0.2) * bob) * this.ROTATION_MULTIPLIER_X) * (Math.PI / 180)
57
+
58
+ return {
59
+ position: { x: xOffset, y: yOffset },
60
+ rotation: { x: xRot, z: zRot }
61
+ }
62
+ }
63
+ }
64
+
65
+ class GameTimer {
66
+ private readonly msPerTick: number
67
+ private lastMs: number
68
+ public partialTick = 0
69
+
70
+ constructor (tickRate = 20) {
71
+ this.msPerTick = 1000 / tickRate
72
+ this.lastMs = performance.now()
73
+ }
74
+
75
+ update (): number {
76
+ const currentMs = performance.now()
77
+ const deltaSinceLastTick = currentMs - this.lastMs
78
+
79
+ // Calculate how much of a tick has passed
80
+ const tickDelta = deltaSinceLastTick / this.msPerTick
81
+ this.lastMs = currentMs
82
+
83
+ // Add to accumulated partial ticks
84
+ this.partialTick += tickDelta
85
+
86
+ // Get whole number of ticks that should occur
87
+ const wholeTicks = Math.floor(this.partialTick)
88
+
89
+ // Keep the remainder as the new partial tick
90
+ this.partialTick -= wholeTicks
91
+
92
+ return wholeTicks
93
+ }
94
+ }