Why does my canvas only draw 1 of the shapes? - javascript

{
var selectEl = document.getElementById("shapes");
var selectedIndex = selectEl.selectedIndex;
var selectedShape = selectEl[selectedIndex].value;
var context = null;
var canvasObj = document.getElementById("myCanvas");
//check if canvas api is supported
if (canvasObj.getContext)
context = canvasObj.getContext("2d");
else
alert("Canvas API not supported");
if(selectedShape === "square")
{
//context.clearRect(0,0,canvasObj.width,canvasObj.height);
for(var i = 0; i<20; i++)
changeBackgroundColor(canvasObj, context);
writeToCanvas(canvasObj, context);
drawSquare(canvasObj,context);
}
else if(selectedShape === "circle")
{
//context.clearRect(0,0,canvasObj.width,canvasObj.height);
for(var i = 0; i<20; i++)
changeBackgroundColor(canvasObj, context);
writeToCanvas(canvasObj, context);
drawCircle(canvasObj,context);
}
}
Here is the code for my getShape function and stuff.
Now here is the code for my drawSquare function:
{
//if I want a random number between 0 and 50 random()*(max-min-1)+min
var xCoord = Math.floor(Math.random()* theCanvas.width); //returns a number between 0 and just under 1
//alert(xCoord);
var yCoord = Math.floor(Math.random()* theCanvas.height);
//alert(yCoord);
ctx.beginPath();
ctx.fillStyle = "#00ff00";
ctx.fillRect(xCoord,yCoord,10,10);
ctx.stroke();
}
Anyone here know why my canvas only draws 1 of its shape? I have for a loop. It worked before, but now it doesn't.

Related

How to integrate WebGL into existing game which is using canvas and 2D context.drawImage?

