Can't Create Random Point in PaperJs per Documentation - javascript

I am using the latest version of PaperJs but when I run the following code from their sample the output is "NaN."
window.onload = function () {
paper.setup('myCanvas');
with (paper) {
// Create a point whose x is between 0 and 50,
// and y is between 0 and 100
var point = new Point(50, 100) * Point.random();
console.log(point);
}
}
The code works online in sketch.paperjs.org but doesn't work when I try locally via the code above or the following (also outputs "NaN"):
// Make the paper scope global, by injecting it into window:
paper.install(window);
window.onload = function () {
// Setup directly from canvas id:
paper.setup('myCanvas');
// Create a point whose x is between 0 and 50,
// and y is between 0 and 100
var point = new Point(50, 100) * Point.random();
console.log(point);
}
The following works, and all my other PaperJs code works; it's just that I can't seem to create a random point per the documentation.
console.log(new Point(50, 100), Point.random());
Outputs:
Point {x: 50, y: 100} Point {x: 0.8624748098043336, y: 0.8705165661914955}
The documenation: http://paperjs.org/tutorials/geometry/mathematical-operations/#random-values

Are you sure you use the paper.js language and not javascript?
Because the multiply operator can't be overloaded in javascript, you have to use pointA.multiply(pointB);.

Related

Auto-adjustable line between canvas objects

My intention is to create a line with canvas that adjusts itself whenever the objects change position, so that it always has a correct shape.
I currently have the following (uses a quadratic curve to make the turn):
I have found a GoJS library that does exactly what I want, which is the following:
The problem is that the library is not open source, so I wanted to know if this is some kind of generic algorithm to do it, or I have to do the calculation manually to identify the positions of the objects and calculate the best trajectory.
As extra information, I am making use of KonvaJS which natively does not implement anything like this.
It depends on how much complexity you need. This is a fiddle that does the basic pathfinding you have in the animation (without rounding the corners).
It figures out what side the paths should start from, and turns that into the offset for the path start and end, by comparing the x and y distances of the two objects:
let startsVertical = Math.abs(dx) < Math.abs(dy);
if (startsVertical) {
anchorPointOffset = {x: 0, y: Math.sign(dy) * circleRadius};
} else {
anchorPointOffset = {x: Math.sign(dx) * circleRadius, y: 0};
}
let stationaryAnchorPoint = {
x: stationaryPosition.x + anchorPointOffset.x,
y: stationaryPosition.y + anchorPointOffset.y
};
let movingAnchorPoint = {
x: movingPosition.x - anchorPointOffset.x,
y: movingPosition.y - anchorPointOffset.y
};
If your shapes do not have the same width and height, you will need to use two variables, instead of circleRadius.
Then it calculates the center point and uses that to create the middle two points of the path.
if (startsVertical) {
middleA = {
x: stationaryAnchorPoint.x,
y: centerPoint.y
}
middleB = {
x: movingAnchorPoint.x,
y: centerPoint.y
}
} else {
middleA = {
x: centerPoint.x,
y: stationaryAnchorPoint.y
}
middleB = {
x: centerPoint.x,
y: movingAnchorPoint.y
}
}
Rounding the corners is a little more complicated, but there are many guides for that.

Javascript object change values between lines

