I’m learning to use Phaser. I made a project in Vanilla Framework using Vite.js. In this project, image and font quality are showing very low. When I try to zoom in, then images and fonts are looking blurry. I want to achieve high quality in this project’s texts and images. How to do it?
This is my code : ----
This is mainScene.js script :—
import { Scene } from "phaser";
class MainScene extends Scene {
constructor() {
super("MainScene");
}
preload() {
console.log("preload");
this.load.image("gameBG", "/Sprites/gameBG.png");
this.load.image("mineDefaultLight", "/Sprites/mineDefaultLight.png");
this.load.image("gameNameBG", "/Sprites/gameNameBG.png");
this.load.image("arrow", "/Sprites/arrow.png");
this.load.image("howToPlayBtn", "/Sprites/howToPlayBtn.png");
this.load.image("menuBtn", "/Sprites/menuBtn.png");
this.load.image("minesSelectionBG", "/Sprites/minesSelectionBG.png");
this.load.image("nextBG", "/Sprites/nextBG.png");
this.load.image("randomBG", "/Sprites/randomBG.png");
this.load.image("autoGameBG", "/Sprites/autoGameBG.png");
this.load.image("refreshImg", "/Sprites/refresh.png");
this.load.image("autoToggleOffImg", "/Sprites/autoToggleOff.png");
this.load.image("betPanelBGImg", "/Sprites/betPanelBG.png");
this.load.image("customBetFieldImg", "/Sprites/customBetFieldImg.png");
this.load.image("minusBtnImg", "/Sprites/minus.png");
this.load.image("betAmountsBtn", "/Sprites/betAmountsBtn.png");
this.load.image("plusBtnImg", "/Sprites/plus.png");
this.load.image("autoPlayBtn", "/Sprites/autoPlayBtn.png");
this.load.image("betBtn", "/Sprites/betBtn.png");
this.load.image("betBtnArrow", "/Sprites/betBtnArrow.png");
this.load.image("minesSVG", "/Sprites/MinusSVG.svg"); // Preload the MinesSVG.svg image
this.load.image("refreshSVG", "/Sprites/refreshSVG.svg");
this.load.spritesheet("demo", "/Sprites/refresh.png", {frameWidth: 22, frameHeight: 18});
}
create() {
console.log("create");
let gameBG = this.add.image(0, 0, "gameBG").setOrigin(0, 0);
gameBG.setDisplaySize(950, 520);
gameBG.setPosition(5, 5);
function preserveAspect(image, targetWidth, targetHeight) {
const scale = Math.min(targetWidth / image.width, targetHeight / image.height);
image.setScale(scale);
}
//Header
let gameHeaderContainer = this.add.container(7, 7);
let gameHeader = this.add.graphics();
gameHeader.fillStyle(0x000000, .3);
gameHeader.fillRoundedRect(0, 0, 946, 30, 12);
gameHeaderContainer.add(gameHeader);
let gameNameBG = this.add.image(3, 3, "gameNameBG").setOrigin(0, 0);
gameNameBG.setDisplaySize(130, 24);
gameHeaderContainer.add(gameNameBG);
let arrow = this.add.image(110, 12, "arrow").setOrigin(0, 0);
preserveAspect(arrow, 10, 10);
gameHeaderContainer.add(arrow);
let gameNameTxt = this.add.text(47.428, 7, "MINES", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
});
gameHeaderContainer.add(gameNameTxt);
let howToPlayBtn = this.add.image(148, 4, "howToPlayBtn").setOrigin(0, 0);
preserveAspect(howToPlayBtn, 150, 22);
gameHeaderContainer.add(howToPlayBtn);
let menuBtn = this.add.image(919, 4, "menuBtn").setOrigin(0, 0);
preserveAspect(menuBtn, 24, 24);
gameHeaderContainer.add(menuBtn);
let totalBalanceTxt = this.add.text(890, 8, "3,000.00 ", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
}).setOrigin(1, 0);
let inrText = this.add.text(totalBalanceTxt.x, totalBalanceTxt.y, "INR", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#6C9FC7",
}).setOrigin(0, 0);
totalBalanceTxt.setText(totalBalanceTxt.text);
gameHeaderContainer.add(inrText);
gameHeaderContainer.add(totalBalanceTxt);
totalBalanceTxt.setOrigin(1, 0);
//Middle
let subHeaderLine = this.add.graphics();
subHeaderLine.fillStyle(0x000000, .3);
subHeaderLine.fillRoundedRect(268.955, 71, 422.09, 4, 2);
const group = this.add.group();
const rows = 5, columns = 5;
const cellWidth = 78.9, cellHeight = 59.46;
const spacingX = 5, spacingY = 6;
const offsetX = 272.75, offsetY = 84;
for (let i = 0; i < rows * columns; i++) {
const col = i % columns;
const row = Math.floor(i / columns);
const x = offsetX + col * (cellWidth + spacingX) + cellWidth / 2;
const y = offsetY + row * (cellHeight + spacingY) + cellHeight / 2;
const box = this.add.image(x, y, 'mineDefaultLight');
preserveAspect(box, cellWidth, cellHeight);
group.add(box);
}
//SubFooter
let subFooterContainer = this.add.container(273, 415);
let randomBG = this.add.image(0, 0, "randomBG").setOrigin(0, 0);
randomBG.setDisplaySize(205.27, 30.05);
subFooterContainer.add(randomBG);
let randomTxt = this.add.text(70, 7, "RANDOM", {
fontSize: "14px",
fontFamily: "Roboto",
color: "#ffffff",
});
subFooterContainer.add(randomTxt);
let autoGameBG = this.add.image(210, 2, "autoGameBG").setOrigin(0, 0);
autoGameBG.setDisplaySize(205.23, 26);
subFooterContainer.add(autoGameBG);
// let refreshImg = this.add.image(214, 6, "refreshImg").setOrigin(0, 0);
// preserveAspect(refreshImg, 22, 18);
// subFooterContainer.add(refreshImg);
// let refreshSVG = this.add.image(214, 6, "refreshSVG").setOrigin(0, 0);
// preserveAspect(refreshSVG, 22, 18);
// subFooterContainer.add(refreshSVG);
let demoSprite = this.add.sprite(214, 6, "refreshImg");
demoSprite.setOrigin(0, 0);
demoSprite.setDisplaySize(22, 18);
subFooterContainer.add(demoSprite);
let autoToggleOffImg = this.add.image(264, 7, "autoToggleOffImg").setOrigin(0, 0);
autoToggleOffImg.setDisplaySize(28, 16);
subFooterContainer.add(autoToggleOffImg);
let autoGameTxt = this.add.text(300, 7, "Auto Game", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
});
subFooterContainer.add(autoGameTxt);
//Footer
let footerContainer = this.add.container(7, 455);
let gameFooter = this.add.graphics();
gameFooter.fillStyle(0x000000, .3);
gameFooter.fillRoundedRect(0, 0, 946, 68, 12);
footerContainer.add(gameFooter);
let betPanelBGImg = this.add.image(170, 9, "betPanelBGImg").setOrigin(0, 0);
betPanelBGImg.setDisplaySize(298, 50);
footerContainer.add(betPanelBGImg);
let betINRTxt = this.add.text(232, 16, "Bet INR", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
});
footerContainer.add(betINRTxt);
let customBetFieldImg = this.add.image(184, 30, "customBetFieldImg").setOrigin(0, 0);
customBetFieldImg.setDisplaySize(142, 22);
footerContainer.add(customBetFieldImg);
let betAmountInputField = this.add.text(240, 32, "0.00", {
fontSize: "14px",
fontFamily: "Roboto",
fontStyle: "bold",
color: "#ffffff",
}).setOrigin(0, 0);
footerContainer.add(betAmountInputField);
let minusBtnImg = this.add.image(340, 20, "minusBtnImg").setOrigin(0, 0);
preserveAspect(minusBtnImg, 33, 33);
footerContainer.add(minusBtnImg);
/* // Add the MinesSVG.svg image at the first position
let minesSVG = this.add.image(340, 20, "minesSVG").setOrigin(0, 0).setToTop();
// minesSVG.setDisplaySize(950, 520);
preserveAspect(minesSVG, 33, 33);
footerContainer.add(minesSVG); */
let betAmountsBtn = this.add.image(380, 18, "betAmountsBtn").setOrigin(0, 0);
preserveAspect(betAmountsBtn, 33, 33);
footerContainer.add(betAmountsBtn);
let plusBtnImg = this.add.image(420, 21, "plusBtnImg").setOrigin(0, 0);
preserveAspect(plusBtnImg, 33, 33);
footerContainer.add(plusBtnImg);
let autoPlayBtn = this.add.image(480, 9, "autoPlayBtn").setOrigin(0, 0);
preserveAspect(autoPlayBtn, 240, 50);
footerContainer.add(autoPlayBtn);
let betBtn = this.add.image(535, 10, "betBtn").setOrigin(0, 0);
betBtn.setDisplaySize(242, 52);
footerContainer.add(betBtn);
let betBtnArrow = this.add.image(554, 22.5, "betBtnArrow").setOrigin(0, 0);
preserveAspect(betBtnArrow, 19, 21);
footerContainer.add(betBtnArrow);
let betBtnTxt = this.add.text(645, 26, "BET", {
fontSize: "14px",
fontFamily: "Roboto",
color: "#ffffff",
});
footerContainer.add(betBtnTxt);
//SubHeader
let subHeaderContainer = this.add.container(268.955, 44);
let subHeader = this.add.graphics();
subHeader.fillStyle(0x000000, .3);
subHeader.fillRoundedRect(0, 0, 422.09, 22, 10);
subHeaderContainer.add(subHeader);
let minesSelectionBG = this.add.image(1, 1.5, "minesSelectionBG").setOrigin(0, 0);
preserveAspect(minesSelectionBG, 138, 20);
subHeaderContainer.add(minesSelectionBG);
let minesSelectionTxt = this.add.text(47, 3, "Mines: ", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
});
let minesSelectionCount = this.add.text(minesSelectionTxt.x + 35, 3, "3", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
});
subHeaderContainer.add(minesSelectionTxt);
subHeaderContainer.add(minesSelectionCount);
let arrowRight = this.add.image(122, 8, "arrow").setOrigin(0, 0);
preserveAspect(arrowRight, 8, 8);
subHeaderContainer.add(arrowRight);
let nextBG = this.add.image(318, 1.5, "nextBG").setOrigin(0, 0);
nextBG.setDisplaySize(102.53, 19);
subHeaderContainer.add(nextBG);
let nextTxt = this.add.text(334, 2, "Next: ", {
fontSize: "14px",
fontFamily: "Roboto",
color: "#343A40",
});
let nextCount = this.add.text(nextTxt.x + 36, 2, "1.10x", {
fontSize: "14px",
fontFamily: "Roboto",
color: "#343A40",
});
subHeaderContainer.add(nextTxt);
subHeaderContainer.add(nextCount);
}
}
export default MainScene;
This is config.js script :----
import Phaser from "phaser";
import MainScene from "./mainScene";
const config = {
type: Phaser.WEBGL,
width: 960,
height: 530,
backgroundColor: "#131419",
scene: [MainScene],
scale: {
mode: Phaser.Scale.MAX_ZOOM,
autoCenter: Phaser.Scale.Center.CENTER_BOTH,
},
};
const game = new Phaser.Game(config);
export default game;
This is My Project Build :---
Build
I’m learning to use Phaser. I made a project in Vanilla Framework using Vite.js. In this project, image and font quality are showing very low. When I try to zoom in, then images and fonts are looking blurry. I want to achieve high quality in this project’s texts and images. How to do it?
This is my code : ----
This is mainScene.js script :—
import { Scene } from "phaser";
class MainScene extends Scene {
constructor() {
super("MainScene");
}
preload() {
console.log("preload");
this.load.image("gameBG", "/Sprites/gameBG.png");
this.load.image("mineDefaultLight", "/Sprites/mineDefaultLight.png");
this.load.image("gameNameBG", "/Sprites/gameNameBG.png");
this.load.image("arrow", "/Sprites/arrow.png");
this.load.image("howToPlayBtn", "/Sprites/howToPlayBtn.png");
this.load.image("menuBtn", "/Sprites/menuBtn.png");
this.load.image("minesSelectionBG", "/Sprites/minesSelectionBG.png");
this.load.image("nextBG", "/Sprites/nextBG.png");
this.load.image("randomBG", "/Sprites/randomBG.png");
this.load.image("autoGameBG", "/Sprites/autoGameBG.png");
this.load.image("refreshImg", "/Sprites/refresh.png");
this.load.image("autoToggleOffImg", "/Sprites/autoToggleOff.png");
this.load.image("betPanelBGImg", "/Sprites/betPanelBG.png");
this.load.image("customBetFieldImg", "/Sprites/customBetFieldImg.png");
this.load.image("minusBtnImg", "/Sprites/minus.png");
this.load.image("betAmountsBtn", "/Sprites/betAmountsBtn.png");
this.load.image("plusBtnImg", "/Sprites/plus.png");
this.load.image("autoPlayBtn", "/Sprites/autoPlayBtn.png");
this.load.image("betBtn", "/Sprites/betBtn.png");
this.load.image("betBtnArrow", "/Sprites/betBtnArrow.png");
this.load.image("minesSVG", "/Sprites/MinusSVG.svg"); // Preload the MinesSVG.svg image
this.load.image("refreshSVG", "/Sprites/refreshSVG.svg");
this.load.spritesheet("demo", "/Sprites/refresh.png", {frameWidth: 22, frameHeight: 18});
}
create() {
console.log("create");
let gameBG = this.add.image(0, 0, "gameBG").setOrigin(0, 0);
gameBG.setDisplaySize(950, 520);
gameBG.setPosition(5, 5);
function preserveAspect(image, targetWidth, targetHeight) {
const scale = Math.min(targetWidth / image.width, targetHeight / image.height);
image.setScale(scale);
}
//Header
let gameHeaderContainer = this.add.container(7, 7);
let gameHeader = this.add.graphics();
gameHeader.fillStyle(0x000000, .3);
gameHeader.fillRoundedRect(0, 0, 946, 30, 12);
gameHeaderContainer.add(gameHeader);
let gameNameBG = this.add.image(3, 3, "gameNameBG").setOrigin(0, 0);
gameNameBG.setDisplaySize(130, 24);
gameHeaderContainer.add(gameNameBG);
let arrow = this.add.image(110, 12, "arrow").setOrigin(0, 0);
preserveAspect(arrow, 10, 10);
gameHeaderContainer.add(arrow);
let gameNameTxt = this.add.text(47.428, 7, "MINES", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
});
gameHeaderContainer.add(gameNameTxt);
let howToPlayBtn = this.add.image(148, 4, "howToPlayBtn").setOrigin(0, 0);
preserveAspect(howToPlayBtn, 150, 22);
gameHeaderContainer.add(howToPlayBtn);
let menuBtn = this.add.image(919, 4, "menuBtn").setOrigin(0, 0);
preserveAspect(menuBtn, 24, 24);
gameHeaderContainer.add(menuBtn);
let totalBalanceTxt = this.add.text(890, 8, "3,000.00 ", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
}).setOrigin(1, 0);
let inrText = this.add.text(totalBalanceTxt.x, totalBalanceTxt.y, "INR", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#6C9FC7",
}).setOrigin(0, 0);
totalBalanceTxt.setText(totalBalanceTxt.text);
gameHeaderContainer.add(inrText);
gameHeaderContainer.add(totalBalanceTxt);
totalBalanceTxt.setOrigin(1, 0);
//Middle
let subHeaderLine = this.add.graphics();
subHeaderLine.fillStyle(0x000000, .3);
subHeaderLine.fillRoundedRect(268.955, 71, 422.09, 4, 2);
const group = this.add.group();
const rows = 5, columns = 5;
const cellWidth = 78.9, cellHeight = 59.46;
const spacingX = 5, spacingY = 6;
const offsetX = 272.75, offsetY = 84;
for (let i = 0; i < rows * columns; i++) {
const col = i % columns;
const row = Math.floor(i / columns);
const x = offsetX + col * (cellWidth + spacingX) + cellWidth / 2;
const y = offsetY + row * (cellHeight + spacingY) + cellHeight / 2;
const box = this.add.image(x, y, 'mineDefaultLight');
preserveAspect(box, cellWidth, cellHeight);
group.add(box);
}
//SubFooter
let subFooterContainer = this.add.container(273, 415);
let randomBG = this.add.image(0, 0, "randomBG").setOrigin(0, 0);
randomBG.setDisplaySize(205.27, 30.05);
subFooterContainer.add(randomBG);
let randomTxt = this.add.text(70, 7, "RANDOM", {
fontSize: "14px",
fontFamily: "Roboto",
color: "#ffffff",
});
subFooterContainer.add(randomTxt);
let autoGameBG = this.add.image(210, 2, "autoGameBG").setOrigin(0, 0);
autoGameBG.setDisplaySize(205.23, 26);
subFooterContainer.add(autoGameBG);
// let refreshImg = this.add.image(214, 6, "refreshImg").setOrigin(0, 0);
// preserveAspect(refreshImg, 22, 18);
// subFooterContainer.add(refreshImg);
// let refreshSVG = this.add.image(214, 6, "refreshSVG").setOrigin(0, 0);
// preserveAspect(refreshSVG, 22, 18);
// subFooterContainer.add(refreshSVG);
let demoSprite = this.add.sprite(214, 6, "refreshImg");
demoSprite.setOrigin(0, 0);
demoSprite.setDisplaySize(22, 18);
subFooterContainer.add(demoSprite);
let autoToggleOffImg = this.add.image(264, 7, "autoToggleOffImg").setOrigin(0, 0);
autoToggleOffImg.setDisplaySize(28, 16);
subFooterContainer.add(autoToggleOffImg);
let autoGameTxt = this.add.text(300, 7, "Auto Game", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
});
subFooterContainer.add(autoGameTxt);
//Footer
let footerContainer = this.add.container(7, 455);
let gameFooter = this.add.graphics();
gameFooter.fillStyle(0x000000, .3);
gameFooter.fillRoundedRect(0, 0, 946, 68, 12);
footerContainer.add(gameFooter);
let betPanelBGImg = this.add.image(170, 9, "betPanelBGImg").setOrigin(0, 0);
betPanelBGImg.setDisplaySize(298, 50);
footerContainer.add(betPanelBGImg);
let betINRTxt = this.add.text(232, 16, "Bet INR", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
});
footerContainer.add(betINRTxt);
let customBetFieldImg = this.add.image(184, 30, "customBetFieldImg").setOrigin(0, 0);
customBetFieldImg.setDisplaySize(142, 22);
footerContainer.add(customBetFieldImg);
let betAmountInputField = this.add.text(240, 32, "0.00", {
fontSize: "14px",
fontFamily: "Roboto",
fontStyle: "bold",
color: "#ffffff",
}).setOrigin(0, 0);
footerContainer.add(betAmountInputField);
let minusBtnImg = this.add.image(340, 20, "minusBtnImg").setOrigin(0, 0);
preserveAspect(minusBtnImg, 33, 33);
footerContainer.add(minusBtnImg);
/* // Add the MinesSVG.svg image at the first position
let minesSVG = this.add.image(340, 20, "minesSVG").setOrigin(0, 0).setToTop();
// minesSVG.setDisplaySize(950, 520);
preserveAspect(minesSVG, 33, 33);
footerContainer.add(minesSVG); */
let betAmountsBtn = this.add.image(380, 18, "betAmountsBtn").setOrigin(0, 0);
preserveAspect(betAmountsBtn, 33, 33);
footerContainer.add(betAmountsBtn);
let plusBtnImg = this.add.image(420, 21, "plusBtnImg").setOrigin(0, 0);
preserveAspect(plusBtnImg, 33, 33);
footerContainer.add(plusBtnImg);
let autoPlayBtn = this.add.image(480, 9, "autoPlayBtn").setOrigin(0, 0);
preserveAspect(autoPlayBtn, 240, 50);
footerContainer.add(autoPlayBtn);
let betBtn = this.add.image(535, 10, "betBtn").setOrigin(0, 0);
betBtn.setDisplaySize(242, 52);
footerContainer.add(betBtn);
let betBtnArrow = this.add.image(554, 22.5, "betBtnArrow").setOrigin(0, 0);
preserveAspect(betBtnArrow, 19, 21);
footerContainer.add(betBtnArrow);
let betBtnTxt = this.add.text(645, 26, "BET", {
fontSize: "14px",
fontFamily: "Roboto",
color: "#ffffff",
});
footerContainer.add(betBtnTxt);
//SubHeader
let subHeaderContainer = this.add.container(268.955, 44);
let subHeader = this.add.graphics();
subHeader.fillStyle(0x000000, .3);
subHeader.fillRoundedRect(0, 0, 422.09, 22, 10);
subHeaderContainer.add(subHeader);
let minesSelectionBG = this.add.image(1, 1.5, "minesSelectionBG").setOrigin(0, 0);
preserveAspect(minesSelectionBG, 138, 20);
subHeaderContainer.add(minesSelectionBG);
let minesSelectionTxt = this.add.text(47, 3, "Mines: ", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
});
let minesSelectionCount = this.add.text(minesSelectionTxt.x + 35, 3, "3", {
fontSize: "12px",
fontFamily: "Roboto",
color: "#ffffff",
});
subHeaderContainer.add(minesSelectionTxt);
subHeaderContainer.add(minesSelectionCount);
let arrowRight = this.add.image(122, 8, "arrow").setOrigin(0, 0);
preserveAspect(arrowRight, 8, 8);
subHeaderContainer.add(arrowRight);
let nextBG = this.add.image(318, 1.5, "nextBG").setOrigin(0, 0);
nextBG.setDisplaySize(102.53, 19);
subHeaderContainer.add(nextBG);
let nextTxt = this.add.text(334, 2, "Next: ", {
fontSize: "14px",
fontFamily: "Roboto",
color: "#343A40",
});
let nextCount = this.add.text(nextTxt.x + 36, 2, "1.10x", {
fontSize: "14px",
fontFamily: "Roboto",
color: "#343A40",
});
subHeaderContainer.add(nextTxt);
subHeaderContainer.add(nextCount);
}
}
export default MainScene;
This is config.js script :----
import Phaser from "phaser";
import MainScene from "./mainScene";
const config = {
type: Phaser.WEBGL,
width: 960,
height: 530,
backgroundColor: "#131419",
scene: [MainScene],
scale: {
mode: Phaser.Scale.MAX_ZOOM,
autoCenter: Phaser.Scale.Center.CENTER_BOTH,
},
};
const game = new Phaser.Game(config);
export default game;
This is My Project Build :---
Build
The easy solution, just make everythink bigger (Images, Text usw.), so that when browser has to fit the canvas into the browser-window, it has to scale down. Because the same way how scaling an image in an ImageEditor makes it blurry, when the browser scales up it will make it Blurry.
The one drawback your game will get alot bigger(except if you use svg's), due to the increase file size (of assets), and depending on how many assets you are using at the same time, this fact could also lead to performance issues.
Side Note: If the Font is the main issue and you could think of using phasers Bitmap text GameObject (link to the documentation). Here you would have to make/find a suitable font first, but it will in more predictable results.
Info: If you are creating a pixelart game, and you want phaser to leave your images "untouched". You can use the property
pixelArt:true
in the gameConfig. (link to documentation)