Sort multidimensional object literal array by external value - javascript

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.

Related

I am trying to remove items from an array of objects used as projectiles for players or enemies to shoot in games made with JavaScript

I am practicing with making players and enemies for 2d games using vanilla JavaScript and HTML Canvas. The only problem I have is that I am trying to remove the projectiles from the playerProjectiles array when the projectile goes off of the screen. This is so that the game doesn't have to keep track of a bunch of projectiles that are not even on the screen, so the game will run smoother. I have tried sifting through the array using .forEach and splicing the current projectile that it is looping through as long as that projectile is off the screen. However, using this method, if there are multiple projectiles on the screen and one of them goes off of the screen, the entire array gets spliced and all of the projectiles are removed. What am I doing wrong here? Also, would it be better to put the code for the different mechanics of the projectiles in a different function? Etc. moving the projectiles up when they are shot out, actually drawing them to the screen, splicing them from the array when they go off the screen.
function populatePlayerProjectilesArray() {
playerProjectiles.forEach(projectile => {
projectile.draw();
projectile.y -= pdy;
if(projectile.y <= 0 - projectile.rad) {
playerProjectiles.splice(projectile)
}
})
}
Array.prototype.splice()
Examples:
splice(start)
splice(start, deleteCount)
deleteCount Optional An integer indicating the number of elements in the array to remove from start. If deleteCount is omitted [...], then all the elements from start to the end of the array will be deleted.
I think you want to change your splice statement to:
playerProjectiles.splice(projectile, 1)

ActionScript 3.0 Reproducing z-index from JavaScript for 2D game

My 2D game uses a "wide" floor, seen below, which requires objects to move behind and in front of each other as they move vertically.
See me!
In JavaScript I would simply apply the "y" position to the z-index property of the object, effectively layering the elements. I've been experimenting with AS3's indexing, addChildAt and setChildIndex, but have not yet figured out a solution. Note that objects will added and modified dynamically as the game updates, and will be numerous.
What is the simplest method to reproduce this in AS3?
This seems to be best matching what you are describing:
Using Matrix3D objects for reordering display
As mentioned previously, the layering order of display objects in the display list determines the display layering order, regardless of their relative z-axes. If your animation transforms the properties of display objects into an order that differs from the display list order, the viewer might see display object layering that does not correspond to the z-axis layering. So, an object that should appear further away from the viewer might appear in front of an object that is closer to the viewer.
To ensure that the layering of 3D display objects corresponds to the relative depths of the objects, use an approach like the following:
Use the getRelativeMatrix3D() method of the Transform object to get the relative z-axes of the child 3D display objects.
Use the removeChild() method to remove the objects from the display list.
Sort the display objects based on their relative z-axis values.
Use the addChild() method to add the children back to the display list in reverse order.
This reordering ensures that your objects display in accordance with their relative z-axes.
The following code enforces the correct display of the six faces of a 3D box. It reorders the faces of the box after rotations have been applied to the it:
public var faces:Array; . . .
public function ReorderChildren()
{
for(var ind:uint = 0; ind < 6; ind++)
{
faces[ind].z = faces[ind].child.transform.getRelativeMatrix3D(root).position.z;
this.removeChild(faces[ind].child);
}
faces.sortOn("z", Array.NUMERIC | Array.DESCENDING);
for (ind = 0; ind < 6; ind++)
{
this.addChild(faces[ind].child);
}
}
It's essentially what you're doing already, using addChild. You could use setChildIndex() instead of removing the objects from the display list as well.

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];
}
}
}

Grouping shapes in paper.js

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?

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.

Categories

Resources