PIXI.js AnimatedSprite lag on first play - javascript

I need some help understanding what the best practice is for creating a PIXI.extras.AnimatedSprite from spritesheet(s). I am currently loading 3 medium-sized spritesheets for 1 animation, created by TexturePacker, I collect all the frames and then play. However the first time playing the animation is very unsmooth, and almost jumps immediately to the end, from then on it plays really smooth. I have read a bit and I can see 2 possible causes. 1) The lag might be caused by the time taken to upload the textures to the GPU. There is a PIXI plugin called prepare renderer.plugins.prepare.upload which should enable me to upload them before playing and possibly smoothen out the initial loop. 2) Having an AnimatedSprite build from more than one texture/image is not ideal and could be the cause.
Question 1: Should I use the PIXI Prepare plugin, will this help, and if so how do I actually use it. Documentation for it is incredibly limited.
Question 2: Is having frames across multiple textures a bad idea, could it be the cause & why?
A summarised example of what I am doing:
function loadSpriteSheet(callback){
let loader = new PIXI.loaders.Loader()
loader.add('http://mysite.fake/sprite1.json')
loader.add('http://mysite.fake/sprite2.json')
loader.add('http://mysite.fake/sprite3.json')
loader.once('complete', callback)
loader.load()
}
loadSpriteSheet(function(resource){
// helper function to get all the frames from multiple textures
let frameArray = getFrameFromResource(resource)
let animSprite = new PIXI.extras.AnimatedSprite(frameArray)
stage.addChild(animSprite)
animSprite.play()
})

Question 1
So I have found a solution, possibly not the solution but it works well for me. The prepare plugin was the right solution but never worked. WebGL needs the entire texture(s) uploaded not the frames. The way textures are uploaded to the GPU is via renderer.bindTexture(texture). When the PIXI loader receives a sprite atlas url e.g. my_sprites.json it automatically downloads the image file and names it as mysprites.json_image in the loaders resources. So you need to grab that, make a texture and upload it to the GPU. So here is the updated code:
let loader = new PIXI.loaders.Loader()
loader.add('http://mysite.fake/sprite1.json')
loader.add('http://mysite.fake/sprite2.json')
loader.add('http://mysite.fake/sprite3.json')
loader.once('complete', callback)
loader.load()
function uploadToGPU(resourceName){
resourceName = resourceName + '_image'
let texture = new PIXI.Texture.fromImage(resourceName)
this.renderer.bindTexture(texture)
}
loadSpriteSheet(function(resource){
uploadToGPU('http://mysite.fake/sprite1.json')
uploadToGPU('http://mysite.fake/sprite2.json')
uploadToGPU('http://mysite.fake/sprite3.json')
// helper function to get all the frames from multiple textures
let frameArray = getFrameFromResource(resource)
let animSprite = new PIXI.extras.AnimatedSprite(frameArray)
this.stage.addChild(animSprite)
animSprite.play()
})
Question 2
I never really discovered and answer but the solution to Question 1 has made my animations perfectly smooth so in my case, I see no performance issues.

Related

PIXI.JS Newbie, looking for advice and troubleshoot of a textureCache, loader issue

