Collider in Phaser 3 randomly doesn't work - javascript

I just began coding in Phaser 3 after developing some games with p5.js and wanted to make a 2d endless runner game. So here's the code for my game:
var game;
var gameOptions = {
monkeyGravity: 1200,
monkeyPower: 1000
}
window.onload = function() {
let gameConfig = {
type: Phaser.AUTO,
backgroundColor:0x87ceeb,
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
parent: 'thegame',
width: 1920,
height: 1080
},
physics: {
default: 'arcade',
arcade: {debug: true}
},
scene: [
startGame,
playGame
]
}
game = new Phaser.Game(gameConfig);
window.focus();
}
class startGame extends Phaser.Scene{
constructor(){
super('StartGame');
}
preload(){
this.load.image('menu-bg', '/jeffrey2nd/menu-bg.png');
this.load.image('play-button', '/jeffrey2nd/play-button.png');
}
create() {
this.menuBg = this.add.sprite(game.config.width / 2, 0, 'menu-bg').setScale(2);
const screenCenterX = this.cameras.main.worldView.x + this.cameras.main.width / 2;
const screenCenterY = this.cameras.main.worldView.y + this.cameras.main.height / 2;
const startButton = this.add.sprite(screenCenterX, screenCenterY, 'play-button');
startButton.setInteractive();
startButton.on('pointerdown', () => this.scene.start('PlayGame'));
}
}
class playGame extends Phaser.Scene{
constructor(){
super('PlayGame');
}
preload(){
this.load.image('background', '/jeffrey2nd/background.png');
this.load.image('backgroundL1', '/jeffrey2nd/backgroundL1.png');
this.load.image('backgroundL2', '/jeffrey2nd/backgroundL2.png');
this.load.image('backgroundL3', '/jeffrey2nd/backgroundL3.png');
this.load.image('backgroundL4', '/jeffrey2nd/backgroundL4.png');
this.load.image('ground', '/jeffrey2nd/ground.png');
//ANIMATIONS
this.load.image('run0', '/jeffrey2nd/animations/monkey/Running_000.png');
this.load.image('run1', '/jeffrey2nd/animations/monkey/Running_001.png');
this.load.image('run2', '/jeffrey2nd/animations/monkey/Running_002.png');
this.load.image('run3', '/jeffrey2nd/animations/monkey/Running_003.png');
this.load.image('run4', '/jeffrey2nd/animations/monkey/Running_004.png');
this.load.image('run5', '/jeffrey2nd/animations/monkey/Running_005.png');
this.load.image('run6', '/jeffrey2nd/animations/monkey/Running_006.png');
this.load.image('run7', '/jeffrey2nd/animations/monkey/Running_007.png');
this.load.image('run8', '/jeffrey2nd/animations/monkey/Running_008.png');
this.load.image('run9', '/jeffrey2nd/animations/monkey/Running_009.png');
this.load.image('run10', '/jeffrey2nd/animations/monkey/Running_010.png');
this.load.image('run11', '/jeffrey2nd/animations/monkey/Running_011.png');
this.load.image('run12', '/jeffrey2nd/animations/monkey/Running_012.png');
this.load.image('run13', '/jeffrey2nd/animations/monkey/Running_013.png');
this.load.image('jump0', '/jeffrey2nd/animations/monkey/Jumping_000.png');
this.load.image('jump1', '/jeffrey2nd/animations/monkey/Jumping_001.png');
this.load.image('jump2', '/jeffrey2nd/animations/monkey/Jumping_002.png');
this.load.image('jump3', '/jeffrey2nd/animations/monkey/Jumping_003.png');
this.load.image('jump4', '/jeffrey2nd/animations/monkey/Jumping_004.png');
}
create(){
//BACKGROUND AND LAYERS
this.bgLs = this.add.group();
this.background = this.bgLs.create(0, game.config.height / 2, 'background');
this.backgroundL1 = this.bgLs.create(0, game.config.height / 2, 'backgroundL1');
this.backgroundL12 = this.bgLs.create(game.config.width, game.config.height / 2, 'backgroundL1');
this.backgroundL2 = this.bgLs.create(0, game.config.height / 2, 'backgroundL2');
this.backgroundL22 = this.bgLs.create(game.config.width, game.config.height / 2, 'backgroundL2');
this.backgroundL3 = this.bgLs.create(0, game.config.height / 2, 'backgroundL3');
this.backgroundL32 = this.bgLs.create(game.config.width, game.config.height / 2, 'backgroundL3');
this.backgroundL4 = this.bgLs.create(0, game.config.height / 2, 'backgroundL4');
this.backgroundL42 = this.bgLs.create(game.config.width, game.config.height / 2, 'backgroundL4');
for (let b of this.bgLs.children.entries) {
b.setOrigin(0, 0.5);
}
//GROUND PLATFORMS
this.groundGroup = this.physics.add.group();
this.ground1 = this.groundGroup.create(0, game.config.height - 50, 'ground');
this.ground2 = this.groundGroup.create(game.config.width, game.config.height - 50, 'ground');
this.ground3 = this.groundGroup.create(game.config.width + game.config.width / 2, game.config.height - 275, 'ground');
this.ground4 = this.groundGroup.create(game.config.width + game.config.width / 1.5, game.config.height - 500, 'ground');
this.ground4.setScale(0.5, 1);
for (let g of this.groundGroup.children.entries) {
g.setOrigin(0, 0.5);
g.setImmovable(true);
g.setScale(1,0.3);
g.body.checkCollision.down = false;
}
//MONKEY
this.monkey = this.physics.add.sprite(game.config.width / 10 * 2, 500, 'run0');
this.monkey.setScale(0.3);
this.anims.create({
key: "player-run",
frames: [
{ key: 'run0' },
{ key: 'run1' },
{ key: 'run2' },
{ key: 'run3' },
{ key: 'run4' },
{ key: 'run5' },
{ key: 'run6' },
{ key: 'run7' },
{ key: 'run8' },
{ key: 'run9' },
{ key: 'run10' },
{ key: 'run11' },
{ key: 'run12' },
{ key: 'run13' }
],
frameRate: 20,
repeat: -1
})
this.anims.create({
key: "player-jump",
frames: [
{ key: 'jump0' },
{ key: 'jump1' },
{ key: 'jump2' },
{ key: 'jump3' },
{ key: 'jump4' }
],
frameRate: 20,
repeat: -1
})
this.monkey.body.setSize(this.monkey.width/2, this.monkey.height/2);
this.input.on('pointerdown', this.jump, this);
this.input.on('pointerup', this.fall, this);
}
update(){
this.backgroundL1.x -= 0.2;
this.backgroundL12.x -= 0.2;
this.backgroundL2.x -= 0.4;
this.backgroundL22.x -= 0.4;
this.backgroundL3.x -= 0.6;
this.backgroundL32.x -= 0.6;
this.backgroundL4.x -= 0.8;
this.backgroundL42.x -= 0.8;
for (let b of this.bgLs.children.entries) {
if (b.x <= -game.config.width) b.setX(game.config.width);
}
var speed = 5;
for (let g of this.groundGroup.children.entries) {
g.setX(g.x-speed);
//if (g.x <= -game.config.width) g.setX(game.config.width);
}
if (this.ground1.x <= -game.config.width) this.ground1.setX(game.config.width);
if (this.ground2.x <= -game.config.width) this.ground2.setX(game.config.width);
if (this.ground3.x <= -game.config.width) {
this.rnd1 = (Phaser.Math.Between(0, 500))/100;
this.ground3.setX(game.config.width + game.config.width / this.rnd1);
}
if (this.ground4.x <= -game.config.width) {
this.rnd2 = (Phaser.Math.Between(0, 500))/100;
this.ground4.setX(game.config.width + game.config.width / this.rnd2);
}
this.physics.world.collide(this.groundGroup, this.monkey, ()=> {console.log('touche' + game.loop.time )}, null, this);
this.monkey.body.gravity.y = gameOptions.monkeyGravity;
if(this.monkey.body.touching.down) this.monkey.anims.play("player-run", true);
else this.monkey.anims.play("player-jump", true);
}
jump(){
if(this.monkey.body.touching.down) {
this.monkey.body.setVelocity(0, -gameOptions.monkeyPower);
this.monkey.anims.stop();
this.monkey.anims.play("player-jump");
}
}
fall(){
if (this.monkey.body.velocity.y < 0) this.monkey.body.setVelocity(0, -100);
}
}
Game start scene has the Start Button, the game begins, the monkey runs on the platforms and you can jump on the upper platforms.
All seems to work fine, but sometimes randomly the monkey falls down off the screen.
You can see a playable version of the bug at https://420videogames.com/jeffrey2nd
Here I added a console log in the 'monkey vs ground goup collide' callback function, logging the game.loop.time to try to understand. My idea was that maybe some frames were missed during Update and the objects did not collide perfectly, but when the monkey falls off, the callback function runs 2 times and then the monkey keeps falling and the game breaks up.
Another strange thing about this issue is that on my mobile phone REDMI8 the game works with no problems, as for the iPhone8 of my GF. On Firefox mobile of another friend, by the way, the game has the same PC issue.
Thank you in advance for your attention, hope someone can help me fix this problem,
Ab