I am creating a Snake game (like those on old phones). I have a snippet of code below, which seems to exhibit the bizarre behavior of an object changing its value between lines.
The function makeSnakeArray is called when the game starts, or when the snake touches itself (the game restarts). It returns the new snake which is an array of objects with x and y properties to be stored in the global variable snakeArray.
The first time it is called, everything works fine. However, when it is called to restart the game, the x and y values are different in consoleLog1 and consoleLog2 (see code comment).
In consoleLog1, the x and y values are as what I expected as calculated in the function. However, in consoleLog2, the tempArray prints out what the snakeArray was when it called for the game to restart (and I made sure to clear the snakeArray by setting snakeArray = []; before calling the makeSnakeArray function). As a result, the snake does not start in the middle of the screen like it does the first time, but it just seems to continue around where it left off.
Why does this happen?
Function:
function makeSnakeArray(){
var tempArray = [];
//Get the position of the head of the snake
var halfWidth = Math.floor(canvasWidth/2) * blockSize;
var halfHeight = Math.floor(canvasHeight/2) * blockSize;
//Add in each block of the snake to the snake array, starting with the head
for (var i = 0; i < startingSnakeLength; i++){
//Create and initialize the snakeBlock
var snakeBlock = {
x: halfWidth,
y: halfHeight + (i*blockSize),
}
console.log(snakeBlock); //consoleLog1
tempArray.push(snakeBlock);
}
console.log(tempArray);//consoleLog2
return tempArray;
}
Example output:
consoleLog1
{x: 180, y: 180}
{x: 180, y: 195}
{x: 180, y: 210}
{x: 180, y: 225}
{x: 180, y: 240}
consoleLog2
0:{x: 60, y: 270}
1:{x: 60, y: 285}
2:{x: 60, y: 300}
3:{x: 60, y: 315}
4:{x: 60, y: 330}
Here is the current version of the snake game, if you wanted to see the full code: https://codepen.io/vrsivananda/pen/NvJyGJ?editors=0010
I did a debugging of your code with dev tools, and makeSnakeArray() function seem to work well. The issue is with updateSnake() function.
//Push this into the front of the snakeArray
snakeArray.unshift(newHead);
//If the head is the same place as the apple, then get a new apple and do not pop the tail off the snake
if(newHead.x == apple.x && newHead.y == apple.y){
apple = placeRandomApple();
}
else{
//Delete the tail fo the snakeArray
snakeArray.pop();
}
//Redraw the canvas
drawCanvas();
At this part you shouldn't update snake with a new head, if you know that game just was restarted. Plus you shouldn't cut the tail in this case either.
The easiest thing will be just to put a return statement after you know that game got restarted:
for (var i = 0; i < snakeArray.length; i++){
//If it is, restart the game
if(newHead.x == snakeArray[i].x && newHead.y == snakeArray[i].y){
restartSnakeGame();
return;
console.log("restarting");
}
}
To avoid all snake body manipulation

Negative coordinates in a grid based game