ive ventured into the world of PIXI and JS, new programming language for me, liking the way it is right now but i have an issue.
I am a bit confused with the TextureCache and the loader. If you look at part of my code i try to add 3 different images to the screen. Ive been following the 'Get Started section' of the pixi website. I wanted to add their cat image, which i have, the tileset image (all of it)* and then a tile of the tileset image.
The issue is, i create 3 new sprite instances and the tileset image shows the area ive set for the tile(rocket) when i want it to show the whole tileset. Ive loaded in the tileset iin the cahce and the loader.
Why does tile show the cropped image and not the whole image?
Am i using the cache correctly to just store images?
Am i using the resources method properly to locate the image FROM the cache or the loader?
Is there any point of the cache?
my thoughts**
when you use the rectangle method, it destroys the original image and the cropped version is now tileset1 (the name of my image)?
<html>
<body>
<script src="pixi.js"></script>
<script>
//Aliases
let Application = PIXI.Application,
loader = PIXI.loader,
resources = PIXI.loader.resources,
Sprite = PIXI.Sprite,
Rectangle = PIXI.Rectangle,
TextureCache = PIXI.utils.TextureCache;
let app = new PIXI.Application({
width: 1000,
height: 600,
antialias: true,
transparent: false,
resolution: 1
}
);
//Add the canvas that Pixi automatically created for you to the HTML document
document.body.appendChild(app.view);
TextureCache["tileset1.png","images/3.png"];
//load an image and run the `setup` function when it's done
loader.add(["images/3.png","tileset1.png"]).load(setup);
//This `setup` function will run when the image has loaded
function setup() {
let texture = TextureCache["tileset1.png"];
let rectangle = new Rectangle(96,64,32,32);
texture.frame = rectangle;
//Create the cat sprite, use a texture from the loader
let card = new Sprite(resources["images/3.png"].texture);
let tile = new Sprite(resources["tileset1.png"].texture);
let rocket = new Sprite(texture);
card.scale.set(0.06,0.06);
tile.x=400;
tile.y=400;
rocket.x=100;
rocket.y=100;
//Add the cat to the stage
app.stage.addChild(card);
app.stage.addChild(tile);
app.stage.addChild(rocket);
app.renderer.render(app.stage);
}
</script>
</body>
</html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.2.4/pixi.js"></script>
Is there any point of the cache? - this question seems to be most important from your questions :)
Searching around about "pixi.js" and "TextureCache" gives following answers for example:
https://github.com/pixijs/pixi.js/issues/4053
MySecret commented on May 23, 2017:
the docs has no specs about PIXI.utils.TextureCache
...
englercj commented on May 26, 2017
This is intentional, it is not meant as a public-facing API. It is an internal cache used by some texture creation methods.
https://www.html5gamedevs.com/topic/17788-loader-and-texturecache-tutorial-anywhere/
xerver - Pixi.js Moderator:
Here is the loader: https://github.com/englercj/resource-loader
The code is really well documented, and there are examples on the readme. The pixi examples also use the loader a few times: http://pixijs.github.io/examples/
The TextureCache is an internal mechanism, there is rarely any reason you should even know it exists.
https://www.html5gamedevs.com/topic/25575-pixiloaderresources-or-texturecache/
xerver - Pixi.js Moderator:
Dont do this:
let e = PIXI.utils.TextureCache[player.img];
Instead use the resources the loader loaded for you:
let e = PIXI.loader.resources[player.img].texture;
...
TLDR: Usually TextureCache shouldnt be used directly :)
See also:
this explanation: https://www.html5gamedevs.com/topic/9255-pixijs-caching/?tab=comments#comment-55233
http://pixijs.download/release/docs/PIXI.BaseTexture.html#.addToCache
^ example of usage: https://jsfiddle.net/themoonrat/br35x20j/

How to get time of page's first paint

While it is easy enough to get firstPaint times from dev tools, is there a way to get the timing from JS?
Yes, this is part of the paint timing API.
You probably want the timing for first-contentful-paint, which you can get using:
const paintTimings = performance.getEntriesByType('paint');
const fmp = paintTimings.find(({ name }) => name === "first-contentful-paint");
enter code here
console.log(`First contentful paint at ${fmp.startTime}ms`);
Recently new browser APIs like PerformanceObserver and PerformancePaintTiming have made it easier to retrieve First Contentful Paint (FCP) by Javascript.
I made a JavaScript library called Perfume.js which works with few lines of code
const perfume = new Perfume({
firstContentfulPaint: true
});
// ⚡️ Perfume.js: First Contentful Paint 2029.00 ms
I realize you asked about First Paint (FP) but would suggest using First Contentful Paint (FCP) instead.
The primary difference between the two metrics is FP marks the point
when the browser renders anything that is visually different from what
was on the screen prior to navigation. By contrast, FCP is the point
when the browser renders the first bit of content from the DOM, which
may be text, an image, SVG, or even a canvas element.
if(typeof(PerformanceObserver)!=='undefined'){ //if browser is supporting
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(entry.entryType);
console.log(entry.startTime);
console.log(entry.duration);
}
});
observer.observe({entryTypes: ['paint']});
}
this will help you just paste this code in starting of your js app before everything else.

performance issue with audioreactive visuals made with pixi and p5 sound lib