The issue was resolved moving the colliders from Update function to Create function.

Related

Reinitialise the coordinate by using setter in Javascripts

I am new to OOP and just learning now. I want to reinitialise the default location of a circle by using the codes below:
function Circle(radius) {
this.radius = radius;
let defaultLocation = {
x: 0,
y: 0
};
this.getDefaultLocation = function(a, b) {
return defaultLocation
};
Object.defineProperty(this, 'defaultLocation', {
get: function(a, b) {
return defaultLocation;
},
set: function(a, b) {
defaultLocation = {
x: a,
y: b
};
}
});
}
const circle = new Circle(10);
circle.defaultLocation = {
x: 5,
y: 6
};
However, i check in the chrome browser console, the result is:
x: {x: 5, y: 6}
y: undefined
Could you tell me where i done wrong and how to correct it?
Thanks.
You can't pass two variables to set, but you can pass an object (or an array).
class Circle {
get defaultLocation() {
return this._defaultLocation
}
set defaultLocation(loc) {
this._defaultLocation = loc
}
constructor(radius) {
this.radius = radius;
this._defaultLocation = {
x: 0,
y: 0
};
}
}
const circle = new Circle(10);
circle.defaultLocation = {
x: 5,
y: 6
};

Can I access this of an object in JavaScript?