I have written a small 2D game in javascript that uses a grid where the player starts at position [0,0] and can move an almost infinite distance in either direction.
Now I want to implement A* pathfinding, but I'm having some problems finding the best way to store the world with all it's different obstacles, enemies and terrain. This is what I have tried or thought about so far.
Array of arrays
Here I store the world in an array of arrays [x][y].
var world = [[]];
world[312][11] = 0;
world[312][12] = 0;
world[312][13] = 1;
world[312][14] = 1;
...
This works great with A* pathfinding! It's easy and very fast to access a specific coordinate and populate the world. In the example above I just store passable (0) or impassable (1) terrain, but I can store pretty much whatever I want there. However, this doesn't work very well with negative coordinates like if my players is at [-12][-230]. Negative keys in a javascript array isn't actually part of the array, they won't be included in world.length or world[3].length and from what I understand, it's overall bad practice and might have some impact on the performance as well. I read somewhere that if you are using negative keys in your array, you are doing it wrong.
I would still not pass the entire world into the A* function for obvious reasons. Just a small part close to my player, but the coordinates would correspond to the positions in the array which is easy to work with.
A separate array of arrays just for A* pathfinding
This is where I'm at right now. I have a separate 50x50 grid called pathMap = [[]], that is only used for pathfinding.
var pathMap = [[]];
pathMap[0][0] = 0;
pathMap[0][1] = 0;
pathMap[0][2] = 1;
pathMap[0][3] = 1;
...
It starts at pathMap[0][0] and goes to pathMap[50][50] and is working as an overlay on my current position where I (as the player) will always be in the center position. My real coordinates may be something like [-5195,323], but it translates to pathMap[25][25] and everything close to me is put on the pathMap in relation to my position.
Now this works, but it's a huge mess. All the translations from one coordinate to another back and forth makes my brain hurt. Also, when I get the path back from A*, I have to translate each step of it back to the actual position my element should move to in the real world. I also have to populate the same object into 2 different grids every update which hurts performance a bit as well.
Array of objects
I think this is where I want to be, but I have some issues with this as well.
var world = [];
world[0] = { x: -10, y: 3, impassable: 0 };
world[1] = { x: -10, y: 4, impassable: 0 };
world[2] = { x: -10, y: 5, impassable: 1 };
world[3] = { x: -10, y: 6, impassable: 1 };
...
Works great with negative x or y values! However, it's not as easy to find for instance [10,3] in this array. I have to loop through the entire array to look for an object where x == 10 and y == 3 instead of the very easy and fast approach world[10][3] in the first example. Also, I can't really rely on the coordinates being in the right order using this version, sorting becomes harder, as does other things that was a lot easier with the array of arrays.
Rebuild the game to always be on the positive side
I would prefer not to do this, but I have considered placing the players starting position at something like [1000000,1000000] instead, and making negative coordinates off limits. It seems like a failure if I have to remove the vision I have of endlessness just to make the pathfinding work with less code. I know there will always be some upper or lower limits anyways, but I just want to start at [0,0] and not some arbitrary coordinate for array related reasons.
Other?
In javascript, is there another option that works better and is not described above? I'm very open to suggestions!
Is there a best practice for similar cases?
You have three coordinates system you must distinguish :
the world coordinates.
the world model / path-finding (array) coordinates.
the screen coordinates.
The screen coordinates system depends upon :
the viewport = the canvas. (width, height in pixels).
a camera = (x,y) center in world coordinates + a viewWidth (in world coordinates).
To avoid headaches, build a small abstraction layer that will do the math for you.
You might want to use Object.defineProperty to define properties, that will provide a fluent interface.
var canvas = ... ;
var canvasWidth = canvas.width;
var canvasHeigth = canvas.heigth;
var world = {
width : 1000, // meters
height : 1000, // meters
tileSize : 0.5, // height and width of a tile, in meter
model : null, // 2D array sized ( width/tileSize, XtileSize )
};
// possibles world coordinates range from -width/2 to width/2 ; - height/2 height/2.
var camera = {
x : -1,
y : -1,
viewWidth : 10, // we see 10 meters wide scene
viewHeight : -1 // height is deduced from canvas aspect ratio
};
camera.viewHeight = camera.viewWidth * canvasWidth / canvasHeight ;
Then your character looks like :
// (x,y) is the center of the character in centered world coordinates
// here (0,0) means (500,500) world coords
// (1000,1000) array coords
// (320, 240) screen coords in 640X480
function /*Class*/ Character(x, y) {
var _x=x;
var _y=y;
var _col=0;
var _row=0;
var _sx=0.0;
var _sy=0.0;
var dirty = true;
Object.defineProperty(this,'x',
{ get : function() {return _x; }
set : function(v) { _x=v;
dirty=true; } });
Object.defineProperty(this,'x',
{ get : function() {return _y; }
set : function(v) { _y=v;
dirty=true; } });
Object.defineProperty(this,'col',
{ get : function() {
if (dirty) updateCoords();
return _col; } });
Object.defineProperty(this,'row',
{ get : function() {
if (dirty) updateCoords();
return _row; } });
Object.defineProperty(this,'sx',
{ get : function() {
if (dirty) updateCoords();
return _sx; } });
Object.defineProperty(this,'sy',
{ get : function() {
if (dirty) updateCoords();
return _sy; } });
function updateCoords() {
_row = ( ( _x + 0.5 * world.width )/ world.tileSize ) | 0 ;
_col = ( ( _x + 0.5 * world.height )/ world.tileSize ) | 0 ;
_sx = canvasWidth * ( 0.5 + ( _x - camera.x ) / camera.viewWidth ) ;
_sy = canvasHeight * ( 0.5 + ( _y - camera.y ) / camera.viewHeight ) ;
dirty = false;
}
}

Drawing images in a 'grid' layout on the HTML5 canvas using JavaScript and the KineticJS library

