Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I'm creating a single player web RPG in JavaScript.
It will not be too heavy of an events-based game, but I will be loading lots of objects to the screen.
I have two questions:
1st: I've used createJS to load my bitmaps, but noticed severe lag when I loaded several objects to the screen at once and animated them. I'm wondering if there is a better library than createJS to load objects.
2nd: I was planning on using PHP for user profiles, stats, etc... but found writing AJAX calls to the server required several steps...
first, send javascript variable to php using jquery .get()
then update database
then send newly updated variable back by using json_encode, and echoing out the variable.
Finally, store that updated variable back in a javascript variable
I'm wondering how something like this is handled in NodeJS. I read How to decide when to use Node.js? to figure out the usage of NodeJS, and this sentence in particular, "I believe Node.js is best suited for real-time applications: online games, collaboration tools, chat rooms, or anything where what one user does with the application needs to be seen by other users immediately, without a page refresh." spoke to me... but I'm still not sure if I'll need to use NodeJS instead of PHP.
Thank you
EDIT:
Hi, I think I'm doing the tiling and caching incorrectly...
In my Game.php, I call several function to create/draw the objects.
Game.php:
function init() {
canvas = document.getElementById("demoCanvas");
start();
}
function start() {
stage = new createjs.Stage("demoCanvas");
stage.mouseMoveOutside = true;
//Create Objects
createWorld();
createTiles();
createPlayers();
In my function tick() I have a centerViewTo which centers the player in the viewport relative to the background (mimicking a camera).
The issue with this is, I pass in a single bitmap bgBMP that I was drawing the player relative to. If I do tiling, I'm not sure how I can draw the player relative to the background image.
centerViewTo(stage.canvas, stage, segment, {x:0, y:0, width:bgBMP.image.width, height:bgBMP.image.height});
Moreover, http://www.createjs.com/Docs/EaselJS/classes/DisplayObject.html#method_cache says I should cache each object before adding it to the container? Anyway, I get why you add all objects to the stage and then cache the stage all at once.
So I've tried that here... but it's not rendering anything:
CreateObjects.js:
var world;
var bgBMP;
var tile;
var mapWidth = 10; //Map size is 1000... so 10x10 tiles
var mapHeight = 10;
//World will be a container to hold all objects
function createWorld() {
world = new createjs.Container();
bgBMP = new createjs.Bitmap("images/bg2.png");
world.cache(0, 0, mapWidth , mapHeight );
world.addChild(bgBMP);
stage.addChild(world);
}
function createTiles() {
for (var x = 0; x < mapWidth; x++){
for (var y = 0; y < mapHeight; y++){
var tile = new createjs.Bitmap('images/myTile.png');
tile.x = x * 32;
tile.y = y * 32;
world.cache(0, 0, mapWidth , mapHeight );
world.addChild(tile);
}
}
}
I'm currently creating a RPG too with createjs, and I can display 200 characters, with their own animations and life, without lag issues.
Createjs is a really good framework, but you have to understand how it works to avoid performance issues. It's very important to separe layers in differents containers, and to cache them. For example, if the background of your game is composed with a lot of 32x32 tiles (like in RPG maker), you should cache it since it's not supposed to change during the game.
For example :
var backgroundContainer = new createjs.Container();
// mapWidth and mapHeight is the number of X and Y tiles
for (var x = 0; x < mapWidth; x++){
for (var y = 0; y < mapHeight; y++){
var tile = new createjs.Bitmap('mytile-'+i+'.png');
tile.x = x * 32;
tile.y = y * 32;
backgroundContainer.addChild(tile);
}
}
backgroundContainer.cache(0, 0, mapWidth, mapHeight);
stage.addChild(backgroundContainer);
When you cache a container, it will draw all the children in a hidden canvas, and then just draw the cached canvas on your current canvas on stage update.
If you don't cache it, just think that every time you call stage.update(), all your children will be drawn one per one on your canvas.
About NodeJS : nodeJS is really cool with the Socket.IO plugin, which use the full power of web sockets. Forget ajax if you need real time for a game : websocket is what you need. Try socket.io http://socket.io/ you will love it ;)
EDIT:
You don't use the cache well, I think you need to understand first what exactly does the cache. In my previous example, you can see we add all tiles in a container. So we have mapWidth * mapHeight tiles. Every time you call stage.update(), it will loop each tile bitmap and draw it on canvas. So if you have a 50x20 map, it will draw 1000 bitmaps every stage.update(), that's not good for performances.
If we cache backgroundContainer all tiles will be draw on an internal canvas, and when stage.update() is called it will only draw 1 image this time instead of 1000. You have to cache your world container after you add all the tiles, as in my example.
The power of createjs is that you can encapsulate your display objects as you want, this is how I organize my containers in my game :
stage
screen
scene
background -> Here I display a background image (E.g: the sky)
body
tiles -> All my background tiles (I cache this)
events -> Map events (moving NPC, my character, etc.)
overlay -> Here I display an overlay image (E.g: a fog image with 0.2 opacity)
transition -> Here I make transition when my character go to a new map
When my character move on the map, I just need to move the body container (changing X and Y properties)
Related
Because drawing objects with p5js every time draw() is called slows down my sketch I wanted to save a copy of my canvas without any moving objects, and then only redraw part of the background that was previously covered by the moving object whenever it moves.
I tried creating an array of colors using get() function and going down the whole screen in hopes that I could then just take a patch from that and replace whatever needed to be cleared to the way it was before. This would work but making a copy of the whole canvas, especially when my canvas takes up the whole screen of the browser, is very slow.
tl;dr I am trying to save my canvas to later patch up parts of the screen but it takes too long
var defaultScreenPixels;
function savePixels(){
for(let i = 0; i < screenHeight; i++){
defaultScreenPixels[i] = [];
for(let j = 0; j < screenWidth; j++){
defaultScreenPixels[i].push(get(j, i));
}
console.log("Saved " + i +" row(s) of the screen, " + (screenHeight - i)
+" rows to go");
}
}
p5js has a built-in API called createGraphics() which according to the documentation says Creates and returns a new p5.Renderer object. Use this class if you need to draw into an off-screen graphics buffer. The two parameters define the width and height in pixels. Which does what you are trying to do and most likely to be far quicker than doing it one pixel at a time.
See p5js.org/reference/#/p5/createGraphics for further details.
There is an example here where you use image() to copy the off-screen graphic buffer back to the screen.
http://p5js.org/examples/structure-create-graphics.html
I'm currently tiling many PNG images on several stacked FastLayers with Konva.js. The PNGs contain opacity, and they do not require dragging or hitboxes. The tiles are replaced often, and this seems to work well for medium-sized grids with dimensions of around 30x30. Once the tiles start growing to around 100x100, or even 60x60, the performance begins to slow when replacing individual tiles.
I've started to work on "chunking" tiles, i.e., adding tiles into smaller FastLayer groups. For example, a single 100x100 FastLayer would be divided into several 10x10 FastLayers. When a single tile changes, the idea is that only that chunk should should re-render, ideally speeding up the rendering time overall.
Is this is a good design to attempt, or should I try a different approach? I've looked over the performance tips in the Konva.js documentation, but I haven't seen anything directly relevant to this case.
So, after some research and tinkering, I've discovered the fastest way to render ~4000 images.
Don't use React components for Konva.js. I use React to structure my app, but I've skipped using an intermediate library for Konva.js rendering. Using React Components for the canvas will halve your performance.
Cache common images. I use a simple LRU cache to reuse HTMLImageElement objects.
Reuse Konva.js nodes (Konva.Image) whenever possible. My implementation is rendering a grid of images. The locations do not change, but the images may. Before, I would destroy() a node, and the add another. The destroy() causes an additional render, which creates jank for your users. Instead, I just use the image() method in combination with id() and name() to find and replace images at grid coordinates.
My app allows users to paint long strokes across the grid. This works OK in small strokes, when only using the literal mouse events. For long strokes, this does not work for two reasons. First, the OS and browser throttle the mouse events, giving you intermittent mouse events. Second, being in the middle of a render will give the same side effect. Instead, the software now detects long strokes, and "fills in" the missing coordinates that the user intended to draw between the intermittent mouse events.
Render at intervals. Since my grid can change often, I decided to sample the grid information 24 times a second, rather than allowing each tile change to queue up a batchDraw(). The underlying implementation is using RxJS to poll a Redux store once every 42ms, and only queues a batchDraw() if something has changed.
Caching definitely helps performance, but so does hiding. Konva doesn't (or didn't last I researched this) do any view culling. Below is code I used to hide the island shapes in my Konva strategy game.
stage.on('dragmove', function() {
cullView();
});
function cullView() {
var boundingX = ((-1 * (stage.x() * (1/zoomLevel)))-(window.innerWidth/2))-degreePixels;
var boundingY = ((-1 * (stage.y() * (1/zoomLevel)))-(window.innerHeight/2))-degreePixels;
var boundingWidth = (2 * window.innerWidth * (1/zoomLevel)) + (2*degreePixels);
var boundingHeight = (2 * window.innerHeight * (1/zoomLevel)) + (2*degreePixels);
var x = 0;
var y = 0;
for (var i = 0; i < oceanIslands.length; i++) {
x = oceanIslands[i].getX();
y = oceanIslands[i].getY();
if (((x > boundingX) && (x < (boundingX + boundingWidth))) && ((y > boundingY) && (y < (boundingY + boundingHeight)))) {
if (!oceanIslands[i].visible()) {
oceanIslands[i].show();
oceanIslands[i].clearCache();
if (zoomLevel <= cacheMaxZoom) {
oceanIslands[i].cache();
}
}
} else {
oceanIslands[i].hide();
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
How to create SVG / canvas sketches with comic style / hand jitter using Javascript
I am aware of the xkcd style JS plotter and of this article.
Note that I am not asking for plots, but for any kind of sketching, lines, shapes, text and so on.
What further methods / technologies exist using JS?
EDIT: After having thought and read some time about this I decided to implement my own JS library providing cartoon style drawing for SVG and HTML5 canvas.
It is called comic.js and can be found here.
I would be using a Canvas library to do that, just for the sake of simplicity when it comes to manipulating shapes.
The ones I would look for are Paper.js and Fabric.js.
However, I will focus on Paper.js because it is the one I worked with.
You can draw beziers or lines to create the shapes. You can even
import SVG's if you want. You can even have predefined shapes
such as Circles/Squares etc.
So you have the shapes, now what?
You can flatten them(subdivide them into segments, adding more
vertices to their geometry). You can increase the subdivision
interval which would result in high number of vertices/nodes per
path. Subdivision interval is the parameter maxDistance of the
flatten function.
Then you can walk along the vertices of each path/shape and move each
one by a certain degree(e.g 1-2 pixels to a random direction), by using position.x and position.y
If this is what you mean:
, then here is the code :
//STEP 1 -- create shapes, a circle and rectangle in this example
var myCircle = new Path.Circle(new Point(100, 70), 50);
myCircle.strokeColor = 'white';
myCircle.strokeWidth = 2;
var mySquare = new Rectangle(new Point(350, 250), new Point(190, 100));
var square = new Path.Rectangle(mySquare);
square.strokeColor = 'white';
square.strokeWidth = 2;
//STEP 2 -- Subdivide the shapes into segments. Parameter here is the max distance we walk along-the-path before adding a new vertex
myCircle.flatten(5);
square.flatten(4);
//STEP 3 -- Loop through the segment points of the path and move each to a random value between 1 and 4
for (var i = 0; i < myCircle.segments.length; i++) { //loop for circle
myCircle.segments[i].point.x += getRandomInt(1,3);
myCircle.segments[i].point.y += getRandomInt(1,3);
};
for (var i = 0; i < square.segments.length; i++){ //loop for square
square.segments[i].point.x += getRandomInt(1,3);
square.segments[i].point.y += getRandomInt(1,3);
};
//draw the paper view
view.draw();
//Utility function that returns a random integer within a range
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
and this is the jsFiddle for it:
The issue with this scenario is that each 'point' on your canvas is an object and the high number of points/nodes/vertices is a bit heavy for the browser to handle. So this might be an obstacle if your designs are complex and/or you want to have the user interact with your drawings(the interaction might prove sluggish).
Alternatively you can use plain-old canvas to do this, without any libraries but I wouldn't do that since I smell the need for algorithms to draw the shapes manually, then introduce jitter in those algorithms. This would be much faster, in terms of computation time, but it would be harder to implement since Canvas is a low-level kind of thing - it only remembers pixels drawed on and you would need to roll-your-own data structures to remember the shapes, their positions etc etc..
Ive written a small game in JavaScript with the html5 canvas and am at the point of collision detection and getting rather confused.
I build my levels in tiled and then import the saved JSON file into the game.
In my level draw function i have a check to see if there are any layer properties and if the layer properties are collisions. If it does, that layer is returned and the loop carries on. When finished, the layer that was returned with collisions gets put through another loop so that the the tile values can be put into an array.
So in this array i have i have a series of arrays depending on how many rows of tiles there are in the layer, and these rows hold the data for that row for each tile.
What i would like to do is when the player x/y is in one of the tiles which doesn't equal 0, then collide.
How would i do this if all i have is the value that is in that tile space?
Here is a link to the live version of the game so you can see for yourself how the tiles are stored, i have put in some console.logs so you might want to use firebug or equivalent to look at that. To log in use
Username - guest
password - guest
TO clarify my question is: How do i create collisions between my player x/y and a tile value??
Thanks very much
UPDATE
Ok so i think im nearly there, my problem at the moment is how do i read the objects x and y out of the array and then check the collision, at the moment the collision detection on works with the last tile in the array (the bottom right of the screen), here is the code i implemented to go through the array:
this.check_coll = function(array,posX, posY){
var collided = false,
block_x,
block_y,
block_cx,
block_cy,
combined_hw = 32,
combined_hh = 32,
player_cx = posX+(32/2),
player_cy = posY+(32/2);
array.forEach(function(value,i){
//get obj x
block_x = value[1];
//get obj y
block_y = value[2];
block_cx = block_x+(32/2);
block_cy = block_y+(32/2);
collided = Math.abs(player_cx - block_cx)< combined_hw
&& Math.abs(player_cy - block_cy)< combined_hh;
});
return collided;
}
Any ideas guys??
It seems certain tiles will not get drawn. I have a tileset split-up into 32x32 squares and uses a 2D 100x100 array to draw the map onto the canvas.
Then it sets the "viewport" for the player. Since it's one big map, the player is always centered on the edge, unless they run near the edge.
However, this has caused problems drawing the map. Red block is "player"
Somethings I found out was that, a higher viewport (15x10) will give the ability to draw SOME previously not-drawn tiles.
Here's the code. You can download the tileset to test on localhost or below on jsFiddle http://mystikrpg.com/images/all_tiles.png
Everything below is well commented.
Even if change viewport I do see some tiles get drawn, not all.
http://pastebin.com/cBTum1aQ
Here is jsFiddle: http://jsfiddle.net/weHXU/
Working Demo
Basically I took a different approach to drawing the tiles. Using putImageData and getImageData can cause performance issues, also by pre-allocating all the image data in the beginning you are incurring a memory penalty to start out with. You already have the data in the form of the image you might as well just reference it directly instead, and it should actually be faster.
Heres the method I use
for (y = 0; y <= vHeight; y++) {
for (x = 0; x <= vWidth; x++) {
theX = x * 32;
theY = y * 32;
var tile = (board[y+vY][x+vX]-1),
tileY = Math.floor(tile/tilesX),
tileX = Math.floor(tile%tilesX);
context.drawImage(imageObj, tileX*tileWidth, tileY*tileHeight, tileWidth, tileHeight, theX, theY, tileWidth, tileHeight);
}
}
Its almost the same, but instead of looking at an array of the pre saved data, I just reference the area of the already loaded image.
Explanation on getting the referenced tile
Say I have a grid thats 4x4, and I need to get tile number 7, to get the y I would do 7/4, then to get the x I would use the remainder of 7/4 (7 mod 4).
As for the original issue.. I really have no idea what was causing the missing tiles, I just changed it to my method so I could test from there but it worked right away for me.