I'm trying to fit the game to the screen, however I'm unable to scale the stage itself. With libraries like EaselJS from CreateJS I can simply do stage.scaleX = stage.scaleY = r.
In Phaser, I want to scale not only the game, but also together a HTML div (for user interface) that is outside Phaser. As you can see, the drawn rectangle is not scaled according to the current screen size, no matter what properties I change (game.scale.scaleMode, game.scale.displayScale etc.). Is there anything I can do?
const ProjectSettings = {
backgroundColor: 0x333333,
resolution: [100, 100],
};
const SceneContainers = {
sceneContent: null,
sceneCanvas: null,
phaserGame: null,
sceneUIDiv: null,
init() {
SceneContainers.sceneContent = document.getElementById('content');
SceneContainers.phaserGame = new Phaser.Game({
width: ProjectSettings.resolution[0],
height: ProjectSettings.resolution[1],
type: Phaser.AUTO,
parent: SceneContainers.sceneContent,
backgroundColor: ProjectSettings.backgroundColor,
scene: [Preloader],
});
SceneContainers.sceneCanvas = SceneContainers.phaserGame.canvas;
SceneContainers.sceneCanvas.classList.add('scene-canvas');
SceneContainers.sceneUIDiv = document.createElement('div');
SceneContainers.sceneUIDiv.id = 'scene-ui';
SceneContainers.sceneContent.appendChild(SceneContainers.sceneUIDiv);
},
};
const SceneScaler = {
init() {
SceneContainers.phaserGame.scale.scaleMode = Phaser.Scale.ScaleModes.RESIZE;
SceneScaler.fitToScreen();
window.addEventListener('resize', e => {
SceneScaler.fitToScreen();
});
},
fitToScreen() {
const [contentW, contentH] = ProjectSettings.resolution;
const [windowW, windowH] = [innerWidth, innerHeight];
const ratio = contentW / contentH;
const windowRatio = windowW / windowH;
let scale = windowW / contentW;
if (windowRatio > ratio) {
scale = windowH / contentH;
}
//SceneContainers.sceneCanvas.width = contentW * scale;
//SceneContainers.sceneCanvas.height = contentH * scale;
SceneContainers.phaserGame.scale.resize(contentW * scale, contentH * scale);
SceneContainers.sceneUIDiv.style.transform = `scale(${scale})`;
SceneContainers.sceneContent.style.width = `${contentW * scale}px`;
SceneContainers.sceneContent.style.height = `${contentH * scale}px`;
SceneContainers.sceneUIDiv.style.width = `${contentW}px`;
SceneContainers.sceneUIDiv.style.height = `${contentH}px`;
SceneContainers.sceneContent.style.left =
SceneContainers.sceneCanvas.style.left =
SceneContainers.sceneUIDiv.style.left = `${windowW / 2 - (contentW * scale) / 2}px`;
SceneContainers.sceneContent.style.top =
SceneContainers.sceneCanvas.style.top =
SceneContainers.sceneUIDiv.style.top = `${windowH / 2 - (contentH * scale) / 2}px`;
//SceneContainers.phaserGame.scale.displayScale = new Phaser.Math.Vector2(scale, scale);
},
};
class Scene extends Phaser.Scene {
constructor(id) {
super(id);
}
init() {
this.events.on('shutdown', () => {
SceneContainers.sceneUIDiv.innerHTML = '';
});
}
}
class Preloader extends Scene {
constructor() {
super('preloader');
}
preload() {
}
create() {
this.add.rectangle(50, 50, 50, 50, 0xff6666);
}
}
class EntryPoint {
constructor() {
this.init();
}
init() {
SceneContainers.init();
SceneScaler.init();
}
}
new EntryPoint;
html, body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
html, body {
background: #333333;
}
#content {
position: absolute;
display: inline-block;
}
.scene-canvas {
position: absolute;
}
#scene-ui {
display: inline-block;
position: absolute;
transform-origin: left top;
}
<script src="https://github.com/photonstorm/phaser/releases/download/v3.55.2/phaser.min.js"></script>
<div id="content"></div>
Also, for some reason my snippet is giving undefined for canvas.classList, so I appreciate if someone could fix that. This classList error is not happening with my project.
If you are only looking for automatic scaling, you could use the config parameter scale.mode (of the Phaser Game Object) and set it to Phaser.Scale.FIT, then everything should be scaled.
Here a very simplified demo:
If you resize the window (when you open the snipplet fullsize and change the height), you should see "the scaling"
var Preloader = {
create() {
this.add.rectangle(50, 50, 50, 50, 0xff6666);
}
};
new Phaser.Game({
width:300,
height:300,
scale: {
mode: Phaser.Scale.FIT,
},
type: Phaser.AUTO,
scene: [Preloader],
});
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>
Related
I want to add Pixi.js to one of my VueJs components, but it doesn't work. What I want to do for now is to implement one of the basic examples from the Pixi.js website.
The problem is that with the same code as the one on the website, I only see the background color on my screen.
Here is my VueJS component:
<template>
<body>
<div id='change'>
<router-link class="changepage" to='/OrdreCouches'> >Retour </router-link>
</div>
<div id="pixi"></div>
</body>
</template>
<script>
import * as PIXI from 'pixi.js'
export default {
name: 'Visualisation',
data(){
return{
app: new PIXI.Application()
}
},
methods: {
init: function() {
const app = new PIXI.Application({
width: 800, height: 600, backgroundColor: 0x1099bb, resolution: window.devicePixelRatio || 1,
});
document.body.appendChild(app.view);
const container = new PIXI.Container();
app.stage.addChild(container);
// Create a new texture
const texture = PIXI.Texture.from('./assets/blob.png');
// Create a 5x5 grid of bunnies
for (let i = 0; i < 25; i++) {
const bunny = new PIXI.Sprite(texture);
bunny.anchor.set(0.5);
bunny.x = (i % 5) * 40;
bunny.y = Math.floor(i / 5) * 40;
container.addChild(bunny);
}
// Move container to the center
container.x = app.screen.width / 2;
container.y = app.screen.height / 2;
// Center bunny sprite in local container coordinates
container.pivot.x = container.width / 2;
container.pivot.y = container.height / 2;
// Listen for animate update
app.ticker.add((delta) => {
// rotate the container!
// use delta to create frame-independent transform
container.rotation -= 0.01 * delta;
});
}
},
mounted() {
this.init();
}
}
</script>
<style>
.changepage{
position: absolute;
color: rgb(0, 0, 0);
font-size: 30px;
}
.changepage:hover{
position: absolute;
color: rgb(53, 20, 199);
font-size: 30px;
}
</style>
Could you help me with this?
Thank you!!
I've been looking for a solution to be able to make my game fully responsive to any screen resolution using Phaser 3, for example:
This example was made with Construct 2, where by the way it is very simple to do this effect.
Does anyone know what is the best approach to achieve this using Phaser 3?
Doing research I was able to find a solution to my problem:
The key is use a parent scene to control all other child scenes, This scene is going to measure the same as the device's screen size. It will also resize the child scenes when the screen size changes, but always keeping the aspect ratio.
HandlerScene.js
export default class Handler extends Phaser.Scene {
// Vars
sceneRunning = null
constructor() {
super('handler')
}
create() {
this.cameras.main.setBackgroundColor('#FFF')
this.launchScene('preload')
}
launchScene(scene, data) {
this.scene.launch(scene, data)
this.gameScene = this.scene.get(scene)
}
updateResize(scene) {
scene.scale.on('resize', this.resize, scene)
const scaleWidth = scene.scale.gameSize.width
const scaleHeight = scene.scale.gameSize.height
scene.parent = new Phaser.Structs.Size(scaleWidth, scaleHeight)
scene.sizer = new Phaser.Structs.Size(scene.width, scene.height, Phaser.Structs.Size.FIT, scene.parent)
scene.parent.setSize(scaleWidth, scaleHeight)
scene.sizer.setSize(scaleWidth, scaleHeight)
this.updateCamera(scene)
}
resize(gameSize) {
// 'this' means to the current scene that is running
if (!this.sceneStopped) {
const width = gameSize.width
const height = gameSize.height
this.parent.setSize(width, height)
this.sizer.setSize(width, height)
const camera = this.cameras.main
const scaleX = this.sizer.width / this.game.screenBaseSize.width
const scaleY = this.sizer.height / this.game.screenBaseSize.height
camera.setZoom(Math.max(scaleX, scaleY))
camera.centerOn(this.game.screenBaseSize.width / 2, this.game.screenBaseSize.height / 2)
}
}
updateCamera(scene) {
const camera = scene.cameras.main
const scaleX = scene.sizer.width / this.game.screenBaseSize.width
const scaleY = scene.sizer.height / this.game.screenBaseSize.height
camera.setZoom(Math.max(scaleX, scaleY))
camera.centerOn(this.game.screenBaseSize.width / 2, this.game.screenBaseSize.height / 2)
}
}
In this way we can start other scenes in parallel within the parent scene.
PreloadScene.js
export default class Preload extends Phaser.Scene {
handlerScene = null
sceneStopped = false
constructor() {
super({ key: 'preload' })
}
preload() {
// Images
this.load.image('logo', 'assets/images/logo.png')
this.width = this.game.screenBaseSize.width
this.height = this.game.screenBaseSize.height
this.handlerScene = this.scene.get('handler')
this.handlerScene.sceneRunning = 'preload'
this.sceneStopped = false
...
}
create() {
const { width, height } = this
// CONFIG SCENE
this.handlerScene.updateResize(this)
// CONFIG SCENE
// GAME OBJECTS
this.add.image(width / 2, height / 2, 'logo').setOrigin(.5)
// GAME OBJECTS
}
}
In the child scenes, the updateResize function of the parent scene must be called from the create function of each scene.
ConfigGame.js
import Handler from './scenes/handler.js'
import Preload from './scenes/preload.js'
// Aspect Ratio 16:9 - Portrait
const MAX_SIZE_WIDTH_SCREEN = 1920
const MAX_SIZE_HEIGHT_SCREEN = 1080
const MIN_SIZE_WIDTH_SCREEN = 270
const MIN_SIZE_HEIGHT_SCREEN = 480
const SIZE_WIDTH_SCREEN = 540
const SIZE_HEIGHT_SCREEN = 960
const config = {
type: Phaser.AUTO,
scale: {
mode: Phaser.Scale.RESIZE,
parent: 'game',
width: SIZE_WIDTH_SCREEN,
height: SIZE_HEIGHT_SCREEN,
min: {
width: MIN_SIZE_WIDTH_SCREEN,
height: MIN_SIZE_HEIGHT_SCREEN
},
max: {
width: MAX_SIZE_WIDTH_SCREEN,
height: MAX_SIZE_HEIGHT_SCREEN
}
},
dom: {
createContainer: true
},
scene: [Handler, Preload]
}
const game = new Phaser.Game(config)
// Global
game.screenBaseSize = {
maxWidth: MAX_SIZE_WIDTH_SCREEN,
maxHeight: MAX_SIZE_HEIGHT_SCREEN,
minWidth: MIN_SIZE_WIDTH_SCREEN,
minHeight: MIN_SIZE_HEIGHT_SCREEN,
width: SIZE_WIDTH_SCREEN,
height: SIZE_HEIGHT_SCREEN
}
The mode: Phaser.Scale.RESIZE is very important and also a maximum and a minimum for the screen size.
My complete solution is here:
https://github.com/shimozurdo/mobile-game-base-phaser3
Explanation:
https://labs.phaser.io/edit.html?src=src/scalemanager/mobile%20game%20example.js
I am trying to replicate the same result as using CSS width: 50vw; and height: 100vh; but in Javascript. My code is not currently creating the desired effect.
const logicalWidth = window.innerWidth / 2;
const logicalHeight = window.innerHeight;
I can see there will be some issues down the line with making this responsive as it will be full-width on ipad/ mobile. What I'm thinking might be the best way to handle this is rendering the image using CSS background-image: and this way I can control width, height and background-position with media query
I tried this but it does not work
.js-canvas {
background-image: url('https://raw.githubusercontent.com/codrops/LiquidDistortion/master/img/13.jpg');
width: 50vw;
height: 100%;
background-position: center center;
}
Can anyone suggest a solution to this? Very happy to do this all with JS but not sure where to begin
// Declare all vars
let bgSprite,
displacementSprite,
displacementFilter,
pointerSprite,
pointerFilter;
// Images used
const images = [
{
name: 'bg',
url: 'https://raw.githubusercontent.com/codrops/LiquidDistortion/master/img/13.jpg'
},
{
name: 'clouds',
url: 'https://raw.githubusercontent.com/pixijs/examples/gh-pages/examples/assets/pixi-filters/displacement_map_repeat.jpg'
}
];
const logicalWidth = 1800;
const logicalHeight = 1080;
// Determine & create the PIXI App instance
const canvasEl = document.querySelector('.js-canvas');
const canvasElOptions = {
autoDensity: true,
backgroundColor: 0xFFFFFF,
resizeTo: window,
resolution: window.devicePixelRatio || 1,
view: canvasEl
};
const resizeHandler = () => {
const scaleFactor = Math.min(
window.innerWidth / logicalWidth,
window.innerHeight / logicalHeight
);
const newWidth = Math.ceil(logicalWidth * scaleFactor);
const newHeight = Math.ceil(logicalHeight * scaleFactor);
app.renderer.view.style.width = `${newWidth}px`;
app.renderer.view.style.height = `${newHeight}px`;
app.renderer.resize(newWidth, newHeight);
mainContainer.scale.set(scaleFactor);
};
let app = new PIXI.Application(canvasElOptions);
let mainContainer = new PIXI.Container();
app.loader
.add(images)
.on('progress', loadProgressHandler)
.load(setup);
app.renderer.plugins.interaction.moveWhenInside = true;
function loadProgressHandler(loader, resource) {
//Display the percentage of files currently loaded
console.log("progress: " + loader.progress + "%");
//If you gave your files names as the first argument
//of the `add` method, you can access them like this
console.log("loading: " + resource.name);
}
function setup(loader, resources){
console.log("All files loaded");
resizeHandler();
app.stage.addChild(mainContainer);
window.addEventListener('resize', resizeHandler);
bgSprite = new PIXI.Sprite(resources.bg.texture);
bgSprite.interactive = true;
displacementSprite = new PIXI.Sprite(resources.clouds.texture);
// Make sure the sprite is wrapping.
displacementSprite.texture.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT;
displacementFilter = new PIXI.filters.DisplacementFilter(displacementSprite);
pointerSprite = new PIXI.Sprite(resources.clouds.texture);
pointerFilter = new PIXI.filters.DisplacementFilter(pointerSprite);
displacementSprite.width = bgSprite.height;
displacementSprite.height = bgSprite.height;
pointerSprite.anchor.set(0.5);
pointerFilter.scale.x = 7;
pointerFilter.scale.y = 7;
mainContainer.addChild(bgSprite);
mainContainer.addChild(displacementSprite);
mainContainer.addChild(pointerSprite);
mainContainer.filters = [displacementFilter, pointerFilter];
pointerSprite.visible = false;
app.ticker.add((delta) => {
// Offset the sprite position to make vFilterCoord update to larger value.
// Repeat wrapping makes sure there's still pixels on the coordinates.
displacementSprite.x += 3.5 * delta;
displacementSprite.y += 3.5 * delta;
// Reset x & y to 0 when x > width to keep values from going to very huge numbers.
if (displacementSprite.x > displacementSprite.width) {
displacementSprite.x = 0;
displacementSprite.y = 0;
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.0.3/pixi.min.js"></script>
<canvas class="test js-canvas"></canvas>
Hi I'm using konva js (https://konvajs.org) with vue and I'm trying to animate the text so that it slides into the screen from off the stage to a certain position, however I'm not 100% sure how this should work, I've been able to get a demo working here;
https://codesandbox.io/s/vue-konva-template-i2em3
Vue;
<v-stage ref="stage" :config="stageSize">
<v-layer ref="layer">
<v-text
ref="text1"
:config="{
text: 'Draggable Text',
x: 50,
y: 50,
draggable: true,
fill: 'black'
}"
/>
</v-layer>
</v-stage>
</template>
<script>
const width = window.innerWidth;
const height = window.innerHeight;
export default {
data() {
return {
stageSize: {
width: width,
height: height
}
};
},
methods: {
changeSize(e) {
// to() is a method of `Konva.Node` instances
e.target.to({
scaleX: Math.random() + 0.8,
scaleY: Math.random() + 0.8,
duration: 0.2
});
}
},
mounted() {
const vm = this;
const amplitude = 100;
const period = 5000;
// in ms
const centerX = vm.$refs.stage.getStage().getWidth() / 2;
const text = this.$refs.text1.getStage();
// example of Konva.Animation
const anim = new Konva.Animation(function(frame) {
text.setX(
amplitude * Math.sin((frame.time * 2 * Math.PI) / period) + centerX
);
}, text.getLayer());
anim.start();
}
};
</script>
any ideas how I can get the text to appear from outside of the stage and then stop at a certain point within the canvas?
You can just use node.to() method to animatio any Konva.Node:
mounted() {
const textNode = this.$refs.text1.getNode();
const endX = width / 2 - textNode.width() / 2;
// run the animation
textNode.to({
x: endX,
onFinish: () => {
// update the state at the end
this.textPos.x = endX;
}
})
}
Demo: https://codesandbox.io/s/vue-konva-animation-demo-lr4qw
I'm making a 3D box with Zdog and I want to let the height of the box grow.
Here is a codepen: https://codepen.io/anon/pen/qzBMgp.
This is my code for the box:
let progressBox = new Zdog.Box({
addTo: progress,
width: 200,
height: boxHeight,
depth: 200,
stroke: 1,
})
This is the code I use to increase the height of the box. If the box is shorter than 400, the box will increase its height with 0.1.
function animate() {
if (boxHeight < 400) {
moveUp = 'up';
} else if (boxHeight > 400) {
moveUp = 'false';
}
boxHeight += moveUp == 'up' ? 0.1 : 0;
}
The problem is that the box stays at a height of 0 (the value I gave to boxHeight), but when I console.log(boxHeight) the boxHeight will grow.
First of all, let me point out that you cannot change the value of a constant . On your code, the boxHeight is declared as const.
Second, you will need to use Zdog's copy() method. Here is your code modified accordingly.
Zdog.Anchor.prototype.renderGraphSvg = function (svg) {
if (!svg) {
throw new Error('svg is ' + svg + '. ' +
'SVG required for render. Check .renderGraphSvg( svg ).');
}
this.flatGraph.forEach(function (item) {
item.render(svg, Zdog.SvgRenderer);
});
};
const TAU = Zdog.TAU;
const light = '#EAE2B7';
const yellow1 = '#FCBF49';
const orange1 = '#F77F00';
const red1 = '#d62828';
const purple1 = '#003049';
const white1 = '#ffffff';
const isSpinning = true;
var boxHeight = 0;
let progress = new Zdog.Illustration({
element: '.progress',
dragRotate: true,
translate: {
y: 25
},
rotate: {
x: -0.4, y: 0.75
}
});
let progressBox = new Zdog.Box({
addTo: progress,
width: 200,
depth: 200,
height: boxHeight,
stroke: 1,
color: purple1, // default face color
leftFace: yellow1,
rightFace: orange1,
topFace: red1,
bottomFace: light,
translate: {
x: 0,
y: 300
},
});
function animate() {
if (boxHeight <= 400) {
boxHeight++; // 1
progressBox = progressBox.copy({
height: boxHeight, // overwrite height
translate: {
y: progressBox.translate.y - 1 // overwrite vertical position to put box in place while height is growing.
}
});
}
progress.updateRenderGraph();
requestAnimationFrame(animate);
}
animate();
I forked your pen and updated it with the code above. See Zdog - progress box
Note that it seems to be expensive doing the copy() method on every animation frame. I am also new to this library and this is currently the fix I know of.