Phaser 3 Canvas as Texture in ThreeJS?

Hi! I’m new here & was looking for a way to use a phaser 3 tiled map on a Three.js Texture. I know it’s possible because I’ve seen a demo over at phaser’s website that allows phaser to render in three.js. Can someone perhaps make an example of this on codepen or jsfiddle?

Thanks!

hello?

This seems pretty straight-forward from what I can see (although admittedly I don’t know Three.js, as I would figure a lot of people around here don’t).

But a quick Google search showed that Three.js has a class called CanvasTexture. If you look at the docs page, its first parameter is an HTML canvas element. There is a code snippet here that shows how to use it with a basic canvas created in memory.

I have actually not tried to run Phaser against a canvas that exists in memory but it appears to be supported. There are a couple of things to keep in mind about setting up your Phaser config object, though:

  1. You will need to pass that canvas you create into the canvas property of the game config. If it is left off, Phaser defaults to adding a new canvas as a child to the body tag, which is most definitely not what you want.

  2. You may need to set the type in the config explicitly to be Phaser.CANVAS. “Canvas” has become a bit of a nebulous term now in JS development, as a canvas can support both the actual Canvas spec, or WebGL. If you leave it up to Phaser, it will choose the best canvas it can for playing a game in the DOM (as in, WebGL if it is available or Canvas if not). But I don’t know if Three.js can make a texture out of WebGL. You may need to experiment to see if it can.

I definitely don’t know enough about Three.js to make an example, but this should be enough to get you going and experimenting. Hope this helps!

@Jackolantern Yes, Threejs can actually use a canvas as a Texture. I can’t seem to find an example of how to do this. I just want to use a tilemap from phaser in threejs.

Are you wanting to do anything dynamic with the tilemap texture? If you are wanting to just use a static tilemap, you may be better off parsing and displaying it yourself in Three.js. Three.js is already a huge resource hog in the browser (until WebGPU gets more browser support at least), so I think you may be taking on too much weight to also be running a 2D game engine to display the tilemap. With 3D in the browser, every drop of performance is so valuable since almost every game will run out at some point and have to make sacrifices.

But anyway, I did think this would be kind of fun to play around with a bit even though I don’t know Three.js. I was able to get it to work pretty easily. I just made a simple Phaser scene with a sprite in the middle of it and then rotated the sprite to see if I could get animations to show up, which it did. There is no real care taken in this code and it could no doubt be put together in a much neater way but it should definitely be enough to get you started.

let canvas = document.createElement('canvas');
let gameScene = new Phaser.Scene('Game');

gameScene.preload = function() {
    this.load.image('barrel', 'assets/barrel.png');
};
gameScene.create = function() {
    this.barrel =  this.add.sprite(18, 18, 'barrel');
};
gameScene.update = function() {
    this.barrel.angle += 1;
};
let config = {
    type: Phaser.CANVAS,
    width: 32,
    height: 32,
    title: 'Phaser Three.js Texture',
    canvas: canvas,
    scene: gameScene
};
let game = new Phaser.Game(config);

// Scene
let scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);

// Camera
let camera = new THREE.PerspectiveCamera(75, 320 / 240, .025, 20);
camera.position.set(1, 1, 1);
camera.lookAt(0, 0, 0);

// GEOMETRY
let geometry = new THREE.BoxGeometry(1, 1, 1);

let texture = new THREE.Texture(canvas);
texture.needsUpdate = true;

// MATERIAL
let material = new THREE.MeshBasicMaterial({
    map: texture
});

// MESH
let mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

// RENDER
let renderer = new THREE.WebGLRenderer();
renderer.setSize(320, 240);
document.getElementById('demo').appendChild(renderer.domElement);

setInterval(() => {
    texture.needsUpdate = true;
    renderer.render(scene, camera);
}, 100);

@Jackolantern : Yes, I would like to use dynamic phaser physics & dynamic collision. That’s the only thing I want to do. Move a character around on a phaser tilemap in threejs.

Ahh, okay. Then yes, it does make sense to bring in Phaser. Well, there you go with the example. That is basically the bridge between Phaser and Three.js. With that in place, you can now just focus on Phaser docs for what you need to do in Phaser and Three.js docs for what you need in Three.js. If possible, I would recommend bringing in some organization early to separate the Phaser code from the Three.js into their own files so you can keep their logic separate.

@Jackolantern THANK YOU! This works GREAT! But I had a couple more questions. How would I remove the black background from the Sprite being Textured to the cube if it’s already got a transparent background to begin with? And 2ndly, how do I make my player in threejs interact with arcade physics & collision in phaser?