var b = {
state: 'initial',
initial: {
onClick: function() {
console.log(this);
},
x: 0,
},
}
Hi, I want to know if its possible to access b object inside onClick function in the code above?
the output is {x: 0, onClick: ƒ} instead of {state: 'initial', ... }
Changing it to arrow func will output window object instead.
Im making an escape room game and kind of have a chicken & egg situation.
var spriteObject =
{
img: null,
INITIAL: {
sourceX: 0,
sourceY: 0,
sourceWidth: 64,
sourceHeight: 64,
x: 0,
y: 0,
width: 64,
height: 64,
isWithinBounds: function(x, y) {
return x > this.x && x < this.x + this.width && y > this.y && y < this.y + this.height;
},
},
state: 'INITIAL',
};
const inventoryItems = [];
let currentRoom = "kitchen";
const knife = {
...spriteObject,
INITIAL: {
...spriteObject.INITIAL,
x: 200,
y: 162,
sourceX: 1330,
sourceY: 8,
sourceWidth: 803,
sourceHeight: 514,
width: 803,
height: 514,
onClick: () => {
inventoryItems.push(knife);
layers.kitchen.sprites = layers.kitchen.sprites.filter(sprite => sprite !== knife);
},
},
img: kitchenLayout,
};
const layers = {
kitchen: {
sprites: [knife],
},
};
window.addEventListener("click", function(e) {
const x = e.pageX - canvas.offsetLeft;
const y = e.pageY - canvas.offsetTop;
layers[currentRoom].sprites.forEach(sprite => {
const currSprite = sprite[sprite.state];
if (currSprite.onClick && currSprite.isWithinBounds(x, y)) {
currSprite.onClick();
render();
}
})
})
Let's say I have a kitchen room and a knife on the counter. I can pick the knife and put it in my inventory. The knife will have 3 different conditions: on the counter (initial), in inventory, and dull (after used). I am not sure if I want to model in inventory as a state, but I have trouble figuring out how to remove the knife from list of sprites in kitchen. It is doable in the code above but it seems to rely on the fact that I declare knife as a variable. I don't want to do this, in case I want to declare my items directly on the sprites array. I appreciate any hints, thanks
You should be able to use javascript classes for this. That way you can reference your current class as this.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

PDFjs view pdf to canvas

