Prechádzať zdrojové kódy

Merge branch '4.1' into 4.2-beta

Harald Csaszar 2 rokov pred
rodič
commit
08b56ea1ca
51 zmenil súbory, kde vykonal 654 pridanie a 2149 odobranie
  1. 4 4
      .github/workflows/spine-godot-v4.yml
  2. 3 3
      .github/workflows/spine-godot.yml
  3. 7 8
      CMakeLists.txt
  4. 0 2
      examples/export/runtimes.sh
  5. 8 5
      examples/stretchyman/export/stretchyman-pma.atlas
  6. BIN
      examples/stretchyman/export/stretchyman-pma.png
  7. 4 4
      examples/stretchyman/export/stretchyman-pro.json
  8. BIN
      examples/stretchyman/export/stretchyman-pro.skel
  9. 8 5
      examples/stretchyman/export/stretchyman.atlas
  10. BIN
      examples/stretchyman/export/stretchyman.png
  11. BIN
      examples/stretchyman/stretchyman-pro.spine
  12. 23 15
      spine-c/spine-c/src/spine/SkeletonBinary.c
  13. 1 10
      spine-cpp/spine-cpp-unit-tests/CMakeLists.txt
  14. 1 1
      spine-godot/build/build-templates-v4.sh
  15. 1 1
      spine-godot/build/build-templates.sh
  16. 1 1
      spine-godot/build/build-v4.sh
  17. 1 1
      spine-godot/build/build.sh
  18. 1 1
      spine-godot/build/setup.sh
  19. 9 7
      spine-ts/index.html
  20. 1 1
      spine-ts/package.json
  21. 61 0
      spine-ts/spine-phaser/example/arcade-physics-example.html
  22. 0 61
      spine-ts/spine-phaser/example/arcade-physics-test.html
  23. 0 1285
      spine-ts/spine-phaser/example/assets/mix-and-match-pro.json
  24. 8 5
      spine-ts/spine-phaser/example/assets/stretchyman-pma.atlas
  25. BIN
      spine-ts/spine-phaser/example/assets/stretchyman-pma.png
  26. 0 512
      spine-ts/spine-phaser/example/assets/stretchyman-pro.json
  27. BIN
      spine-ts/spine-phaser/example/assets/stretchyman-pro.skel
  28. 22 24
      spine-ts/spine-phaser/example/basic-example.html
  29. 16 17
      spine-ts/spine-phaser/example/basic-vanilla-js-example.html
  30. 4 4
      spine-ts/spine-phaser/example/batching-test.html
  31. 5 5
      spine-ts/spine-phaser/example/blend-test.html
  32. 3 3
      spine-ts/spine-phaser/example/bounds-test.html
  33. 4 4
      spine-ts/spine-phaser/example/camera-pipeline-test.html
  34. 3 3
      spine-ts/spine-phaser/example/canvas-test.html
  35. 72 0
      spine-ts/spine-phaser/example/control-bones-example.html
  36. 0 72
      spine-ts/spine-phaser/example/control-bones-test.html
  37. 3 3
      spine-ts/spine-phaser/example/depth-test.html
  38. 70 0
      spine-ts/spine-phaser/example/events-example.html
  39. 4 4
      spine-ts/spine-phaser/example/extended-class-test.html
  40. 5 5
      spine-ts/spine-phaser/example/mix-and-match-example.html
  41. 4 4
      spine-ts/spine-phaser/example/multi-scene-test.html
  42. 4 4
      spine-ts/spine-phaser/example/render-to-texture-test.html
  43. 7 8
      spine-ts/spine-phaser/example/typescript/index.ts
  44. 4 4
      spine-ts/spine-phaser/example/visibility-test.html
  45. 48 4
      spine-ts/spine-phaser/src/SpineGameObject.ts
  46. 70 45
      spine-ts/spine-phaser/src/SpinePlugin.ts
  47. 6 0
      spine-ts/spine-phaser/src/index.ts
  48. 0 1
      spine-ts/spine-phaser/src/keys.ts
  49. 155 0
      spine-ts/spine-threejs/example/coordinate-transform.html
  50. 2 2
      spine-unity/Assets/Spine/Runtime/spine-unity/Components/RootMotion/SkeletonRootMotionBase.cs
  51. 1 1
      spine-unity/Assets/Spine/package.json

+ 4 - 4
.github/workflows/spine-godot-v4.yml

@@ -13,8 +13,8 @@ env:
   AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
   AWS_EC2_METADATA_DISABLED: true
   EM_VERSION: 3.1.18
-  GODOT_TAG: 4.0-stable
-  GODOT_VERSION: 4.0.stable
+  GODOT_TAG: 4.0.1-stable
+  GODOT_VERSION: 4.0.1.stable
 
 jobs:
 
@@ -41,7 +41,7 @@ jobs:
           path: spine-godot/godot/bin/godot.windows.editor.x86_64.exe
 
   godot-editor-linux:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     steps:
       - uses: actions/checkout@v3
         with:
@@ -135,7 +135,7 @@ jobs:
           path: spine-godot/godot/bin/macos.zip
 
   godot-template-linux:
-    runs-on: ubuntu-18.04
+    runs-on: ubuntu-20.04
     steps:
       - uses: actions/checkout@v3
         with:

+ 3 - 3
.github/workflows/spine-godot.yml

@@ -13,8 +13,8 @@ env:
   AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
   AWS_EC2_METADATA_DISABLED: true
   EM_VERSION: 3.1.14
-  GODOT_TAG: 3.5.1-stable
-  GODOT_VERSION: 3.5.1.stable
+  GODOT_TAG: 3.5.2-stable
+  GODOT_VERSION: 3.5.2.stable
 
 jobs:
 
@@ -132,7 +132,7 @@ jobs:
           path: spine-godot/godot/bin/osx.zip
 
   godot-template-linux:
-    runs-on: ubuntu-18.04
+    runs-on: ubuntu-20.04
     steps:
       - uses: actions/checkout@v3
         with:

+ 7 - 8
CMakeLists.txt

@@ -26,12 +26,10 @@ if((${SPINE_SFML}) OR (${CMAKE_CURRENT_BINARY_DIR} MATCHES "spine-sfml"))
 		set(ONLY_ACTIVE_ARCH NO)
 	endif()
 	add_subdirectory(spine-c)
-	add_subdirectory(spine-sfml/c)
 	add_subdirectory(spine-cpp)
+	add_subdirectory(spine-sfml/c)
 	add_subdirectory(spine-sfml/cpp)
-endif()
-
-if((${SPINE_SDL}) OR (${CMAKE_CURRENT_BINARY_DIR} MATCHES "spine-sdl"))
+elseif((${SPINE_SDL}) OR (${CMAKE_CURRENT_BINARY_DIR} MATCHES "spine-sdl"))
 	if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
 		set(CMAKE_OSX_ARCHITECTURES x86_64;arm64)
 		set(ONLY_ACTIVE_ARCH NO)
@@ -39,7 +37,8 @@ if((${SPINE_SDL}) OR (${CMAKE_CURRENT_BINARY_DIR} MATCHES "spine-sdl"))
 	add_subdirectory(spine-c)
 	add_subdirectory(spine-cpp)
 	add_subdirectory(spine-sdl)
-endif()
-
-# add_subdirectory(spine-c/spine-c-unit-tests)
-add_subdirectory(spine-cpp/spine-cpp-unit-tests)
+else()
+	add_subdirectory(spine-c)
+	add_subdirectory(spine-cpp)
+	add_subdirectory(spine-cpp/spine-cpp-unit-tests)
+endif()

+ 0 - 2
examples/export/runtimes.sh

@@ -374,12 +374,10 @@ cp -f ../coin/export/coin-pro.skel "$ROOT/spine-ts/spine-phaser/example/assets/"
 cp -f ../coin/export/coin-pma.atlas "$ROOT/spine-ts/spine-phaser/example/assets/"
 cp -f ../coin/export/coin-pma.png "$ROOT/spine-ts/spine-phaser/example/assets/"
 
-cp -f ../stretchyman/export/stretchyman-pro.json "$ROOT/spine-ts/spine-phaser/example/assets/"
 cp -f ../stretchyman/export/stretchyman-pro.skel "$ROOT/spine-ts/spine-phaser/example/assets/"
 cp -f ../stretchyman/export/stretchyman-pma.atlas "$ROOT/spine-ts/spine-phaser/example/assets/"
 cp -f ../stretchyman/export/stretchyman-pma.png "$ROOT/spine-ts/spine-phaser/example/assets/"
 
-cp -f ../mix-and-match/export/mix-and-match-pro.json "$ROOT/spine-ts/spine-phaser/example/assets/"
 cp -f ../mix-and-match/export/mix-and-match-pro.skel "$ROOT/spine-ts/spine-phaser/example/assets/"
 cp -f ../mix-and-match/export/mix-and-match-pma.atlas "$ROOT/spine-ts/spine-phaser/example/assets/"
 cp -f ../mix-and-match/export/mix-and-match-pma.png "$ROOT/spine-ts/spine-phaser/example/assets/"

+ 8 - 5
examples/stretchyman/export/stretchyman-pma.atlas

@@ -3,14 +3,17 @@ stretchyman-pma.png
 	filter: Linear, Linear
 	pma: true
 back-arm
-	bounds: 149, 45, 72, 202
+	bounds: 679, 173, 72, 202
+	rotate: 90
 back-leg
-	bounds: 312, 4, 100, 318
+	bounds: 2, 2, 100, 318
 	rotate: 90
 body
-	bounds: 223, 106, 141, 452
+	bounds: 2, 104, 141, 452
 	rotate: 90
 front-arm
-	bounds: 2, 26, 145, 221
+	bounds: 456, 100, 145, 221
+	rotate: 90
 head
-	bounds: 223, 2, 87, 102
+	bounds: 322, 15, 87, 102
+	rotate: 90

BIN
examples/stretchyman/export/stretchyman-pma.png


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 4 - 4
examples/stretchyman/export/stretchyman-pro.json


