Grouping shapes in paper.js - javascript

Trying out paper.js for the first time, working on some generative visuals. Trying to figure out the best route to accomplish the following:
Each cloud shape is individual, but when they intersect each other, I want them to compound into one larger cloud.
Within that larger cloud, I want the individual shape to retain it's properties, so that it can eventually detach and become a single cloud again.
So I am running into a few problems trying to accomplish this. I check for intersections:
//cloudArray refers to an array of path items
Cloud.prototype.checkIntersection = function() {
//loop through all existing cloud shapes
for(var i=0;i<cloudArray.length;i++){
//avoid checking for intersections on the same cloud path
if(this.path !== cloudArray[i].path){
//if path intersects another, group the two, and
//sort them in the order of their id
if(this.path.intersects(cloudArray[i].path)){
tmpGrp = [this.path,cloudArray[i].path];
tmpGrp.sort(function(a,b){return a.id - b.id});
groupClouds(tmpGrp);
}
}
}
}
Now after intersections are checked, I attempt to group the clouds together into arrays:
function groupClouds(tmpGrp){
if(grps.length > 0){
for(var i=0;i<grps.length;i++){
if(tmpGrp !== grps[i]){
console.log('doesnt match');
grps.push(tmpGrp);
}else{
console.log('matches');
}
}
}else{
grps[0] = tmpGrp;
}
console.log(grps);
}
Now I know that I can't compare arrays this way, so I have tried to use the solution given here, but I didn't want to further clutter this question.
Is this method reasonable? I know that I could create a new compoundPath if I could create arrays for each group. The problem is assuring that each collection of intersecting clouds is correct, and that they are being updated efficiently.
Any advice?

Related

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.

Javascript board game: looking for optimization

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.

I'm having trouble with a small algorithm

Imagine I have a number of objects represented as balls in a gravity simulation, they're clumped together in 3 groups (for example, but it could be any number), how can give each object value depending on which group (1,2,3) it's in?
I only got this far, I can't figure it out...
var objects = [/* the balls */];
...
this.objects.forEach(
function(one) {
this.objects.forEach(
function(two) {
if(distance(one, two) <= 0) {
// these two are in the same group
}
}
);
}
);
The thing is, two balls in the same group might not necessarily be touching because there may a another ball in between them, but all balls in a group touch at least one other ball in the group.
The value would just be something like "this.group = 1;".
Any ideas are much appreciated, thanks.
Your problem is that you cannot disambiguate balls from which group it came from.
Try using three arrays to represent the three groups, or a more object-like structure that can reference which group the balls come from.

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