I am developing a pdf viewer, with the ability to apply additional elements by the user.
Pdf has drag and drop capability, zoom in and out.
I ran into the following problems that baffle me:
Correctly position the new elements so that the image is set at coordinates x: 0, y: 0. (image 1) When displacing pdf, I can not track what distance to displace the coordinates of the new element. (image 2)
To keep the image quality when zooming in, I set the camera Zoom (init scale) to 3. I can't find a solution how to display it in a smaller size when opening the page, so as not to lose quality when zooming in. (image 3)
import React, { useEffect, useState, useRef } from 'react';
import * as PDFJS from 'pdfjs-dist'
import pdfjsWorker from "pdfjs-dist/build/pdf.worker.entry";
import {makeStyles} from "#material-ui/core/styles";
export const PdfCanvas = ({pageNum, editCanvas, colorCircle}) => {
const canvasRef = useRef();
const [image, setImage] = useState();
const fileUri = "https://s3-us-east-2.amazonaws.com/c9e8e9c8-7ec0-412f-81cc-60fc07201419/Bar%20Yohai_Coordination%20plane%2000.pdf";
const mainCanvas = canvasRef.current
const mainCtx = mainCanvas?.getContext('2d');
let cameraOffset = { x: window.innerWidth/2, y: window.innerHeight/2 }
let cameraZoom = 3
let MAX_ZOOM = 108
let MIN_ZOOM = 0.01
let SCROLL_SENSITIVITY = 0.0005
const [positionArr, setPositionArr] = useState([
{id: '1', x: 400, y: 40, radius: 10, color: 'rgb(255,0,0)'},
{id: '2', x: 800, y: 40, radius: 10, color: 'rgb(134,211,17)'},
{id: '3', x: 100, y: 40, radius: 10, color: 'rgb(32,52,157)'},
{id: '4', x: 720, y: 40, radius: 10, color: 'rgb(10,9,9)'},
{id: '5', x: 640, y: 40, radius: 10, color: 'rgb(227,170,24)'},
]);
function isIntersect(point: { x: any; y: any; }, circle: { id?: string; x: any; y: any; radius: any; color?: string; }) {
return Math.sqrt((point.x-circle.x) ** 2 + (point.y - circle.y) ** 2) < circle.radius;
}
const renderPage = (pageNum) => {
const canvas = document.createElement('canvas'), ctx = canvas.getContext('2d');
const container = document.getElementById("container")
if (fileUri) {
const loadingTask = PDFJS.getDocument(fileUri);
loadingTask.promise.then(loadedPdf => {
loadedPdf && loadedPdf.getPage(pageNum).then(function(page) {
const viewport = page.getViewport({scale: cameraZoom});
canvas.width = viewport.width;
canvas.height = viewport.height ;
canvas.style.width = "100%";
canvas.style.height = "100%";
container.style.width = Math.floor(viewport.width/cameraZoom) + 'pt';
container.style.height = Math.floor(viewport.height/cameraZoom) + 'pt';
const renderContext = {
canvasContext: ctx,
viewport: viewport
};
page.render(renderContext).promise.then(() => {
var pdfImage = new Image();
pdfImage.src = canvas.toDataURL("image/png", 1)
setImage(pdfImage)
})
});
}, function (reason) {
console.error(reason);
});
}
};
function draw()
{
if (mainCanvas) {
mainCanvas.width = visualViewport.width
mainCanvas.height = visualViewport.height
}
// Translate to the canvas centre before zooming - so you'll always zoom on what you're looking directly at
if (mainCtx) {
mainCtx.scale(cameraZoom, cameraZoom)
mainCtx.translate( -window.innerWidth / .8 + cameraOffset.x, -window.innerHeight / .8 + cameraOffset.y )
mainCtx.clearRect(0,0, window.innerWidth, window.innerHeight)
mainCtx.fillStyle = "#991111"
if (image) {
mainCtx.drawImage(image, 1, 1);
(positionArr || []).map(circle => {
mainCtx?.beginPath();
mainCtx?.arc(circle.x, circle.y, circle.radius / cameraZoom, 0, 2 * Math.PI, false);
if (mainCtx) {
mainCtx.fillStyle = circle.color
}
mainCtx?.fill();
});
}
}
requestAnimationFrame( draw )
}
// Gets the relevant location from a mouse or single touch event
function getEventLocation(e)
{
if (e.touches && e.touches.length === 1)
{
return { x:e.touches[0].clientX, y: e.touches[0].clientY }
}
else if (e.clientX && e.clientY)
{
return { x: e.clientX, y: e.clientY }
}
}
let isDragging = false
let dragStart = { x: 0, y: 0 }
function onPointerDown(e)
{
isDragging = true
dragStart.x = getEventLocation(e).x/cameraZoom - cameraOffset.x
dragStart.y = getEventLocation(e).y/cameraZoom - cameraOffset.y
}
function onPointerUp(e)
{
isDragging = false
initialPinchDistance = null
lastZoom = cameraZoom
}
function onPointerMove(e)
{
if (isDragging)
{
cameraOffset.x = getEventLocation(e).x/cameraZoom - dragStart.x
cameraOffset.y = getEventLocation(e).y/cameraZoom - dragStart.y
}
}
function handleTouch(e, singleTouchHandler)
{
if ( e.touches.length === 1 )
{
singleTouchHandler(e)
}
else if (e.type === "touchmove" && e.touches.length === 2)
{
isDragging = false
handlePinch(e)
}
}
let initialPinchDistance = null
let lastZoom = cameraZoom
function handlePinch(e)
{
e.preventDefault()
let touch1 = { x: e.touches[0].clientX, y: e.touches[0].clientY }
let touch2 = { x: e.touches[1].clientX, y: e.touches[1].clientY }
// This is distance squared, but no need for an expensive sqrt as it's only used in ratio
let currentDistance = (touch1.x - touch2.x)**2 + (touch1.y - touch2.y)**2
if (initialPinchDistance == null)
{
initialPinchDistance = currentDistance
}
else
{
adjustZoom( null, currentDistance/initialPinchDistance )
}
}
function adjustZoom(zoomAmount, zoomFactor, e)
{
if (!isDragging)
{
if (zoomAmount)
{
cameraZoom += zoomAmount*zoomFactor
}
else if (zoomFactor)
{
cameraZoom = zoomFactor*lastZoom
}
cameraZoom = Math.min( cameraZoom, MAX_ZOOM )
cameraZoom = Math.max( cameraZoom, MIN_ZOOM )
}
}
const handleAddIcon = (event: React.MouseEvent<HTMLCanvasElement, MouseEvent>) => {
if (editCanvas){
const x = event.nativeEvent.offsetX / cameraZoom
const y = event.nativeEvent.offsetY / cameraZoom
console.log(x, y)
const circle = {
id: Math.random().toFixed(2), x, y, radius: 10, color: colorCircle
}
mainCtx?.beginPath();
mainCtx?.arc(circle.x, circle.y, circle.radius, 0, 2 * Math.PI, false);
if (mainCtx) {
mainCtx.fillStyle = circle.color
}
mainCtx?.fill();
const newArr = positionArr;
newArr.push(circle)
setPositionArr(newArr)
} else {
const point = {
x : event.nativeEvent.offsetX / cameraZoom,
y : event.nativeEvent.offsetY / cameraZoom
};
console.log(cameraOffset, "cameraOffset")
console.log(point, "point")
positionArr.forEach(circle => {
if (isIntersect(point, circle)) {
alert('click on circle: ' + circle.id);
}
});
}
};
// Ready, set, go
useEffect(() => {
renderPage(pageNum)
}, [])
draw()
return (
<div id="container">
<canvas
onWheel={(e) => adjustZoom(cameraZoom, e.deltaY*SCROLL_SENSITIVITY, e)}
onMouseMove={onPointerMove}
onMouseUp={onPointerUp}
onTouchStart={(e) => handleTouch(e, onPointerDown)}
onTouchMove={(e) => handleTouch(e, onPointerMove)}
onTouchEnd={(e) => handleTouch(e, onPointerUp)}
onMouseDown={(e) => {onPointerDown(e)}}
onClick={(e) => handleAddIcon(e)}
ref={canvasRef} />
</div>
)
}
image 1
image 2
image 3
I would be very glad if someone can tell me the ways to solve these problems.