see the example here
I guess it depends on your machine, but for me, after the first song the framerate just drops like crazy. I make sure there are not more sprites than necessary (4: 2 images and 2 displacement maps).
Is this a pixi thing, perhaps WebGL? I'm not sure how to improve it or where to look for a better performance.
Ok. I found the issue. You are adding displacementTexture to the stage (stage.addChild(displacementTexture) again and again and you are never removing it really. So your totalSpritesOnStage do not work correctly.
How about adding something like this:
if (stage.children.length > 4) {
// let's destroy the sprite now
stage.removeChildren(4);
It would quickly looking seem to work with that too, though I didn't check the functionality very thoroughly.
Also this bothered me personally, as the sounds were downloaded again and again :)
function preload(song) {
console.log('preloading song: ' + currentSong);
console.log(song.filename);
if (allSounds[song]) {
sound = allSounds[song];
sound.setVolume(volume);
sound.play();
return;
}
allSounds[song] = sound = new p5.SoundFile('songs/' + song.filename,
onMusicLoaded,
h.onError
);
// The volume is reset (to 1) when a new song is loaded. so we force it
sound.setVolume(volume);
}

html 5 canvas: using draw image in game makes loop very slow

i am making a game based on draw images and clear it every some part of second.
i started with:
var peng = new Image();
and then:
peng.onload = function() {
context.drawImage(peng, pengXPosition, pengYPosition, pengWidth, pengHight);
};
and in the loop:
var i=0;
function pengMoveRight(){ i++;if(i==1){peng.src = 'images/1.png';}else if(i==2)
{peng.src = 'images/2.png';} else if(i==3){peng.src = 'images/3.png';}else if(i==4){
peng.src = 'images/4.png';}else if(i==5){peng.src = 'images/5.png';}else if(i==6){
peng.src = 'images/6.png';i-=6;}}
when i run it it works well on IE but on chrome and mozilla it`s too slow and the character is about to disappear .. i used setinterval(); once and window.requestAnimationFrame(); once and both of them cause the same problem.
what should i do to make it smooth move?
here is the full script http://mark-tec.com/custom%20game/
Instead of changing the source, try to create several Image objects instead. That way, the drawImage call can always use a pre-loaded image.
You need to preload all the images or use the sprite method (all images packed into a single sprite) in order to avoid the initial delay caused by the image loading only when it's needed.
However, after that initial problem, your example should run fine once all the images are cached.

ThreeJS, Websockets, and NodeJS Client/Server Experiment

I was toying with socket.io, ThreeJS, Javascript, and NodeJS to create a simple client/server using ThreeJS's graphics. I wasn't sure if all of these frameworks would even work together, but I decided to give it a shot since I've seen similar examples online before even though I cannot find a simple one to dissect or experiment with. It's mainly to experiment with, but I also wanted to make a small little concept-game as proof of what I've learned so far.
I posted my code here: https://gist.github.com/netsider/63c414d83bd806b4e7eb
Sorry if it's a little untidy, but I did my best to make it as readable as possible.
Basically, right now the server-side NodeJS script seems to run fine (Run with "node server-alpha.js"), and the client script (client-alpha.html, which you can just open in a browser) connects to the server, and displays a list of users (who are also connected). However, my intention was for each user to be able to move his/her own cube around, and right now each cube only gets added to the screen (rather than being added, subtracted, and then added again - to give the illusion of movement). If you run both pieces of code and connected one or two users and move the arrow keys a few times for each, you'll see what I'm talking about.
Can anybody help me with this? I tried several different ways to remove the cube (and remembered to call render(), after each)... but everything I tried didn't seem to work. It always resulted in the cubes just being added to the screen, and never subtracted.
I added comments in the code to make things a little easier, as I know this is quite a bit of code to go through (if it's not your own, anyway).
Thanks, any help would be greatly appreciated... as I'm really stuck trying to make the cubes just move.
Also, I'm having trouble adding the Fly-Controls (FlyControls.js - it's commented out ATM), so if someone could tell me where I went wrong I'd appreciate that a lot also.
Ok so you don't want to keep remaking the cubes, all you need to do is change the position.
Also in game development, it is almost a requirement to use object oriented design, a good way to go about this would be to make a player object, so..
CPlayerList = new Array(); // an array of player objects
function ClientPlayer()
{
this.Cube;
this.Name = "unnamed";
this.Id = 0;
this.Create = function(name,pos,id)
{
this.Name = name;
this.Id = id;
var cubeGeometry = new THREE.BoxGeometry(10, 10, 10);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 'red', transparent:false, opacity:1.0});
this.Cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
this.Cube.position.x = pos.x;
this.Cube.position.y = pos.y;
this.Cube.position.z = 20; // don't know why this is 20, remember y axis is up & down in opengl/threejs
scene.add(this.Cube);
}
this.Move = function(vector)
{
this.Cube.position.set(this.Cube.position.x + vector.x, this.Cube.position.y + vector.y, 20);
}
}
So on the server you need a ServerPlayer object which holds similar data, and assign ids on the server before sending them to the clients. So when you send it to the client you want to make a new ClientPlayer, call player.Create() and then push it to the CPlayerList, like so:
function newCPlayer(data)
{
var newPly = new ClientPlayer();
newPly.Create(data.name,data.pos,data.id);
CPlayerList.push(newPly);
}
Then when you call your movePlayer() function, you can simply loop through your players array
function movePlayer(keyStroke, clientID)
{
if (keyStroke == 39)
{
CPlayerList.forEach(function(player,i,a)
{
if(player.Id === clientID)
{
player.Move(new THREE.Vector3(1,0,0));
}
}
}
}
This is just the client code, but this should help you get started, let me know if there's anything you're unclear on.
Also here's an example of a game using a similar design: http://82.199.155.77:3000/ (ctrl+shift+j in chrome to view client sources) and server code: http://pastebin.com/PRPaimG9

Categories