let input = [
[[1, 4], [40, 4]],
[[1, 5], [40, 5]],
[[4, 7], [4, 24]],
[[1, 9], [4, 1]],
[[1, 2], [6, 4]],
[[80, 4], [90, 4]],
[[4, 1], [4, 40]],
[[4, 35], [4, 29]],
[[4, 28], [4, 35]],
[[5, 3.6], [9, 5.2]],
]; // Input
Output = [
[[[1, 4], [40, 4]], [[80, 4], [90, 4]]],
[[[1, 5], [40, 5]]],
[[[4, 7], [4, 24]], [[4, 1], [4, 40]]],
[[[4, 35], [4, 29]], [[4, 28], [4, 35]]],
[[[1, 9], [4, 1]]],
[[[1, 2], [6, 4]], [[5, 3.6], [9, 5.2]]],
];
If given an input of series of each start and end coordinates of a line, for example, [[1,4],[40,4]] means that it has 2 points connecting [1,4] and [40,4] to form a straight line. My objective now is to group all those lines which share the same equation y=mx+c, together into a nested array as shown above. For example,
[[1,4],[40,4]] and [[80,4],[90,4]] share the same linear equation y=4
[[4,7],[4,24]],[[4,1],[4,40]] share the same linear equation x=4
[[1,2],[6,4]] and [[5,3.6],[9,5.2]] share the same linear equation y=0.4x+1.6
[[1,9],[4,1]] is alone and it has the linear equation of -2.67x+11.67
Here is my working codepen demo
I know how to code out to find those m and c in y=mx+c, but the problem is when for example,[[4,7],[4,24]] and [[4,1],[4,40]] , the m gradient becomes infinity which unsolvable.
Can anyone please guide me on this on how to get the correct output?
You can calculate the slope equation for each set of points and assign it to each array item, then group:
const input=[[[1,4],[40,4]],[[1,5],[40,5]],[[4,7],[4,24]],[[1,9],[4,1]],[[1,2],[6,4]],[[80,4],[90,4]],[[4,1],[4,40]],[[4,35],[4,29]],[[4,28],[4,35]],[[5,3.6],[9,5.2]]];
const inputsWithSlope = input.map((points) => {
const [[x, y], [x1, y1]] = points;
const slope = (y1 - y) / (x1 - x)
const b = y1 - slope * x1
return {
points,
line: x1 == x ? `x = ${x}` : `y = ${slope}x + ${b}`
}
})
const res = inputsWithSlope.reduce((acc, curr) => {
const accProp = acc[curr.line]
acc[curr.line] = !accProp ? [curr.points] : [...accProp, curr.points]
return acc
}, {})
const result = Object.values(res)
result.forEach(e => console.log(JSON.stringify(e)))
To deal with the rounding issue, you'll have to round it:
const input=[[[1,4],[40,4]],[[1,5],[40,5]],[[4,7],[4,24]],[[1,9],[4,1]],[[1,2],[6,4]],[[80,4],[90,4]],[[4,1],[4,40]],[[4,35],[4,29]],[[4,28],[4,35]],[[5,3.6],[9,5.2]]];
const inputsWithSlope = input.map((points) => {
const [[x, y], [x1, y1]] = points;
const slope = (y1 - y) / (x1 - x)
const b = y1 - slope * x1
return {
points,
line: x1 == x ? `x = ${x}` : `y = ${slope.toFixed(2)}x + ${b.toFixed(2)}`
}
})
const res = inputsWithSlope.reduce((acc, curr) => {
const accProp = acc[curr.line]
acc[curr.line] = !accProp ? [curr.points] : [...accProp, curr.points]
return acc
}, {})
const result = Object.values(res)
result.forEach(e => console.log(JSON.stringify(e)))
Here's my take at it. The strategy is to first get a description of the line for each pair of points, and then group those together into a map of maps, first keyed by slopes, and then by intercepts (either x or y, depending on if the line is vertical or not), and then extract the groups into a single array.
let input=[ [[1,4],[40,4]] , [[1,5],[40,5]] , [[4,7],[4,24]] ,[[1,9],[4,1]], [[1,2],[6,4]], [[80,4],[90,4]] , [[4,1],[4,40]] , [[4,35],[4,29]] , [[4,28],[4,35]] ,[[5,3.6],[9,5.2]] ] ;
// a function to get the slope and intercept of the line formed by a pair of points
function describeLine([[x1, y1], [x2, y2]]) {
if (x1 == x2) { // vertical line
return {m: "vertical", x: x1}
}
const p1 = x1 > x2 ? { x: x1, y: y1 } : { x: x2, y: y2 }
const p2 = x1 < x2 ? { x: x1, y: y1 } : { x: x2, y: y2 }
const m = (p1.y - p2.y) / (p1.x - p2.x)
const y = y1 - m * x1
return { m, y }
}
// this runs through the input array and accumulates all the pairs of points into a dictionary structure keyed by slope and then intercept
// so for a line with slope 2 and y-intercept 3, it would go into the map at { 2 : { 3: [[ [point 1], [point2]] ], [ line 2 with same props] ...
const maps = input.reduce((acc, line) => {
const desc = describeLine(line)
const m = acc[desc.m] || { }
if (desc.x) { // vertical line
x = m[desc.x] || []
return { ...acc, [desc.m]: { ...m, [desc.x]: [ ...x, line ]}}
} else {
y = m[desc.y] || []
return { ...acc, [desc.m]: { ...m, [desc.y]: [ ...y, line ]}}
}
}, {})
// once we've accumulated that structure, we can just collect the individual arrays into one big array
const sameLines = Object.values(maps).flatMap(Object.values)
console.log(JSON.stringify(sameLines, null, 2))
Related
let's say I have a grid i.e. 2d array
const grid = [
[0, 0, A, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, B, 0],
[D, E, 0, C, F],
[0, 0, 0, 0, 0],
]
if some cell in the grid can visit all adjacent cells 4-diredtionally, for example, C is at [3, 3] so it can visit [3, 3 + 1], [3 - 1, 3],[3 +1, 3]``[3, 3 - 1], so normally I would have to hard code this like
// 👇 hard-coded directions
const dirs = [
[1, 0],
[-1, 0],
[0, 1],
[0, -1],
]
const possibleMoves = []
for (const [dx, dy] of dirs) {
possibleMoves.push([dx + x, dy +y])
}
then if it can move 8-directionally then you have to hard code more directions
const dirs = [[1, 0], [-1, 0] , [0,1], [0,-1], [1,1], [-1,1], [-1,-1], [1,-1]]
Is there a smarter way to generate the dirs array for the next moves?
Yes!
First: any time you're doing grid-logic, start by checking what Amit Patel has to say.
Honestly, that link has everything you could ever need.
The short version is: if you know the grid width and cell layout, you can easily calculate coordinate offsets of any cell neighbor for any definition of "neighbor."
That logic can be implemented as a pure function that requires both the grid dimensions and the coordinates of the cell whose neighbors you want (aka the "target" cell):
let myNeighbors = getCellNeighbors(
{ x: 2, y: 2 }, // coords of target cell
{ width: 10, height: 10 } // grid dimensions, in cells
)
Or you can create a stateful thing that takes the grid dimensions at creation and calculates the offsets once, to be re-used for all getNeighbors calls:
let myGrid = new Grid(10, 10)
let myNeighbors = myGrid.getNeighbors(2, 5)
let myBiggerGrid = new Grid(25, 25)
let otherNeighbors = myBiggerGrid(2, 5)
I would like to fill until a specific Y value in PlotlyJS. This is as far as I got from the PlotlyJS docs: Fiddle
{
"x": [
"2016-01-31T00:03:57.000Z",
"2016-02-12T04:35:26.000Z"
],
"y": [
100,
100
],
"fill": "tonexty",
"fillcolor": "#8adcb3"
}
In the documentation, there seems to be two options:
tonexty - Fills as below. The problem is 'tonexty' is a bit limiting - The use case is 'filling until the line', so shading ONLY above 110. Example:
tozeroy - Fills till zero:
Also, do you need to introduce a new trace in order to create a fill?
This means that if I have a chart as follows (with only one trace but a threshold line as a shape): I need to introduce another trace just to create a fill. Maybe there's something I missed in the docs, or this is the wrong approach altogether.
So, how do you fill an area in a trace above a specific Y value in PlotlyJS?
A solution is to use multiple traces.
Split all your traces between ones which are above 0 and ones which are not.
When you are done you can fill them (or not) with the 'tozeroy' value.
The following jsfiddle shows a working example.
The code is as following :
HTML:
<div id="myDiv" style="width:600px;height:250px;"></div>
JS:
var data = [
{
x: ['A', 'B', 'C', 'D'],
y: [1, 3, 6, 0],
fill: 'tozeroy',
fillcolor: '#8adcb3'
},
{
x: ['D', 'F', 'G', 'I'],
y: [0, -3, -2, 0],
fill: 'toself'
},
{
x: ['I', 'J', 'K'],
y: [0, 5, 7],
fill: 'tozeroy',
fillcolor: '#0adcb3'
}
];
Plotly.newPlot('myDiv', data);
The result looks as following :
Here is another solution exploiting Plotly's fill: "toself". The idea is to create a closed line trace which encloses the area above the threshold and the markers of the main line. Works for threshold values above zero and for numerical x-values.
The helper traces have their legend hidden and are grouped with the main trace, thereby preventing ugly artifacts when toggling the legend.
The function checks for each x-y-pair if the y-value is above the threshold, if yes
check if there is already a segment above the threshold and use this one OR create a new sgement
the segement starts from the y-value of the threshold and the intermediate x-value from the point above the threshold and the one before.
each segment is terminated with an y-value which is equal to the threshol and the x-value which the mean of the last point in the segment and the next one
The function itself can be surely written in a nicer way but it's just a proof-of-concept.
function dataToTraces(data, threshold) {
var fillers = [];
var emptyFiller = {
x: [],
y: [],
fill: "toself",
mode: "lines",
line: {
width: 0
},
opacity: 0.5,
fillcolor: "#8adcb3",
showlegend: false,
legendgroup: "main"
}
fillers.push(emptyFiller);
for (var i = 0; i < data.y.length; i += 1) {
if (data.y[i] >= threshold) {
if (i !== 0 && data.y[i - 1] < threshold) {
fillers[fillers.length - 1].x.push(data.x[i - 1] + (threshold - data.y[i - 1]) / (data.y[i] - data.y[i - 1]));
fillers[fillers.length - 1].y.push(threshold);
}
fillers[fillers.length - 1].x.push(data.x[i]);
fillers[fillers.length - 1].y.push(data.y[i]);
} else if (fillers[fillers.length - 1].x.length > 0) {
if (i !== 0 && data.y[i - 1] !== threshold) {
fillers[fillers.length - 1].x.push(data.x[i - 1] + (threshold - data.y[i - 1]) / (data.y[i] - data.y[i - 1]));
fillers[fillers.length - 1].y.push(threshold);
}
fillers.push(emptyFiller);
}
}
return fillers;
}
var data = [{
x: [0, 1, 2, 3, 4, 5, 6, 7, 8],
y: [1, 3, 6, 2, -1, 5, 1, 3, 0],
name: "main",
legendgroup: "main"
}];
var fillers = dataToTraces(data[0], 2);
Plotly.newPlot("myDiv", data.concat(fillers));
<div id="myDiv"></div>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
I have to display around 20 lines within a line chart with Google's Line Chart. It might happen, that these lines overlap. What is the best way to add noise to the data so all the lines are visible.
the values for cat1, cat2 and cat3 are the same but I want that the it is evident from the image, that they are really close - so my idea is that the lines should not overlap but be a bit apart. The user cannot assume, that all the values overlap since for some events, let's say D, the values might be missing.
Given this chart:
function drawVisualization() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['x', '#1', '#2', '#3'],
['A', 1, 1, 1],
['B', 2, 2, 2],
['C', 3, 3, 3],
['D', 4, 4, 4],
['E', 5, 5, 5],
['F', 6, 6, 6],
['G', 7, 7, 7],
['H', 8, 8, 8],
['I', 9, 9, 9],
]);
// Create and draw the visualization.
new google.visualization.LineChart(document.getElementById('visualization')).
draw(data, {width: 500, height: 400,
vAxis: {maxValue: 10}}
);
}
One way is just to add a consistent +/- per series:
function drawVisualization() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['x', '#1', '#2', '#3'],
['A', 1, 1, 1],
['B', 2, 2, 2],
['C', 3, 3, 3],
['D', 4, 4, 4],
['E', 5, 5, 5],
['F', 6, 6, 6],
['G', 7, 7, 7],
['H', 8, 8, 8],
['I', 9, 9, 9],
]);
for (var i = 1;i < data.getNumberOfColumns();i++) {
// Algorithm to add +/- 0.1 for each series
var dither = Math.round((i - 1)/2)/5;
if ( (i - 1) % 2 == 0 ) {
dither = dither * -1;
}
for (var j = 0;j < data.getNumberOfRows();j++){
// Add dither to series to display differently, but keep same data for tooltip
data.setCell(j, i, data.getValue(j, i) + dither, data.getValue(j, i) + '', undefined)
}
}
// Create and draw the visualization.
new google.visualization.LineChart(document.getElementById('visualization')).
draw(data, {width: 500, height: 400,
vAxis: {maxValue: 10}}
);
}
The issue with this method is that if the values of your axes or data change significantly, you won't be able to see the gap (because the resolution of the screen won't be big enough). To get around this issue, we would need to manually set the min/max values of the axes in order to be able to come up with an appropriate factor. For instance, from this answer we can take the following algorithm to determine min and max axes values that approximate what google will set for us automagically:
// Take the Max/Min of all data values in all graphs
var totalMax = 345;
var totalMin = -123;
// Figure out the largest number (positive or negative)
var biggestNumber = Math.max(Math.abs(totalMax),Math.abs(totalMin));
// Round to an exponent of 10 appropriate for the biggest number
var roundingExp = Math.floor(Math.log(biggestNumber) / Math.LN10);
var roundingDec = Math.pow(10,roundingExp);
// Round your max and min to the nearest exponent of 10
var newMax = Math.ceil(totalMax/roundingDec)*roundingDec;
var newMin = Math.floor(totalMin/roundingDec)*roundingDec;
// Determine the range of your values
var range = newMax - newMin;
// Define the number of gridlines (default 5)
var gridlines = 5;
// Determine an appropriate gap between gridlines
var interval = range / (gridlines - 1);
// Round that interval up to the exponent of 10
var newInterval = Math.ceil(interval/roundingDec)*roundingDec;
// Re-round your max and min to the new interval
var finalMax = Math.ceil(totalMax/newInterval)*newInterval;
var finalMin = Math.floor(totalMin/newInterval)*newInterval;
We can add this all together, and see that it will even work if all the values are increased in factor by 10 (which wouldn't have worked with the hard-coded version):
function drawVisualization() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['x', '#1', '#2', '#3'],
['A', 10, 10, 10],
['B', 20, 20, 20],
['C', 30, 30, 30],
['D', 40, 40, 40],
['E', 50, 50, 50],
['F', 60, 60, 60],
['G', 70, 70, 70],
['H', 80, 80, 80],
['I', 90, 90, 90],
]);
// Get max and min values for the data table
var totalMin = data.getValue(0,1);
var totalMax = data.getValue(0,1);
for (var i = 1;i < data.getNumberOfColumns();i++) {
for (var j = 0;j < data.getNumberOfRows();j++){
if ( data.getValue(j, i) < totalMin ) {
totalMin = data.getValue(j, i);
}
if ( data.getValue(j, i) > totalMax ) {
totalMax = data.getValue(j, i);
}
}
}
// Calculate grid line axes and min/max settings
// Figure out the largest number (positive or negative)
var biggestNumber = Math.max(Math.abs(totalMax),Math.abs(totalMin));
// Round to an exponent of 10 appropriate for the biggest number
var roundingExp = Math.floor(Math.log(biggestNumber) / Math.LN10);
var roundingDec = Math.pow(10,roundingExp);
// Round your max and min to the nearest exponent of 10
var newMax = Math.ceil(totalMax/roundingDec)*roundingDec;
var newMin = Math.floor(totalMin/roundingDec)*roundingDec;
// Determine the range of your values
var range = newMax - newMin;
// Define the number of gridlines (default 5)
var gridlines = 5;
// Determine an appropriate gap between gridlines
var interval = range / (gridlines - 1);
// Round that interval up to the exponent of 10
var newInterval = Math.ceil(interval/roundingDec)*roundingDec;
// Re-round your max and min to the new interval
var finalMax = Math.ceil(totalMax/newInterval)*newInterval;
var finalMin = Math.floor(totalMin/newInterval)*newInterval;
// Calculate Dither
for (var i = 1;i < data.getNumberOfColumns();i++) {
// Algorithm to add +/- 0.1 for each series
var dither = Math.round((i - 1)/2)/(10/newInterval);
if ( (i - 1) % 2 == 0 ) {
dither = dither * -1;
}
for (var j = 0;j < data.getNumberOfRows();j++){
// Add dither to series to display differently, but keep same data for tooltip
data.setCell(j, i, data.getValue(j, i) + dither, data.getValue(j, i) + '', undefined)
}
}
// Create and draw the visualization.
new google.visualization.LineChart(document.getElementById('visualization')).
draw(data, {width: 500, height: 400,
vAxis: {minValue: finalMin, maxValue: finalMax}}
);
}
(disclosure, I'm mostly math illiterate).
I have an array in this format:
var grid = [
[0,0], [0,1], [0,2], [0,3],
[1,0], [1,1], [1,2], [1,3],
[2,0], [2,1], [2,2], [2,3],
[3,0], [3,1], [3,2], [3,3]
];
I need to "rotate" it by 90deg increments, so it's like this:
var grid = [
[3,0], [2,0], [1,0], [0,0],
[3,1], [2,1], [1,1], [0,1],
[3,2], [2,2], [1,2], [0,2],
[3,3], [2,3], [1,3], [0,3]
];
How do I accomplish this in Javascript?
Rotating a two dimensional m x n matrix
Those looking for Rotating a two dimensional matrix (a more general case) here is how to do it.
example:
Original Matrix:
[
[1,2,3],
[4,5,6],
[7,8,9]
]
Rotated at 90 degrees:
[
[7,4,1]
[8,5,2]
[9,6,3]
]
This is done in following way:
matrix[0].map((val, index) => matrix.map(row => row[index]).reverse())
For counter-clockwise rotation (Thanks to #karn-ratana):
matrix[0].map((val, index) => matrix.map(row => row[row.length-1-index]));
Credit goes to this answer for the actual rotation method.
My method was pretty straightforward. Just determine what the row length was, and then iterate through each item, converting the array index to x/y equivalents and then apply the method used in the linked answer to rotate. Finally I converted the rotated X/Y coordinates back to an array index.
var grid = [
[0,0], [0,1], [0,2], [0,3],
[1,0], [1,1], [1,2], [1,3],
[2,0], [2,1], [2,2], [2,3],
[3,0], [3,1], [3,2], [3,3]
];
var newGrid = [];
var rowLength = Math.sqrt(grid.length);
newGrid.length = grid.length
for (var i = 0; i < grid.length; i++)
{
//convert to x/y
var x = i % rowLength;
var y = Math.floor(i / rowLength);
//find new x/y
var newX = rowLength - y - 1;
var newY = x;
//convert back to index
var newPosition = newY * rowLength + newX;
newGrid[newPosition] = grid[i];
}
for (var i = 0; i < newGrid.length; i++)
{
console.log(newGrid[i])
}
The output:
[3, 0] [2, 0] [1, 0] [0, 0]
[3, 1] [2, 1] [1, 1] [0, 1]
[3, 2] [2, 2] [1, 2] [0, 2]
[3, 3] [2, 3] [1, 3] [0, 3]
Fiddle for the lazy. And a 5x5 grid fiddle to demonstrate that the algorithm works for N grid sizes as long as they are square.
These are two function for clockwise and counterclockwise 90-degree rotation:
function rotateCounterClockwise(a){
var n=a.length;
for (var i=0; i<n/2; i++) {
for (var j=i; j<n-i-1; j++) {
var tmp=a[i][j];
a[i][j]=a[j][n-i-1];
a[j][n-i-1]=a[n-i-1][n-j-1];
a[n-i-1][n-j-1]=a[n-j-1][i];
a[n-j-1][i]=tmp;
}
}
return a;
}
function rotateClockwise(a) {
var n=a.length;
for (var i=0; i<n/2; i++) {
for (var j=i; j<n-i-1; j++) {
var tmp=a[i][j];
a[i][j]=a[n-j-1][i];
a[n-j-1][i]=a[n-i-1][n-j-1];
a[n-i-1][n-j-1]=a[j][n-i-1];
a[j][n-i-1]=tmp;
}
}
return a;
}
I don't really need to deal with indices, since I can copy the values from one place to the other, this simplifies the answer a bit:
var grid = [
[0,0], [0,1], [0,2], [0,3], [0,4],
[1,0], [1,1], [1,2], [1,3], [1,4],
[2,0], [2,1], [2,2], [2,3], [2,4],
[3,0], [3,1], [3,2], [3,3], [3,4],
[4,0], [4,1], [4,2], [4,3], [4,4]
];
var side = Math.sqrt(grid.length);
var rotate = function(d,i){
return [Math.abs(i % side - side+1), Math.floor(i/side)]
}
grid = grid.map(rotate);
You can see a jsfiddle here: http://jsfiddle.net/KmtPg/
This solution will work with any kind of matrix but if it's not nn and the size is nm it will have undefined items in the array (I set it to return null in case of undefined), but it works at the end and you will have a rotated array.
//ES6 function
const rotateMatrix = (matrix) => {
let temp;
for (let i = 1; i < matrix.length; i++) {
for (let j = 0; j < matrix.length / 2; j++) {
temp = matrix[i][j];
matrix[i][j] = matrix[j][i] === undefined ? null : matrix[j][i];
matrix[j][i] = temp;
}
}
return matrix;
};
// 3,3 matrix example
console.table(rotateMatrix([[1, 2, 64], [4, 5, 55], [7, 8, 34]]));
// 5*3 matrix example
console.table(rotateMatrix([[1, 2, 64], [4, 5, 55], [7, 8, 34], [10, 15, 65], [22, 24, 56]]));
I'm using http://craftyjs.com/ for the Github Game Off, and I'm having some trouble with animation. The first time I start the animation (when I initialize the player entity in the main scene) it works. But when I set the animation via my CustomControls component, it only plays the first frame of the animation.
I believe the problem is in the CustomControls component, so here's the code for that:
https://gist.github.com/3992392
Here's all the code if you want to clone it and test: https://github.com/RylandAlmanza/dragons-suck
If anyone knows what the problem might be, let me know. Thanks!
EDIT: Here's a minimal jsfiddle example with everything stripped out except for movement and what should be animation: http://jsfiddle.net/x7FDF/
var SPRITE_SIZE = 32;
Crafty.init();
Crafty.canvas.init();
Crafty.sprite(SPRITE_SIZE, "http://i.imgur.com/9sN9V.png", {
player_east_1: [0, 0],
player_east_2: [1, 0],
player_east_3: [2, 0],
player_west_1: [0, 1],
player_west_2: [1, 1],
player_west_3: [2, 1],
player_south_1: [0, 2],
player_south_2: [1, 2],
player_south_3: [2, 2],
player_north_1: [0, 3],
player_north_2: [1, 3],
player_north_3: [2, 3]
});
Crafty.scene("loading", function() {
Crafty.background("#000");
Crafty.e("2D, DOM, Text")
.attr({
w: 100,
h: 20,
x: 150,
y: 120
})
.text("Loading")
.css({"text-align": "center"});
Crafty.load(["http://i.imgur.com/9sN9V.png"], function() {
Crafty.scene("main");
});
});
Crafty.scene("main", function() {
Crafty.background("#000");
var player = Crafty.e("2D, DOM, SpriteAnimation, player_east_1, Collision, TileCollision, CustomControls")
.attr({
x: 0,
y: 0,
x_velocity: 0,
y_velocity: 0,
w: SPRITE_SIZE,
h: SPRITE_SIZE
})
.animate("stand_east", 0, 0, 0)
.animate("stand_west", 0, 1, 0)
.animate("stand_south", 0, 2, 0)
.animate("stand_north", 0, 3, 0)
.animate("walk_east", [[0, 0], [1, 0], [0, 0], [2, 0]])
.animate("walk_west", [[0, 1], [1, 1], [0, 1], [2, 1]])
.animate("walk_south", [[0, 2], [1, 2], [0, 2], [2, 2]])
.animate("walk_north", [[0, 3], [1, 3], [0, 3], [2, 3]])
.animate("stand_east", 45, -1)
.CustomControls();
});
Crafty.c("CustomControls", {
CustomControls: function() {
this.bind("EnterFrame", function() {
var up = Crafty.keydown[Crafty.keys.UP_ARROW];
var down = Crafty.keydown[Crafty.keys.DOWN_ARROW];
var left = Crafty.keydown[Crafty.keys.LEFT_ARROW];
var right = Crafty.keydown[Crafty.keys.RIGHT_ARROW];
if (up) {
this.y_velocity = -2;
if (!this.isPlaying("walk_north")) {
this.stop().animate("walk_north", 45, -1);
}
}
if (down) {
this.y_velocity = 2;
if (!this.isPlaying("walk_south")) {
this.stop().animate("walk_south", 45, -1);
}
}
if (left) {
this.x_velocity = -2;
if (!this.isPlaying("walk_west")) {
this.stop().animate("walk_west", 45, -1);
}
}
if (right) {
this.x_velocity = 2;
if (!this.isPlaying("walk_east")) {
this.stop().animate("walk_east", 45, -1);
}
}
if (!left && !right) {
this.x_velocity = 0;
this.stop();
}
if (!up && !down) {
this.y_velocity = 0;
this.stop();
}
this.x += this.x_velocity;
this.y += this.y_velocity;
});
}
});
Crafty.scene("loading");​
In the end of "enterFrame" you have:
if (!left && !right) {
this.x_velocity = 0;
this.stop();
}
if (!up && !down) {
this.y_velocity = 0;
this.stop();
}
Therefore, the animation is always stopped and then restarted from the beginning in the next frame. For example, when you're player is moving down, (!left && !right) evaluates true and the animations is stopped.
One solution is to stop the animation only if all 4 directions are false.
if (!left && !right) {
this.x_velocity = 0;
}
if (!up && !down) {
this.y_velocity = 0;
}
if (!(up | down | left | right)) {
this.stop();
}