Phaser - How to make images fit on all devices

So I have a source code that I'm learning from but I'm having trouble making images such as the background and sprites fitting on various devices.
Here is what I have so far:
var game = new Phaser.Game(800, 600, Phaser.AUTO, '');
game.state.add('play', {
preload: function() {
this.game.load.image('forest-back', 'assets/parallax_forest_pack/layers/parallax-forest-back-trees.png');
this.game.load.image('forest-lights', 'assets/parallax_forest_pack/layers/parallax-forest-lights.png');
this.game.load.image('forest-middle', 'assets/parallax_forest_pack/layers/parallax-forest-middle-trees.png');
this.game.load.image('forest-front', 'assets/parallax_forest_pack/layers/parallax-forest-front-trees.png');
this.game.load.image('aerocephal', 'assets/allacrost_enemy_sprites/aerocephal.png');
this.game.load.image('arcana_drake', 'assets/allacrost_enemy_sprites/arcana_drake.png');
this.game.load.image('aurum-drakueli', 'assets/allacrost_enemy_sprites/aurum-drakueli.png');
this.game.load.image('bat', 'assets/allacrost_enemy_sprites/bat.png');
this.game.load.image('daemarbora', 'assets/allacrost_enemy_sprites/daemarbora.png');
this.game.load.image('deceleon', 'assets/allacrost_enemy_sprites/deceleon.png');
this.game.load.image('demonic_essence', 'assets/allacrost_enemy_sprites/demonic_essence.png');
this.game.load.image('dune_crawler', 'assets/allacrost_enemy_sprites/dune_crawler.png');
this.game.load.image('green_slime', 'assets/allacrost_enemy_sprites/green_slime.png');
this.game.load.image('nagaruda', 'assets/allacrost_enemy_sprites/nagaruda.png');
this.game.load.image('rat', 'assets/allacrost_enemy_sprites/rat.png');
this.game.load.image('scorpion', 'assets/allacrost_enemy_sprites/scorpion.png');
this.game.load.image('skeleton', 'assets/allacrost_enemy_sprites/skeleton.png');
this.game.load.image('snake', 'assets/allacrost_enemy_sprites/snake.png');
this.game.load.image('spider', 'assets/allacrost_enemy_sprites/spider.png');
this.game.load.image('stygian_lizard', 'assets/allacrost_enemy_sprites/stygian_lizard.png');
this.game.load.image('gold_coin', 'assets/496_RPG_icons/I_GoldCoin.png');
this.game.load.image('dagger', 'assets/496_RPG_icons/W_Dagger002.png');
this.game.load.image('swordIcon1', 'assets/496_RPG_icons/S_Sword15.png');
// build panel for upgrades
var bmd = this.game.add.bitmapData(250, 500);
bmd.ctx.fillStyle = '#9a783d';
bmd.ctx.strokeStyle = '#35371c';
bmd.ctx.lineWidth = 12;
bmd.ctx.fillRect(0, 0, 250, 500);
bmd.ctx.strokeRect(0, 0, 250, 500);
this.game.cache.addBitmapData('upgradePanel', bmd);
var buttonImage = this.game.add.bitmapData(476, 48);
buttonImage.ctx.fillStyle = '#e6dec7';
buttonImage.ctx.strokeStyle = '#35371c';
buttonImage.ctx.lineWidth = 4;
buttonImage.ctx.fillRect(0, 0, 225, 48);
buttonImage.ctx.strokeRect(0, 0, 225, 48);
this.game.cache.addBitmapData('button', buttonImage);
// the main player
this.player = {
clickDmg: 1,
gold: 50,
dps: 0
};
// world progression
this.level = 1;
// how many monsters have we killed during this level
this.levelKills = 0;
// how many monsters are required to advance a level
this.levelKillsRequired = 10;
},
create: function() {
var state = this;
this.background = this.game.add.group();
// setup each of our background layers to take the full screen
['forest-back', 'forest-lights', 'forest-middle', 'forest-front']
.forEach(function(image) {
var bg = state.game.add.tileSprite(0, 0, state.game.world.width,
state.game.world.height, image, '', state.background);
bg.tileScale.setTo(4,4);
});
this.upgradePanel = this.game.add.image(10, 70, this.game.cache.getBitmapData('upgradePanel'));
var upgradeButtons = this.upgradePanel.addChild(this.game.add.group());
upgradeButtons.position.setTo(8, 8);
var upgradeButtonsData = [
{icon: 'dagger', name: 'Attack', level: 0, cost: 5, purchaseHandler: function(button, player) {
player.clickDmg += 1;
}},
{icon: 'swordIcon1', name: 'Auto-Attack', level: 0, cost: 25, purchaseHandler: function(button, player) {
player.dps += 5;
}}
];
var button;
upgradeButtonsData.forEach(function(buttonData, index) {
button = state.game.add.button(0, (50 * index), state.game.cache.getBitmapData('button'));
button.icon = button.addChild(state.game.add.image(6, 6, buttonData.icon));
button.text = button.addChild(state.game.add.text(42, 6, buttonData.name + ': ' + buttonData.level, {font: '16px Arial Black'}));
button.details = buttonData;
button.costText = button.addChild(state.game.add.text(42, 24, 'Cost: ' + buttonData.cost, {font: '16px Arial Black'}));
button.events.onInputDown.add(state.onUpgradeButtonClick, state);
upgradeButtons.addChild(button);
});
var monsterData = [
{name: 'Aerocephal', image: 'aerocephal', maxHealth: 10},
{name: 'Arcana Drake', image: 'arcana_drake', maxHealth: 20},
{name: 'Aurum Drakueli', image: 'aurum-drakueli', maxHealth: 30},
{name: 'Bat', image: 'bat', maxHealth: 5},
{name: 'Daemarbora', image: 'daemarbora', maxHealth: 10},
{name: 'Deceleon', image: 'deceleon', maxHealth: 10},
{name: 'Demonic Essence', image: 'demonic_essence', maxHealth: 15},
{name: 'Dune Crawler', image: 'dune_crawler', maxHealth: 8},
{name: 'Green Slime', image: 'green_slime', maxHealth: 3},
{name: 'Nagaruda', image: 'nagaruda', maxHealth: 13},
{name: 'Rat', image: 'rat', maxHealth: 2},
{name: 'Scorpion', image: 'scorpion', maxHealth: 2},
{name: 'Skeleton', image: 'skeleton', maxHealth: 6},
{name: 'Snake', image: 'snake', maxHealth: 4},
{name: 'Spider', image: 'spider', maxHealth: 4},
{name: 'Stygian Lizard', image: 'stygian_lizard', maxHealth: 20}
];
this.monsters = this.game.add.group();
var monster;
monsterData.forEach(function(data) {
// create a sprite for them off screen
monster = state.monsters.create(1000, state.game.world.centerY, data.image);
// use the built in health component
monster.health = monster.maxHealth = data.maxHealth;
// center anchor
monster.anchor.setTo(0.5, 1);
// reference to the database
monster.details = data;
//enable input so we can click it!
monster.inputEnabled = true;
monster.events.onInputDown.add(state.onClickMonster, state);
// hook into health and lifecycle events
monster.events.onKilled.add(state.onKilledMonster, state);
monster.events.onRevived.add(state.onRevivedMonster, state);
});
// display the monster front and center
this.currentMonster = this.monsters.getRandom();
this.currentMonster.position.set(this.game.world.centerX + 100, this.game.world.centerY + 50);
this.monsterInfoUI = this.game.add.group();
this.monsterInfoUI.position.setTo(this.currentMonster.x - 220, this.currentMonster.y + 120);
this.monsterNameText = this.monsterInfoUI.addChild(this.game.add.text(0, 0, this.currentMonster.details.name, {
font: '48px Arial Black',
fill: '#fff',
strokeThickness: 4
}));
this.monsterHealthText = this.monsterInfoUI.addChild(this.game.add.text(0, 80, this.currentMonster.health + ' HP', {
font: '32px Arial Black',
fill: '#ff0000',
strokeThickness: 4
}));
this.dmgTextPool = this.add.group();
var dmgText;
for (var d=0; d<50; d++) {
dmgText = this.add.text(0, 0, '1', {
font: '64px Arial Black',
fill: '#fff',
strokeThickness: 4
});
// start out not existing, so we don't draw it yet
dmgText.exists = false;
dmgText.tween = game.add.tween(dmgText)
.to({
alpha: 0,
y: 100,
x: this.game.rnd.integerInRange(100, 700)
}, 1000, Phaser.Easing.Cubic.Out);
dmgText.tween.onComplete.add(function(text, tween) {
text.kill();
});
this.dmgTextPool.add(dmgText);
}
// create a pool of gold coins
this.coins = this.add.group();
this.coins.createMultiple(50, 'gold_coin', '', false);
this.coins.setAll('inputEnabled', true);
this.coins.setAll('goldValue', 1);
this.coins.callAll('events.onInputDown.add', 'events.onInputDown', this.onClickCoin, this);
this.playerGoldText = this.add.text(30, 30, 'Gold: ' + this.player.gold, {
font: '24px Arial Black',
fill: '#fff',
strokeThickness: 4
});
// 100ms 10x a second
this.dpsTimer = this.game.time.events.loop(100, this.onDPS, this);
// setup the world progression display
this.levelUI = this.game.add.group();
this.levelUI.position.setTo(this.game.world.centerX, 30);
this.levelText = this.levelUI.addChild(this.game.add.text(0, 0, 'Level: ' + this.level, {
font: '24px Arial Black',
fill: '#fff',
strokeThickness: 4
}));
this.levelKillsText = this.levelUI.addChild(this.game.add.text(0, 30, 'Kills: ' + this.levelKills + '/' + this.levelKillsRequired, {
font: '24px Arial Black',
fill: '#fff',
strokeThickness: 4
}));
},
onDPS: function() {
if (this.player.dps > 0) {
if (this.currentMonster && this.currentMonster.alive) {
var dmg = this.player.dps / 10;
this.currentMonster.damage(dmg);
// update the health text
this.monsterHealthText.text = this.currentMonster.alive ? Math.round(this.currentMonster.health) + ' HP' : 'DEAD';
}
}
},
onUpgradeButtonClick: function(button, pointer) {
// make this a function so that it updates after we buy
function getAdjustedCost() {
return Math.ceil(button.details.cost + (button.details.level * 1.46));
}
if (this.player.gold - getAdjustedCost() >= 0) {
this.player.gold -= getAdjustedCost();
this.playerGoldText.text = 'Gold: ' + this.player.gold;
button.details.level++;
button.text.text = button.details.name + ': ' + button.details.level;
button.costText.text = 'Cost: ' + getAdjustedCost();
button.details.purchaseHandler.call(this, button, this.player);
}
},
onClickCoin: function(coin) {
if (!coin.alive) {
return;
}
// give the player gold
this.player.gold += coin.goldValue;
// update UI
this.playerGoldText.text = 'Gold: ' + this.player.gold;
// remove the coin
coin.kill();
},
onKilledMonster: function(monster) {
// move the monster off screen again
monster.position.set(1000, this.game.world.centerY);
var coin;
// spawn a coin on the ground
coin = this.coins.getFirstExists(false);
coin.reset(this.game.world.centerX + this.game.rnd.integerInRange(-100, 100), this.game.world.centerY);
coin.goldValue = Math.round(this.level * 1.33);
this.game.time.events.add(Phaser.Timer.SECOND * 3, this.onClickCoin, this, coin);
this.levelKills++;
if (this.levelKills >= this.levelKillsRequired) {
this.level++;
this.levelKills = 0;
}
this.levelText.text = 'Level: ' + this.level;
this.levelKillsText.text = 'Kills: ' + this.levelKills + '/' + this.levelKillsRequired;
// pick a new monster
this.currentMonster = this.monsters.getRandom();
// upgrade the monster based on level
this.currentMonster.maxHealth = Math.ceil(this.currentMonster.details.maxHealth + ((this.level - 1) * 10.6));
// make sure they are fully healed
this.currentMonster.revive(this.currentMonster.maxHealth);
},
onRevivedMonster: function(monster) {
monster.position.set(this.game.world.centerX + 100, this.game.world.centerY + 50);
// update the text display
this.monsterNameText.text = monster.details.name;
this.monsterHealthText.text = monster.health + 'HP';
},
onClickMonster: function(monster, pointer) {
// apply click damage to monster
this.currentMonster.damage(this.player.clickDmg);
// grab a damage text from the pool to display what happened
var dmgText = this.dmgTextPool.getFirstExists(false);
if (dmgText) {
dmgText.text = this.player.clickDmg;
dmgText.reset(pointer.positionDown.x, pointer.positionDown.y);
dmgText.alpha = 1;
dmgText.tween.start();
}
// update the health text
this.monsterHealthText.text = this.currentMonster.alive ? this.currentMonster.health + ' HP' : 'DEAD';
}
});
game.state.start('play');
In your init or preload function, you should choose your scale mode. Please check the documentation to understand the different options:
//Options here are: NO_SCALE, EXACT_FIT, SHOW_ALL, RESIZE and USER_SCALE
this.scale.scaleMode = Phaser.ScaleManager.EXACT_FIT;
Please also check if you want to set pageAlignHorizontally and pageAlignVertically to true:
this.scale.pageAlignHorizontally = true;
this.scale.pageAlignVertically = true;
In some cases, you will want to call the refresh method:
this.scale.refresh();

