Sprite Animations In the Phaserjs Duration error - javascript

I Have a phaser animation from the default phaser make your first game tutorial on the website
this.load.spritesheet(
"Player",
"https://cdn.glitch.global/cc90578e-c3d0-47c5-bb0d-f5a81263b5b6/pixil-frame-0%20(10).png?v=1675733526924",
{ frameWidth: 16, frameHeight: 24 }
);
The Animations
this.anims.create({
key: "left",
frames: this.anims.generateFrameNumbers("player", { start: 0, end: 3 }),
frameRate: 10,
repeat: -1,
});
this.anims.create({
key: "turn",
frames: [{ key: "player", frame: 4 }],
frameRate: 20,
});
this.anims.create({
key: "right",
frames: this.anims.generateFrameNumbers("player", { start: 5, end: 8 }),
frameRate: 10,
repeat: -1,
});
I get the Error
Uncaught TypeError: Cannot read properties of undefined (reading 'duration')
when ever i use the animations in update
what is the issue?

The problem is that you are using the two different key's for the sprite.
On this.load.spritesheet("Player",... you are using 'Player' (upper case P) and on this.anims.generateFrameNumbers("player",... you are using 'player' (lower case p).
And since in Phaser the key-names are case sensitive it is not found, and this error is occurs.
Just make all keys the same (I recommend lowercase 'player', I personally always use lower case and dash-case, to prevent such typos/errors), and it should work.

Related

Stop animation at specific frame?

I'm making a game with Phaser, and I need to have an animation for the health bar going down dynamically stop on a frame, and I couldn't find any clear documentation on the stopOnFrame() method, or the this.anims.getFrame(index) method, both of which woulden't work. I believe that stopOnFrame accepts a frame object, not a frame number but I coulden't figure out how to get that specific frame, as the getFrame() method returned undefined. If there's something I'm missing, my ideal solution looks something like this:
this.hpBar.play({key: 'damageAnimation', startFrame: this.hp})
this.hpBar.stopOnFrame(this.hpBar.getFrame(this.hp - amountOfDamage))
Thanks for any suggestions, cheers!
PS: I know there's some more nuance to how I would use the animations in forwards and reverse to properly create this effect, the example is purely for demonstration.
Two points, you would have to pass a Phaser.Textures.Frame to the stopOnFrame function, and as far as I know the function getFrame doesn't exist (atleast on the phaser sprite GameObject, as shown in your code).
You can use the function getFrameAt on the Animation object, the index has to be here only a valid integer, in the range from 0 - to max frame of the animation.
(btw.: here is the link to the documenation of the stopOnFrame function)
Info: the frame index-count, is based on the frames of the specific animation, not the frame in the spritesheet. (In this example the sprite frame index of the kick is 12, but in the kick animation the index for that specific frame is 2)
Here a Demo:
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536,
height: 183,
scene: {
preload,
create
}
};
function preload(){
this.load.spritesheet('brawler',
'http://labs.phaser.io/assets/animations/brawler48x48.png',
{ frameWidth: 48, frameHeight: 48 }
);
this.load.image('brawler-sheet',
'http://labs.phaser.io/assets/animations/brawler48x48.png');
}
function create () {
this.add.text(10,10, 'Click, to Stop on kick (third frame)')
.setScale(1.5)
.setOrigin(0)
.setStyle({fontStyle: 'bold', fontFamily: 'Arial'});
this.anims.create({
key: 'kick',
frames: this.anims.generateFrameNumbers('brawler',
{ frames: [ 10, 11, 12, 13, 10 ] }),
frameRate: 8,
repeat: -1,
repeatDelay: 0
});
this.add.image(140, 20, 'brawler-sheet')
.setOrigin(0)
const cody = this.add.sprite(100, 90);
cody.setScale(3);
cody.play('kick');
this.input.on('pointerdown', () => {
cody.stopOnFrame(cody.anims.currentAnim.getFrameAt(2))
});
}
new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
But for a simple healt-bar, I would use a phaser tween, not an animation, like this you can set the value more precise, you can easily update the max-health and "animation" is easy.
Here a demo how I would do it (two visula alternatives):
(I would opt for the second version, if you have some nice heart images or so, I could find a better image for the demo)
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536,
height: 183,
scene: {
create,
preload
},
banner: false
};
function preload ()
{
this.load.image('mushroom',
'https://labs.phaser.io/assets/sprites/mushroom16x16.png');
}
let healthMax = 32*5
function create () {
this.add.text(10,10, 'Click, to animate healthbar')
.setScale(1.5)
.setOrigin(0)
.setStyle({fontStyle: 'bold', fontFamily: 'Arial'});
this.healthbarBG = this.add.rectangle(10, 50, 32*5, 10, 0xffffff)
.setOrigin(0);
this.healthbar = this.add.rectangle(12, 52, healthMax - 4, 10 - 4, 0xff0000)
.setOrigin(0);
this.add.text(10, 75, 'Or abit more flashy')
.setOrigin(0)
.setStyle({fontStyle: 'bold', fontFamily: 'Arial'});
let tilespriteBG = this.add.tileSprite(10, 100, 16*5, 16, 'mushroom')
.setOrigin(0)
.setScale(2);
tilespriteBG.setTint(0x2a2a2a)
let tilesprite = this.add.tileSprite(10, 100, 16*5, 16, 'mushroom')
.setOrigin(0)
.setScale(2);
this.input.on('pointerdown', () => {
// remove 50% health
let newHealthWidth = healthMax * .5;
this.tweens.add({
targets: this.healthbar,
width: newHealthWidth,
duration: 750,
ease: 'Power2',
/* this two following properties must be remove, just for demo
yoyo: true,
repeat:-1*/
});
this.tweens.add({
targets: tilesprite,
width: { to: 16 * 5 * .5, from: 16 * 5},
duration: 750,
/* this two following properties must be remove, just for demo
yoyo:true,
repeat:-1*/
});
})
}
new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
modifying the ease and/or the duration property (and others), you can make the animation suitable (and spicy) for the most usecases.

