Trying to make an array of class objects in JS. I don't know how Javascript handles this but instead of a 10x10 grid, all numbers are set to 10 instead of the i and j values I want to assign.
class Box {
constructor(width, height, x, y, inside) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.inside = inside;
}
getHeight() {
return this.height;
}
setHeight(newHeight) {
this.height = newHeight;
}
let boxes = [
[]
];
let testBox = new Box(1, 1, 1, 1, "Test")
for (let i = 0; i < 11; i++) {
for (let j = 0; j < 11; j++) {
boxes[i[j]] = new Box(i, j, i, j, "Test");
}
}
console.log(testBox.getHeight()); //Working Example
console.log(boxes[3[3]].getHeight()); //outputs 10?
console.log(boxes[4[6]].getHeight()); //outputs 10?
An example of what i wrote about in the comments
class Box {
constructor(width, height, x, y, inside) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.inside = inside;
}
getHeight() {
return this.height;
}
setHeight(newHeight) {
this.height = newHeight;
}
}
let boxes = [];
for (let i = 0; i < 11; i++) {
for (let j = 0; j < 11; j++) {
boxes[i] = [...(boxes[i] ? boxes[i] : []),
new Box(i, j, i, j, "Test")
];
}
}
console.log(boxes[3][3].getHeight());
console.log(boxes[4][6].getHeight());
From what I understand, you have declared a class box and you want to create an array of objects of this class. Considering this is the case,
you code has syntax error : the array and loop must be outside of the class definition.
Now since you want to make an array of objects, it's not a 2-D array it is just a one dimensional array.So the code should look like this
class Box {
constructor( width, height, x ,y, inside) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.inside = inside;
}
getHeight(){
return this.height;
}
setHeight(newHeight){
this.height = newHeight;
}}
let boxes = [];
for(let i = 0; i < 11; i++){
boxes.push(new Box(i,i+2,i,i+2,"Test"));
}
for(var cnt in boxes)
console.log(boxes[cnt]);
Related
I am trying to make one of those sorting algorithms and want to have the bars get randomly generated with height and x position. However, when I run the code, it doesn't draw any bars. I'm also not getting any errors sent so I have no idea what's going wrong.
class Bar {
constructor(x, height) {
this.height = height;
this.size = 10;
this.x = x;
}
draw() {
fill("blue");
rect(this.x * this.size, height - (this.height * this.size), this.size, this.height * this.size);
}
}
let bars = [];
function setup() {
createCanvas(400, 400);
generateBars();
}
function generateBars() {
for (let i = 0; i < 39; i++) {
randomX = random(0, 39);
randomHeight = random(0, 40)
for (let j = 0; j < bars.length; j++) {
if (bars[j].x == randomX) {
randomX = random(0, 39);
} else {
for (let h = 0; h < bars.length; h++) {
if (bars[j].height == randomHeight) {
randomHeight = random(0, 40);
} else {
bars[i] = new Bar(randomX, randomHeight);
}
}
}
}
}
}
function draw() {
background(220);
for (let k = 0; k < bars.length; k++) {
bars[k].draw();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.min.js"></script>
The logic in generateBars seems convoluted and the intention is unclear.
As far as I see Bar's x property acts more of a value property storing the number to be sorted later because it is multiplied by size in draw(). (e.g. x is not the final x position the bar should be rendered at, as it's name implies).
I would simply intanstiate Bar like so:
class Bar{
constructor(x, height){
this.height = height;
this.size = 10;
this.x = x;
}
draw(){
fill("blue");
rect(this.x * this.size, height - (this.height * this.size), this.size, this.height * this.size);
}
}
let bars = [];
function setup() {
createCanvas(400, 400);
generateBars();
}
function generateBars(){
for(let i = 0; i < 40; i++){
randomHeight = random(0, 40)
bars[i] = new Bar(i, randomHeight);
}
}
function draw() {
background(220);
for(let k = 0; k < bars.length; k++){
bars[k].draw();
}
}
function mouseClicked(){
setup();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.min.js"></script>
(I've added a hacky mouseClicked() handler so it's easy to regenerate the bars for testing/debugging purposes. You may not need it in your final code)
Update Based on your comment, it's the bar height that is tightly coupled to the value to be sorted later.
One idea is to simply pre-generate the list of numbers to sort and shuffle() them first:
class Bar{
constructor(x, height){
this.height = height;
this.size = 10;
this.x = x;
}
draw(){
fill("blue");
rect(this.x * this.size, height - (this.height * this.size), this.size, this.height * this.size);
}
}
let bars = [];
function setup() {
createCanvas(400, 400);
generateBars();
}
function generateBars(){
// array to be sorted
let barValues = [];
for(let i = 0; i < 40; i++){
// values are sorted first
barValues[i] = i;
}
// then we shuffle them: second argument = shuffle in place (replacing the old array)
shuffle(barValues, true);
// assign shuffled values to Bar instances
for(let i = 0; i < 40; i++){
bars[i] = new Bar(i, barValues[i]);
}
}
function draw() {
background(220);
for(let k = 0; k < bars.length; k++){
bars[k].draw();
}
}
function mouseClicked(){
setup();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.min.js"></script>
For my space invader like game I want to make bullets that get shot by the enemies but the problem is that the bullets dont appear in this loop that I made. I tried several things like making only one bullet appear while that works it is not the result that I want. My idea behind the code is that a new bullet gets shot from the position of the enemies when the enemybullet.position == 1 and if it exceeds the height of the canvas I want the bullet to return to the enemies and be shot again.
The code that I used for this result is here:
sketch.js
var enemies = [];
var enemybullet = [];
function setup() {
createCanvas(800, 600);
for (var i = 0; i < 2; i++) {
enemies[i] = new Enemy(i*300+300, 100);
}
// I tried enemybullet = new Enemybullet(120, 200); and that drew the bullet but it wasnt assigned to the enemy
rectMode(CENTER);
}
function draw() {
background(0);
// enemybullet.show(); this is wat I used to draw the single projectile
// enemybullet.move();
var edge = false;
for (var i = 0; i < enemies.length; i++) {
enemies[i].show();
enemies[i].move();
if(enemies[i].x > width || enemies[i].x < 0) {
edge = true;
}
}
if (edge) {
for (var i = 0; i < enemies.length; i++) {
enemies[i].shiftDown();
}
}
for (var i = 0; i < enemybullet.length; i++) {
enemybullet[i].show();
enemybullet[i].move();
for (var j = 0; j < enemies.length; j++) {
if(enemybullet[i].position == 1){
var enemybullets = new Enemybullet(enemies[j].x(), enemies[j].y());
enemybullet.push(enemybullets);
enemybullet[i].x = enemybullet[i].x;
enemybullet[i].y = enemybullet[i].y + enemybullet[i].speed;
if(enemybullet[i].y >= height){
enemybullet[i].position = 2;
}
}
else{
enemybullet[i].y = enemies[i].y;
enemybullet[i].x = enemies[i].x;
}
if(enemybullet[i].position == 2 ){
enemybullet[i].y = enemies[i].y;
enemybullet[i].x = enemies[i].x;
enemybullet[i].position = 1;
}
}
}
enemybullet.js
function Enemybullet(x, y) {
this.x = x;
this.y = y;
this.width = 10;
this.height = 20;
this.position = 1;
this.speed = 2;
this.show = function() {
fill('#ADD8E6');
rect(this.x, this.y, this.width, this.height);
}
this.move = function() {
this.x = this.x;
this.y = this.y + this.speed;
}
}
enemy.js
function Enemy(x, y) {
this.x = x;
this.y = y;
this.r = 100;
this.xdir = 1;
this.shot = function() {
this.r = this.r * 0;
this.xdir = this.xdir * 0;
}
this.shiftDown = function() {
this.xdir *= -1;
this.y += this.r/2;
}
this.show = function() {
fill('#0000FF');
rect(this.x, this.y, this.r, this.r);
}
this.move = function() {
this.x = this.x + this.xdir;
}
}
Rather than having the bullets be in their own global array, try having the bullets be a variable in the Enemy class.
this.bullet = new Enemybullet(this.x, this.y);
Then you can give the enemies functions such as the following to update the bullets.
this.updateBullet = function() {
this.bullet.move();
this.bullet.show();
}
this.resetBullet = function() {
this.bullet = new Enemybullet(this.x, this.y);
}
Where you were looping through each bullet before, you can instead call enemies[i].updateBullet(); when you move and show the enemies.
And when you want the enemies to shoot another shot, call enemies[i].resetBullet();
You can see my implementation here.
I've been trying to follow this tutorial: https://www.youtube.com/watch?v=aKYlikFAV4k&t=1848s&ab_channel=TheCodingTrain
However, I'm using vanilla Javascript. I'm struggling to get the neighboring cells for each cell in my grid. I'm pretty new to coding so help would be very much appreciated!
Here is my code so far:
//GLOBAL VARIABLES
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const wh = 600;
const cellSize = 30;
const rows = 20;
const cols = 20;
const grid = new Array(rows);
const open = [];
const closed = [];
let start;
let end;
//FUNCTIONS
//Immediately-invoked function expression
//Runs code immediately when the page loads and keeps it out of the global scope (avoids naming conflicts)
(function() {
setup();
})();
function Cell(x, y) { //Constructor function for each cell in the array
this.x = 0;
this.y = 0;
this.f = 0;
this.g = 0;
this.h = 0;
this.show = function(color) { //Function to show cell on grid
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, cellSize, cellSize);
ctx.strokeStyle = 'white';
ctx.strokeRect(this.x, this.y, cellSize, cellSize);
}
}
//Function to setup the canvas
function setup() {
let interval = setInterval(update, 120);
canvas.setAttribute('width', wh);
canvas.setAttribute('height', wh);
document.body.insertBefore(canvas, document.body.childNodes[0]); //Inserts canvas before the first element in body
createGrid();
setStartEnd();
}
//Function to create grid
function createGrid() {
for (let i = 0; i < rows; i++) { //Creating 2D array
grid[i] = new Array(cols);
}
let x = 0;
let y = 0;
for (let i = 0; i < rows; i++) { //Creating a new cell for each spot in the array
for (let j = 0; j < cols; j++) {
grid[i][j] = new Cell();
grid[i][j].x = x;
grid[i][j].y = y;
grid[i][j].show();
x = x + 1 * 30;
}
x = 0;
y = y + 1 * 30;
}
}
//Function that defines the start and end points
function setStartEnd() {
start = grid[0][0];
end = grid[cols - 1][rows - 1];
open.push(start);
}
//Function to remove a node from an array
function removeArray(arr, e) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === e) {
arr.splice(i, 1);
}
}
}
//Main function
function update() {
//nodes part of "open" array are green
for (let i = 0; i < open.length; i++) {
open[i].show('green');
}
//nodes part of "closed" array are red
for (let i = 0; i < closed.length; i++) {
closed[i].show('red');
}
}
You've made it a bit hard for yourself by having Cell not store its own x,y position in the grid.
If you move some logic from your nested i,j for loop to your Cell class, it gets easier. I modified Cell to store its x and y grid coordinate rather than pixel coordinate. You can then, in update, do something like this:
const nextOpenSet = new Set();
open.forEach(cell => {
const above = grid[cell.y - 1]?.[cell.x];
if (above) nextOpenSet.add(above);
const below = grid[cell.y + 1]?.[cell.x];
if (below) nextOpenSet.add(below);
const left = grid[cell.y][cell.x - 1];
if (left) nextOpenSet.add(left);
const right = grid[cell.y][cell.x + 1];
if (right) nextOpenSet.add(right);
});
open = Array.from(nextOpenSet);
Here's a runnable example:
//GLOBAL VARIABLES
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const wh = 600;
const cellSize = 30;
const rows = 20;
const cols = 20;
const grid = new Array(rows);
let open = [];
const closed = [];
let start;
let end;
//FUNCTIONS
//Immediately-invoked function expression
//Runs code immediately when the page loads and keeps it out of the global scope (avoids naming conflicts)
(function() {
setup();
})();
function Cell(x, y) { //Constructor function for each cell in the array
this.x = x;
this.y = y;
this.show = function(color) { //Function to show cell on grid
ctx.fillStyle = color;
ctx.fillRect(this.x * cellSize, this.y * cellSize, cellSize, cellSize);
ctx.strokeStyle = 'white';
ctx.strokeRect(this.x * cellSize, this.y * cellSize, cellSize, cellSize);
}
}
//Function to setup the canvas
function setup() {
let interval = setInterval(update, 120);
canvas.setAttribute('width', wh);
canvas.setAttribute('height', wh);
document.body.insertBefore(canvas, document.body.childNodes[0]); //Inserts canvas before the first element in body
createGrid();
setStartEnd();
}
//Function to create grid
function createGrid() {
for (let i = 0; i < rows; i++) { //Creating 2D array
grid[i] = new Array(cols);
}
for (let i = 0; i < rows; i++) { //Creating a new cell for each spot in the array
for (let j = 0; j < cols; j++) {
grid[i][j] = new Cell(i, j);
grid[i][j].show();
}
}
}
//Function that defines the start and end points
function setStartEnd() {
start = grid[0][0];
end = grid[cols - 1][rows - 1];
open.push(start);
}
//Function to remove a node from an array
function removeArray(arr, e) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === e) {
arr.splice(i, 1);
}
}
}
//Main function
function update() {
//nodes part of "open" array are green
for (let i = 0; i < open.length; i++) {
open[i].show('green');
}
//nodes part of "closed" array are red
for (let i = 0; i < closed.length; i++) {
closed[i].show('red');
}
const nextOpenSet = new Set();
open.forEach(cell => {
const above = grid[cell.y - 1]?.[cell.x];
if (above) nextOpenSet.add(above);
const below = grid[cell.y + 1]?.[cell.x];
if (below) nextOpenSet.add(below);
const left = grid[cell.y][cell.x - 1];
if (left) nextOpenSet.add(left);
const right = grid[cell.y][cell.x + 1];
if (right) nextOpenSet.add(right);
});
open = Array.from(nextOpenSet);
}
I know a bunch of people have already asked this, but nothing I have tried has worked. I have been stuck for days.
I suspect it may just be because the thing I am using (code.org) is a pile of flaming garbage, and it uses ES5. If you notice anything wrong, though, please let me know!
function Vector2(x, y)
{
this.x = x;
this.y = y;
return this;
}
function Pixel(x, y, darkness)
{
this.position = Vector2(x, y);
this.darkness = darkness;
this.rgbDarkness = this.darkness * 255;
return this;
}
function DataTexture2D(offsetX, offsetY, width, height)
{
this.offset = Vector2(offsetX, offsetY);
this.size = Vector2(width, height);
this.pixels = [];
for (var x = 0; x < width; x++)
{
this.pixels[x] = [];
for (var y = 0; y < height; y++)
{
this.pixels[x][y] = Pixel(x + this.offset.x, y + this.offset.y, 0.5);
}
}
return this;
}
var test = DataTexture2D(100, 50, 200, 300);
console.log(test.offset.x);
So in the p5js editor, I am trying to visualize a 2d array using squares. I want a square to change color via mousPressed() depending on the coordinates of the mouse in relation to the square. I am getting color changes but the square I click isn't the one that changes.
I am logging the node that I am clicking, and it seems like it is correct, but the visualization of the 2d array seems wrong.
I have a 3x3 grid of square x's such that:
x x x
x x x
x x x
I expect when I click the top left then top middle, it would change color to blue such that
o o x
x x x
x x x
But when I click the top left then the top middle, i get
x o o
x x x
x x x
it seems the square that I click changes the square next to it, rather than the one I expect.
example in p5.editor:
https://editor.p5js.org/julien24lopez/present/8_vwyHTjRW
let arr = [];
function setup(){
canvas = createCanvas(200, 200);
for(var j = 0; j < 3; j++){
var inArr = [];
for(var i = 0; i < 3; i++){
var rect = new Rect(i,j);
inArr.push(rect);
}
arr.push(inArr)
}
}
function draw(){
for(var i = 0; i < arr.length; i++){
for(var j = 0; j < arr[i].length; j++){
arr[i][j].show()
}
}
}
function mousePressed(){
arr.forEach(function(e, index){
e.forEach(function(d,index2){
arr[index][index2].clicked()
});
});
}
function Rect(i,j){
this.fill = 'red'
this.i = i;
this.j = j;
this.x = i * 20
this.y = j * 20
this.clicked = function(){
let x1 = this.x, x2 = x1 + 20,
y1 = this.y, y2 = y1 + 20;
if((mouseX>x1&&mouseX<x2)&&(mouseY>y1&&mouseY< y2)){
console.log(this)
this.fill = 'black'
}
}
this.show = function(){
rect(i*20,j*20,20,20)
fill(this.fill)
stroke('blue')
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>
You do not draw the quads at the correct position. The position of the quads is (this.x, this.y) rather than (i*20, j*20):
function Rect(i,j){
// [...]
this.show = function(){
fill(this.fill)
stroke('blue')
// rect(i*20,j*20,20,20)
rect(this.x, this.y, 20, 20)
}
}
Example:
let arr = [];
function setup(){
canvas = createCanvas(200, 200);
for(var j = 0; j < 3; j++){
var inArr = [];
for(var i = 0; i < 3; i++){
var rect = new Rect(i,j);
inArr.push(rect);
}
arr.push(inArr)
}
}
function draw(){
background(255);
for(var i = 0; i < arr.length; i++){
for(var j = 0; j < arr[i].length; j++){
arr[i][j].show()
}
}
}
function mousePressed(){
arr.forEach(function(e, index){
e.forEach(function(d,index2){
arr[index][index2].clicked()
});
});
}
function Rect(i,j){
this.fill = 'red'
this.i = i;
this.j = j;
this.x = i * 20
this.y = j * 20
this.clicked = function(){
let x1 = this.x, x2 = x1 + 20,
y1 = this.y, y2 = y1 + 20;
if( mouseX > x1 && mouseX < x2 && mouseY > y1 && mouseY < y2){
console.log(this)
this.fill = 'black'
}
}
this.show = function(){
fill(this.fill)
stroke('blue')
rect(this.x, this.y, 20, 20)
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>