I have a game which uses context.drawImage() to draw spritesheets of the game objects into a hidden canvas which is then copied over to another canvas(viewport). The current renderer has a camera which copies a portion of the canvas to the view. Each gameobject is added to a layer in the renderer and sorted by some value x each frame before rendering. Layers are drawn in a specific order and objects in the layers aswell.
So I have following structure:
//Renderer object
var layers = [[object,object,object,object],//objects sorted according to when they should be rendered
[object,object,object,object],
[object,object,object]];
//Simplified one frame render function
for(var i = 0; i < layers.length;i++){
for(var j = 0; j < layers[i].length;j++){
this.drawImage(layers[i][j]);
}
}
...
//DrawImage function
this.drawImage = function(object){
if(typeof object.currentAnimation !== "undefined"){//draw animation
var tileId = object.currentAnimation.tileIds[object.currentAnimation.currentTile];
var amountOfBlocksInARow = object.currentAnimation.tilesheet.width/object.currentAnimation.tileSize;
var sourceX = Math.floor(tileId % amountOfBlocksInARow) *object.currentAnimation.tileSize;
var sourceY = Math.floor(tileId / amountOfBlocksInARow) *object.currentAnimation.tileSize;
this.canvasContext.drawImage(object.currentAnimation.tilesheet, sourceX, sourceY, object.currentAnimation.tileSize, object.currentAnimation.tileSize, object.x, object.y,object.width,object.height);
object.currentAnimation.nextFrame();
}else{//if theres no animation just an image then draw with object properties}
}
...
//Rest of the render function
//snap camera to its target then copy the camera to the view
this.cameraSnapToTarget();
this.viewportContext.drawImage(this.canvas, this.camera.x, this.camera.y, this.camera.width, this.camera.height, 0, 0, this.viewportCanvas.width, this.viewportCanvas.height);
And this html: <canvas id="hiddenCanvas"></canvas> <canvas id="viewportCanvas"></canvas>
I was wondering if there was a way to implement the WebGL into this so I wouldn't have to change the structure. Currently I have tried to initialize webgl, make some buffers and shaders, but I can't seem to draw anything with it. I followed https://webglfundamentals.org/webgl/lessons/webgl-2d-drawimage.html this and don't know how to set up the buffers and shaders to benefit from the original code.
Do I have to change this structure or can it be implemented in this?
Thank you in advance for any help!
There was a few things I needed to add for my code for this to work
First I needed to make textures of the spritesheets I use for the gameobjects:
//I load all my images into an array I can search from
var imageArray = [];//global variables
var textures = [];//global variables
//and use it after defining onload like this:
imageArray.push(img);
After images have all loaded I initialize the textures for the webgl:
for(var i = 0; i < imageArray.length; i++){
initializeTexture(imageArray[i]);
}
function initializeTexture(img){//these images are already loaded into the dom
var tex = renderer.viewportContext.createTexture();
renderer.viewportContext.bindTexture(renderer.viewportContext.TEXTURE_2D, tex);
renderer.viewportContext.texParameteri(renderer.viewportContext.TEXTURE_2D, renderer.viewportContext.TEXTURE_WRAP_S, renderer.viewportContext.CLAMP_TO_EDGE);
renderer.viewportContext.texParameteri(renderer.viewportContext.TEXTURE_2D, renderer.viewportContext.TEXTURE_WRAP_T, renderer.viewportContext.CLAMP_TO_EDGE);
renderer.viewportContext.texParameteri(renderer.viewportContext.TEXTURE_2D, renderer.viewportContext.TEXTURE_MIN_FILTER, renderer.viewportContext.LINEAR);
var texture = {
width: img.width,
height: img.height,
texture: tex,
};
renderer.viewportContext.bindTexture(renderer.viewportContext.TEXTURE_2D, tex);
renderer.viewportContext.texImage2D(renderer.viewportContext.TEXTURE_2D, 0, renderer.viewportContext.RGBA, renderer.viewportContext.RGBA, renderer.viewportContext.UNSIGNED_BYTE, img);
textures.push(texture);//array containing one of each spritesheet texture
}
Then I have Animation object which I use to assign spritesheets to gameobjects:
function Animation(spritesheet,tileSize,tileIds,name = "",playOnce = false){
this.name = name;
this.spritesheet = spritesheet;
this.tileSize = tileSize;
this.tileIds = tileIds;
this.speed = 1;
this.currentTile = 0;
this.playOnce = playOnce;
this.texture;
this.state = "stopped";
this.setAnimationSpeed = function(speed){
this.speed = speed;
}
this.setTextureFromImage = function(img){
this.texture = textures[imageArray.indexOf(img)];//find the spritesheet from array of images which is indexed same as textures array texture[i] = imageArray[i] etc.
}
this.setName = function(name){
this.name = name;
}
this.setLoop = function (loop){
this.loop = loop;
}
this.setSpritesheet = function (spritesheet){
this.spritesheet = spritesheet;
}
this.setState = function(state){
this.state = state;
}
this.getState = function(){
return this.state;
}
this.play = function(){
this.state = "playing";
}
this.stop = function(){
this.state = "stopped";
}
this.nextFrame = function(){
if(this.state == "playing"){
if(typeof this.tileIds[this.currentTile+1] !== "undefined"){
this.currentTile++;
}else{
if(this.playOnce)
this.setState("played");
else
this.currentTile = 0;
}
}
}
this.setTextureFromImage(this.spritesheet);
}
As optimization I could use the index of imageArray and get the texture from the original texture array when rendering.
I use the Animation object in all gameobjects like this:
this.animations = [
new Animation(this.spritesheet,32,[0,1],"walkDown"),//walkdown
new Animation(this.spritesheet,32,[2,3],"walkRight"),//walkright
new Animation(this.spritesheet,32,[4,5],"walkLeft"),//walkleft
new Animation(this.spritesheet,32,[6,7],"walkUp"),//walkup
]
Finally I can render them with:
//Renderer
this.viewportContext = this.viewportCanvas.getContext("webgl",{ alpha: false ,premultipliedAlpha: false});
this.render = function(){//render one frame
this.sortLayers();//can do sorting here
this.viewportContext.viewport(0,0,this.viewportContext.canvas.width,
this.viewportContext.canvas.height);
this.viewportContext.clear(this.viewportContext.COLOR_BUFFER_BIT);//clear buffers before rendering
for(var i = 0; i < this.layerArray.length;i++){
if(this.layerArray[i].constructor === Array){
for(var j = 0; j < this.layerArray[i].length;j++){
var object = this.layerArray[i][j];
if(typeof object.currentAnimation !== "undefined"){
var tileId = object.currentAnimation.tileIds[object.currentAnimation.currentTile];
var amountOfBlocksInARow = object.currentAnimation.spritesheet.width/object.currentAnimation.tileSize;
var sourceX = Math.floor(tileId % amountOfBlocksInARow) *object.currentAnimation.tileSize;
var sourceY = Math.floor(tileId / amountOfBlocksInARow) *object.currentAnimation.tileSize;
this.drawImage(object.currentAnimation.texture.texture,
object.currentAnimation.texture.width,
object.currentAnimation.texture.height,
sourceX, sourceY,
object.currentAnimation.tileSize,
object.currentAnimation.tileSize,
object.x,object.y,
object.width,object.height);
}
}
}
}
}
}
this.drawImage = function(tex, texWidth, texHeight,srcX, srcY, srcWidth, srcHeight,dstX, dstY, dstWidth, dstHeight){
if (dstX === undefined) {
dstX = srcX;
srcX = 0;
}
if (dstY === undefined) {
dstY = srcY;
srcY = 0;
}
if (srcWidth === undefined) {
srcWidth = texWidth;
}
if (srcHeight === undefined) {
srcHeight = texHeight;
}
if (dstWidth === undefined) {
dstWidth = srcWidth;
srcWidth = texWidth;
}
if (dstHeight === undefined) {
dstHeight = srcHeight;
srcHeight = texHeight;
}
this.viewportContext.enable(this.viewportContext.BLEND);
this.viewportContext.blendFunc(this.viewportContext.SRC_ALPHA, this.viewportContext.ONE_MINUS_SRC_ALPHA);
this.viewportContext.bindTexture(this.viewportContext.TEXTURE_2D, tex);
this.viewportContext.useProgram(program);
this.viewportContext.bindBuffer(this.viewportContext.ARRAY_BUFFER,positionBuffer);
this.viewportContext.enableVertexAttribArray(positionAttributeLocation);
this.viewportContext.vertexAttribPointer(positionAttributeLocation, 2, this.viewportContext.FLOAT, false, 0, 0);
this.viewportContext.bindBuffer(this.viewportContext.ARRAY_BUFFER, textureCoordinateBuffer);
this.viewportContext.enableVertexAttribArray(textureCoordinateLocation);
this.viewportContext.vertexAttribPointer(textureCoordinateLocation, 2, this.viewportContext.FLOAT, false, 0, 0);
this.matrix = m4.orthographic(0, this.viewportContext.canvas.width, this.viewportContext.canvas.height, 0, -1, 1);
this.matrix = m4.translate(this.matrix,dstX,dstY,0);
this.matrix = m4.scale(this.matrix, dstWidth, dstHeight, 1);
this.viewportContext.uniformMatrix4fv(matrixLocation,false,this.matrix);
var textureMatrix = m4.scaling(1/ texWidth, 1/texHeight, 1);
//scaling
textureMatrix = m4.translate(textureMatrix, srcX, srcY, 0);
textureMatrix = m4.scale(textureMatrix, srcWidth, srcHeight, 1);
this.viewportContext.uniformMatrix4fv(textureMatrixLocation, false, textureMatrix);
this.viewportContext.drawArrays(this.viewportContext.TRIANGLES, 0, 6);
}

