Javascript board game: looking for optimization - javascript

I'm working on a html/javascript game for android. It's a board game which does the following.
It has tiles of different colors and user can place one tile (chosen programatically) on the board. If we get 4 or more tiles of the same color/shape we score some points and these tiles will disappear. The tiles above the removed tiles will replace them and new tiles will be added to the empty places. The image below shows how it works (this is just an example, the real board can have different dimensions):
The Tiles are <img> elements with their ids stored in an array which I use to check for matches and replacement.
It all works pretty well but once the new tiles are added to board I need to examine the whole board to check if new matches are avalable. And I want some advice here, because examining the whole board can be really slow. Is there a way I can do this efficiently?
Here's what I thought about doing:
Given the previous example,I thought about examining only the elements in the red area, i.e. only the elements that have been moved or added. It can be effective if the tiles move vertically, as I'll only have to check the moved/added tiles and it'll give me the new matches. But in case where I remove tiles horizontally it can be problematic, because if these tiles are at the bottom i'll have to examine the whole board and i confront the same problem.
Any advice or suggestion will be appreciated.
Note: I didn't add any code because it simply consists of checking the lines and columns for a given tile and look for matches. But if needed I can provide it.
EDIT: Before anyone can object I want to inform that I just added this question to Game Development section as I didn't receive any answers here :).
EDIT: Adding my code
function initializeBoard(){
//items is an array which contains tiles/images names
for(var i=0; i < totalItems; i++)
board[i+1] = Math.floor(Math.random() * (items.length - 1)) + 1;
for(var i=0; i < totalItems; i++)
{
if( !(i % numberShapesXAxis) )
document.write("<BR>");
document.write("<img src=\"images/"+ items[board[i+1]]+ ".gif\" style = \"border:0; height:"+ itemSize+ "px; width:"+ itemSize+ "px;\" name=\"t", i+1,"\" onclick = \"replaceAndCheck(", i+1, ")\"><\/a>");
}
}
//so basically board contains image ids.

How about checking if there is a new match when you move a stone. So when stone x moves down you check if the new position of X creates a match. That way you can create a recursive kind of method.

Related

How to make multiple circle objects not go into each other with collision detection?

I have a total of 1 to 64 blobs and they all move to my mouse position. But i want them to not go into each other, in other words circle collision detection. However i can't seem to make it smooth and also push new objects after they move for the first time?
Tried checking each blob for collision with other blobs. If collosion is true, then set the distance between the blobs to their accumulated radiuses.
This is how i wrote the colliding function, but this way of doing it makes the resetting of positions too fast. I want it to be a smooth, but fast transition. Like instead of now 1 frame, lets say 10 frames. And another problem is when two objects' are distanced to their radiuses, they might collide into new ones and that will cause this code to run again, and then all blobs go crazy.
this.collide = function() {
var length = this.blobs.length; // How many blobs?
this.blobs.forEach(function(item, index) {
for (var i = 0; i < length; i++) {
// Get absolute distance between two vectors
var v0 = vectorFromTo(blob.blobs[i].pos.x, blob.blobs[i].pos.y, //[x2, y2]
item.pos.x, item.pos.y); //[x1, y1]
// if colliding, set distance between to their accumulated radiuses
if (magnitude(v0) < blob.blobs[i].r + item.r) {
item.pos.add(v0.setMag(magnitude(v0) - (blob.blobs[i].r + item.r)));
}
}
});
}
I haven't tried to code another way of doing this yet because i haven't learned about vectors in school, but i do understand them quite a bit. But what i think would work is if i checked for collision, and if they collide they go opposite directions 50% of the deficit distance, and then they check if they hit new blobs. But this would require physics right? Cause then it would have to do something with the mass and speed of the blob as well to know whats gonna happen to the new blob it crashes into?
EDIT:
This is what im looking for: https://youtu.be/QvlhRGtlcsw
This is what it currently looks like: https://youtu.be/QEpHnCgomqY

Arrays Inside Objects: Conditional Updating Of One Object's Array From Another Object's Array