EaselJs performance issue for many sprite classes

I would like to ask whether does easeljs has performance issue for many sprite class objects? It seems that from my codepen demo, its terribly lagging...below's code as follows:
var $window = $(window),
wh = $window.innerHeight(),
ww = $window.innerWidth();
var stage = new createjs.Stage("sceneStage");
var w, h, drone;
var runnerSprite2, runnerContainer, drone2, droneContainer, robot;
var robot__movement_speed = 1;
var building_right, building_left;
var queue = new createjs.LoadQueue(),
$state = $('#state'),
$progress = $('#progress'),
$progressbar = $('#progressbar .bar');
queue.on('complete', onComplete);
queue.on('error', onError);
queue.on('fileload', onFileLoad);
queue.on('fileprogress', onFileProgress);
queue.on('progress', onProgress);
queue.loadManifest([
{
id: '2',
src: 'images/sprite_robot_test_plus_toss.png'
},
{
id: '3',
src: 'images/Drones-Hovering-Loop-12fps.png'
},
{
id: '4',
src: 'images/sprite_robot_plus_toss.png'
},
{
id: '5',
src: 'images/sprite_protestor.png'
}
]);
function onComplete(event) {
console.log('Complete', event);
$state.text( $state.text() + '[All loaded]' );
$progressbar.addClass('complete');
$('#mainContainer').addClass('hide');
$('#drone').removeClass('hidden');
loadScenes();
}
function onError(event) {
console.log('Error', event);
$state.text( $state.text() + '[' + event + ' errored] ');
}
function onFileLoad(event) {
console.log('File loaded', event);
$state.text( $state.text() + '[' + event.item.id + ' loaded] ');
}
function onFileProgress(event) {
console.log('File progress', event);
}
function onProgress(event) {
var progress = Math.round(event.loaded * 100);
console.log('General progress', Math.round(event.loaded) * 100, event);
$progress.text(progress + '%');
$progressbar.css({
'width': progress + '%'
});
}
function loadScenes() {
// grab canvas width and height for later calculations:
stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;
w = stage.canvas.width;
h = stage.canvas.height;
//----- Drones --------//
var data = new createjs.SpriteSheet({
"images": ["images/Drones-Hovering-Loop-12fps.png"],
"frames": {"regX": 0, "height": 262, "count": 25, "regY": 0, "width": 250},
"animations": {
"idle": [0, 24],
"stun": [0, 0]
},
framerate: 24
});
drone = new createjs.Sprite(data, "idle");
drone.setBounds(null, null, 250, 262);
drone.y = h - drone.getBounds().height;
drone.x = w - drone.getBounds().width;
building_right = drone;
var drone_left = new createjs.Sprite(data, "stun");
drone_left.setBounds(null, null, 250, 262);
drone_left.regX = 250;
drone_left.y = h - drone_left.getBounds().height;
drone_left.x = drone_left.regX;
building_left = drone_left;
droneContainer = new createjs.Container();
droneContainer.addChild(drone, drone_left);
stage.addChild(droneContainer, runnerContainer);
var robot_walk_left_arry = [],
robot_walk_right_arry = [];
for(var i = 14; i< 50; i++) {
robot_walk_left_arry.push(i);
}
for(var i = 49; i > 13; i--) {
robot_walk_right_arry.push(i);
}
console.log(robot_walk_right_arry);
var robot_data = new createjs.SpriteSheet({
"images": ["images/sprite_robot_test_plus_toss.png"],
"frames": {"regX": 0, "height": 540, "count": 83, "regY": 0, "width": 810},
"animations": {
idle: {
frames: [0,1,2,3,4,5,6,7,8,9,10,11,12,11,10,9,8,7,6,5,4,3,2,1]
},
walk_left: {
frames: robot_walk_left_arry,
speed: 1 * robot__movement_speed
},
walk_right: {
frames: robot_walk_right_arry,
speed: 1 * robot__movement_speed
},
toss_left: [50, 82, "idle", 0.8 * robot__movement_speed]
},
framerate: 24
});
robot = new createjs.Sprite(robot_data, "idle");
robot.setBounds(null, null, 810, 540);
robot.regX = 405;
robot.x = (w - robot.getBounds().width);
robot.y = h - robot.getBounds().height;
robot._body_dimen = 162;
stage.addChild(robot);
var protestor_data = new createjs.SpriteSheet({
"images": ["images/sprite_protestor.png"],
"frames": {"regX": 0, "height": 216, "count": 39, "regY": 0, "width": 384},
"animations": {
idle: {
frames: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,13,12,11,10,9,8,7,6,5,4,3,2,1]
},
recovery: [33, 38, "idle", 1],
nudge: [15,33, "recovery", 1]
},
framerate: 24
});
var protestor = new createjs.Sprite(protestor_data, "idle");
protestor.setBounds(null, null, 384, 216);
protestor.x = 200;
protestor.y = h - protestor.getBounds().height;
stage.addChild(protestor);
drone_left.on("click", function() {
tweenthis(robot, robot.x, "left");
});
drone.on("click", function() {
tweenthis(robot, robot.x, "right");
});
createjs.Ticker.framerate = 30;
createjs.Ticker.timingMode = createjs.Ticker.RAF;
createjs.Ticker.addEventListener("tick", tick);
// createjs.Ticker.on("tick", stage);
}
function handleClick(evt, data) {
console.log('test');
}
function tick(event) {
stage.update(event);
}
Generally I just create 4 sprite classes with 3 different sprite images. But didn't expect it to be running so lagging.
The protestors image seems to be 8k x 8k pixel in size (with only the top part filled apparently)... That's about 192 MB unpacked... That will bring down any engine... Make sure your animation images are more efficiently packed and of a more reasonable size...

Categories