HTML5/Javascript Game

I'm currently working on a game where I need a bunch of random bubbles to fall, and a rectangle below it that can move to "burst" these bubbles. I have a code currently that is not dropping these bubbles. Can someone tell me where I am going wrong? Here is my code:
var canvasColor;
var x,y,radius,color;
var x=50, y=30;
var bubbles= [];
var counter;
var lastBubble=0;
var steps=0, burst=0, escaped=0;
var xx=200;
var moveRectangleRight=false;
var moveRectangleLeft=false;
function startGame()
{
var r, g, b;
canvasColor= '#f1f1f1';
x=10;
y=10;
radius=10;
clearScreen();
counter=0;
while (counter<100)
{
x= Math.floor(450*Math.random()+1);
r = Math.floor(Math.random()*256);
g = Math.floor(Math.random()*256);
b = Math.floor(Math.random()*256);
color='rgb('+r+','+g+','+b+')';
bubbles[counter]=new Bubble(x,y,radius,color);
counter+=1;
}
setInterval('drawEverything()',50);
}
function Bubble(x,y,radius,color)
{
this.x=x;
this.y=y;
this.radius=radius;
this.color=color;
this.active=false;
}
function drawEverything()
{
var canvas=document.getElementById('myCanvas');
var context= canvas.getContext('2d');
steps+=1;
clearScreen();
if (steps%20==0 && lastBubble <100) {
bubbles[lastBubble].active=true;
lastBubble+=1;
}
drawRectangle();
counter=0;
while(counter<100)
{
if (bubbles[counter].active==true) {
context.fillStyle= bubbles[counter].color;
context.beginPath();
context.arc(bubbles[counter].x, bubbles[counter].y,
bubbles[counter.radius], 0, 2*Math.PI);
context.fill();
bubbles[counter].y+=2;
}
y=bubbles[counter].y;
x=bubbles[counter].x;
if (y>=240 && y<=270 && x>=xx-10 && x<=xx+60)
{
bubbles[counter]=false;
}
else if (y>=450)
{
bubbles[counter]=false;
}
counter+=1;
}
}
function clearScreen ()
{
var canvas=document.getElementById('myCanvas');
var context= canvas.getContext('2d');
context.fillStyle= canvasColor;
context.fillRect(0,0,450,300);
}
function drawRectangle()
{ var canvas, context;
if (moveRectangleRight==true && xx<400){
xx+=20;
}
if (moveRectangleLeft==true && xx>0){
xx-=20;
}
canvas=document.getElementById('myCanvas');
context= canvas.getContext('2d');
context.fillStyle = 'blue';
context.fillRect(xx,250,50,10);
}
function moveLeft () {
moveRectangleLeft=true;
}
function moveRight() {
moveRectangleRight=true;
}
function stopMove () {
moveRectangleRight=false;
moveRectangleLeft=false;
}
Your problem is that you initialize counter as 1, so when you add items to counter, you begin with the index of 1, which is actually the 2nd item. Thus, when you try to access bubbles[0], it returns undefined. Instead, initialize counter as 0.
A bracket was located in the wrong place, and this solved the problem.