DISCLAIMER
I have absolutely no idea how to succinctly describe the nature of the problem I am trying to solve without going deep into context. It took me forever to even think of an appropriate title. For this reason I've found it nearly impossible to find an answer both on here and the web at large that will assist me. It's possible my question can be distilled down into something simple which does already have an answer on here. If this is the case I apologise for the elaborate duplicate
TL;DR
I have two arrays: a main array members and a destination array neighbours (technically many destination arrays but this is the tl;dr). The main array is a property of my custom group object which is auto-populated with custom ball objects. The destination array is a property of my custom ball object. I need to scan each element inside of the members array and calculate distance between that element and every other element in the members group. If there exist other elements within a set distance of the current element then these other elements need to be copied into the current element's destination array. This detection needs to happen in realtime. When two elements become close enough to be neighbours they are added to their respective neighbours array. The moment they become too far apart to be considered neighbours they need to be removed from their respective neighbours array.
CONTEXT
My question is primarily regarding array iteration, comparison and manipulation but to understand my exact dilemma I need to provide some context. My contextual code snippets have been made as brief as possible. I am using the Phaser library for my project, but my question is not Phaser-dependent.
I have made my own object called Ball. The object code is:
Ball = function Ball(x, y, r, id) {
this.position = new Vector(x, y); //pseudocode Phaser replacement
this.size = r;
this.id = id;
this.PERCEPTION = 100;
this.neighbours = []; //the destination array this question is about
}
All of my Ball objects (so far) reside in a group. I have created a BallGroup object to place them in. The relevant BallGroup code is:
BallGroup = function BallGroup(n) { //create n amount of Balls
this.members = []; //the main array I need to iterate over
/*fill the array with n amount of balls upon group creation*/
for (i = 0; i < n; i++) {
/*code for x, y, r, id generation not included for brevity*/
this.members.push(new Ball(_x, _y, _r, _i)
}
}
I can create a group of 4 Ball objects with the following:
group = new BallGroup(4);
This works well and with the Phaser code I haven't included I can click/drag/move each Ball. I also have some Phaser.utils.debug.text(...) code which displays the distance between each Ball in an easy to read 4x4 table (with duplicates of course as distance Ball0->Ball3 is the same as distance Ball3->Ball0). For the text overlay I calculate the distance with a nested for loop:
for (a = 0; a < group.members.length; a++) {
for (b = 0; b < group.members.length; b++) {
distance = Math.floor(Math.sqrt(Math.pow(Math.abs(group.members[a].x - group.members[b].x), 2) + Math.pow(Math.abs(group.members[a].y - group.members[b].y), 2)));
//Phaser text code
}
}
Now to the core of my problem. Each Ball has a range of detection PERCEPTION = 100. I need to iterate over every group.members element and calculate the distance between that element (group.members[a]) and every other element within the group.members array (this calculation I can do). The problem I have is I cannot then copy those elements whose distance to group.members[a] is < PERCEPTION into the group.members[a].neighbours array.
The reason I have my main array (BallGroup.members) inside one object and my destination array inside a different object (Ball.neighbours) is because I need each Ball within a BallGroup to be aware of it's own neighbours without caring for what the neighbours are for every other Ball within the BallGroup. However, I believe that the fact these two arrays (main and destination) are within different objects is why I am having so much difficulty.
But there is a catch. This detection needs to happen in realtime and when two Balls are no longer within the PERCEPTION range they must then be removed from their respective neighbours array.
EXAMPLE
group.members[0] -> no neighbours
group.members[1] -> in range of [2] and [3]
group.members[2] -> in range of [1] only
group.members[3] -> in range of [1] only
//I would then expect group.members[1].neighbours to be an array with two entries,
//and both group.members[2].neighbours and group.members[3].neighbours to each
//have the one entry. group.members[0].neighbours would be empty
I drag group.members[2] and group.members[3] away to a corner by themselves
group.members[0] -> no neighbours
group.members[1] -> no neighbours
group.members[2] -> in range of [3] only
group.members[3] -> in range of [2] only
//I would then expect group.members[2].neighbours and group.members[3].neighbours
//to be arrays with one entry. group.members[1] would change to have zero entries
WHAT I'VE TRIED
I've tried enough things to confuse any person, which is why I'm coming here for help. I first tried complex nested for loops and if/else statements. This resulted in neighbours being infinitely added and started to become too complex for me to keep track of.
I looked into Array.forEach and Array.filter. I couldn't figure out if forEach could be used for what I needed and I got very excited learning about what filter does (return an array of elements that match a condition). When using Array.filter it either gives the Ball object zero neighbours or includes every other Ball as a neighbour regardless of distance (I can't figure out why it does what it does, but it definitely isn't what I need it to do). At the time of writing this question my current code for detecting neighbours is this:
BallGroup = function BallGroup(n) {
this.members = []; //the main array I need to iterate over
//other BallGroup code here
this.step = function step() { //this function will run once per frame
for (a = 0; a < this.members.length; a++) { //members[a] to be current element
for (b = 0; b < this.members.length; b++) { //members[b] to be all other elements
if (a != b) { //make sure the same element isn't being compared against itself
var distance = Math.sqrt(Math.pow(Math.abs(this.members[a].x - this.members[b].x), 2) + Math.pow(Math.abs(this.members[a].y - this.members[b].y), 2));
function getNeighbour(element, index, array) {
if (distance < element.PERCEPTION) {
return true;
}
}
this.members[a].neighbours = this.members.filter(getNeighbour);
}
}
}
}
}
I hope my problem makes sense and is explained well enough. I know exactly what I need to do in the context of my own project, but putting that into words for others to understand who have no idea about my project has been a challenge. I'm learning Javascript as I go and have been doing great so far, but this particular situation has me utterly lost. I'm in too deep, but I don't want to give up - I want to learn!
Many, many, many thanks for those who took the time read my very long post and tried provide some insight.
edit: changed a > to a <
I was learning more on object literals, I'm trying to learn JS to ween myself off of my jQuery dependency. I'm making a simple library and I made a function that adds properties of one object to another object. It's untested, but I think if you were apply something similar it might help. I'll try to find my resources. Btw, I don't have the articles on hand right now, but I recall that using new could incur complications, sorry I can't go any further than that, I'll post more info as I find it.
xObject could be the ball group
Obj2 could be the members
Obj1 could be the destination
/* augment(Obj1, Obj2) | Adds properties of Obj2 to Obj1. */
// xObject has augment() as a method called aug
var xObject = {
aug: augument
}
/* Immediately-Invoked Function Expression (IIFE) */
(function() {
var Obj1 = {},
Obj2 = {
bool: true,
num: 3,
str: "text"
}
xObject.aug(Obj1, Obj2);
}()); // invoke immediately
function augment(Obj1, Obj2) {
var prop;
for (prop in Obj2) {
if (Obj2.hasOwnProperty(prop) && !Obj1[prop]) {
Obj1[prop] = Obj2[prop];
}
}
}

Sort multidimensional object literal array by external value

I am trying to make a homemade line of sight for a game im building which is a gridbased, 2D top-view board game. The board has divs in a 2-dimensional array which are all black and will be transparent if the player is in a corridor which are also in a 2-dimensional array with objects. There are miscellaneous blocks in the corridors and i need to take them into consideration so the divs will stop getting transparent if they appear in the corridors where the player is.
So i've got an idea to sort the array of objects in a given corridor where the player is located by the x,y values.
corridors[i].sort(
function(a)
{
if(a.y > playerObj.position.y && a.x > playerObj.position.x) return 1;
if(a.y < playerObj.position.y && a.x < playerObj.position.x) return -1;
return 0;
});
But this does not seem to work. The changing of the divs background-color to transparent is still beginning from the array's first index. I want it to start from the players position in the corridor and work itself outwards like so:
O is simply a tile, P is the player, X is the tile that has just been made transparent
OOOOOOOOOOOPOOOOOO
OOOOOOOOOOXPOOOOOO
OOOOOOOOOOXPXOOOOO
OOOOOOOOOXXPXOOOOO
But for this scenario to function i need to find how to sort my array correctly, and i hope you can help me with this. The examples i've seen on the net has parameters a and b, so is it not possible to use an external variable? Should i perhaps create the players position as a new object and push it to the array and then sort the array?
Okay so i think i solved it. I simply made the sorting function be stored in a new array and used that instead.

Click detection in a 2D isometric grid?

I've been doing web development for years now and I'm slowly getting myself involved with game development and for my current project I've got this isometric map, where I need to use an algorithm to detect which field is being clicked on. This is all in the browser with Javascript by the way.
The map
It looks like this and I've added some numbers to show you the structure of the fields (tiles) and their IDs. All the fields have a center point (array of x,y) which the four corners are based on when drawn.
As you can see it's not a diamond shape, but a zig-zag map and there's no angle (top-down view) which is why I can't find an answer myself considering that all articles and calculations are usually based on a diamond shape with an angle.
The numbers
It's a dynamic map and all sizes and numbers can be changed to generate a new map.
I know it isn't a lot of data, but the map is generated based on the map and field sizes.
- Map Size: x:800 y:400
- Field Size: 80x80 (between corners)
- Center position of all the fields (x,y)
The goal
To come up with an algorithm which tells the client (game) which field the mouse is located in at any given event (click, movement etc).
Disclaimer
I do want to mention that I've already come up with a working solution myself, however I'm 100% certain it could be written in a better way (my solution involves a lot of nested if-statements and loops), and that's why I'm asking here.
Here's an example of my solution where I basically find a square with corners in the nearest 4 known positions and then I get my result based on the smallest square between the 2 nearest fields. Does that make any sense?
Ask if I missed something.
Here's what I came up with,
function posInGrid(x, y, length) {
xFromColCenter = x % length - length / 2;
yFromRowCenter = y % length - length / 2;
col = (x - xFromColCenter) / length;
row = (y - yFromRowCenter) / length;
if (yFromRowCenter < xFromColCenter) {
if (yFromRowCenter < (-xFromColCenter))--row;
else++col;
} else if (yFromRowCenter > xFromColCenter) {
if (yFromRowCenter < (-xFromColCenter))--col;
else++row;
}
return "Col:"+col+", Row:"+row+", xFC:"+xFromColCenter+", yFC:"+yFromRowCenter;
}
X and Y are the coords in the image, and length is the spacing of the grid.
Right now it returns a string, just for testing.. result should be row and col, and those are the coordinates I chose: your tile 1 has coords (1,0) tile 2 is(3,0), tile 10 is (0,1), tile 11 is (2,1). You could convert my coordinates to your numbered tiles in a line or two.
And a JSFiddle for testing http://jsfiddle.net/NHV3y/
Cheers.
EDIT: changed the return statement, had some variables I used for debugging left in.
A pixel perfect way of hit detection I've used in the past (in OpenGL, but the concept stands here too) is an off screen rendering of the scene where the different objects are identified with different colors.
This approach requires double the memory and double the rendering but the hit detection of arbitrarily complex scenes is done with a simple color lookup.
Since you want to detect a cell in a grid there are probably more efficient solutions but I wanted to mention this one for it's simplicity and flexibility.
This has been solved before, let me consult my notes...
Here's a couple of good resources:
From Laserbrain Studios, The basics of isometric programming
Useful article in the thread posted here, in Java
Let me know if this helps, and good luck with your game!
This code calculates the position in the grid given the uneven spacing. Should be pretty fast; almost all operations are done mathematically, using just one loop. I'll ponder the other part of the problem later.
def cspot(x,y,length):
l=length
lp=length+1
vlist = [ (l*(k%2))+(lp*((k+1)%2)) for k in range(1,y+1) ]
vlist.append(1)
return x + sum(vlist)

How can I stop elements overlapping using JavaScript and the Raphael JavaScript library

I’m generating multiple, random sized, circular elements using the Raphael JavaScript library but because it’s random a lot of the circular elements being generate overlap or cover each other. What I wanted to know, is there any way with JavaScript to tell if one element is in already in particular position so to avoid the overlapping? Essentially, I want to create random elements on a canvas, of a random size that don’t overlap or cover each other.
There's a couple of test files I created here to give you an idea of what I'm doing. The first one generates random objects and the second link sets them to a grid to stop the overlapping.
http://files.nicklowman.co.uk/movies/raphael_test_01/
http://files.nicklowman.co.uk/movies/raphael_test_03/
The easiest way is to create an object and give it a repulsive force that degrades towards zero at it's edge. As you drop these objects onto the canvas the objects will push away from each other until they reach a point of equilibrium.
Your examples aren't working for me, so I cannot visualize your exact scenario.
Before you "drop" an element on the canvas, you could query the positions of your other elements and do some calculations to check if the new element will overlap.
A very simple example of this concept using circle elements might look like this:
function overlap(circ1, circ2) {
var attrs = ["cx", "cy", "r"];
var c1 = circ1.attr(attrs);
var c2 = circ2.attr(attrs);
var dist = Math.sqrt(Math.pow(c1.cx - c2.cx ,2) + Math.pow(c1.cy - c2.cy, 2));
return (dist < (c1.r + c2.r));
}
var next_drop = paper.circle(x, y, r);
for (var i in circles) {
if (overlap(next_drop, circles[i])) {
// do something
}
}
Of course calculating just where you're going to place a circle after you've determined it overlaps with others is a little more complicated.

Categories

Resources