How would I remove the black background from the Sprite being Textured to the cube if it’s already got a transparent background to begin with?

The black background is coming from Phaser itself, since the default background color in Phaser is black. I don’t think it would matter that you make it transparent in Three.js. Every pixel of that texture is coming from the Phaser canvas and that includes the black background. Maybe there are some tricks in Three.js to make the black in the CanvasTexture transparent but if there is I am not aware how. Otherwise, you would have to do any kind of color manipulation on the Phaser side.

And 2ndly, how do I make my player in threejs interact with arcade physics & collision in phaser?

This would be extremely difficult. You need to look at this as having two different, encapsulated sets of game logic: one in Phaser and one in Three.js. The set of logic in the Phaser app is producing a texture that you have in Three.js, but all you have in Three.js is a set of pixels that make up that Phaser canvas. You don’t have sprites, physics, collisions, etc.

To merge these two sets of game logic, you would essentially have to wire it all together yourself. The best way I can decide to do it would be to choose which game engine you want the logic to run in, be it Phaser or Three.js. Then on that side, you would have to invisibly represent whatever exists in the other engine and send events back and forth to keep them in sync. So for example, if you wanted to have a 3D Three.js character existing inside of a Phaser game and you wanted it to react to collisions and the physics inside that Phaser game, you would need to make an invisible physics body in the Phaser game so you can actually run Phaser’s physics engine on it. But instead of displaying a sprite in Phaser for that character, you put the Three.js 3D character there. You would have to set up an event that you can call to update Three.js with how and where the 3D character should be displayed since the Phaser logic and the Three.js logic will be running separately. See what I mean?

The only other way I can see doing it would be to make an abstraction of the whole game that runs “above” both engines, and then it pushes that game state down to both Phaser and Three.js that displays the game correctly. This would still essentially use the method outlined in the previous paragraph but it would abstract it away from the game logic.

Either way, this will be a lot of work. The first option would be significantly less. The latter would be a very large project since you would essentially be making an entire game engine to stitch both engines together as a rendering layer.

@Jackolantern : Got the black background removed! Phaser’s config has a “transparent : true” parameter! Working on collision / physics.

Ahh, I forgot about that config option. That is interesting that it worked, though. I guess Three.js can preserve the transparency from the canvas.

What are you making, by the way? Are you wanting to add a 3D character to a 2D game, or something more complex?

@Jackolantern Essentially I am making a 2-1/2-D game but with the character code of a three.js game so that I can utilize near-perfect collision & physics from phaser in a three.js game. Its a platformer! :slight_smile:

Hmmm…have you considered not bringing the Phaser canvas into Three.js, but rather, just overlaying them? It would essentially be the same effect but it may simplify the code a bit since they won’t have to contain that “bridge” between them. I would assume that Three.js can render just a character on a transparent background the same way Phaser can. It would still have the same potential limitations, such as the fact that nothing in the Phaser background could obscure the Three.js character, etc.

It may also help with Three.js performance. Every frame Three.js is likely having to process the Phaser canvas to determine how to display the pixels in 3D space, even if it is laid right up against the view in a 2D fashion.

@Jackolantern : Could you perhaps make a small example demonstrating this? I know you don’t know much three.js but I would truly appreciate it if you will.

I’d be MORE THAN happy to have your name in the credits at the end of the game if you wish. <3

Much appreciation!

Yeah, unfortunately that would be way beyond my level with Three.js (which is pretty close to 0). The only way I was able to provide the previous example was because of that article I had found and because, amazingly, my initial hunch about how it would work turned out to be correct. A working example with interaction between the Three.js character and the Phaser game world would likely also take a week or more to do even with good knowledge of Three.js so it is way beyond the scope of what I can do. I’m afraid the best I can really offer is brainstorming. Sorry!

@Jackolantern Is there not a TMX loader for three.js? If I could get tilemaps working in three.js then I wouldn’t need all this.

I couldn’t find one doing a search for it, but of course that doesn’t mean one doesn’t exist. However, the TMX JSON export format is human-readable. Even creating your own procedure to render TMX maps would likely be easier and more performant than trying to bridge Phaser and Three.js and keep them in sync. Here is an older tutorial that discusses parsing and rendering a TMX map for ActionScript 3. It is from 2013, so it is likely that the format has changed a bit since then but probably a lot of the basic concepts will be the same. And here is an example of displaying a tilemap in Three.js once you can parse the TMX file enough to make sense of what it is representing. Between the two of these and likely some related tutorials that can be found on Google I think you could put it together.

And if you do, you could package it and put it on npm since I have to assume you aren’t the only person who would want something like this :slight_smile: