I'm using a A* pathfinding script in a simple JavaScript. I broke my game down to a SSCCE. Anyway, my game is 15 columns across and 10 rows down.
The pathfinding works until you click anywhere on the 5-most-right columns. So if X is 11 or greater. You will get this error. Uncaught TypeError: Cannot read property '7' of undefined Where 7 is the Y axis of where you clicked.
Here is my SSCCE.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type='text/javascript' src='graphstar.js'></script>
<script type="text/javascript">
var board;
</script>
<script type='text/javascript' src='astar.js'></script>
<script type="text/javascript">
$(document).ready(function()
{
// UP to DOWN - 10 Tiles (Y)
// LEFT to RIGHT - 15 Tiles (X)
graph = new Graph([
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1],
[1, 13, 1, 13, 13, 13, 13, 13, 1, 1, 1, 1, 1, 13, 13, 1],
[1, 13, 1, 1, 13, 1, 1, 13, 1, 13, 13, 1, 13, 13, 13, 1],
[1, 13, 13, 1, 1, 1, 13, 13, 1, 13, 13, 1, 1, 1, 13, 1],
[1, 13, 13, 1, 13, 1, 13, 13, 13, 13, 13, 1, 13, 13, 13, 1],
[1, 13, 13, 13, 13, 1, 13, 13, 13, 13, 13, 1, 13, 13, 13, 1],
[1, 13, 1, 13, 13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 1],
[1, 13, 1, 1, 1, 1, 13, 13, 13, 13, 1, 13, 13, 13, 13, 1],
[1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]);
//Let's do an example test.
start = graph.nodes[1][2]; // x - y (15 columns across, 10 rows down)
end = graph.nodes[12][7]; // x - y (15 columns across, 10 rows down)
result = astar.search(graph.nodes, start, end);
});
</script>
</head>
<body>
Loading... pathfinding. Look in Chrome Console/Firefox Firebug for more information.
</body>
</html>
As you can see, my game is jQuery. Also there is graphstar.js and astar.js. Don't worry about astar.js because it works fine. graphstar.js is the where my problem is. astar.js is where the nodes and such are laid out. graphstar.js is where the map is graphed.
See the whole graphstar.js here: http://pastebin.com/kx4mw86z (Here is astar.js: http://pastebin.com/wtN2iF15)
This is where it's laid out in graphstar.js:
// Creates a Graph class used in the astar search algorithm.
function Graph(grid) {
var nodes = [];
var row, rowLength, len = grid.length;
for (x = 0; x <= 10; x++) {
row = grid[x];
nodes[x] = new Array(15);
for (y = 0; y <= 15; y++) {
nodes[x][y] = new GraphNode(x, y, row[y]);
}
}
this.input = grid;
this.nodes = nodes;
}
I know that my X's highest is 15 while my Y's highest is 10. But I tried messing around with it.. and I would get errors. Sometimes no errors and the page would get stuck.
Help?
New graphing format:
for (y = 0; y <= 10; y++) {
row = grid[y];
nodes[y] = new Array(15);
for (x = 0; x <= 15; x++) {
console.log("X: " + x + " Y: " + y);
//console.log("Row: " + row[x]);
nodes[x][y] = new GraphNode(x, y, row[x]);
}
}
If I'm understanding this all correctly, I think you just have your indexes backwards.
graph.nodes[12][7]
graph.nodes[12] is undefined because there are only 11 elements in nodes:
for (x = 0; x <= 10; x++) {
nodes[x] = new Array(15); // x only goes up to 10
EDIT:
This comment says it all:
// UP to DOWN - 10 Tiles (Y)
// LEFT to RIGHT - 15 Tiles (X)
This is backwards. You do not have 15 x and 10 y, you have 10 x and 15 y.
Related
I've successfully generated the pattern in the picture. Now i need to figure out how i can do it automatically. Basically every second square needs to be mirrored.
If there's an easier way to do this i'm happy to take suggestions.
image
This is how my code looks:
// For widthSegments
for (let x = 0; x < world.plane.widthSegments; x++){
for (let y = 0; y < world.plane.heightSegments; y++){
vertices.push(x, y, 0) // 0, 4, 8, 12, 16, 20, 24, 28, 32,
vertices.push(x+1, y, 0) // 1, 5, 9, 13, 17, 21, 25, 29, 33,
vertices.push(x+1, y+1, 0) // 2, 6, 10, 14, 18, 22, 26, 30, 34,
vertices.push(x, y+1, 0) // 3, 7, 11, 15, 19, 23, 27, 31, 35,
}
}
planeMesh.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3))
planeMesh.geometry.setIndex([ // I want to generate these automatically
0, 1, 3, 3, 1, 2, // 1
2, 6, 3, 3, 6, 7, // 2
7, 6, 11, 11, 6, 10, // 3
10, 14, 11, 11, 14, 15, // 4
1, 17, 18, 18, 2, 1, // 5
2, 18, 6, 6, 18, 22, // 6
6, 22, 26, 26, 10, 6, // 7
10, 26, 14, 14, 26, 30, // 4
17, 33, 18, 18, 33, 34, // 9
18, 34, 38, 38, 22, 18, // 10
22, 38, 26, 26, 38, 42, // 11
26, 42, 46, 46, 30, 26, // 4
33, 49, 50, 50, 34, 33, // 13
34, 50, 38, 38, 50, 54, // 14
38, 54, 58, 58, 42, 38, // 15
42, 58, 46, 46, 58, 62, // 16
]);
You can take PlaneGeometry and re-calculate its index.
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three#0.136.0";
import { OrbitControls } from "https://cdn.skypack.dev/three#0.136.0/examples/jsm/controls/OrbitControls";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(
60,
innerWidth / innerHeight,
0.1,
100
);
camera.position.set(0, 0, 10);
let renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", (event) => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});
let controls = new OrbitControls(camera, renderer.domElement);
let g = new THREE.PlaneGeometry(10, 10, 10, 10);
recalcIndex(g);
let m = new THREE.MeshBasicMaterial({ color: "aqua", wireframe: true });
let o = new THREE.Mesh(g, m);
scene.add(o);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
function recalcIndex(plane) {
let w = plane.parameters.widthSegments;
let h = plane.parameters.heightSegments;
let idx = [];
for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
let a = x + ((w + 1) * y);
let b = x + ((w + 1) * (y + 1));
let c = (x + 1) + ((w + 1) * (y + 1));
let d = (x + 1) + ((w + 1) * y);
if ((x + (y % 2)) % 2 == 0) {
idx.push(a, b, d, b, c, d);
} else {
idx.push(b, c, a, c, d, a);
}
}
}
plane.setIndex(idx);
}
</script>
I'm trying to get a beveled cube, but I can't seem to figure out how. I've found THREE.ExtrudeGeometry here, but if you notice, in the sample editor it only has beveled sides on the top and bottom faces, so I'm getting something like this:
Instead of something like this, which is what I'm going for:
Code:
var bevelShape = new THREE.Shape();
bevelShape.moveTo(0, unitSize - 0.2);
bevelShape.lineTo(0, unitSize - 0.2);
bevelShape.lineTo(unitSize - 0.2, unitSize - 0.2);
bevelShape.lineTo(unitSize - 0.2, 0);
bevelShape.lineTo(0, 0);
var extrudeSettings = {
steps: 20,
depth: unitSize - 0.2,
bevelEnabled: true,
bevelThickness: 0.1,
bevelSize: 0.1,
bevelOffset: 0,
bevelSegments: 1
};
var blockGeometry = new THREE.ExtrudeGeometry(bevelShape, extrudeSettings);
var blockMaterial = new THREE.MeshStandardMaterial({color: color, roughness: 1, metalness: -1});
var block = new THREE.Mesh(blockGeometry, blockMaterial);
scene.add(block);
What should I do to achieve this?
Thanks!
You can build your own geometry.
Or feel free to search the forum, as you can find many useful and intersting things there.
For example: https://discourse.threejs.org/t/faceted-box-geometry/5474
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);
camera.position.set(15, 10, 20).setLength(130);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0x404040);
//renderer.setPixelRatio(0.5);
var canvas = renderer.domElement;
document.body.appendChild(canvas);
var controls = new THREE.OrbitControls(camera, canvas);
var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.set(1, 2, 1);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
for (let i = 0; i < 11; i++) {
let r = 10;
let posX = (-5 + i) * 12.5;
let wireGeom = facetedBox(r, r, r, i * 0.5, true);
let wire = new THREE.LineSegments(
wireGeom,
new THREE.LineBasicMaterial({ color: Math.random() * 0x808080 + 0x808080 })
);
wire.position.x = posX;
scene.add(wire);
let geom = facetedBox(r, r, r, i * 0.5, false);
let mesh = new THREE.Mesh(
geom,
new THREE.MeshStandardMaterial({
color: Math.random() * 0x808080 + 0x808080,
flatShading: true
})
);
mesh.position.x = posX;
scene.add(mesh);
}
var clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
if (resize(renderer)) {
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
});
function resize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
html, body {
height: 100%;
margin: 0;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
display; block;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script>
function facetedBox(w, h, d, f, isWireframed){
let hw = w * 0.5, hh = h * 0.5, hd = d * 0.5;
let vertices = [
// px
hw, hh - f, -hd + f, // 0
hw, -hh + f, -hd + f, // 1
hw, -hh + f, hd - f, // 2
hw, hh - f, hd - f, // 3
// pz
hw - f, hh - f, hd, // 4
hw - f, -hh + f, hd, // 5
-hw + f, -hh + f, hd, // 6
-hw + f, hh - f, hd, // 7
// nx
-hw, hh - f, hd - f, // 8
-hw, -hh + f, hd - f, // 9
-hw, -hh + f, -hd + f, // 10
-hw, hh - f, -hd + f, // 11
// nz
-hw + f, hh - f, -hd, // 12
-hw + f, -hh + f, -hd, // 13
hw - f, -hh + f, -hd, // 14
hw - f, hh - f, -hd, // 15
// py
hw - f, hh, -hd + f, // 16
hw - f, hh, hd - f, // 17
-hw + f, hh, hd - f, // 18
-hw + f, hh, -hd + f, // 19
// ny
hw - f, -hh, -hd + f, // 20
hw - f, -hh, hd - f, // 21
-hw + f, -hh, hd - f, // 22
-hw + f, -hh, -hd + f // 23
];
let indices = [
0, 2, 1, 3, 2, 0,
4, 6, 5, 7, 6, 4,
8, 10, 9, 11, 10, 8,
12, 14, 13, 15, 14, 12,
16, 18, 17, 19, 18, 16,
20, 21, 22, 23, 20, 22,
// link the sides
3, 5, 2, 4, 5, 3,
7, 9, 6, 8, 9, 7,
11, 13, 10, 12, 13, 11,
15, 1, 14, 0, 1, 15,
// link the lids
// top
16, 3, 0, 17, 3, 16,
17, 7, 4, 18, 7, 17,
18, 11, 8, 19, 11, 18,
19, 15, 12, 16, 15, 19,
// bottom
1, 21, 20, 2, 21, 1,
5, 22, 21, 6, 22, 5,
9, 23, 22, 10, 23, 9,
13, 20, 23, 14, 20, 13,
// corners
// top
3, 17, 4,
7, 18, 8,
11, 19, 12,
15, 16, 0,
// bottom
2, 5, 21,
6, 9, 22,
10, 13, 23,
14, 1, 20
];
let indicesWire = [
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
8, 9, 9, 10, 10, 11, 11, 8,
12, 13, 13, 14, 14, 15, 15, 12,
16, 17, 17, 18, 18, 19, 19, 16,
20, 21, 21, 22, 22, 23, 23, 20,
// link the sides
2, 5, 3, 4, //px - pz
6, 9, 7, 8, // pz - nx
10, 13, 11, 12, // nx - nz
15, 0, 14, 1, // nz - px
// link the lids
// top
16, 0, 17, 3, // px
17, 4, 18, 7, // pz
18, 8, 19, 11, // nx
19, 12, 16, 15, // nz
// bottom
20, 1, 21, 2,
21, 5, 22, 6,
22, 9, 23, 10,
23, 13, 20, 14
];
let geom = new THREE.BufferGeometry();
geom.setAttribute("position", new THREE.BufferAttribute(new Float32Array(vertices), 3));
geom.setIndex(isWireframed ? indicesWire : indices);
if (!isWireframed) geom.computeVertexNormals();
return geom;
}
</script>
I am using Highcharts Stream graph and everything is working fine except the yaxis labels are coming wrong. Even in the example page, the Y axis is equally divided into two parts and the mid point is zero and all the other labels are relative to that.
I want the labels to render the value which is actually on the graph.
Highcharts.chart('container', {
chart: {
type: 'streamgraph'
},
legend: {
enabled: false
},
// Data parsed with olympic-medals.node.js
series: [{
name: "Finland",
data: [
0, 11, 4, 3, 6, 0, 0, 6, 9, 7, 8, 10, 5, 5, 7, 9, 13, 7, 7, 6, 12, 7, 9, 5, 5
]
}, {
name: "Austria",
data: [
0, 3, 4, 2, 4, 0, 0, 8, 8, 11, 6, 12, 11, 5, 6, 7, 1, 10, 21, 9, 17, 17, 23, 16, 17
]
}, {
name: "Sweden",
data: [
0, 2, 5, 3, 7, 0, 0, 10, 4, 10, 7, 7, 8, 4, 2, 4, 8, 6, 4, 3, 3, 7, 14, 11, 15
]
}, {
name: "Norway",
data: [
0, 17, 15, 10, 15, 0, 0, 10, 16, 4, 6, 15, 14, 12, 7, 10, 9, 5, 20, 26, 25, 25, 19, 23, 26
]
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/streamgraph.js"></script>
<script src="https://code.highcharts.com/modules/series-label.js"></script>
<script src="https://code.highcharts.com/modules/annotations.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>
<div id="container"></div>
That is how streamgraph series works, please check a official example: https://www.highcharts.com/demo/streamgraph - areas are displaced around a central axis, y-axis is not relevant.
Please also check the streamStacker function in the module source code: https://code.highcharts.com/modules/streamgraph.src.js
I recommend you to use areaspline series with stacking if you want to use y-axis.
chart: {
type: 'areaspline'
},
plotOptions: {
series: {
stacking: 'normal'
}
},
Live example: http://jsfiddle.net/BlackLabel/o4drspjq/
I have two flot charts and three data sets with crosshair in sync on both charts and dynamic legends that indicates value of each point on graph. Legend in the second chart does not show value where other two work fine. How would one make third or more legends show dynamic values as well. Moreover, can one make improvements to existing code where any number of charts with crosshair in sync can be displayed? Thanks,
Here is the fiddle: http://jsfiddle.net/mashinista/Q24qN/
and this is the code
plot = null;
plot2 = null;
var data1 = [
[gd(2012, 0, 1), 8],
[gd(2012, 1, 1), 13],
[gd(2012, 2, 1), 4],
[gd(2012, 3, 4), 8],
[gd(2012, 4, 1), 16],
[gd(2012, 5, 1), 20],
[gd(2012, 6, 1), 29],
[gd(2012, 7, 1), 23],
[gd(2012, 8, 1), 28],
[gd(2012, 9, 1), 16],
[gd(2012, 10, 1), 8],
[gd(2012, 11, 2), 4]
];
var data2 = [
[gd(2012, 0, 1), 16],
[gd(2012, 1, 1), 14],
[gd(2012, 2, 1), 22],
[gd(2012, 3, 1), 30],
[gd(2012, 4, 1), 28],
[gd(2012, 5, 1), 39],
[gd(2012, 6, 1), 38],
[gd(2012, 7, 1), 28],
[gd(2012, 8, 1), 31],
[gd(2012, 9, 1), 28],
[gd(2012, 10, 1), 22],
[gd(2012, 11, 1), 16]
];
var data3 = [
[gd(2012, 0, 1), 16],
[gd(2012, 1, 1), 14],
[gd(2012, 2, 1), 22],
[gd(2012, 3, 1), 30],
[gd(2012, 4, 1), 28],
[gd(2012, 5, 1), 39],
[gd(2012, 6, 1), 29],
[gd(2012, 7, 1), 23],
[gd(2012, 8, 1), 28],
[gd(2012, 9, 1), 16],
[gd(2012, 10, 1), 8],
[gd(2012, 11, 2), 4]
];
function gd(year, month, day) {
return new Date(year, month, day).getTime();
}
$(function () {
var sin = [], cos = [];
for (var i = 0; i < 14; i += 0.1) {
sin.push([i, Math.sin(i)]);
cos.push([i, Math.cos(i)]);
}
plot = $.plot($("#placeholder"),
[ { data: data1, label: "Query1 = 0.00"}, {
data: data2, label: "Query2 = 0.00"}],
{
series: {
lines: { show: true }
},
crosshair: { mode: "x" },
grid: { hoverable: true, autoHighlight: false},
yaxis: { min: 0, max: 40 },
xaxis: {mode: "time"}
});
plot2 = $.plot($("#placeholder2"),
[ { data: data3, label: "Query3 = 0.00"} ], {
series: {
lines: { show: true },
color: "#2eef34"
},
crosshair: { mode: "x" },
grid: { hoverable: true, autoHighlight: false},
yaxis: { min: 0, max: 40 },
xaxis: {mode: "time"}
});
var legends = $("#placeholder .legendLabel, #placeholder .legendLabel");
var updateLegendTimeout = null;
var latestPosition = null;
function updateLegend() {
updateLegendTimeout = null;
var pos = latestPosition;
var axes = plot.getAxes();
if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max || pos.y < axes.yaxis.min || pos.y > axes.yaxis.max) return;
var i, j, dataset = plot.getData();
for (i = 0; i < dataset.length; ++i) {
var series = dataset[i];
// find the nearest points, x-wise
for (j = 0; j < series.data.length; ++j)
if (series.data[j][0] > pos.x) break;
// now interpolate
var y, p1 = series.data[j - 1],
p2 = series.data[j];
if (p1 == null) y = p2[1];
else if (p2 == null) y = p1[1];
else y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);
legends.eq(i).text(series.label.replace(/=.*/, "= " + y.toFixed(2) + " "));
}
}
$("#placeholder").bind("plothover", function (event, pos, item) {
plot2.setCrosshair({x: pos.x}),
latestPosition = pos;
if (!updateLegendTimeout) updateLegendTimeout = setTimeout(updateLegend, 50);
});
$("#placeholder2").bind("plothover", function (event, pos, item) {
plot.setCrosshair({x: pos.x}),
latestPosition = pos;
if (!updateLegendTimeout) updateLegendTimeout = setTimeout(updateLegend, 50);
});
});
There were two errors which needed fixing:
1) Your legends array contains only the legends from the first plot:
var legends = $("#placeholder .legendLabel, #placeholder .legendLabel");
needs to be
var legends = $("#placeholder .legendLabel, #placeholder2 .legendLabel");
2) In your updateLegend method you only use the data from the first plot:
var i, j, dataset = plot.getData();
I added a for loop over both plots / datasets:
for (var p = 0; p <= 1; p++) {
var i, j, dataset;
if (p == 0) dataset = plot.getData();
else dataset = plot2.getData();
...
legends.eq(i + p * 2).text(series.label.replace(/=.*/, "= " + y.toFixed(2) + " "));
See this updated fiddle for the working code.
3) More charts:
If you want to add a larger number of charts then you need to change the same lines of code as above. For the dataset you can use a switch statement or build an array of flot objects and then use something like
var dataset = plot[p].getData();
And for the legend number you have to count the number of legends / dataseries per chart:
legends.eq(i + countOfLegendsFromOtherCharts(p)).text( ... );
with something like this (but maybe better store this values somewhere):
function countOfLegendsFromOtherCharts(p) {
var count = 0;
for (var i = 0; i < p; i++) {
var dataset = plot[p].getData();
count += dataset.length;
}
return count;
}
Is there any option available for increasing the line width of line-charts? I have tried to alter the stroke, but that does not seem to have any affect.
Here is how the line-chart is initialized:
paper.linechart(10, 30, 400, 240, [
[5, 10, 15, 20, 25, 30, 35]
], [
[15, 10, 20, 14, 13, 17, 9],
[7, 13, 17, 9, 10, 20, 14],
[5, 4, 14, 12, 20, 3, 16]
]);
Currently your only option would be to specify a higher width value in the options. From the documentation, under the width property of Paper.lineChart's options:
(width) controls the size of the plotted symbol. Also controls the thickness
of the line using a formula stroke-width=width/2.
To only control the line's stroke-width, you should be able to pass an empty symbol and the desired width value to the opts, e.g.:
paper.linechart(10, 30, 400, 240, [
[5, 10, 15, 20, 25, 30, 35]
], [
[15, 10, 20, 14, 13, 17, 9],
[7, 13, 17, 9, 10, 20, 14],
[5, 4, 14, 12, 20, 3, 16]
], {
symbol: '',
width: 5
});
(You can pass circle as a symbol, of course, but its size will be derived from the width value).