javascript image slider start

I'm trying to understand javascript before going to jQuery and I made a simple image slider.
I ended up with the following code working well when I manually start it on browser console, and I can't figure out how to start it and if using Promise would do, and how.
Reduced code:
/*some variable declarations and value assignations*/
function cut(p1){
for (var i = 0; i < cuts; i++){
/*canvas working with path pattern and fill*/
slice[p1][i] = new Image();
slice[p1][i].src = canvas.toDataURL();
}
}
function slider(){
/*time based image selection and canvas clear*/
for (var i = 0; i < 10; i++){
y = /*timebased calc*/;
if(y<0){y=0;}
ctx.drawImage(slice[im][i], 0, y);
}
window.requestAnimationFrame(slider);
}
img[0].onload = function() {cut(0);};
img[1].onload = function() {cut(1);};
Full code:
var height = 500, width = 707, cuts = 10, cW = Math.ceil(width/cuts);
var img = [new Image(), new Image()];
var slice = [];
for (var i = 0; i < img.length; i++){
slice[i] = [];
}
var x = [];
for (var i=0; i<cuts; i++){
x[i]=Math.ceil(((i+1)*width)/cuts);
}
function cut(p1){
for (var i = 0; i < cuts; i++){
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var context = canvas.getContext('2d');
var pat = context.createPattern( img[p1], 'no-repeat' );
context.fillStyle = pat;
context.beginPath();
context.moveTo(x[i], 0);
context.lineTo(x[i], height);
context.lineTo(x[i]-cW, height);
context.lineTo(x[i]-cW, 0);
context.closePath();
context.fill();
slice[p1][i] = new Image();
slice[p1][i].src = canvas.toDataURL();
}
}
var canv = document.createElement('canvas');
document.body.appendChild(canv);
canv.width = width;
canv.height = height;
var ctx = canv.getContext('2d');
var sTime= 0;
function slider(){
var t = (performance.now() - sTime) % 10000;
if(t%5000 === 2000){
ctx.clear();
}
var im = 0;
if(t >= 5000){
im = 1;
} else {
im = 0;
}
for (var i = 0; i < 10; i++){
t = t%5000;
y = 2000-((t)+(i*100));
if(y<0){y=0;}
ctx.drawImage(slice[im][i], 0, y);
}
window.requestAnimationFrame(slider);
}
CanvasRenderingContext2D.prototype.clear = function () {this.clearRect(0, 0, this.canvas.width, this.canvas.height);}
img[0].onload = function() {cut(0);};
img[1].onload = function() {cut(1);};
img[0].src = 'mountain.jpg';
img[1].src = 'beach.jpg';
Haven't tested this but it might come close:
function imageLoader(imagePaths, onLoad, onFinished) {
var images = [];
var arrayLength = imagePaths.length;
function callback() {
if(--arrayLength === 0) onFinished();
}
imagePaths.forEach(function(imagePath, index) {
var image = new Image();
image.onload(onLoad(index, callback));
image.src = imagePath;
images[index] = image;
});
return images;
}
modify cut() to:
function cut(p1, cb){
//.
//.
//.
cb();
}
replace
img[0].onload = function() {cut(0);};
img[1].onload = function() {cut(1);};
img[0].src = 'mountain.jpg';
img[1].src = 'beach.jpg';
with:
img = imageLoader(['mountain.jpg', 'beach.jpg'], cut, slider);

Can't create text in easeljs

currelty working on a small matching puzzle game. Currently it displays text for the time remaining and the number of tiles that have been macthes. I'm trying to create on for best completion time as well (How fast the person finishes the game) however have been running into a lot of problems. for two variables that I created "txt" and "matchesFoundText" when I type them the autocomplete box will popup and ".text" is displayed as one of the options so i would get something like "txt.text. however I'm not getting that option at all for "bestTimeTxt" and I have no idea as to why this is happening. I did all three variables the same way so I'm at a loss as to why Text is not available to select from for "bestTimeTxt". Here is my entire script.
<!DOCTYPE html>
<html>
<head>
<title>Recipe: Drawing a square</title>
<script src="easel.js"></script>
<script type="text/javascript">
var canvas;
var stage;
var squareSide = 70;
var squareOutline = 5;
var max_rgb_color_value = 255;
var gray = Graphics.getRGB(20, 20, 20);
var placementArray = [];
var tileClicked;
var timeAllowable;
var totalMatchesPossible;
var matchesFound;
var txt;
var bestTime;
var bestTimeTxt;
var matchesFoundText;
var squares;
function init() {
var rows = 5;
var columns = 6;
var squarePadding = 10;
canvas = document.getElementById('myCanvas');
stage = new Stage(canvas);
var numberOfTiles = rows*columns;
matchesFound = 0;
timeAllowable = 5;
bestTime = 0;
txt = new Text(timeAllowable, "30px Monospace", "#000");
txt.textBaseline = "top"; // draw text relative to the top of the em box.
txt.x = 500;
txt.y = 0;
bestTimeTxt = new Text(bestTime, "30px Monospace", "#000");
bestTimeTxt.textBaseLine = "top";
bestTimeTxt.x = 500;
bestTimeTxt.y = 80;
stage.addChild(txt);
stage.addChild(bestTimeTxt);
squares = [];
totalMatchesPossible = numberOfTiles/2;
Ticker.init();
Ticker.addListener(window);
Ticker.setPaused(false);
matchesFoundText = new Text("Pairs Found: "+matchesFound+"/"+totalMatchesPossible, "30px Monospace", "#000");
matchesFoundText.textBaseline = "top"; // draw text relative to the top of the em box.
matchesFoundText.x = 500;
matchesFoundText.y = 40;
stage.addChild(matchesFoundText);
setPlacementArray(numberOfTiles);
for(var i=0;i<numberOfTiles;i++){
var placement = getRandomPlacement(placementArray);
if (i % 2 === 0){
var color = randomColor();
}
var square = drawSquare(gray);
square.color = color;
square.x = (squareSide+squarePadding) * (placement % columns);
square.y = (squareSide+squarePadding) * Math.floor(placement / columns);
squares.push(square);
stage.addChild(square);
square.cache(0, 0, squareSide + squarePadding, squareSide + squarePadding);
square.onPress = handleOnPress;
stage.update();
};
}
function drawSquare(color) {
var shape = new Shape();
var graphics = shape.graphics;
graphics.setStrokeStyle(squareOutline);
graphics.beginStroke(gray);
graphics.beginFill(color);
graphics.rect(squareOutline, squareOutline, squareSide, squareSide);
return shape;
}
function randomColor(){
var color = Math.floor(Math.random()*255);
var color2 = Math.floor(Math.random()*255);
var color3 = Math.floor(Math.random()*255);
return Graphics.getRGB(color, color2, color3)
}
function setPlacementArray(numberOfTiles){
for(var i = 0;i< numberOfTiles;i++){
placementArray.push(i);
}
}
function getRandomPlacement(placementArray){
randomNumber = Math.floor(Math.random()*placementArray.length);
return placementArray.splice(randomNumber, 1)[0];
}
function handleOnPress(event){
var tile = event.target;
tile.graphics.beginFill(tile.color).rect(squareOutline, squareOutline, squareSide, squareSide);
if(!!tileClicked === false || tileClicked === tile){
tileClicked = tile;
tileClicked.updateCache("source-overlay");
}else{
if(tileClicked.color === tile.color && tileClicked !== tile){
tileClicked.visible = false;
tile.visible = false;
matchesFound++;
matchesFoundText.text = "Pairs Found: "+matchesFound+"/"+totalMatchesPossible;
if (matchesFound===totalMatchesPossible){
gameOver(true);
}
}else{
tileClicked.graphics.beginFill(gray).rect(squareOutline, squareOutline, squareSide, squareSide);
}
tileClicked.updateCache("source-overlay");
tile.updateCache("source-overlay");
tileClicked = tile;
}
stage.update();
}
function tick() {
secondsLeft = Math.floor((timeAllowable-Ticker.getTime()/1000));
txt.text = secondsLeft;
;
if (secondsLeft <= 0){
gameOver(false);
}
stage.update();
}
function gameOver(win){
Ticker.setPaused(true);
for(var i=0;i<squares.length;i++){
squares[i].graphics.beginFill(squares[i].color).rect(5, 5, 70, 70);
squares[i].onPress = null;
if (win === false){
squares[i].uncache();
}
}
var replayParagraph = document.getElementById("replay");
replayParagraph.innerHTML = "<a href='#' onClick='history.go(0);'>Play Again?</a>";
if (win === true){
matchesFoundText.text = "You win!"
}else{
txt.text = secondsLeft + "... Game Over";
}
}
function replay(){
init();
}
</script>
</head>
<body onload="init()">
<header id="header">
<p id="replay"></p>
</header>
<canvas id="myCanvas" width="960" height="400"></canvas>
</body>
</html>
Okay so apparently the reason why I was having issues is because the x and y positions of the bestTimeTxt variable was causing it to be obscured by the position of everything else.