phaser AnimationFrame size isse

my atlas pack the frame image size is not equal. so I need to determine the display position by setting the coordinates of the frame image.but phaser AnimationFrame image size needs to be equal.
Otherwise, it cannot be displayed in the correct position.
this.anims.create({
key: 'snooze',
frames: [
{ key: 'cat1' },
{ key: 'cat2' },
{ key: 'cat3' },
{ key: 'cat4', duration: 50 }
],
frameRate: 8,
repeat: -1
});
this.anims.create({
key: 'snooze',
frames: [
{ key: 'cat1',px:-100:py:0},
{ key: 'cat2',px:-50,py:-30},
{ key: 'cat3',px:-50,py:-30},
{ key: 'cat4', duration: 50,px:-50,py:-30 }
],
frameRate: 8,
repeat: -1
});
How to set the relative display position of AnimationFrame image by px like expected code effect or other way
this.anims.create({
key: 'snooze',
frames: [
{ key: 'cat1',px:-100:py:0},
{ key: 'cat2',px:-50,py:-30},
{ key: 'cat3',px:-50,py:-30},
{ key: 'cat4', duration: 50,px:-50,py:-30 }
],
frameRate: 8,
repeat: -1
});
If I understand your question correct, what you are looking for is not possible, at least not out-of-the-box.
My suggestion is to create a new json, with matching frames, or creating two distinct json's
// in preload function/method
this.load.atlas('atlas1', 'image.png', 'first.json');
this.load.atlas('atlas2', 'image.png', 'second.json');
Or if you want to create dynamically frame, you could,
load the image
// in preload function/method
this.load.image('image', 'image.png');
and create a texture and frame (for details check documentation)
let canvas = this.textures.createCanvas('player', 42 * FRAMES, 68);
let width = 16;
let height = 32;
for(let frameIdx = 0; frameIdx < FRAMES; frameIdx ++){
canvas.drawFrame('image', null, width * idx, height);
canvas.add(idx, 0, width * idx, 0, width, height);
}
canvas.refresh();
Or similar, you could checkout this example from the offical website (https://phaser.io/examples/v3/view/animation/create-animation-from-canvas-texture)

How do I prevent the Three.js OBJLoader from merging all the parts of my obj into 1 mesh?

Allright, I've been stuck on this issue for a while now so here I am.
I have an .obj file, created by one of my colleagues, that I need to load into a three.js scene. I need to be able to change the materials and texture of individual parts of said object. Only when I try loading this .obj in three.js and log the object I loaded in, I noticed it gets merged into 1 mesh.
I've been looking around for an answer to this problem, but I haven't even found someone with the same problem as me. I am currently loading the .obj and it's .mtl like this:
loadMTL = (mtlLoader, mtlPath, texPath, loader, objPath) => {
mtlLoader.load(
mtlPath,
mat => {
mat.preload();
loader.setMaterials(mat);
loader.load(
objPath,
object => {
console.log(object);
this.scene.add(object);
},
// called when loading is in progresses
function(xhr) {
// console.log("Obj - " + (xhr.loaded / xhr.total) * 100 + "% loaded");
},
// called when loading has errors
function(error) {
console.log("An error happened loading an OBJ");
console.log(error);
}
);
},
// called when loading is in progresses
function(xhr) {
// console.log("Mat - " + (xhr.loaded / xhr.total) * 100 + "% loaded");
},
// called when loading has errors
function(error) {
console.log("An error happened loading a MTL");
console.log(error);
}
);
};
The OBJLoader I'm using is the Three.js OBJLoader, not the OBJLoader2. The resulting log output is as follows:
Group {uuid: "DCA4C797-A66E-4007-ADAF-C4060FD9D886", name: "", type: "Group", parent: null, children: Array(1), …}
castShadow: false
children: Array(1)
0: Mesh {uuid: "76EA3F31-CB49-4D5F-A95C-B45A751DFBBE", name: "Kamer", type: "Mesh", parent: Group, children: Array(0), …}
length: 1
__proto__: Array(0)
frustumCulled: true
layers: Layers {mask: 1}
materialLibraries: ["Kastje1_test.mtl"]
matrix: Matrix4 {elements: Array(16)}
matrixAutoUpdate: true
matrixWorld: Matrix4 {elements: Array(16)}
matrixWorldNeedsUpdate: false
name: ""
parent: null
position: Vector3 {x: 20, y: 0, z: 0}
quaternion: Quaternion {_x: -0.7071067811865475, _y: 0, _z: 0, _w: 0.7071067811865476, _onChangeCallback: ƒ}
receiveShadow: false
renderOrder: 0
rotation: Euler {_x: -1.5707963267948966, _y: 0, _z: 0, _order: "XYZ", _onChangeCallback: ƒ}
scale: Vector3 {x: 33, y: 70, z: 55}
type: "Group"
up: Vector3 {x: 0, y: 1, z: 0}
userData: {}
uuid: "DCA4C797-A66E-4007-ADAF-C4060FD9D886"
visible: true
eulerOrder: (...)
id: 20
modelViewMatrix: Matrix4 {elements: Array(16)}
normalMatrix: Matrix3 {elements: Array(9)}
useQuaternion: (...)
__proto__: Object3D
As you can see, the Group has only 1 child Mesh. That mesh itself has no further children. The problem is that I need to retexture certain parts of the object, seeing as it only has 1 mesh and said mesh can only have 1 texture, as far as I know, I don't know how to proceed. Is there some Three.js fundamental concept I'm missing?
EDIT:
After some more searching we figured out what went wrong: apparently my colleague only defined one group in the .obj file. We fixed the .obj file and now I do get different meshes.

JustGauge.js Insert Comma

I am struggling to insert a comma into my JustGauge Chart.
So far I have the following code. most of it is working as expected;
window.onload = function() {
var g1 = new JustGage({
id: "g1",
value: 24692,
min: 0,
max: 30009,
title: 'Document Countdown',
titlePosition: 'above',
width: 800,
height: 800,
pointer: true,
textRenderer: function(val) {
return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
},
gaugeWidthScale: 1.2,
noGradient: true,
customSectors: [{
color: '#32CD32',
lo: 0,
hi: 30009
}]
});
}
Fiddle https://jsfiddle.net/johnny_s/xsgpp4ng/1/
The 'textRenderer' part of the above code adds a comma to the 'value', I'm not sure how to do the same with 'max'.
I need to add a comma to the 'max' value - so it's '30,009'. When I try to add it manually the chart won't load.
Any help is appreciated.
This has been a feature request posted as request 193 and has been implemented as an extra property maxTxt in the update of February 3, 2016 and is part of release 1.2.7. Current version is 1.2.9.
Note that several features changed in version 1.2.9 compared to the version you used (1.2.2):
the structure of the customSectors: it is no longer an array. The array part is now moved into a subproperty ranges
Support for title has been removed, as this really does not belong to the "core business" of the widget; one can better control the position and style of such a title in the surrounding HTML/CSS.
There is a bug related to the noGradient setting: issue 270. The suggested fix has not been included in the latest release. Instead of tampering with the library yourself, I would suggest working around that issue by adding a customSectors.length property with a positive value.
I have included these changes also in the updated fiddle which uses version 1.2.9:
var g1 = new JustGage({
id: "g1",
value: 24692,
min: 0,
max: 30009,
maxTxt: "30,009", // <------ add this
// remove title attributes -- no longer supported
//title: 'Document Countdown',
//titlePosition: 'above',
width: 800,
height: 400, // <--- reduced to allow title to be closer to gauge
pointer: true,
textRenderer: function(val) {
return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
},
gaugeWidthScale: 1.2,
pointerOptions: {
toplength: -15,
bottomlength: 10,
bottomwidth: 12,
color: '#8e8e93',
stroke: '#ffffff',
stroke_width: 3,
stroke_linecap: 'round'
},
noGradient: true,
customSectors: { // <--- no longer an array...
ranges: [{ // <--- ... which has moved to this property
color: '#32CD32',
lo : 0,
hi : 30009
}],
length: 1 // fixes a bug
}
});
The HTML should contain the title. Something like this:
<div style="display: inline-block">
<h2 style="text-align:center;">Document Countdown</h2>
<div id="g1"></div>
</div>
Another way of doing it is add formatNumber: true when you initialize. It will format min max and value. You can also get rid of the textRenderer field.
I updated your fiddle
window.onload = function(){
var g1 = new JustGage({
id: "g1",
value: 24692, /* <-- just change this to your current value */
min: 0,
max: 30009, /* start amount */
title: 'Document Countdown',
titlePosition: 'above',
width: 800,
height: 800,
pointer: true,
formatNumber: true,
gaugeWidthScale: 1.2,
pointerOptions: {
toplength: -15,
bottomlength: 10,
bottomwidth: 12,
color: '#8e8e93',
stroke: '#ffffff',
stroke_width: 3,
stroke_linecap: 'round'
},
noGradient: true,
customSectors: [{
color: '#32CD32',
lo: 0,
hi: 30009
}]
});
}

Reverse direction of Kendo UI Linear Gauge

Using a Kendo UI Datawiz component (Linear gauge) in my project. It's supposed to be an indicator for depth, where surface is at 0 (top) and bottom should be at x (bottom). Currently I have not figured out how to 'reverse' the direction of the gauge, causing it to start at 0, and move downwards towards x at bottom.
Does anyone know how to achieve this?
Here's my gauge:
function createGauges() {
var value = $("#depthBar").val();
$("#depthBar").kendoLinearGauge({
pointer: {
value: 28,
shape: "arrow"
},
scale: {
majorUnit: 20,
minorUnit: 2,
min: -40,
max: 60,
vertical: true,
directions:
}
});
}
$(document).ready(function() {
createGauges();
});
Aaand, I've found the answer. Actually missed a tiny piece of code in the docs;
...
scale: {
majorUnit: 1000,
minorUnit: 500,
min: 0,
max: 12000,
vertical: true,
reverse: true
}
...

Categories

Resources