BIN
examples/stretchyman/export/stretchyman-pro.skel


+ 8 - 5
examples/stretchyman/export/stretchyman.atlas

@@ -2,14 +2,17 @@ stretchyman.png
 	size: 1024, 256
 	filter: Linear, Linear
 back-arm
-	bounds: 149, 45, 72, 202
+	bounds: 679, 173, 72, 202
+	rotate: 90
 back-leg
-	bounds: 312, 4, 100, 318
+	bounds: 2, 2, 100, 318
 	rotate: 90
 body
-	bounds: 223, 106, 141, 452
+	bounds: 2, 104, 141, 452
 	rotate: 90
 front-arm
-	bounds: 2, 26, 145, 221
+	bounds: 456, 100, 145, 221
+	rotate: 90
 head
-	bounds: 223, 2, 87, 102
+	bounds: 322, 15, 87, 102
+	rotate: 90

BIN
examples/stretchyman/export/stretchyman.png


BIN
examples/stretchyman/stretchyman-pro.spine


+ 23 - 15
spine-c/spine-c/src/spine/SkeletonBinary.c

@@ -114,7 +114,7 @@ static int readInt(_dataInput *input) {
 
 static int readVarint(_dataInput *input, int /*bool*/ optimizePositive) {
 	unsigned char b = readByte(input);
-	uint32_t value = b & 0x7F;
+	int32_t value = b & 0x7F;
 	if (b & 0x80) {
 		b = readByte(input);
 		value |= (b & 0x7F) << 7;
@@ -124,13 +124,12 @@ static int readVarint(_dataInput *input, int /*bool*/ optimizePositive) {
 			if (b & 0x80) {
 				b = readByte(input);
 				value |= (b & 0x7F) << 21;
-				if (b & 0x80) value |= (uint32_t) (readByte(input) & 0x7F) << 28;
+				if (b & 0x80) value |= (readByte(input) & 0x7F) << 28;
 			}
 		}
 	}
-	if (!optimizePositive)
-		value = ((unsigned int) value >> 1) ^ (~(value & 1));
-	return (int) value;
+	if (!optimizePositive) value = (((unsigned int) value >> 1) ^ -(value & 1));
+	return value;
 }
 
 float readFloat(_dataInput *input) {
@@ -1031,9 +1030,10 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput
 			{
 				spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name,
 																			   path, sequence);
+				spRegionAttachment *region = NULL;
 				if (!attachment)
 					return NULL;
-				spRegionAttachment *region = SUB_CAST(spRegionAttachment, attachment);
+				region = SUB_CAST(spRegionAttachment, attachment);
 				region->path = path;
 				region->rotation = rotation;
 				region->x = x;
@@ -1053,9 +1053,10 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput
 			int vertexCount = readVarint(input, 1);
 			spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0,
 																		   NULL);
+			spVertexAttachment *vertexAttachment = NULL;
 			if (!attachment)
 				return NULL;
-			spVertexAttachment *vertexAttachment = SUB_CAST(spVertexAttachment, attachment);
+			vertexAttachment = SUB_CAST(spVertexAttachment, attachment);
 			_readVertices(self, input, &vertexAttachment->bonesCount, &vertexAttachment->bones,
 						  &vertexAttachment->verticesCount, &vertexAttachment->vertices,
 						  &vertexAttachment->worldVerticesLength, vertexCount);
@@ -1106,9 +1107,10 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput
 
 			{
 				spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path, sequence);
+				spMeshAttachment *mesh = NULL;
 				if (!attachment)
 					return NULL;
-				spMeshAttachment *mesh = SUB_CAST(spMeshAttachment, attachment);
+				mesh = SUB_CAST(spMeshAttachment, attachment);
 				mesh->path = path;
 				spColor_setFromColor(&mesh->color, &color);
 				mesh->regionUVs = regionUVs;
@@ -1157,9 +1159,10 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput
 
 			{
 				spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path, sequence);
+				spMeshAttachment *mesh = NULL;
 				if (!attachment)
 					return NULL;
-				spMeshAttachment *mesh = SUB_CAST(spMeshAttachment, attachment);
+				mesh = SUB_CAST(spMeshAttachment, attachment);
 				mesh->path = path;
 				spColor_setFromColor(&mesh->color, &color);
 				mesh->sequence = sequence;
@@ -1172,11 +1175,13 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput
 		case SP_ATTACHMENT_PATH: {
 			spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0,
 																		   NULL);
+			spPathAttachment *path = NULL;
+			spVertexAttachment *vertexAttachment = NULL;
+			int vertexCount = 0;
 			if (!attachment)
 				return NULL;
-			spPathAttachment *path = SUB_CAST(spPathAttachment, attachment);
-			spVertexAttachment *vertexAttachment = SUPER(path);
-			int vertexCount = 0;
+			path = SUB_CAST(spPathAttachment, attachment);
+			vertexAttachment = SUPER(path);
 			path->closed = readBoolean(input);
 			path->constantSpeed = readBoolean(input);
 			vertexCount = readVarint(input, 1);
@@ -1197,9 +1202,10 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput
 		case SP_ATTACHMENT_POINT: {
 			spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0,
 																		   NULL);
+			spPointAttachment *point = NULL;
 			if (!attachment)
 				return NULL;
-			spPointAttachment *point = SUB_CAST(spPointAttachment, attachment);
+			point = SUB_CAST(spPointAttachment, attachment);
 			point->rotation = readFloat(input);
 			point->x = readFloat(input) * self->scale;
 			point->y = readFloat(input) * self->scale;
@@ -1215,10 +1221,12 @@ spAttachment *spSkeletonBinary_readAttachment(spSkeletonBinary *self, _dataInput
 			int vertexCount = readVarint(input, 1);
 			spAttachment *attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, 0,
 																		   NULL);
+			spClippingAttachment *clip = NULL;
+			spVertexAttachment *vertexAttachment = NULL;
 			if (!attachment)
 				return NULL;
-			spClippingAttachment *clip = SUB_CAST(spClippingAttachment, attachment);
-			spVertexAttachment *vertexAttachment = SUPER(clip);
+			clip = SUB_CAST(spClippingAttachment, attachment);
+			vertexAttachment = SUPER(clip);
 			_readVertices(self, input, &vertexAttachment->bonesCount, &vertexAttachment->bones,
 						  &vertexAttachment->verticesCount, &vertexAttachment->vertices,
 						  &vertexAttachment->worldVerticesLength, vertexCount);

+ 1 - 10
spine-cpp/spine-cpp-unit-tests/CMakeLists.txt

@@ -1,18 +1,9 @@
 project(spine_cpp_unit_test)
 
-set(CMAKE_INSTALL_PREFIX "./")
-set(CMAKE_VERBOSE_MAKEFILE ON)
-
-include_directories(../spine-cpp/include teamcity minicppunit tests memory)
-
-set(SRC
-        src/main.cpp
-        )
-
+set(SRC src/main.cpp)
 add_executable(spine_cpp_unit_test ${SRC})
 target_link_libraries(spine_cpp_unit_test spine-cpp)
 
-
 #########################################################
 # copy resources to build output directory
 #########################################################

+ 1 - 1
spine-godot/build/build-templates-v4.sh

@@ -2,7 +2,7 @@
 set -e
 
 dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
-pushd $dir > /dev/null
+pushd "$dir" > /dev/null
 
 if [ ! "$#" -eq 1 ]; then
 	echo "Usage: ./build-templates.sh <platform>"

+ 1 - 1
spine-godot/build/build-templates.sh

@@ -2,7 +2,7 @@
 set -e
 
 dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
-pushd $dir > /dev/null
+pushd "$dir" > /dev/null
 
 if [ ! "$#" -eq 1 ]; then
 	echo "Usage: ./build-templates.sh <platform>"

+ 1 - 1
spine-godot/build/build-v4.sh

@@ -2,7 +2,7 @@
 set -e
 
 dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
-pushd $dir > /dev/null
+pushd "$dir" > /dev/null
 
 if [ ! -d ../godot ]; then
 	echo "No Godot clone found. Run ./setup.sh <Godot branch or tag> <dev> first."

+ 1 - 1
spine-godot/build/build.sh

@@ -2,7 +2,7 @@
 set -e
 
 dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
-pushd $dir > /dev/null
+pushd "$dir" > /dev/null
 
 if [ ! "$#" -eq 1 ]; then
 	echo "Usage: ./build.sh <target>"

+ 1 - 1
spine-godot/build/setup.sh

@@ -2,7 +2,7 @@
 set -e
 
 dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
-pushd $dir > /dev/null
+pushd "$dir" > /dev/null
 
 if [ ! "$#" -eq 2 ]; then
 	echo "Usage: ./setup.sh <Godot branch or tag> <dev:true|false>"

+ 9 - 7
spine-ts/index.html

@@ -19,19 +19,20 @@
 		<li>Phaser</li>
 		<ul>
 			<li><a href="/spine-phaser/example/basic-example.html">Basic example</a></li>
+			<li><a href="/spine-phaser/example/events-example.html">Events example</a></li>
+			<li><a href="/spine-phaser/example/mix-and-match-example.html">Mix and match example</a></li>
+			<li><a href="/spine-phaser/example/arcade-physics-example.html">Arcade physics example</a></li>
+			<li><a href="/spine-phaser/example/control-bones-example.html">Control bones example</a></li>
 			<li><a href="/spine-phaser/example/batching-test.html">Batching test</a></li>
 			<li><a href="/spine-phaser/example/multi-scene-test.html">Multi-scene test</a></li>
 			<li><a href="/spine-phaser/example/bounds-test.html">Bounds test</a></li>
-			<li><a href="/spine-phaser/example/visibility-test.html">Visibility test</a></li>
-			<li><a href="/spine-phaser/example/arcade-physics-test.html">Arcade physics example</a></li>
+			<li><a href="/spine-phaser/example/visibility-test.html">Visibility test</a></li>			
 			<li><a href="/spine-phaser/example/blend-test.html">Blend test</a></li>
-			<li><a href="/spine-phaser/example/camera-pipeline-test.html">Camera pipeline test</a></li>
-			<li><a href="/spine-phaser/example/control-bones-test.html">Control bones</a></li>
+			<li><a href="/spine-phaser/example/camera-pipeline-test.html">Camera pipeline test</a></li>			
 			<li><a href="/spine-phaser/example/extended-class-test.html">Extended class</a></li>
 			<li><a href="/spine-phaser/example/canvas-test.html">Canvas test</a></li>
-			<li><a href="/spine-phaser/example/depth-test.html">Depth test</a></li>
-			<li><a href="/spine-phaser/example/render-to-texture-test.html">Render to texture test</a></li>
-			<li><a href="/spine-phaser/example/mix-and-match.html">Mix and match</a></li>
+			<li><a href="/spine-phaser/example/depth-test.html">Depth test</a></li>			
+			<li><a href="/spine-phaser/example/render-to-texture-test.html">Render to texture test</a></li>			
 		</ul>
 		<li>Player</li>
 		<ul>
@@ -65,6 +66,7 @@
 		<li>THREE.JS</li>
 		<ul>
 			<li><a href="/spine-threejs/example/index.html">Example</a></li>
+			<li><a href="/spine-threejs/example/coordinate-transform.html">Coordinate transform</a></li>
 		</ul>
 	</ul>
 </body>

+ 1 - 1
spine-ts/package.json

@@ -18,7 +18,7 @@
     "build:phaser": "npx esbuild  --bundle spine-phaser/src/index.ts  --tsconfig=spine-phaser/tsconfig.json   --sourcemap --outfile=spine-phaser/dist/iife/spine-phaser.js   --external:Phaser --alias:phaser=Phaser --format=iife --global-name=spine",
     "build:threejs": "npx esbuild --bundle spine-threejs/src/index.ts --tsconfig=spine-threejs/tsconfig.json  --sourcemap --outfile=spine-threejs/dist/iife/spine-threejs.js --external:three --format=iife --global-name=spine",
     "minify": "npx esbuild --minify spine-core/dist/iife/spine-core.js --outfile=spine-core/dist/iife/spine-core.min.js && npx esbuild --minify spine-canvas/dist/iife/spine-canvas.js --outfile=spine-canvas/dist/iife/spine-canvas.min.js && npx esbuild --minify spine-player/dist/iife/spine-player.js --outfile=spine-player/dist/iife/spine-player.min.js && npx esbuild --minify spine-phaser/dist/iife/spine-phaser.js --outfile=spine-phaser/dist/iife/spine-phaser.min.js && npx esbuild --minify spine-webgl/dist/iife/spine-webgl.js --outfile=spine-webgl/dist/iife/spine-webgl.min.js && npx esbuild --minify spine-threejs/dist/iife/spine-threejs.js --outfile=spine-threejs/dist/iife/spine-threejs.min.js",
-    "dev": "concurrently \"npx live-server --no-browser\" \"npm run dev:canvas\" \"npm run dev:webgl\" \"npm run dev:phaser\" \"npm run dev:player\" \"npm run dev:threejs\"",
+    "dev": "concurrently \"npx live-server\" \"npm run dev:canvas\" \"npm run dev:webgl\" \"npm run dev:phaser\" \"npm run dev:player\" \"npm run dev:threejs\"",
     "dev:modules": "npm run build:modules -- --watch",
     "dev:canvas": "npm run build:canvas -- --watch",
     "dev:webgl": "npm run build:webgl -- --watch",

+ 61 - 0
spine-ts/spine-phaser/example/arcade-physics-example.html

@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>
+    <script src="../dist/iife/spine-phaser.js"></script>
+    <title>Spine Phaser Example</title>
+</head>
+
+<body>
+    <h1>Arcade Physics example</h1>
+</body>
+<script>
+    class PhysicsExample extends Phaser.Scene {
+        preload() {
+            this.load.spineBinary("coin-data", "assets/coin-pro.skel");
+            this.load.spineAtlas("coin-atlas", "assets/coin-pma.atlas");
+        }
+
+        create() {
+            const coin = this.add.spine(400, 200, 'coin-data', "coin-atlas");
+            coin.animationState.setAnimation(0, "animation", true);
+            coin.setScale(0.3);
+            coin.setSize(280, 280);
+
+            this.physics.add.existing(coin);
+
+            coin.body.setOffset(0, 50);
+            coin.body.setVelocity(100, 200);
+            coin.body.setBounce(1, 1);
+            coin.body.setCollideWorldBounds(true);
+        }
+    }
+
+    const config = {
+        type: Phaser.AUTO,
+        width: 800,
+        height: 600,
+        type: Phaser.WEBGL,
+        physics: {
+            default: 'arcade',
+            arcade: {
+                debug: true,
+                gravity: { y: 200 }
+            }
+        },
+        scene: [PhysicsExample],
+        plugins: {
+            scene: [
+                { key: "spine.SpinePlugin", plugin: spine.SpinePlugin, mapping: "spine" }
+            ]
+        }
+    };
+
+    const game = new Phaser.Game(config);
+</script>
+
+</html>

+ 0 - 61
spine-ts/spine-phaser/example/arcade-physics-test.html

@@ -1,61 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-
-<head>
-    <meta charset="UTF-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>
-    <title>Spine Phaser Example</title>
-</head>
-
-<body>
-    <h1>Arcade Physics example</h1>
-</body>
-<script>
-    var config = {
-        type: Phaser.AUTO,
-        width: 800,
-        height: 600,
-        type: Phaser.WEBGL,
-        physics: {
-            default: 'arcade',
-            arcade: {
-                debug: true,
-                gravity: { y: 200 }
-            }
-        },
-        scene: {
-            preload: preload,
-            create: create,
-            pack: {
-                files: [
-                    { type: "scenePlugin", key: "spine.SpinePlugin", url: "../dist/iife/spine-phaser.js", sceneKey: "spine" }
-                ]
-            }
-        }
-    };
-
-    let game = new Phaser.Game(config);
-
-    function preload() {
-        this.load.spineBinary("coin-data", "assets/coin-pro.skel");
-        this.load.spineAtlas("coin-atlas", "assets/coin-pma.atlas");
-    }
-
-    function create() {
-        let coin = this.add.spine(400, 200, 'coin-data', "coin-atlas");
-        coin.animationState.setAnimation(0, "animation", true);
-        coin.setScale(0.3);
-        coin.setSize(280, 280);
-
-        this.physics.add.existing(coin);
-
-        coin.body.setOffset(0, 50);
-        coin.body.setVelocity(100, 200);
-        coin.body.setBounce(1, 1);
-        coin.body.setCollideWorldBounds(true);
-    }
-</script>
-
-</html>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 1285
spine-ts/spine-phaser/example/assets/mix-and-match-pro.json


+ 8 - 5
spine-ts/spine-phaser/example/assets/stretchyman-pma.atlas

@@ -3,14 +3,17 @@ stretchyman-pma.png
 	filter: Linear, Linear
 	pma: true
 back-arm
-	bounds: 149, 45, 72, 202
+	bounds: 679, 173, 72, 202
+	rotate: 90
 back-leg
-	bounds: 312, 4, 100, 318
+	bounds: 2, 2, 100, 318
 	rotate: 90
 body
-	bounds: 223, 106, 141, 452
+	bounds: 2, 104, 141, 452
 	rotate: 90
 front-arm
-	bounds: 2, 26, 145, 221
+	bounds: 456, 100, 145, 221
+	rotate: 90
 head
-	bounds: 223, 2, 87, 102
+	bounds: 322, 15, 87, 102
+	rotate: 90

BIN
spine-ts/spine-phaser/example/assets/stretchyman-pma.png


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 512
spine-ts/spine-phaser/example/assets/stretchyman-pro.json


BIN
spine-ts/spine-phaser/example/assets/stretchyman-pro.skel


+ 22 - 24
spine-ts/spine-phaser/example/basic-example.html

@@ -6,6 +6,7 @@
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>
+    <script src="../dist/iife/spine-phaser.js"></script>
     <title>Spine Phaser Example</title>
 </head>
 
@@ -13,34 +14,31 @@
     <h1>Basic example</h1>
 </body>
 <script>
-    var config = {
-        type: Phaser.AUTO,
+    class BasicExample extends Phaser.Scene {
+        preload() {
+            this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
+            this.load.spineAtlas("spineboy-atlas", "assets/spineboy-pma.atlas");
+        }
+
+        create() {
+            const spineboy = this.add.spine(400, 500, 'spineboy-data', "spineboy-atlas");
+            spineboy.scale = 0.5;
+            spineboy.animationState.setAnimation(0, "walk", true);
+        }
+    }
+    
+    new Phaser.Game({
+        type: Phaser.AUTO,        
         width: 800,
         height: 600,
         type: Phaser.WEBGL,
-        scene: {
-            preload: preload,
-            create: create,
-            pack: {
-                files: [
-                    { type: "scenePlugin", key: "spine.SpinePlugin", url: "../dist/iife/spine-phaser.js", sceneKey: "spine" }
-                ]
-            }
+        scene: [BasicExample],
+        plugins: {
+            scene: [
+                { key: "spine.SpinePlugin", plugin: spine.SpinePlugin, mapping: "spine" }
+            ]
         }
-    };
-
-    let game = new Phaser.Game(config);
-
-    function preload() {
-        this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
-        this.load.spineAtlas("spineboy-atlas", "assets/spineboy-pma.atlas");
-    }
-
-    function create() {
-        let spineboy = this.add.spine(400, 500, 'spineboy-data', "spineboy-atlas");
-        spineboy.scale = 0.5;
-        spineboy.animationState.setAnimation(0, "walk", true);
-    }
+    });
 </script>
 
 </html>

+ 16 - 17
spine-ts/spine-phaser/example/basic-vanilla-js-example.html

@@ -14,15 +14,25 @@
     <h1>Basic example</h1>
 </body>
 <script>
-    var config = {
+    class BasicExample extends Phaser.Scene {
+        preload() {
+            this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
+            this.load.spineAtlas("spineboy-atlas", "assets/spineboy-pma.atlas");
+        }
+
+        create() {
+            const spineboy = this.add.spine(400, 500, 'spineboy-data', "spineboy-atlas");
+            spineboy.scale = 0.5;
+            spineboy.animationState.setAnimation(0, "walk", true);
+        }
+    }
+
+    const config = {
         type: Phaser.AUTO,
         width: 800,
         height: 600,
         type: Phaser.WEBGL,
-        scene: {
-            preload: preload,
-            create: create,
-        },
+        scene: [BasicExample],
         plugins: {
             scene: [
                 { key: "spine.SpinePlugin", plugin: spine.SpinePlugin, mapping: "spine" }
@@ -30,18 +40,7 @@
         }
     };
 
-    let game = new Phaser.Game(config);
-
-    function preload() {
-        this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
-        this.load.spineAtlas("spineboy-atlas", "assets/spineboy-pma.atlas");
-    }
-
-    function create() {
-        let spineboy = this.add.spine(400, 500, 'spineboy-data', "spineboy-atlas");
-        spineboy.scale = 0.5;
-        spineboy.animationState.setAnimation(0, "walk", true);
-    }
+    const game = new Phaser.Game(config);
 </script>
 
 </html>

+ 4 - 4
spine-ts/spine-phaser/example/batching-test.html

@@ -13,7 +13,7 @@
     <h1>Batching test</h1>
 </body>
 <script>
-    var config = {
+    const config = {
         type: Phaser.AUTO,
         width: 800,
         height: 600,
@@ -30,7 +30,7 @@
         }
     };
 
-    let game = new Phaser.Game(config);
+    const game = new Phaser.Game(config);
     let debug;
 
     function preload() {
@@ -41,12 +41,12 @@
     }
 
     function create() {
-        let plugin = this.spine;
+        const plugin = this.spine;
         let x = 25;
         let y = 60;
         for (let j = 0; j < 10; j++, y += 600 / 10) {
             for (let i = 0; i < 20; i++, x += 800 / 20) {
-                let obj = Math.random() > 0.5
+                const obj = Math.random() > 0.5
                     ? this.add.spine(x, y, 'spineboy-data', "spineboy-atlas")
                     : this.add.spine(x, y, 'raptor-data', "raptor-atlas");
                 obj.animationState.setAnimation(0, "walk", true);

+ 5 - 5
spine-ts/spine-phaser/example/blend-test.html

@@ -13,7 +13,7 @@
     <h1>Blend test</h1>
 </body>
 <script>
-    var config = {
+    const config = {
         type: Phaser.AUTO,
         width: 800,
         height: 600,
@@ -32,7 +32,7 @@
     };
 
     let controls;
-    let game = new Phaser.Game(config);
+    const game = new Phaser.Game(config);
 
     function preload() {
         this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
@@ -41,14 +41,14 @@
 
     function create() {
         for (var i = 0; i < 4; i++) {
-            let obj = this.add.spine(i * 200, 600, 'spineboy-data', 'spineboy-atlas').setScale(0.25);
+            const obj = this.add.spine(i * 200, 600, 'spineboy-data', 'spineboy-atlas').setScale(0.25);
             obj.setScale(0.25);
             obj.animationState.setAnimation(0, "idle", true);
             obj.animationState.setAnimation(1, "shoot", true);
         }
-        var cursors = this.input.keyboard.createCursorKeys();
+        const cursors = this.input.keyboard.createCursorKeys();
 
-        var controlConfig = {
+        const controlConfig = {
             camera: this.cameras.main,
             left: cursors.left,
             right: cursors.right,

+ 3 - 3
spine-ts/spine-phaser/example/bounds-test.html

@@ -13,7 +13,7 @@
     <h1>Bounds test</h1>
 </body>
 <script>
-    var config = {
+    const config = {
         type: Phaser.AUTO,
         width: 800,
         height: 600,
@@ -30,7 +30,7 @@
         }
     };
 
-    let game = new Phaser.Game(config);
+    const game = new Phaser.Game(config);
     let spineboy;
 
     function preload() {
@@ -49,7 +49,7 @@
     let time = 0;
     function update(t, delta) {
         time += delta / 1000;
-        let scale = 0.4 + Math.cos(time) * 0.2;
+        const scale = 0.4 + Math.cos(time) * 0.2;
         spineboy.scale = scale;
         spineboy.angle++;
     }

+ 4 - 4
spine-ts/spine-phaser/example/camera-pipeline-test.html

@@ -12,7 +12,7 @@
 <body>
     <h1>Camera pipeline test</h1>
     <script>
-        var config = {
+        const config = {
             type: Phaser.AUTO,
             width: 800,
             height: 600,
@@ -84,7 +84,7 @@
             }
         }
 
-        let game = new Phaser.Game(config);
+        const game = new Phaser.Game(config);
 
         function preload() {
             this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
@@ -98,9 +98,9 @@
             // FIXME: Need a dummy sprite so the MultiPipeline sets up state
             // so rendering the Spine sprite actually works. Unsure what state
             // is needed.
-            var s = this.add.sprite(0, 0, 'img');
+            this.add.sprite(0, 0, 'img');
 
-            let spineboy = this.add.spine(400, 300, 'spineboy-data', "spineboy-atlas");
+            const spineboy = this.add.spine(400, 300, 'spineboy-data', "spineboy-atlas");
             spineboy.scale = 0.5;
             spineboy.animationState.setAnimation(0, "walk", true);
 

+ 3 - 3
spine-ts/spine-phaser/example/canvas-test.html

@@ -13,7 +13,7 @@
     <h1>Canvas test</h1>
 </body>
 <script>
-    var config = {
+    const config = {
         type: Phaser.AUTO,
         width: 800,
         height: 600,
@@ -29,7 +29,7 @@
         }
     };
 
-    let game = new Phaser.Game(config);
+    const game = new Phaser.Game(config);
 
     function preload() {
         this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
@@ -37,7 +37,7 @@
     }
 
     function create() {
-        let spineboy = this.add.spine(400, 300, 'spineboy-data', "spineboy-atlas");
+        const spineboy = this.add.spine(400, 300, 'spineboy-data', "spineboy-atlas");
         spineboy.scale = 0.5;
         spineboy.animationState.setAnimation(0, "walk", true);
     }

+ 72 - 0
spine-ts/spine-phaser/example/control-bones-example.html

@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>
+    <script src="../dist/iife/spine-phaser.js"></script>
+    <title>Spine Phaser Example</title>
+</head>
+
+<body>
+    <h1>Control bones</h1>
+    <script>        
+        class ControlBonesExample extends Phaser.Scene {
+            preload() {
+                this.load.spineBinary("stretchyman-data", "assets/stretchyman-pro.skel");
+                this.load.spineAtlas("stretchyman-atlas", "assets/stretchyman-pma.atlas");
+            }
+
+            create() {
+                const stretchyman = this.add.spine(400, 580, 'stretchyman-data', "stretchyman-atlas");                  
+                stretchyman.animationState.setAnimation(0, "idle", true);
+                stretchyman.updatePose(0);
+
+                const controlBoneNames = ["back-arm-ik-target", "back-leg-ik-target", "front-arm-ik-target", "front-leg-ik-target"];
+                const controlBones = [];
+                for (var i = 0; i < controlBoneNames.length; i++) {
+                    const bone = stretchyman.skeleton.findBone(controlBoneNames[i]);
+                    const point = { x: bone.worldX, y: bone.worldY };
+                    stretchyman.skeletonToPhaserWorldCoordinates(point);
+
+                    const control = this.add.circle(point.x, point.y, 4, 0xff00ff).setData('bone', bone);
+                    controlBones.push(control);
+
+                    control.setInteractive();
+                    this.input.setDraggable(control);
+                    this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
+                        gameObject.x = dragX;
+                        gameObject.y = dragY;                        
+                    }, this);
+                }
+
+                stretchyman.beforeUpdateWorldTransforms = () => {
+                    for (let controlBone of controlBones) {                        
+                        const bone = controlBone.getData('bone');
+                        const point = { x: controlBone.x, y: controlBone.y};
+                        stretchyman.phaserWorldCoordinatesToBone(point, bone);
+                        bone.x = point.x;
+                        bone.y = point.y;
+                    }
+                }
+            }
+        }
+
+        new Phaser.Game({
+            type: Phaser.AUTO,
+            width: 800,
+            height: 600,
+            type: Phaser.WEBGL,
+            scene: [ControlBonesExample],
+            plugins: {
+                scene: [
+                    { key: "spine.SpinePlugin", plugin: spine.SpinePlugin, mapping: "spine" }
+                ]
+            }
+        });    
+    </script>
+</body>
+
+</html>

+ 0 - 72
spine-ts/spine-phaser/example/control-bones-test.html

@@ -1,72 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-
-<head>
-    <meta charset="UTF-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>
-    <title>Spine Phaser Example</title>
-</head>
-
-<body>
-    <h1>Control bones</h1>
-    <script>
-        var config = {
-            type: Phaser.AUTO,
-            width: 800,
-            height: 600,
-            type: Phaser.WEBGL,
-            scene: {
-                preload: preload,
-                create: create,
-                pack: {
-                    files: [
-                        { type: "scenePlugin", key: "spine.SpinePlugin", url: "../dist/iife/spine-phaser.js", sceneKey: "spine" }
-                    ]
-                }
-            }
-        };
-
-        let game = new Phaser.Game(config);
-
-        function preload() {
-            this.load.spineBinary("stretchyman-data", "assets/stretchyman-pro.skel");
-            this.load.spineAtlas("stretchyman-atlas", "assets/stretchyman-pma.atlas");
-        }
-
-        function create() {
-            let stretchyman = this.add.spine(400, 550, 'stretchyman-data', "stretchyman-atlas");
-            stretchyman.scale = 0.8;
-            stretchyman.skeleton.updateWorldTransform();
-
-            var controlBones = ["back-arm-ik-target", "back-leg-ik-target", "front-arm-ik-target", "front-leg-ik-target"];
-            for (var i = 0; i < controlBones.length; i++) {
-                var bone = stretchyman.skeleton.findBone(controlBones[i]);
-                let point = { x: bone.worldX, y: bone.worldY };
-                stretchyman.skeletonToPhaserWorldCoordinates(point);
-
-                var control = this.add.circle(point.x, point.y, 4, 0xff00ff).setData('bone', bone);
-
-                control.setInteractive();
-                this.input.setDraggable(control);
-                this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
-
-                    gameObject.x = dragX;
-                    gameObject.y = dragY;
-
-                    var bone = gameObject.getData('bone');
-                    let point = { x: dragX, y: dragY };
-                    stretchyman.phaserWorldCoordinatesToBone(point, bone);
-
-                    bone.x = point.x;
-                    bone.y = point.y;
-                    bone.update();
-
-                }, this);
-            }
-        }
-    </script>
-</body>
-
-</html>

+ 3 - 3
spine-ts/spine-phaser/example/depth-test.html

@@ -13,7 +13,7 @@
     <h1>Depth test</h1>
 </body>
 <script>
-    var config = {
+    const config = {
         type: Phaser.AUTO,
         width: 800,
         height: 600,
@@ -29,7 +29,7 @@
         }
     };
 
-    let game = new Phaser.Game(config);
+    const game = new Phaser.Game(config);
 
     function preload() {
         this.load.image('logo', 'phaser.png');
@@ -39,7 +39,7 @@
 
     function create() {
         this.add.image(400, 350, 'logo').setName('logo1').setDepth(2);
-        let spineboy = this.add.spine(400, 600, 'spineboy-data', "spineboy-atlas");
+        const spineboy = this.add.spine(400, 600, 'spineboy-data', "spineboy-atlas");
         spineboy.animationState.setAnimation(0, "walk", true)
         spineboy.setScale(0.5)
         spineboy.setDepth(1);

+ 70 - 0
spine-ts/spine-phaser/example/events-example.html

@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>
+    <script src="../dist/iife/spine-phaser.js"></script>
+    <title>Spine Phaser Example</title>
+</head>
+
+<body>
+    <h1>Events example</h1>
+    <div style="display: flex; flex-direction: column; width: 800px">
+        <canvas id="game" width="800" height="600"></canvas>
+        <textarea id="log" style="height: 10em;"></textarea>
+    </div>
+</body>
+<script>    
+    function log(message) {
+        let log = document.querySelector("#log");
+        log.textContent += message + "\n";
+        log.scrollTop = log.scrollHeight;
+        console.log(message);
+    }
+
+    class EventsExample extends Phaser.Scene {
+        preload() {
+            this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
+            this.load.spineAtlas("spineboy-atlas", "assets/spineboy-pma.atlas");
+        }
+
+        create() {
+            const spineboy = this.add.spine(400, 500, 'spineboy-data', "spineboy-atlas");
+            spineboy.scale = 0.5;
+
+            spineboy.animationState.addListener({
+                start: (entry) => log(`Started animation ${entry.animation.name}`),
+                interrupt: (entry) => log(`Interrupted animation ${entry.animation.name}`),
+                end: (entry) => log(`Ended animation ${entry.animation.name}`),
+                dispose: (entry) => log(`Disposed animation ${entry.animation.name}`),
+                complete: (entry) => log(`Completed animation ${entry.animation.name}`),                
+            })
+
+            spineboy.animationState.setAnimation(0, "walk", true);
+            const trackEntry = spineboy.animationState.addAnimation(0, "run", 3, true);
+            trackEntry.listener = {
+                event: (entry, event) => log(`Custom event for ${entry.animation.name}: ${event.data.name}`)
+            }
+        }
+    }
+
+    const config = {        
+        canvas: document.querySelector("#game"),
+        width: 800,
+        height: 600,
+        type: Phaser.WEBGL,
+        scene: [EventsExample],
+        plugins: {
+            scene: [
+                { key: "spine.SpinePlugin", plugin: spine.SpinePlugin, mapping: "spine" }
+            ]
+        }
+    };
+
+    const game = new Phaser.Game(config);
+</script>
+
+</html>

+ 4 - 4
spine-ts/spine-phaser/example/extended-class-test.html

@@ -22,7 +22,7 @@
     }
 
     function create() {
-        let spineboy = this.add.spine(400, 300, 'spineboy-data', "spineboy-atlas");
+        const spineboy = this.add.spine(400, 300, 'spineboy-data', "spineboy-atlas");
         spineboy.scale = 0.5;
         spineboy.animationState.setAnimation(0, "walk", true);
     }
@@ -71,11 +71,11 @@
         create() {
             this.add.image(0, 0, 'logo').setOrigin(0);
 
-            let custom1 = new CustomSpineObject1(this, 100, 550, 'spineboy-data', 'spineboy-atlas', 'idle', true);
+            const custom1 = new CustomSpineObject1(this, 100, 550, 'spineboy-data', 'spineboy-atlas', 'idle', true);
             custom1.spine.setScale(0.5);
-            let custom2 = new CustomSpineObject2(this, 350, 550, 'spineboy-data', 'spineboy-atlas', 'walk', true);
+            const custom2 = new CustomSpineObject2(this, 350, 550, 'spineboy-data', 'spineboy-atlas', 'walk', true);
             custom2.spine.setScale(0.5);
-            let custom3 = new CustomSpineObject3(this, 600, 550, 'spineboy-data', 'spineboy-atlas', 'run', true);
+            const custom3 = new CustomSpineObject3(this, 600, 550, 'spineboy-data', 'spineboy-atlas', 'run', true);
             custom3.spine.setScale(0.5);
 
             this.add.image(400, 0, 'logo').setOrigin(0);

+ 5 - 5
spine-ts/spine-phaser/example/mix-and-match.html → spine-ts/spine-phaser/example/mix-and-match-example.html

@@ -13,7 +13,7 @@
     <h1>Mix and match</h1>
 </body>
 <script>
-    var config = {
+    const config = {
         type: Phaser.AUTO,
         width: 800,
         height: 600,
@@ -29,7 +29,7 @@
         }
     };
 
-    let game = new Phaser.Game(config);
+    const game = new Phaser.Game(config);
 
     function preload() {
         this.load.spineBinary("mix-and-match-data", "assets/mix-and-match-pro.skel");
@@ -37,12 +37,12 @@
     }
 
     function create() {
-        let mixAndMatch = this.add.spine(400, 500, 'mix-and-match-data', "mix-and-match-atlas");
+        const mixAndMatch = this.add.spine(400, 500, 'mix-and-match-data', "mix-and-match-atlas");
         mixAndMatch.scale = 0.5;
         mixAndMatch.animationState.setAnimation(0, "walk", true);
 
-        let skeletonData = mixAndMatch.skeleton.data;
-        let skin = new spine.Skin("custom");
+        const skeletonData = mixAndMatch.skeleton.data;
+        const skin = new spine.Skin("custom");
         skin.addSkin(skeletonData.findSkin("skin-base"));
         skin.addSkin(skeletonData.findSkin("nose/short"));
         skin.addSkin(skeletonData.findSkin("eyelids/girly"));

+ 4 - 4
spine-ts/spine-phaser/example/multi-scene-test.html

@@ -25,7 +25,7 @@
         }
 
         create() {
-            let spineboy = this.add.spine(400, 500, 'spineboy-data', "spineboy-atlas");
+            const spineboy = this.add.spine(400, 500, 'spineboy-data', "spineboy-atlas");
             spineboy.scale = 0.5;
             spineboy.animationState.setAnimation(0, "walk", true);
             this.input.once('pointerdown', () => this.scene.start('Scene2'));
@@ -43,14 +43,14 @@
         }
 
         create() {
-            let raptor = this.add.spine(300, 600, 'raptor-data', "raptor-atlas");
+            const raptor = this.add.spine(300, 600, 'raptor-data', "raptor-atlas");
             raptor.scale = 0.5;
             raptor.animationState.setAnimation(0, "walk", true);
             this.input.once('pointerdown', () => this.scene.start('Scene1'));
         }
     }
 
-    var config = {
+    const config = {
         type: Phaser.AUTO,
         width: 800,
         height: 600,
@@ -62,7 +62,7 @@
             ]
         }
     };
-    let game = new Phaser.Game(config);
+    const game = new Phaser.Game(config);
 </script>
 
 </html>

+ 4 - 4
spine-ts/spine-phaser/example/render-to-texture-test.html

@@ -13,7 +13,7 @@
     <h1>Render to texture</h1>
 </body>
 <script>
-    var config = {
+    const config = {
         type: Phaser.AUTO,
         width: 800,
         height: 600,
@@ -29,7 +29,7 @@
         }
     };
 
-    let game = new Phaser.Game(config);
+    const game = new Phaser.Game(config);
 
     function preload() {
         this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
@@ -37,8 +37,8 @@
     }
 
     function create() {
-        let renderTexture = this.add.renderTexture(0, 0, 800, 600);
-        let spineboy = this.add.spine(400, 300, 'spineboy-data', "spineboy-atlas");
+        const renderTexture = this.add.renderTexture(0, 0, 800, 600);
+        const spineboy = this.add.spine(400, 300, 'spineboy-data', "spineboy-atlas");
         spineboy.scale = 0.5;
         spineboy.animationState.setAnimation(0, "walk", true);
         this.add.text(200, 8, 'Click to stamp SpineBoy');

+ 7 - 8
spine-ts/spine-phaser/example/typescript/index.ts

@@ -1,30 +1,29 @@
-import {Scene} from "phaser"
-import {SpinePlugin} from "@esotericsoftware/spine-phaser"
+import * as Phaser from "phaser"
+import * as spine from "@esotericsoftware/spine-phaser"
 
-class SpineDemo extends Scene {
+class SpineDemo extends Phaser.Scene {
     preload() {
         this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
         this.load.spineAtlas("spineboy-atlas", "assets/spineboy-pma.atlas");
     }
 
     create() {
-        let spineboy = this.add.spine(400, 500, 'spineboy-data', "spineboy-atlas");
-        this.make
+        const spineboy = this.add.spine(400, 500, 'spineboy-data', "spineboy-atlas");        
         spineboy.scale = 0.5;
         spineboy.animationState.setAnimation(0, "walk", true);
     }
 }
 
-var config = {    
+const config = {    
     width: 800,
     height: 600,
     type: Phaser.WEBGL,
     scene: [SpineDemo],
     plugins: {
         scene: [
-            { key: "spine.SpinePlugin", plugin: SpinePlugin, mapping: "spine" }
+            { key: "spine.SpinePlugin", plugin: spine.SpinePlugin, mapping: "spine" }
         ]
     }
 };
 
-let game = new Phaser.Game(config);
+new Phaser.Game(config);

+ 4 - 4
spine-ts/spine-phaser/example/visibility-test.html

@@ -14,7 +14,7 @@
     <h1>Basic example</h1>
 </body>
 <script>
-    var config = {
+    const config = {
         type: Phaser.AUTO,
         width: 800,
         height: 600,
@@ -30,7 +30,7 @@
         }
     };
 
-    let game = new Phaser.Game(config);
+    const game = new Phaser.Game(config);
 
     function preload() {
         this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
@@ -38,11 +38,11 @@
     }
 
     function create() {
-        let spineboy = this.add.spine(250, 500, 'spineboy-data', "spineboy-atlas");
+        const spineboy = this.add.spine(250, 500, 'spineboy-data', "spineboy-atlas");
         spineboy.scale = 0.5;
         spineboy.animationState.setAnimation(0, "walk", true);
 
-        let spineboy2 = this.add.spine(550, 500, 'spineboy-data', "spineboy-atlas");
+        const spineboy2 = this.add.spine(550, 500, 'spineboy-data', "spineboy-atlas");
         spineboy2.scale = 0.5;
         spineboy2.animationState.setAnimation(0, "run", true);
 

+ 48 - 4
spine-ts/spine-phaser/src/SpineGameObject.ts

@@ -9,10 +9,13 @@ class BaseSpineGameObject extends Phaser.GameObjects.GameObject {
 	}
 }
 
+/** A bounds provider calculates the bounding box for a skeleton, which is then assigned as the size of the SpineGameObject. */
 export interface SpineGameObjectBoundsProvider {
+	// Returns the bounding box for the skeleton, in skeleton space.
 	calculateBounds (gameObject: SpineGameObject): { x: number, y: number, width: number, height: number };
 }
 
+/** A bounds provider that calculates the bounding box from the setup pose. */
 export class SetupPoseBoundsProvider implements SpineGameObjectBoundsProvider {
 	calculateBounds (gameObject: SpineGameObject) {
 		if (!gameObject.skeleton) return { x: 0, y: 0, width: 0, height: 0 };
@@ -26,9 +29,14 @@ export class SetupPoseBoundsProvider implements SpineGameObjectBoundsProvider {
 	}
 }
 
+/** A bounds provider that calculates the bounding box by taking the maximumg bounding box for a combination of skins and specific animation. */
 export class SkinsAndAnimationBoundsProvider implements SpineGameObjectBoundsProvider {
+	/**
+	 * @param animation The animation to use for calculating the bounds. If null, the setup pose is used.
+	 * @param skins The skins to use for calculating the bounds. If empty, the default skin is used.
+	 * @param timeStep The time step to use for calculating the bounds. A smaller time step means more precision, but slower calculation.
+	 */
 	constructor (private animation: string, private skins: string[] = [], private timeStep: number = 0.05) {
-
 	}
 
 	calculateBounds (gameObject: SpineGameObject): { x: number; y: number; width: number; height: number; } {
@@ -75,11 +83,34 @@ export class SkinsAndAnimationBoundsProvider implements SpineGameObjectBoundsPro
 	}
 }
 
+/**
+ * A SpineGameObject is a Phaser {@link GameObject} that can be added to a Phaser Scene and render a Spine skeleton.
+ * 
+ * The Spine GameObject is a thin wrapper around a Spine {@link Skeleton}, {@link AnimationState} and {@link AnimationStateData}. It is responsible for:
+ * - updating the animation state
+ * - applying the animation state to the skeleton's bones, slots, attachments, and draw order.
+ * - updating the skeleton's bone world transforms
+ * - rendering the skeleton
+ * 
+ * See the {@link SpinePlugin} class for more information on how to create a `SpineGameObject`.
+ * 
+ * The skeleton, animation state, and animation state data can be accessed via the repsective fields. They can be manually updated via {@link updatePose}.
+ * 
+ * To modify the bone hierarchy before the world transforms are computed, a callback can be set via the {@link beforeUpdateWorldTransforms} field.
+ * 
+ * To modify the bone hierarchy after the world transforms are computed, a callback can be set via the {@link afterUpdateWorldTransforms} field.
+ * 
+ * The class also features methods to convert between the skeleton coordinate system and the Phaser coordinate system. 
+ * 
+ * See {@link skeletonToPhaserWorldCoordinates}, {@link phaserWorldCoordinatesToSkeleton}, and {@link phaserWorldCoordinatesToBoneLocal.}
+ */
 export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(ScrollFactorMixin(TransformMixin(VisibleMixin(AlphaMixin(BaseSpineGameObject))))))) {
 	blendMode = -1;
 	skeleton: Skeleton;
 	animationStateData: AnimationStateData;
 	animationState: AnimationState;
+	beforeUpdateWorldTransforms: (object: SpineGameObject) => void = () => { };
+	afterUpdateWorldTransforms: (object: SpineGameObject) => void = () => { };
 	private premultipliedAlpha = false;
 	private _displayOriginX = 0;
 	private _displayOriginY = 0;
@@ -94,6 +125,7 @@ export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(Scro
 		this.skeleton = this.plugin.createSkeleton(dataKey, atlasKey);
 		this.animationStateData = new AnimationStateData(this.skeleton.data);
 		this.animationState = new AnimationState(this.animationStateData);
+		this.skeleton.updateWorldTransform();
 		this.updateSize();
 	}
 
@@ -142,6 +174,7 @@ export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(Scro
 		this.displayOriginY = -bounds.y;
 	}
 
+	/** Converts a point from the skeleton coordinate system to the Phaser world coordinate system. */
 	skeletonToPhaserWorldCoordinates (point: { x: number, y: number }) {
 		let transform = this.getWorldTransformMatrix();
 		let a = transform.a, b = transform.b, c = transform.c, d = transform.d, tx = transform.tx, ty = transform.ty;
@@ -151,6 +184,7 @@ export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(Scro
 		point.y = x * b + y * d + ty;
 	}
 
+	/** Converts a point from the Phaser world coordinate system to the skeleton coordinate system. */
 	phaserWorldCoordinatesToSkeleton (point: { x: number, y: number }) {
 		let transform = this.getWorldTransformMatrix();
 		transform = transform.invert();
@@ -161,6 +195,7 @@ export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(Scro
 		point.y = x * b + y * d + ty;
 	}
 
+	/** Converts a point from the Phaser world coordinate system to the bone's local coordinate system. */
 	phaserWorldCoordinatesToBone (point: { x: number, y: number }, bone: Bone) {
 		this.phaserWorldCoordinatesToSkeleton(point);
 		if (bone.parent) {
@@ -170,12 +205,21 @@ export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(Scro
 		}
 	}
 
-	preUpdate (time: number, delta: number) {
-		if (!this.skeleton || !this.animationState) return;
-
+	/**
+	 * Updates the {@link AnimationState}, applies it to the {@link Skeleton}, then updates the world transforms of all bones.
+	 * @param delta The time delta in milliseconds
+	 */
+	updatePose (delta: number) {
 		this.animationState.update(delta / 1000);
 		this.animationState.apply(this.skeleton);
+		this.beforeUpdateWorldTransforms(this);
 		this.skeleton.updateWorldTransform();
+		this.afterUpdateWorldTransforms(this);
+	}
+
+	preUpdate (time: number, delta: number) {
+		if (!this.skeleton || !this.animationState) return;
+		this.updatePose(delta);
 	}
 
 	preDestroy () {

+ 70 - 45
spine-ts/spine-phaser/src/SpinePlugin.ts

@@ -27,54 +27,69 @@
  * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
 
-import phaser from "phaser";
-import { SPINE_ATLAS_CACHE_KEY, SPINE_CONTAINER_TYPE, SPINE_GAME_OBJECT_TYPE, SPINE_ATLAS_TEXTURE_CACHE_KEY, SPINE_SKELETON_DATA_FILE_TYPE, SPINE_ATLAS_FILE_TYPE, SPINE_SKELETON_FILE_CACHE_KEY as SPINE_SKELETON_DATA_CACHE_KEY } from "./keys";
-import { AtlasAttachmentLoader, Bone, GLTexture, SceneRenderer, Skeleton, SkeletonBinary, SkeletonData, SkeletonJson, TextureAtlas } from "@esotericsoftware/spine-webgl"
+import Phaser from "phaser";
+import { SPINE_ATLAS_CACHE_KEY, SPINE_CONTAINER_TYPE, SPINE_GAME_OBJECT_TYPE, SPINE_SKELETON_DATA_FILE_TYPE, SPINE_ATLAS_FILE_TYPE, SPINE_SKELETON_FILE_CACHE_KEY as SPINE_SKELETON_DATA_CACHE_KEY } from "./keys";
+import { AtlasAttachmentLoader, GLTexture, SceneRenderer, Skeleton, SkeletonBinary, SkeletonData, SkeletonJson, TextureAtlas } from "@esotericsoftware/spine-webgl"
 import { SpineGameObject, SpineGameObjectBoundsProvider } from "./SpineGameObject";
 import { CanvasTexture, SkeletonRenderer } from "@esotericsoftware/spine-canvas";
 
+/**
+ * Configuration object used when creating {@link SpineGameObject} instances via a scene's
+ * {@link GameObjectCreator} (`Scene.make`).
+ */
 export interface SpineGameObjectConfig extends Phaser.Types.GameObjects.GameObjectConfig {
+	/** The x-position of the object, optional, default: 0 */
 	x?: number,
+	/** The y-position of the object, optional, default: 0 */
 	y?: number,
+	/** The skeleton data key */
 	dataKey: string,
+	/** The atlas key */
 	atlasKey: string
+	/** The bounds provider, optional, default: `SetupPoseBoundsProvider` */
 	boundsProvider?: SpineGameObjectBoundsProvider
 }
 
+/**
+ * {@link ScenePlugin} implementation adding Spine Runtime capabilities to a scene.
+ * 
+ * The scene's {@link LoaderPlugin} (`Scene.load`) gets these additional functions:
+ * * `spineBinary(key: string, url: string, xhrSettings?: XHRSettingsObject)`: loads a skeleton binary `.skel` file from the `url`.
+ * * `spineJson(key: string, url: string, xhrSettings?: XHRSettingsObject)`: loads a skeleton binary `.skel` file from the `url`.
+ * * `spineAtlas(key: string, url: string, premultipliedAlpha: boolean = true, xhrSettings?: XHRSettingsObject)`: loads a texture atlas `.atlas` file from the `url` as well as its correponding texture atlas page images.
+ * 
+ * The scene's {@link GameObjectFactory} (`Scene.add`) gets these additional functions:
+ * * `spine(x: number, y: number, dataKey: string, atlasKey: string, boundsProvider: SpineGameObjectBoundsProvider = SetupPoseBoundsProvider())`: 
+ *    creates a new {@link SpineGameObject} from the data and atlas at position `(x, y)`, using the {@link BoundsProvider} to calculate its bounding box. The object is automatically added to the scene.
+ * 
+ * The scene's {@link GameObjectCreator} (`Scene.make`) gets these additional functions:
+ * * `spine(config: SpineGameObjectConfig)`: creates a new {@link SpineGameObject} from the given configuration object.
+ * 
+ * The plugin has additional public methods to work with Spine Runtime core API objects:
+ * * `getAtlas(atlasKey: string)`: returns the {@link TextureAtlas} instance for the given atlas key.
+ * * `getSkeletonData(skeletonDataKey: string)`: returns the {@link SkeletonData} instance for the given skeleton data key.
+ * * `createSkeleton(skeletonDataKey: string, atlasKey: string, premultipliedAlpha: boolean = true)`: creates a new {@link Skeleton} instance from the given skeleton data and atlas key.
+ * * `isPremultipliedAlpha(atlasKey: string)`: returns `true` if the atlas with the given key has premultiplied alpha.
+ */
 export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
 	game: Phaser.Game;
-	isWebGL: boolean;
-	gl: WebGLRenderingContext | null;
-	textureManager: Phaser.Textures.TextureManager;
-	phaserRenderer: Phaser.Renderer.Canvas.CanvasRenderer | Phaser.Renderer.WebGL.WebGLRenderer | null;
+	private isWebGL: boolean;
+	private gl: WebGLRenderingContext | null;
 	webGLRenderer: SceneRenderer | null;
 	canvasRenderer: SkeletonRenderer | null;
-	skeletonDataCache: Phaser.Cache.BaseCache;
-	atlasCache: Phaser.Cache.BaseCache;
+	private skeletonDataCache: Phaser.Cache.BaseCache;
+	private atlasCache: Phaser.Cache.BaseCache;
 
 	constructor (scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) {
 		super(scene, pluginManager, pluginKey);
-		var game = this.game = pluginManager.game;
+		this.game = pluginManager.game;
 		this.isWebGL = this.game.config.renderType === 2;
 		this.gl = this.isWebGL ? (this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).gl : null;
-		this.textureManager = this.game.textures;
-		this.phaserRenderer = this.game.renderer;
 		this.webGLRenderer = null;
 		this.canvasRenderer = null;
 		this.skeletonDataCache = this.game.cache.addCustom(SPINE_SKELETON_DATA_CACHE_KEY);
 		this.atlasCache = this.game.cache.addCustom(SPINE_ATLAS_CACHE_KEY);
 
-		if (!this.phaserRenderer) {
-			this.phaserRenderer = {
-				width: game.scale.width,
-				height: game.scale.height,
-				preRender: () => { },
-				postRender: () => { },
-				render: () => { },
-				destroy: () => { }
-			} as unknown as Phaser.Renderer.Canvas.CanvasRenderer;
-		}
-
 		let skeletonJsonFileCallback = function (this: any, key: string,
 			url: string,
 			xhrSettings: Phaser.Types.Loader.XHRSettingsObject) {
@@ -84,7 +99,6 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
 		};
 		pluginManager.registerFileType("spineJson", skeletonJsonFileCallback, scene);
 
-
 		let skeletonBinaryFileCallback = function (this: any, key: string,
 			url: string,
 			xhrSettings: Phaser.Types.Loader.XHRSettingsObject) {
@@ -94,7 +108,6 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
 		};
 		pluginManager.registerFileType("spineBinary", skeletonBinaryFileCallback, scene);
 
-
 		let atlasFileCallback = function (this: any, key: string,
 			url: string,
 			premultipliedAlpha: boolean,
@@ -113,7 +126,7 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
 			return gameObject;
 		};
 
-		let makeSpineGameObject = function (this: Phaser.GameObjects.GameObjectFactory, config: SpineGameObjectConfig, addToScene: boolean) {
+		let makeSpineGameObject = function (this: Phaser.GameObjects.GameObjectFactory, config: SpineGameObjectConfig, addToScene: boolean = false) {
 			let x = config.x ? config.x : 0;
 			let y = config.y ? config.y : 0;
 			let boundsProvider = config.boundsProvider ? config.boundsProvider : undefined;
@@ -130,7 +143,7 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
 		Skeleton.yDown = true;
 		if (this.isWebGL) {
 			if (!this.webGLRenderer) {
-				this.webGLRenderer = new SceneRenderer((this.phaserRenderer! as Phaser.Renderer.WebGL.WebGLRenderer).canvas, this.gl!, true);
+				this.webGLRenderer = new SceneRenderer((this.game.renderer! as Phaser.Renderer.WebGL.WebGLRenderer).canvas, this.gl!, true);
 			}
 			this.onResize();
 			this.game.scale.on(Phaser.Scale.Events.RESIZE, this.onResize, this);
@@ -147,7 +160,7 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
 	}
 
 	onResize () {
-		var phaserRenderer = this.phaserRenderer;
+		var phaserRenderer = this.game.renderer;
 		var sceneRenderer = this.webGLRenderer;
 
 		if (phaserRenderer && sceneRenderer) {
@@ -178,13 +191,8 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
 		if (this.webGLRenderer) this.webGLRenderer.dispose();
 	}
 
-	isAtlasPremultiplied (atlasKey: string) {
-		let atlasFile = this.game.cache.text.get(atlasKey);
-		if (!atlasFile) return false;
-		return atlasFile.premultipliedAlpha;
-	}
-
-	createSkeleton (dataKey: string, atlasKey: string) {
+	/** Returns the TextureAtlas instance for the given key */
+	getAtlas (atlasKey: string) {
 		let atlas: TextureAtlas;
 		if (this.atlasCache.exists(atlasKey)) {
 			atlas = this.atlasCache.get(atlasKey);
@@ -195,19 +203,32 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
 				let gl = this.gl!;
 				gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
 				for (let atlasPage of atlas.pages) {
-					atlasPage.setTexture(new GLTexture(gl, this.textureManager.get(atlasKey + "!" + atlasPage.name).getSourceImage() as HTMLImageElement | ImageBitmap, false));
+					atlasPage.setTexture(new GLTexture(gl, this.game.textures.get(atlasKey + "!" + atlasPage.name).getSourceImage() as HTMLImageElement | ImageBitmap, false));
 				}
 			} else {
 				for (let atlasPage of atlas.pages) {
-					atlasPage.setTexture(new CanvasTexture(this.textureManager.get(atlasKey + "!" + atlasPage.name).getSourceImage() as HTMLImageElement | ImageBitmap));
+					atlasPage.setTexture(new CanvasTexture(this.game.textures.get(atlasKey + "!" + atlasPage.name).getSourceImage() as HTMLImageElement | ImageBitmap));
 				}
 			}
 			this.atlasCache.add(atlasKey, atlas);
 		}
+		return atlas;
+	}
+
+	/** Returns whether the TextureAtlas uses premultiplied alpha */
+	isAtlasPremultiplied (atlasKey: string) {
+		let atlasFile = this.game.cache.text.get(atlasKey);
+		if (!atlasFile) return false;
+		return atlasFile.premultipliedAlpha;
+	}
 
+	/** Returns the SkeletonData instance for the given data and atlas key */
+	getSkeletonData (dataKey: string, atlasKey: string) {
+		const atlas = this.getAtlas(atlasKey)
+		const combinedKey = dataKey + atlasKey;
 		let skeletonData: SkeletonData;
-		if (this.skeletonDataCache.exists(dataKey)) {
-			skeletonData = this.skeletonDataCache.get(dataKey);
+		if (this.skeletonDataCache.exists(combinedKey)) {
+			skeletonData = this.skeletonDataCache.get(combinedKey);
 		} else {
 			if (this.game.cache.json.exists(dataKey)) {
 				let jsonFile = this.game.cache.json.get(dataKey) as any;
@@ -218,19 +239,23 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
 				let binary = new SkeletonBinary(new AtlasAttachmentLoader(atlas));
 				skeletonData = binary.readSkeletonData(new Uint8Array(binaryFile));
 			}
-			this.skeletonDataCache.add(dataKey, skeletonData);
+			this.skeletonDataCache.add(combinedKey, skeletonData);
 		}
+		return skeletonData;
+	}
 
-		return new Skeleton(skeletonData);
+	/** Creates a new Skeleton instance from the data and atlas. */
+	createSkeleton (dataKey: string, atlasKey: string) {
+		return new Skeleton(this.getSkeletonData(dataKey, atlasKey));
 	}
 }
 
-export enum SpineSkeletonDataFileType {
+enum SpineSkeletonDataFileType {
 	json,
 	binary
 }
 
-export class SpineSkeletonDataFile extends Phaser.Loader.MultiFile {
+class SpineSkeletonDataFile extends Phaser.Loader.MultiFile {
 	constructor (loader: Phaser.Loader.LoaderPlugin, key: string, url: string, public fileType: SpineSkeletonDataFileType, xhrSettings: Phaser.Types.Loader.XHRSettingsObject) {
 		let file = null;
 		let isJson = fileType == SpineSkeletonDataFileType.json;
@@ -261,7 +286,7 @@ export class SpineSkeletonDataFile extends Phaser.Loader.MultiFile {
 	}
 }
 
-export class SpineAtlasFile extends Phaser.Loader.MultiFile {
+class SpineAtlasFile extends Phaser.Loader.MultiFile {
 	constructor (loader: Phaser.Loader.LoaderPlugin, key: string, url: string, public premultipliedAlpha: boolean = true, xhrSettings: Phaser.Types.Loader.XHRSettingsObject) {
 		super(loader, SPINE_ATLAS_FILE_TYPE, key, [
 			new Phaser.Loader.FileTypes.TextFile(loader, {
@@ -278,7 +303,7 @@ export class SpineAtlasFile extends Phaser.Loader.MultiFile {
 			this.pending--;
 
 			if (file.type == "text") {
-				var lines = file.data.split('\n');
+				var lines = file.data.split(/\r\n|\r|\n/);
 				let textures = [];
 				textures.push(lines[0]);
 				for (var t = 1; t < lines.length; t++) {

+ 6 - 0
spine-ts/spine-phaser/src/index.ts

@@ -28,4 +28,10 @@ declare global {
 			spine (config: SpineGameObjectConfig, addToScene?: boolean): SpineGameObject;
 		}
 	}
+
+	namespace Phaser {
+		export interface Scene {
+			spine: SpinePlugin;
+		}
+	}
 }

+ 0 - 1
spine-ts/spine-phaser/src/keys.ts

@@ -1,6 +1,5 @@
 export const SPINE_SKELETON_FILE_CACHE_KEY = "esotericsoftware.spine.skeletonFile.cache";
 export const SPINE_ATLAS_CACHE_KEY = "esotericsoftware.spine.atlas.cache";
-export const SPINE_ATLAS_TEXTURE_CACHE_KEY = "esotericsoftware.spine.atlas.texture.cache";
 export const SPINE_LOADER_TYPE = "spine";
 export const SPINE_SKELETON_DATA_FILE_TYPE = "spineSkeletonData";
 export const SPINE_ATLAS_FILE_TYPE = "spineAtlasData";

+ 155 - 0
spine-ts/spine-threejs/example/coordinate-transform.html

@@ -0,0 +1,155 @@
+<html>
+
+<head>
+	<meta charset="UTF-8">
+	<title>spine-threejs</title>
+	<script src="https://unpkg.com/[email protected]/build/three.js"></script>
+	<script src="../dist/iife/spine-threejs.js"></script>
+	<script src="./OrbitalControls.js"></script>
+</head>
+<style>
+	* {
+		margin: 0;
+		padding: 0;
+	}
+
+	body,
+	html {
+		height: 100%
+	}
+
+	canvas {
+		position: absolute;
+		width: 100%;
+		height: 100%;
+	}
+</style>
+
+<body>
+	<script>
+		(function () {
+			let scene, camera, renderer;
+			let skeletonMesh, cube, tailBone;
+			let assetManager;
+			let canvas;
+			let controls;
+			let lastFrameTime = Date.now() / 1000;
+
+			let baseUrl = "assets/";
+			let skeletonFile = "raptor-pro.json";
+			let atlasFile = skeletonFile.replace("-pro", "").replace("-ess", "").replace(".json", ".atlas");
+			let animation = "walk";
+
+			function init() {
+				// create the THREE.JS camera, scene and renderer (WebGL)
+				let width = window.innerWidth, height = window.innerHeight;
+				camera = new THREE.PerspectiveCamera(75, width / height, 1, 3000);
+				camera.position.y = 200;
+				camera.position.z = 800;
+				scene = new THREE.Scene();
+				renderer = new THREE.WebGLRenderer();
+				renderer.setSize(width, height);
+				document.body.appendChild(renderer.domElement);
+				canvas = renderer.domElement;
+				controls = new OrbitControls(camera, renderer.domElement);
+
+				// load the assets required to display the Raptor model
+				assetManager = new spine.AssetManager(baseUrl);
+				assetManager.loadText(skeletonFile);
+				assetManager.loadTextureAtlas(atlasFile);
+
+				requestAnimationFrame(load);
+			}
+
+			function load(name, scale) {
+				if (assetManager.isLoadingComplete()) {
+					// Load the texture atlas using name.atlas and name.png from the AssetManager.
+					// The function passed to TextureAtlas is used to resolve relative paths.
+					atlas = assetManager.require(atlasFile);
+
+					// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
+					atlasLoader = new spine.AtlasAttachmentLoader(atlas);
+
+					// Create a SkeletonJson instance for parsing the .json file.
+					let skeletonJson = new spine.SkeletonJson(atlasLoader);
+
+					// Set the scale to apply during parsing, parse the file, and create a new skeleton.
+					skeletonJson.scale = 0.4;
+					let skeletonData = skeletonJson.readSkeletonData(assetManager.require(skeletonFile));
+
+					// Create a SkeletonMesh from the data and attach it to the scene
+					skeletonMesh = new spine.SkeletonMesh(skeletonData, (parameters) => {
+						parameters.depthTest = true;
+						parameters.depthWrite = true;
+						parameters.alphaTest = 0.001;
+					});
+					skeletonMesh.state.setAnimation(0, animation, true);
+                    skeletonMesh.position.x = 120;
+                    skeletonMesh.position.y = -20;
+                    skeletonMesh.position.z = 10;
+					scene.add(skeletonMesh);
+
+                    // Add a wireframe cube which will be positioned at the tail bone
+                    geometry = new THREE.BoxGeometry(20, 20, 20);
+                    material = new THREE.MeshBasicMaterial({ color: 0xff00, wireframe: true });
+                    cube = new THREE.Mesh(geometry, material);
+                    scene.add(cube);
+
+                    // Get the tail bone
+                    tailBone = skeletonMesh.skeleton.findBone("tail10");
+
+					requestAnimationFrame(render);
+				} else requestAnimationFrame(load);
+			}            
+
+			let lastTime = Date.now();
+			function render() {
+				// calculate delta time for animation purposes
+				let now = Date.now() / 1000;
+				let delta = now - lastFrameTime;
+				lastFrameTime = now;
+
+				// resize canvas to use full page, adjust camera/renderer
+				resize();
+
+				// Update orbital controls
+				controls.update();
+
+				// update the animation
+				skeletonMesh.update(delta);
+
+                // Get the tail bone coordinates in the skeleton's local coordinate space.
+                let position = new THREE.Vector3(tailBone.worldX, tailBone.worldY, 0);
+
+                // Convert the tail bone coordinates to world coordinates.
+                skeletonMesh.localToWorld(position)
+
+                // Set the tail bone coordinates as the cube's position.
+                cube.position.set(position.x, position.y, position.z);
+
+				// render the scene
+				renderer.render(scene, camera);
+
+				requestAnimationFrame(render);
+			}
+
+			function resize() {
+				let w = window.innerWidth;
+				let h = window.innerHeight;
+				if (canvas.width != w || canvas.height != h) {
+					canvas.width = w;
+					canvas.height = h;
+				}
+
+				camera.aspect = w / h;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize(w, h);
+			}
+
+			init();
+		}());
+	</script>
+</body>
+
+</html>

+ 2 - 2
spine-unity/Assets/Spine/Runtime/spine-unity/Components/RootMotion/SkeletonRootMotionBase.cs

@@ -198,11 +198,11 @@ namespace Spine.Unity {
 					}
 
 					Vector2 rigidbodyDisplacement2D = new Vector2(rigidbodyDisplacement.x, rigidbodyDisplacement.y);
-					rigidBody2D.MovePosition(gravityAndVelocityMovement + new Vector2(transform.position.x, transform.position.y)
+					rigidBody2D.MovePosition(gravityAndVelocityMovement + new Vector2(rigidBody2D.position.x, rigidBody2D.position.y)
 						+ rigidbodyDisplacement2D + additionalRigidbody2DMovement);
 					rigidBody2D.MoveRotation(rigidbody2DRotation + rigidBody2D.rotation);
 				} else if (rigidBody != null) {
-					rigidBody.MovePosition(transform.position
+					rigidBody.MovePosition(rigidBody.position
 						+ new Vector3(rigidbodyDisplacement.x, rigidbodyDisplacement.y, rigidbodyDisplacement.z));
 					rigidBody.MoveRotation(rigidBody.rotation * rigidbodyLocalRotation);
 				}

+ 1 - 1
spine-unity/Assets/Spine/package.json

@@ -2,7 +2,7 @@
 	"name": "com.esotericsoftware.spine.spine-unity",
 	"displayName": "spine-unity Runtime",
 	"description": "This plugin provides the spine-unity runtime core.",
-	"version": "4.1.0",
+	"version": "4.1.10",
 	"unity": "2018.3",
 	"author": {
 		"name": "Esoteric Software",

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov