I found this codepen.io for the game 2048: http://codepen.io/anon/pen/dMzmae
The game is written in JavaScript with a GameManager, HTMLActuator to create the HTML elements, a ScoreManager to keep track of the score and a KeyboardInputManager to track what is pressed and what to do.
The application uses window.requestAnimationFrame to redraw the window. I was wondering how it does that. When the code actuates, it uses the window.requestAnimationFrame() and inside for each cell in the grid it uses the addTile() method to add each tile to the DOM.
HTMLActuator.prototype.actuate = function (grid, metadata) {
var self = this;
window.requestAnimationFrame(function () {
self.clearContainer(self.tileContainer);
grid.cells.forEach(function (column) {
column.forEach(function (cell) {
if (cell) {
self.addTile(cell);
}
});
});
self.updateScore(metadata.score);
if (metadata.over) self.message(false); // You lose
if (metadata.won) self.message(true); // You win!
});
};
If you look at the addTime() method, it too has a window.requestAnimationFrame method that updates the class with the currentPosition if the tile it's adding had a previousPosition property:
HTMLActuator.prototype.addTile = function (tile) {
var self = this;
var element = document.createElement("div");
var position = tile.previousPosition || { x: tile.x, y: tile.y };
positionClass = this.positionClass(position);
// We can't use classlist because it somehow glitches when replacing classes
var classes = ["tile", "tile-" + tile.value, positionClass];
this.applyClasses(element, classes);
element.textContent = tile.value;
if (tile.previousPosition) {
// Make sure that the tile gets rendered in the previous position first
window.requestAnimationFrame(function () {
classes[2] = self.positionClass({ x: tile.x, y: tile.y });
self.applyClasses(element, classes); // Update the position
});
} else if (tile.mergedFrom) {
classes.push("tile-merged");
this.applyClasses(element, classes);
// Render the tiles that merged
tile.mergedFrom.forEach(function (merged) {
self.addTile(merged);
});
} else {
classes.push("tile-new");
this.applyClasses(element, classes);
}
// Put the tile on the board
this.tileContainer.appendChild(element);
};
I guess I'm wondering how does this requestAnimationFrame work to correctly display the tiles when moved? It's building up each tile with the tile information in the grid. Then in addTile() it first uses the tile's previousPosition to build a tile that used to be on the board and creates a class for that position but then it checks if the tile has a previous position and updates the class back to the tile's new position on the grid.
But that only happens in a requestAnimationFrame method for tiles with a previous position and before the method finishes and appends the tile to the tile container in the DOM.
I hope the question makes sense. Are those nested window.RequestAnimationFrame's in the addTile method() called right after the original window.RequestAnimationFrame call in the HTMLActuator.prototype.actuate method so it moves to the new position after an instant and the CSS transition shows it moving?
Related
I have the following code in my requestAnimationFrame loop:
//move obstacles
game.obstacles.forEach(function(obstacle, index) {
obstacle.shape.left-=OBSTACLE_SPEED
//if outside to the left of canvas remove element,
//splice: https://stackoverflow.com/questions/9882284/
//index in foreach: https://stackoverflow.com/questions/10179815/
if (obstacle.shape.left < 0-OBSTACLE_SIZE*2) {
game.obstacles.splice(index, 1) //removes invisible obstacle
console.log("obstacles.size: " + game.obstacles.length)
addObstacle() //adds new obstacle
}
//check if player intersects with obstacle
//console.log("intersects? " + obstacle.shape.intersectsWithObject(player.avatar))
if (obstacle.shape.intersectsWithObject(player.avatar)) {
console.log("YO ITS OVER!")
alert("asdas")
}
})
obstacle.shape are fabricjs.Rect objects and player.avatar is a fabricjs.Circle object.
any idea why the obstacle.shape.intersectsWithObject(player.avatar) always returns false even though they are visibly clipping in the game?
player.avatar is also drawn by adjusting player.avatar.top or .left and I draw everything by calling canvas.renderAll()
if (player.moving == true ) { //move player
//console.log("moving")
player.avatar.top+=player.dy
}
//console.log(player.avatar.top)
canvas.renderAll()
I am basically trying to achieve the basic functionality of this game:
https://www.youtube.com/watch?v=WtsMbQRViFE
I'm running into a bit of an odd issue with Paper.js - I'm using the library to scale the "petals" of a randomly generated flower while audio plays.
The issue crops up if the flower is "growing" and the user navigates to a different tab in the browser. Even though it appears that the onFrame event is not firing when the window is out of view, whichever petal is currently scaling at the time will continue to scale indefinitely.
I even tried using a special js library to determine if the window is in view and still wasn't able to get the petals to stop scaling.
You can view a demo here, as I was not even able to replicate this in a Paper sketch: https://demos2.paperbeatsscissors.com/
Also including my onFrame code here in case the problem is obvious to someone:
view.onFrame = function(event) {
// See if something is playing
if (playing > -1) {
// Get the active flower
var activeFlower = garden[playing],
activeData = activeFlower.data;
// Active layer and petal
var activeLayer = getEl(activeFlower, activeData.lIndex),
activePetal = getEl(activeLayer, activeData.pIndex);
// Variables
var time = activeData.audio.seek(),
scaleAmount = (1 / (activeData.timing / event.delta.toFixed(3))) * 2;
// Petal progression
if (!activeData.completed) {
if (activePetal.scaling.x < 1 && activePetal.scaling.y < 1) {
activePetal.pivot = {x: 0, y: activePetal.height / 2};
activePetal.scaling.x = activePetal.scaling.x + scaleAmount;
activePetal.scaling.y = activePetal.scaling.y + scaleAmount;
} else {
if (activeData.pIndex < (activeLayer.children.length - 1)) {
// If the petal is scaled, jump to a new petal
activeData.pIndex += 1;
} else {
if (activeData.lIndex > 0) {
// When all petals are bloomed, jump to a new layer
activeData.pIndex = 0;
activeData.lIndex -= 1;
} else {
// Set the flower as completed
activeData.completed = true;
}
}
}
}
activeFlower.rotate(.125, activeData.center);
// Reset the playing variable if the audio clip is complete and the flower has completed
if (!activeData.audio.playing() && time === 0 && activeData.completed) {
playing = -1;
}
}
}
Really stumped on this one so any help is greatly appreciated!
I think that your problem is coming from the fact that you base your scaling calculation on event.delta which represents the time elapsed since the last event fired.
The thing is that, if I'm not mistaken, under the hood, Paper.js onFrame event relies on requestAnimationFrame which does not fire when the tab if inactive.
So when you switch tab, wait for a while and get back to your tab event.delta value is big and your scaling value too, hence the size of your petals. This basic sketch showcase this behavior.
So in my opinion, you should simply check event.delta value and limit it if it's too high.
I have written a function loja() in an external js. In another html file, at the end of the file I have linked it to the external js and then at the body of the html file I have created a div and onclick it will call the function loja(). It all works well but the thing is that the javascript function is not loaded inside the div but at the end of the page.Can you help me out?
This is from html file.
<div class="section-title" onclick="loja()">Luaj
</div>
This one is the javascript file.
// Create our 'main' state that will contain the game
function loja(){
var mainState = {
preload: function() {
game.load.image('bird', 'assets/car.png');
game.load.image('pipe', 'assets/pipe.png');
game.load.audio('jump', 'assets/jump.wav');
game.load.image('background', 'assets/background.png');
},
create: function() {
game.add.tileSprite(0, 0, 1000, 600, 'background');
// Set the physics system
game.physics.startSystem(Phaser.Physics.ARCADE);
// Display the bird at the position x=100 and y=245
this.bird = game.add.sprite(100, 245, 'bird');
// Add physics to the bird
// Needed for: movements, gravity, collisions, etc.
game.physics.arcade.enable(this.bird);
// Add gravity to the bird to make it fall
this.bird.body.gravity.y = 1000;
// Call the 'jump' function when the spacekey is hit
var spaceKey = game.input.keyboard.addKey(
Phaser.Keyboard.SPACEBAR);
spaceKey.onDown.add(this.jump, this);
// Create an empty group
this.pipes = game.add.group();
this.timer = game.time.events.loop(1500, this.addRowOfPipes, this);
this.score = 0;
this.labelScore = game.add.text(20, 20, "0",
{ font: "30px Arial", fill: "#ffffff" });
// Move the anchor to the left and downward
this.bird.anchor.setTo(-0.2, 0.5);
this.jumpSound = game.add.audio('jump');
},
update: function() {
// If the bird is out of the screen (too high or too low)
// Call the 'restartGame' function
if (this.bird.y < 0 || this.bird.y > 490)
this.restartGame();
game.physics.arcade.overlap(
this.bird, this.pipes, this.hitPipe, null, this);
if (this.bird.angle < 20)
this.bird.angle += 1;
},
// Make the bird jump
jump: function() {
// Add a vertical velocity to the bird
this.bird.body.velocity.y = -300;
// Create an animation on the bird
var animation = game.add.tween(this.bird);
// Change the angle of the bird to -20° in 100 milliseconds
animation.to({angle: -20}, 100);
// And start the animation
animation.start();
if (this.bird.alive == false)
return;
this.jumpSound.play();
},
// Restart the game
restartGame: function() {
// Start the 'main' state, which restarts the game
game.state.start('main');
},
addOnePipe: function(x, y) {
// Create a pipe at the position x and y
var pipe = game.add.sprite(x, y, 'pipe');
// Add the pipe to our previously created group
this.pipes.add(pipe);
// Enable physics on the pipe
game.physics.arcade.enable(pipe);
// Add velocity to the pipe to make it move left
pipe.body.velocity.x = -200;
// Automatically kill the pipe when it's no longer visible
pipe.checkWorldBounds = true;
pipe.outOfBoundsKill = true;
},
addRowOfPipes: function() {
// Randomly pick a number between 1 and 5
// This will be the hole position
var hole = Math.floor(Math.random() * 5) + 1;
// Add the 6 pipes
// With one big hole at position 'hole' and 'hole + 1'
for (var i = 0; i < 8; i++)
if (i != hole && i != hole + 1)
this.addOnePipe(400, i * 60 + 10);
this.score += 1;
this.labelScore.text = this.score;
},
hitPipe: function() {
// If the bird has already hit a pipe, do nothing
// It means the bird is already falling off the screen
if (this.bird.alive == false)
return;
// Set the alive property of the bird to false
this.bird.alive = false;
// Prevent new pipes from appearing
game.time.events.remove(this.timer);
// Go through all the pipes, and stop their movement
this.pipes.forEach(function(p){
p.body.velocity.x = 0;
}, this);
},
};
// Initialize Phaser, and create a 400px by 490px game
var game = new Phaser.Game(600, 800);
// Add the 'mainState' and call it 'main'
game.state.add('main', mainState);
// Start the state to actually start the game
game.state.start('main');
}
Where javascript code appears in your page in this case seems out of point.
You linked it at the end of file? Than it will appear at the end of file.
What I understand you want is your code to interact with some part of a html file structure, called DOM, some DIV tag in particular.
You need to use Javascript to interact with that DIV node. Probably to render your game inside of it.
In your JS file I only see definition and some method calls. I cant see part that would render some content into DOM.
Summarizing: place where your javascript methods definitions are it not the same place where effects of execution of those methods will appear.
It looks like you're trying to implement an open-source Phaser game (https://github.com/photonstorm/phaser/blob/v2.4.4/src/core/Game.js)
Since your issue is with functionality regarding that framework, that should be your starting place for information. Also you shouldn't leave out important information like any framework you're using when asking for help (especially since in this case the issue is only that you're not using the it properly).
If you look at the fourth parameter it actually allows you to specify a DOM parent, it accepts either the ID or the element itself. So you could just do something like this after inserting another element in your HTML with the ID pgame:
var game = new Phaser.Game(600, 800, void(0), 'pgame');
Hi everyone I'm new to Phaser, its really cool but I'm having an issue trying to use add.sprite, I have an array filled with the game information and I'm trying to paste the pictures into the map on the screen the code is as follows. It is the full game code however I'll elaborate further. I have an array called 'paises' which has the name of each country as well as the population and a little bit of more information. I'm trying to add a function for adding the sprites (images) so that later on I can just use a for loop to add all of them to the screen. This function is known as addSprite();
The error message that I get is that the location of the image that the addSprite function will use is considered as undefined since it doesnt know where 'venezuela' inside the following code is located:
addSprite:function(){ this.add.sprite(85,2,'venezuela');}
Its the same issue for the other addSprite functions.
I'm a little new to prototyping so that might be it. Also tried adding the array paises inside the create function to give it time to load the assets but no luck.
BasicGame = {};
BasicGame.Game = function (game) {};
var paises = [
{
name:'venezuela',
population: 30620404,
brandRecognition: 0,
clients:0,
sales:0,
addSprite:function(){
this.add.sprite(85,2,'venezuela');
}},
{
name:'colombia',
population:48264000,
brandRecognition:0,
clients:0,
sales:0,
addSprite:function(){
this.add.sprite(40,2,'colombia');
}},
{
name:'ecuador',
population:16309000,
brandRecognition:0,
clients:0,
sales:0,
addSprite:function(){
this.add.sprite(25,80,'ecuador');}
},
{
name:'guayana',
population:747884,
brandRecognition:0,
clients:0,
sales:0,
addSprite:function(){
this.add.sprite(164,26,'guayana');}
}];
BasicGame.Game.prototype = {
init: function () {
// set up input max pointers
this.input.maxPointers = 1;
// set up stage disable visibility change
this.stage.disableVisibilityChange = true;
// Set up the scaling method used by the ScaleManager
// Valid values for scaleMode are:
// * EXACT_FIT
// * NO_SCALE
// * SHOW_ALL
// * RESIZE
// See http://docs.phaser.io/Phaser.ScaleManager.html for full document
this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
// If you wish to align your game in the middle of the page then you can
// set this value to true. It will place a re-calculated margin-left
// pixel value onto the canvas element which is updated on orientation /
// resizing events. It doesn't care about any other DOM element that may
// be on the page, it literally just sets the margin.
this.scale.pageAlignHorizontally = true;
this.scale.pageAlignVertically = false;
// Force the orientation in landscape or portrait.
// * Set first to true to force landscape.
// * Set second to true to force portrait.
this.scale.forceOrientation(true, false);
// Sets the callback that will be called when the window resize event
// occurs, or if set the parent container changes dimensions. Use this
// to handle responsive game layout options. Note that the callback will
// only be called if the ScaleManager.scaleMode is set to RESIZE.
this.scale.setResizeCallback(this.gameResized, this);
// Set screen size automatically based on the scaleMode. This is only
// needed if ScaleMode is not set to RESIZE.
this.scale.setScreenSize(true);
// Re-calculate scale mode and update screen size. This only applies if
// ScaleMode is not set to RESIZE.
this.scale.refresh();
},
preload: function () {
// Here we load the assets required for our preloader (in this case a
// background and a loading bar)
this.load.image('logo', 'asset/phaser.png');
this.load.image('brasil','asset/brasil.png');
this.load.image('colombia','asset/colombia.png');
this.load.image('venezuela','asset/venezuela.png');
this.load.image('ecuador','asset/ecuador.png');
this.load.image('peru','asset/peru.png');
this.load.image('guayana','asset/guayana.png');
this.load.image('surinam','asset/surinam.png');
this.load.image('guayanaFrancesa','asset/guayanaFrancesa.png');
this.load.image('brasil','asset/brasil.png');
this.load.image('chile','asset/chile.png');
this.load.image('bolivia','asset/bolivia.png');
this.load.image('argentina','asset/argentina.png');
this.load.image('paraguay','asset/paraguay.png');
this.load.image('uruguay','asset/uruguay.png');
this.load.image('menu','asset/menu.png');
this.load.image('oceano','asset/oceano.jpg');
},
create: function () {
var oceano = this.add.sprite(0,0,'oceano');
var menu = this.add.sprite(450,50,'menu');
for(var i=0;i<3;i++){
paises[i].addSprite();
}
},
gameResized: function (width, height) {
// This could be handy if you need to do any extra processing if the
// game resizes. A resize could happen if for example swapping
// orientation on a device or resizing the browser window. Note that
// this callback is only really useful if you use a ScaleMode of RESIZE
// and place it inside your main game state.
}};
Hi guys just got it to work, the solution involved moving the function outside the object and just saving the parameters inside the object (the x,y and file name). I also made the paises variable a global one. It might not be the most elegant solution but it does what I need it to do. I'll post the code in case someone else can benefit from it.
var paises = [
{
name:'venezuela',
population: 30620404,
brandRecognition: 0,
clients:0,
sales:0,
x:85,
y:2
},
{
name:'colombia',
population:48264000,
brandRecognition:0,
clients:0,
sales:0,
x:40,
y:2
},
{
name:'ecuador',
population:16309000,
brandRecognition:0,
clients:0,
sales:0,
x:25,
y:80
},
{
name:'guayana',
population:747884,
brandRecognition:0,
clients:0,
sales:0,
x: 164,
y:26
}];
BasicGame = {
};
BasicGame.Game = function (game) {
};
BasicGame.Game.prototype = {
init: function () {
// set up input max pointers
this.input.maxPointers = 1;
// set up stage disable visibility change
this.stage.disableVisibilityChange = true;
// Set up the scaling method used by the ScaleManager
// Valid values for scaleMode are:
// * EXACT_FIT
// * NO_SCALE
// * SHOW_ALL
// * RESIZE
// See http://docs.phaser.io/Phaser.ScaleManager.html for full document
this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
// If you wish to align your game in the middle of the page then you can
// set this value to true. It will place a re-calculated margin-left
// pixel value onto the canvas element which is updated on orientation /
// resizing events. It doesn't care about any other DOM element that may
// be on the page, it literally just sets the margin.
this.scale.pageAlignHorizontally = true;
this.scale.pageAlignVertically = false;
// Force the orientation in landscape or portrait.
// * Set first to true to force landscape.
// * Set second to true to force portrait.
this.scale.forceOrientation(true, false);
// Sets the callback that will be called when the window resize event
// occurs, or if set the parent container changes dimensions. Use this
// to handle responsive game layout options. Note that the callback will
// only be called if the ScaleManager.scaleMode is set to RESIZE.
this.scale.setResizeCallback(this.gameResized, this);
// Set screen size automatically based on the scaleMode. This is only
// needed if ScaleMode is not set to RESIZE.
this.scale.setScreenSize(true);
// Re-calculate scale mode and update screen size. This only applies if
// ScaleMode is not set to RESIZE.
this.scale.refresh();
},
preload: function () {
// Here we load the assets required for our preloader (in this case a
// background and a loading bar)
this.load.image('logo', 'asset/phaser.png');
this.load.image('brasil','asset/brasil.png');
this.load.image('colombia','asset/colombia.png');
this.load.image('venezuela','asset/venezuela.png');
this.load.image('ecuador','asset/ecuador.png');
this.load.image('peru','asset/peru.png');
this.load.image('guayana','asset/guayana.png');
this.load.image('surinam','asset/surinam.png');
this.load.image('guayanaFrancesa','asset/guayanaFrancesa.png');
this.load.image('brasil','asset/brasil.png');
this.load.image('chile','asset/chile.png');
this.load.image('bolivia','asset/bolivia.png');
this.load.image('argentina','asset/argentina.png');
this.load.image('paraguay','asset/paraguay.png');
this.load.image('uruguay','asset/uruguay.png');
this.load.image('menu','asset/menu.png');
this.load.image('oceano','asset/oceano.jpg');
},
create: function () {
var oceano = this.add.sprite(0,0,'oceano');
var menu = this.add.sprite(450,50,'menu');
for(var i=0;i<3;i++){
this.add.sprite(paises[i].x,paises[i].y,paises[i].name);
}
},
gameResized: function (width, height) {
// This could be handy if you need to do any extra processing if the
// game resizes. A resize could happen if for example swapping
// orientation on a device or resizing the browser window. Note that
// this callback is only really useful if you use a ScaleMode of RESIZE
// and place it inside your main game state.
}
};
I am in the prototyping stage of making a 2d map builder for a hybrid web/text adventure game and so far KineticJS seems like an ideal fit. Only issue currently is that given enough velocity on mouse movement, it will skip over cells and never fire their mouseover event handler.
2 core functionality goals: When the user highlights a cell, it would be marked as "active". Additionally if they're holding the mouse down and move across the grid, cells would be flipped on or off ( this maybe refactored to set all on if not if the first cell is not active, or vice versa ).
My question: Is there a way to ensure all cells are triggered, regardless of mouse cursor velocity? If not, is there a better way to draw a line over the cells so that it consistently triggers all relevant cells?
The entire prototype has been put into jsFiddle ( http://jsfiddle.net/7ggS4/ ) but for future sake, the rest will be copied below as well.
<head>
<title>KineticJS</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/kineticjs/4.7.2/kinetic.min.js"></script>
</head>
<body>
<div id="canvas"></div>
</body>
<script defer="defer">
/**
Return's a KS layer
*/
function Grid(cells, stage) {
//Constants
// Illrelevant comment - It seriously pisses me off that canvas uses
// string color codes ( either name or string hexidecimal ) instead of taking an
// integer or actual hexidecimal 0xFFFF values. This just seems painfully inefficient.
this.activeCellColor = "green";
this.clearCellColor = "blue";
this.highlightCellColor = "red";
this.cells = cells,
this.layer = new Kinetic.Layer(),
this.grid = new Array(),
this.isMouseDown = false,
this.mouseLeft = false,
this.mouseRight = false,
this.adjRow = stage.getWidth() / cells,
this.adjCol = stage.getHeight() / cells;
this.generate();
stage.add(this.layer)
}
Grid.prototype.generate = function(){
var i, rx, ry, rect;
for (i = 0; i < this.cells * this.cells; i++) {
rx = Math.floor(i / this.cells) * this.adjRow;
ry = (i % this.cells) * this.adjCol;
rect = new Kinetic.Rect({
x: rx,
y: ry,
width: this.adjRow,
height: this.adjCol,
fill: this.clearCellColor,
stroke: 'black',
strokeWidth: .2,
cell: {x: Math.floor(i / this.cells), y: i % this.cells},
active: false,
grid: this //Just in case .bind(this) doesn't work right
});
rect.on('mouseenter', this.onMouseEnter.bind(this));
rect.on('mouseleave', this.onMouseLeave.bind(this));
rect.on('mousedown', this.onMouseDown.bind(this));
rect.on('mouseup', this.onMouseUp.bind(this));
this.grid.push(rect);
this.layer.add(rect);
}
}
Grid.prototype.onMouseEnter = function(evt) {
var src = evt.targetNode;
console.log(evt.type, this.isMouseDown, src.attrs.cell)
if (this.isMouseDown == true) {
src.attrs.active = ! src.attrs.active;
}
if (src.attrs.active == false) {
src.setFill(this.highlightCellColor);
} else {
src.setFill(this.activeCellColor);
}
this.layer.batchDraw();
}
Grid.prototype.onMouseLeave = function(evt) {
var src = evt.targetNode;
console.log(evt.type, this.isMouseDown, src.attrs.cell)
if (src.attrs.active == false) {
src.setFill(this.clearCellColor);
this.layer.batchDraw();
}
}
Grid.prototype.onMouseUp = function(evt){
var src = evt.targetNode;
console.log(evt.type, this.isMouseDown, src.attrs.cell)
this.isMouseDown = false;
}
Grid.prototype.onMouseDown = function(evt){
var src = evt.targetNode;
console.log(evt.type, this.isMouseDown, src.attrs.cell)
this.isMouseDown = true;
src.attrs.active = ! src.attrs.active;
if (src.attrs.active) {
src.setFill(this.activeCellColor);
} else {
src.setFill(this.clearCellColor);
}
this.layer.batchDraw();
}
var stage = new Kinetic.Stage({
container: 'canvas',
width: 600,
height: 600
}),
myGrid = new Grid(50, stage);
</script>
50x50=2500 active objects: that's too many for Kinetic to handle.
Remember that each "intelligent" Kinetic cell has a lot of overhead associated with it.
How about reducing your grid to 20x20?
Alternatively, you will have to separate the mouse handling from the cell handling to gain the required performance.
Mouse Handling
Your mouse handling would only involve capturing mouse points into an array of accumulated points. You can use this kind of code to capture mouse points on the stage:
$(stage.getContent()).on('click', function (event) {
myPointsArray.push(stage.getMousePosition());
});
Cell processing
The cell processing would involve applying those accumulated points to affect your grid cells. An effective place to do this code would be in a requestAnimationFrame (RAF) loop. You won't be doing animations, but RAF gives high performance because it is aware of the availability of system resources. An RAF loop would look like this:
function processPointsArray(array){
// request another loop even before we're done with this one
requestAnimationFrame(processPointsArray);
// process the points array and affect your cells here
}
A processing efficiency
RAF is called up to 60 times per second, so your user will probably navagate only a small portion of your grid during that time. You can increase performance by calculating the min/max x and y coordinates in the accumulated points array and only process those grid cells within that boundary.