Exchange image of Spine object during runtime

Hi there,

I wanted to replace my spine image, which is defined in the atlas, with any other image (from a remote location) but during runtime.

This is how I load and use spine:

// preload():
this.load.spine('fish', 'fish.json', 'fish.atlas.txt', true);
// ... create():
this.add.spine(450, 300, "fish", "animationName", true);

Now I get an event that a user has uploaded an image on my server and I simply want to apply all the spine data to that image.

onImageUploaded(image_url) {
   // Take image_url as graphic and apply it to my fish spine
}

The problem is that the image name is defined in the atlas file.

Is there any way to dynamically create or alter the atlas file?

I don’t want and can’t create a new atlas file for every upload on the server!

I tried already to create a Blob() on the fly with the edited atlas content and then load it, but that didn’t work out:

var atlas_content = `

http://example.com/img/new-img.png
size: 1024,1024
format: RGBA8888
filter: Linear,Linear
repeat: none
fish
  rotate: false
  xy: 2, 2
  size: 961, 582
  orig: 961, 582
  offset: 0, 0
  index: -1
`;

var data = new Blob([atlas_content], { type: 'text/plain'} );
var atlas_file = window.URL.createObjectURL(data);

this.load.spine('fish', 'export/fish.json', atlas_file, true);

Or in other words: I want to have a “skeleton” and simply apply any image I want to it during run time:

var spine = this.add.spine(450, 300, "fish", "animationName", true);
spine.image = "http://example.com/my-new-image.png"

Thanks a lot for any ideas and help!

Using Phaser 3.5.0

There is a demonstration here on how a character changes images or skin:

I found a (dirty) solution to loading custom atlas.txt files.

I hacked into the onProcess function of the TextFile class in the phaser-spine-plugin.js

onProcess() {
  // ...
  if (this.src.endsWith(".atlas.txt") && window['spineFactory']) {
      this.data = window.spineFactory.create(this.src);
  } else {
      this.data = this.xhrLoader.responseText;
  }
}

Also in the File Class I edited the load function:

if (this.src.endsWith(".atlas.txt")) {

  var my_xhr = {
     responseURL: this.src,
    readyState: 4
  };
  var my_event = {
    target: {
      status: 200
    }
  };
  this.onLoad(my_xhr, my_event);

} else {
  this.xhrLoader = XHRLoader(this, this.loader.xhr);
}

Instead of making a remote request to get an .atlas.txt file, I return a string from a factory function:

window.spineFactory = {};
window.spineFactory.base_url = ""; // Can be a remote url for the image

// My url look like this: IMAGE_NAME.IMAGE_TYPE.atlas.txt
window.spineFactory.create = function(url) {
  var paths = url.split("/");
  var filename = paths[paths.length - 1];
  var file_parts = filename.split(".");
  var image_file = this.base_url + file_parts[0];
  var type = file_parts[1];

// Fish
if (type === "fish") {

// Make sure to have no indentations!
  const atlas_str = `
${image_file}.png
size: 1024,1024
format: RGBA8888
filter: Linear,Linear
repeat: none
fish
  rotate: false
  xy: 2, 2
  size: 961, 582
  orig: 961, 582
  offset: 0, 0
  index: -1`;
}

  return atlas_str;
}

Now I can apply a spine to any image which has been loaded dynamically / on run time.

Other ideas I had were to Proxy the XMLHttpRequest object or to use a service worker, but in the end it didn’t work out.

Hi, @Zeus , can you share the files where we need to update these code?