I wrote a simple particle filter and it won't work with more than a few hundred particles. I can't tell why

I have written a very simple 1d particle filter using javascript and a HTML5 canvas. It seems to work pretty well until the number of particles hits 283. I am not all that experienced with either particle filters or javascript, but I cannot see why 283 is the magic number! Please could someone help?
Edit:
OK, so it seems the magic number isn't fixed between browsers, but if I set nparticles = 1000 it complains TypeError: particles[count] is undefined and I don't know why that should be the case. Any tips would be gratefully received.
var c;
var ctx;
var start_x = 600;
var x_speed = 2;
var dt = 1;
var nparticles = 282;
var gauss_dist;
var particles = [];
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
function drawBackground()
{
ctx.clearRect(0, 0, c.width, c.height);
ctx.fillStyle="#FFFFFF";
ctx.fillRect(0,0,800,400);
ctx.fillStyle="#00FF00";
ctx.fillRect(0,350,800,50);
ctx.fillStyle="#FF0000";
ctx.fillRect(50,300,5,50);
ctx.fillRect(750,300,5,50);
}
function drawRobot()
{
ctx.fillStyle="#000000";
start_x += x_speed*dt;
if (start_x >= 750 || start_x <= 50)
{
x_speed *= -1;
}
ctx.fillRect(start_x, 300, 10, 50);
}
function getDistanceToNearest(x)
{
var to_far =Math.abs(x - 750);
var to_near = Math.abs(x - 50);
var true_dist;
if (to_far > to_near)
{
true_dist = to_near;
}
else
{
true_dist = to_far;
}
true_dist = true_dist - 25 + 50.0*(Math.random()+Math.random()+Math.random()+Math.random()+Math.random()+Math.random()) / 3.0;
return true_dist;
}
function w_gauss(a, b)
{
error = a - b;
g = Math.exp(-((error *error) / (2 * 50.*50.)));
return g;
}
function loop()
{
var i = 0;
drawBackground();
drawRobot();
for (i=0; i < nparticles; i++)
{
ctx.fillStyle="#0000FF";
ctx.fillRect(particles[i].x, 345, 2,2);
}
var u = getDistanceToNearest(start_x);
var weights = [];
var wsum = 0.0;
for (i=0; i < nparticles; i++)
{
var distance = getDistanceToNearest(particles[i].x);
var w = w_gauss(u, distance);
// console.log(""+w);
weights.push(w);
wsum += w;
}
//console.log("Wsum = "+wsum);
var weights_norm = [];
var trimmed_particles = [];
for (i=0; i < nparticles; i++)
{
var w_norm = weights[i] / wsum;
if (w_norm > 0.0001)
{
weights_norm.push(w_norm);
trimmed_particles.push(particles[i]);
// console.log(""+w_norm);
}
}
particles = [];
for (i=0; i< trimmed_particles.length; i++)
{
particles.push(trimmed_particles[i]);
}
//particles = trimmed_particles;
console.log("Number of particles remaining = " + weights_norm.length + " " + particles.length);
var cummul = [weights_norm[0]];
for (i=1; i < weights_norm.length; i++)
{
cummul.push(cummul[i-1]+weights_norm[i]);
// console.log(""+cummul[i]);
}
/*
for (i=0; i<particles.length; i++)
{
console.log(particles[i]);
}
*/
// console.log("Beginning Resampling");
var resample = [];
for (i = 0; i < nparticles; i++)
{
var rand = Math.random();
var count = 0;
while(cummul[count]<=rand /*&& count < cummul.length*/)
{
count += 1;
}
//console.log("Count: "+count+ "Trimmed Particles: "+ particles.length);
//console.log("Cumulative frequency: "+cummul[count]);
//console.log(particles[count]);
//console.log("x "+particles[count].x+" y "+particles[count].y+" weight "+weights_norm[count]);
resample.push({"x":particles[count].x + (x_speed+ getRandomArbitrary(-0.5,0.5))*dt, "y":particles[count].y, "weight":weights_norm[count]});
}
for (i=0; i < resample.length; i++)
{
particles[i] = resample[i];
}
//particles = resample;
}
function init()
{
c=document.getElementById("theCanvas");
ctx = c.getContext("2d");
//gauss_dist = gaussian(50, 50);
// Take a random sample using inverse transform sampling method.
//setup initial particle sample
for (i=0; i < nparticles; i++)
{
rand_x = getRandomArbitrary(50, 750);
particle = {"x": rand_x, "y": 345.0, "weight":1.0/100.0};
particles.push(particle);
rand_y = 345;
}
ctx=c.getContext("2d");
drawBackground();
setInterval(loop, 500);
}
init();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<body>
<canvas id="theCanvas" width="800" height="400" style="border:2px solid #FFFFFF;">
</canvas>
</body>
</html>
In the function loop the variable count gets larger than the length of the array particles. If I change the line
while(cummul[count]<=rand)
to
while(cummul[count]<=rand && count < particles.length-1)
I can raise nparticles without error.
You need to check the array boundaries more often.

Categories

Resources