I have an array of images which I want to draw to the HTML5 canvas in specific locations (i.e. using a 'grid' type layout).
I have a function called drawImage(imageObj) which currently draws all of the images in the array to random locations on the canvas. However, I want to be able to predetermine a set number of locations at which the images should be drawn, and then choose which image is drawn at which of these set locations randomly (it doesn't matter if more than one image is drawn to the same location).
My drawImage(imageObj) function currently looks like this:
function drawImage(imageObj) {
var canvasImage = new Kinetic.Image({
image: imageObj,
width: 50,
height: 50,
/* puts the images in random locations on the canvas */
x: stage.getWidth() / 20*Math.floor(Math.random()*20),
y: stage.getHeight() / 15*Math.floor(Math.random()*8+2),
draggable: true
});
// add cursor styling
canvasImage.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
canvasImage.on('mouseout', function() {
document.body.style.cursor = 'default';
});
imagesLayer.add(canvasImage);
}
I tried altering the function slightly to create a 'grid' of locations, and then draw each image to a random 'cell' in the grid:
function drawImage(imageObj) {
/* Create arrays of X & Y coordinates, and select the array elements randomly for use as
coordinates at which to draw the images*/
var xPos = new Array();
xPos[0] = 10;
xPos[1] = 70;
xPos[2] = 130;
xPos[3] = 190;
xPos[4] = 250;
xPos[5] = 310;
xPos[6] = 370;
xPos[7] = 430;
xPos[8] = 490;
xPos[9] = 550;
xPos[10] = 610;
xPos[11] = 670;
xPos[12] = 730;
xPos[13] = 790;
xPos[14] = 850;
xPos[15] = 910;
var yPos = new Array();
yPos[0] = 10;
yPos[1] = 70;
yPos[2] = 130;
yPos[3] = 190;
yPos[4] = 250;
yPos[5] = 310;
yPos[6] = 370;
yPos[7] = 430;
var canvasImage = new Kinetic.Image({
image: imageObj,
width: 50,
height: 50,
/* Now select a random X & Y position from the arrays to draw the images to */
x: xPos(getRandomXPosition),
y: yPos(getRandomYPosition),
draggable: true
/* puts the images in random locations on the canvas
x: stage.getWidth() / 20*Math.floor(Math.random()*20),
y: stage.getHeight() / 15*Math.floor(Math.random()*8+2),
draggable: true */
});
I had expected that the lines
x: xPos(getRandomXPosition),
y: yPos(getRandomYPosition),
would set the x and y coordinates of the image that is being drawn to the canvas to a random 'cell' in my 'grid' determined by which random elements of the xPos and yPos arrays were set as the x and y values of the image that was to be drawn.
However, when I view my page in the browser, I'm getting a console error which says that "xPos is not a function" on the line
x: xPos(getRandomXPosition),
I can't figure out why this is- does anyone have any ideas? I assume I will have the same error on the line
y: yPos(getRandomYPosition),
for the same reason.
I know that xPos is not a function- it is an array, and I am simply trying to retrieve the array element at position 'getRandomXPosition'.
I thought that this might be because 'getRandomXPosition' is not an int itself, it is a function, so I tried storing its output in a variable by changing those function definition lines to:
var randomXPosition = function getRandomXPosition(minX, maxX){
return Math.floor(Math.random()*(maxX - minX +1)) +minX;
}
var randomYPosition = function getRandomYPosition(minY, maxY){
return Math.floor(Math.random()*(maxY - minY +1)) +minY;
}
and then updating where I was using them so that I was now passing the variables as parameters instead of the functions:
x: xPos(randomXPosition),
y: yPos(randomYPosition),
draggable: true
However, when viewing the page in the browser, I am still getting the console error that says that "xPos is not a function" on the line
x: xPos(randomXPosition),
I can't figure out why this is- can anyone point me in the right direction? It's probably also worth mentioning that I'm using the kineticJS library to make the images 'draggable' when they're drawn to the canvas- just to give a more complete picture of my code.
Any advice would be much appreciated!
Edited 28/01/2013 # 18:05
Ok, I think I know why the images are all being drawn in the top left corner- the drawImage function that is being called is the one from the KineticJS library, not my own one. I am using a copy of the library that I've saved locally, as there are a few things that I have changed regarding the functionality that the library provides. Would it make sense to copy the code creating the arrays of positions and selecting the random elements from those positions into the drawImage function in the library instead?
Edited 29/01/2013 # 23:15
Right, I've had a look at the drawImage function in the kineticJS library (I'm using a local copy of the library), and it looks like this:
drawImage: function() {
var context = arguments[0];
context.save();
var a = Array.prototype.slice.call(arguments);
if(a.length === 6 || a.length === 10) {
if(a.length === 6) {
context.drawImage(a[1], a[2], a[3], a[4], a[5]);
}
else {
context.drawImage(a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
}
}
context.restore();
}
I'm not sure that I fully understand all of the code here... What is the line
var a = Array.prototype.slice.call(arguments);
doing? I've not seen this 'slice' function before...
Can anyone point out how I would edit this function to include the code I've written to enable the images all to be drawn in separate locations by selecting the coordinates randomly from the arrays of coordinates? Presumably, I should just be able to copy and paste this code into the function, but I'm not sure where in the function I should put it... any suggestions?
xPos is an array , so you need to use array format to get its element , like xPos[key] ,
and randomXPosition is a function , you need to execute it to get its return value , like randomXPosition() .
In conclusion ,
X: xPos[randomXPosition()],
Well, to access a certain index in the array you have to use [] not (), like so:
xPos[randomXPosition] // if randomXPosition = 1, then this gives you the value at xPos[1].
xPos(randomXPosition) // <-- this is a function call, what it is expecting is something like:
function xPos(number){
var value = number * Math.random();
return value; //return some value maybe?
};

raphaelJS 2.1 animate along path

I want to animate a path (actually a set of paths, but I'll get to that) along a curved path.
RaphaelJS 2 removed the animateAlong method, for reasons I haven't been able to discern. Digging into the Raphael documentation's gears demo as abstracted by Zevan, I have got this far:
//adding a custom attribute to Raphael
(function() {
Raphael.fn.addGuides = function() {
this.ca.guide = function(g) {
return {
guide: g
};
};
this.ca.along = function(percent) {
var g = this.attr("guide");
var len = g.getTotalLength();
var point = g.getPointAtLength(percent * len);
var t = {
transform: "t" + [point.x, point.y]
};
return t;
};
};
})();
var paper = Raphael("container", 600, 600);
paper.addGuides();
// the paths
var circ1 = paper.circle(50, 150, 40);
var circ2 = paper.circle(150, 150, 40);
var circ3 = paper.circle(250, 150, 40);
var circ4 = paper.circle(350, 150, 40);
var arc1 = paper.path("M179,204c22.667-7,37,5,38,9").attr({'stroke-width': '2', 'stroke': 'red'});
// the animation
// works but not at the right place
circ3.attr({guide : arc1, along : 1})
.animate({along : 0}, 2000, "linear");
http://jsfiddle.net/hKGLG/4/
I want the third circle to animate along the red path. It is animating now, but at a distance from the red path equal to the third circle's original coordinates. The weird thing is that this happens whether the transform translate in the along object is relative (lowercase "t") or absolute (uppercase "T"). It also always animates in the same spot, even if I nudge it with a transform translation just before the animate call.
Any help very appreciated. I just got off the boat here in vector-land. Pointers are helpful--a working fiddle is even better.
You're just a hop, skip, and jump away from the functionality that you want. The confusion here concerns the interaction between transformations and object properties -- specifically, that transformations do not modify the original object properties. Translating simply adds to, rather than replaces, the original coordinates of your circles.
The solution is extremely straightforward. In your along method:
this.ca.along = function(percent) {
var box = this.getBBox( false ); // determine the fundamental location of the object before transformation occurs
var g = this.attr("guide");
var len = g.getTotalLength();
var point = g.getPointAtLength(percent * len);
var t = {
transform: "...T" + [point.x - ( box.x + ( box.width / 2 ) ), point.y - ( box.y + ( box.height / 2 ) )] // subtract the center coordinates of the object from the translation offset at this point in the guide.
};
return t;
Obviously, there's some room for optimization here (i.e., it might make sense to create all your circles at 0,0 and then translate them to the display coordinates you want, avoiding a lot of iterative math). But it's functional... see here.
One other caveat: the ...T translation won't effect any other transforms that have already been applied to a given circle. This implementation is not guaranteed to play nicely with other transforms.

Categories

Resources