How to draw map from pixel array - javascript
I'm trying to load a map from a image, I get the hex codes for every pixel on my image, which is put into map[]. The world[] will store 1 or 0 or whatever number for number of sprite on the spritesheet. If the color is #8aff00 then it will store 0 for grass. The map is 16 by 16 pixels, which is my world size. When I try to make the world array, the for statement is working right, there is no errors. I know I have all the data, but this part of my function is not working, it just stops after these for statements:
function createWorld() {
for (var y=0; y < worldHeight; y++) {
for (var x=0; x < worldWidth; x++) {
if (map[pl] == '#8aff00') world[x][y] = 0;
if (map[pl] == '#000000') world[x][y] = 1;
pl+=4;
}
}
alert('about to draw');
draw();
}
The alert never gets called. When I displayed the x and y, it went '0,0' to '1,0' then back to '0,0' for the value x and y. The pl is for which number of the array I want. When I put another for statement to handle that it messed up more. Is there something wrong with the code, if you need more of the code just let me know.
I've managed to build code which is working.
Now it's Your turn to implement it as You need.
worldHeight = 16;
worldWidth = 16;
world = {};
map = ['#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000','#8aff00','#000000']
pl = 0
function draw(){
console.log(world);
}
function createWorld() {
for (var y=0; y < worldHeight; y++) {
for (var x=0; x < worldWidth; x++) {
if (map[pl] == '#8aff00')
world[x] = 0;
world[x][y] = 0;
if (map[pl] == '#000000')
world[x] = 0;
world[x][y] = 1;
pl+=4;
}
}
alert('about to draw');
draw();
}
createWorld();
Cheers.
Related
3d array movement in p5.js?
I'm in dire need of help with a graduation project that I'm working on. What I'm trying to achieve here in the code below is -to put it very simply- to initialize a 3d array of box() objects (this works) and then introduce another box() object (the end goal is to have an array of these as well) to move about within the same 3D grid. The moving unit picks a random location for initialization and a random target for destination (both within the 3D grid). But the problem is that I need the moving unit not to overlap with the static base units, also move orthogonally, and always move one unit size each time. If I run the code below the moving unit reaches the target but without any of the restrictions that I mentioned above. It just takes the shortest vector and goes there regardless. PS: Since p5js doesn't support wireframe in webgl mode I tried to show them with some transparency for better visual legibility. Although, the loadImage() functions are still there and could be replaced with any image of your liking to better differentiate units from one another. I'd sincerely appreciate help with this since I'm also very short on time. Thanks in advance. Here's the verifiable code: var matrixSize = 5; var locations = new Array(matrixSize); var locBool = new Array(matrixSize); //unit stuff var unitSize = 40; var units_a = [] var units_b; function setup() { createCanvas(windowWidth, windowHeight, WEBGL); //3D array of location vectors & booleans for(var i = 0; i < locations.length; i++){ locations[i] = new Array(matrixSize); locBool[i] = new Array(matrixSize); for(var j = 0; j < locations[i].length; j++){ locations[i][j] = new Array(matrixSize); locBool[i][j] = new Array(matrixSize); for(var k = 0; k < locations[i][j].length; k++){ locations[i][j][k] = createVector(i*unitSize, j*unitSize, k*unitSize); locBool[i][j][k] = false; } } } //base units var threshold = 2; //decides on the percentage to be initialized for (var i = 0; i < matrixSize; i++) { for(var j = 0; j < matrixSize; j++){ for(var k = 0; k < matrixSize; k++){ stateRndm = random(10); if(stateRndm <= threshold){ state = 1; locBool[i][j][k] = true; }else{ state = 0 } units_a.push(new UnitOne( i*unitSize,j*unitSize,k*unitSize, state)); } } } units_b = new UnitTwo(); } function draw() { background(20); ambientLight(235); orbitControl(); rotateX(10); rotateY(-10); rotateZ(0); //center the window and display the units push(); translate(-unitSize*matrixSize/2, -unitSize*matrixSize/2, 0); for(var i = 0; i < units_a.length; i++){ units_a[i].display(); } units_b.display(); units_b.update(); units_b.move(); pop(); } function UnitOne (x, y, z, state){ this.x = x; this.y = y; this.z = z; this.state = state; //this.img = loadImage("assets/tex_1.jpg"); //basic movement parameters this.acceleration = createVector(); this.velocity = createVector(); this.location = createVector(this.x, this.y, this.z); this.update = function(){ this.velocity.add(this.acceleration); this.location.add(this.velocity); this.acceleration.mult(0); } this.display = function(){ if(this.state == 1){ push(); scale(1); //texture(this.img); ambientMaterial(50, 200, 100, 20); translate(this.x, this.y, this.z); box(unitSize); pop(); } } } function UnitTwo() { //assign random initial location this.selector; for(var i = 0; i < locations.length; i++){ for(var j = 0; j < locations[i].length; j++){ for(var k = 0; k < locations[i][j].length; k++){ this.selector = createVector( floor(random(i))*unitSize, floor(random(j))*unitSize, floor(random(k))*unitSize); } } } print(this.selector); //assign random target this.targetSelector; for(var i = 0; i < locations.length; i++){ for(var j = 0; j < locations[i].length; j++){ for(var k = 0; k < locations[i][j].length; k++){ this.targetSelector = createVector( floor(random(i))*unitSize, floor(random(j))*unitSize, floor(random(k))*unitSize); } } } print(this.targetSelector); //basic movement parameters this.location = createVector( this.selector.x, this.selector.y, this.selector.z); this.acceleration = createVector(); this.velocity = createVector(); this.maxSpeed = 1; this.maxForce = 2; //this.img = loadImage("assets/tex_2.jpg"); this.display = function(){ push(); //texture(this.img); ambientMaterial(200, 100, 40); translate(this.location.x, this.location.y, this.location.z); scale(1); box(unitSize); pop(); } this.update = function(){ this.velocity.add(this.acceleration); this.location.add(this.velocity); this.acceleration.mult(0); } } UnitTwo.prototype.move = function(){ var target = createVector(this.targetSelector.x, this.targetSelector.y, this.targetSelector.z); var desired = p5.Vector.sub(target, this.location); var d = desired.mag(); //check the distance to slow down if (d < unitSize/2) desired.setMag(this.maxSpeed/2); else desired.setMag(this.maxSpeed); var steer = p5.Vector.sub(desired, this.velocity); steer.limit(this.maxForce); this.acceleration.add(steer); }
You've outlined both things you need to do. Which part of them are you stuck on? Step 1: Make your unit move one cube at a time. You could do this by simply adding or subtracting 1 to its x, y, or z coordinate. Get this working first. Don't worry about avoiding collisions with the other cubes yet. Step 2: When you get that working, add code that detects when the cube it's about to move to is occupied, and go in a different direction. You might have to implement a basic path finding algorithm, and Google is your friend for that. You might also want to consider the possibility that your random generation has blocked all of the paths to the goal. What do you want to do in that case? And one more note: you don't need a triple-nested for loop just to generate a random value. If you get stuck on one of these steps, please narrow your problem down to a MCVE showing just that step before you post again. Good luck.
Using arrays for tetris pieces and grid. Why won't this piece show up completely?
Here's the code, below is a link to the jsfiddle. The first row of the block isn't drawn for some reason, all these 2 dimension for loops are hard for me to wrap my head around, and can't find the reason why the block is only being drawn from the second row and not complete. The add_block function is supposed to read array data from any block and put it on the grid where my x and y coordinates are. If there's anyone who knows how to rotate the block, that would be cool too, i know in order to turn something +90 degrees i need to transpose and then revese each row, but it hasn't really worked in earlier tries. I know i'm not good at explaining but i'll be sure to answer any of your questions. Thanks in advance! I really want to have a complete picture of how arrays and double for loops interact with eachother, in my head. var canvas = document.getElementById('c'); var ctx = canvas.getContext('2d'); canvas.width = 300; canvas.height = 500; var grid_columns = 10; var grid_rows = 15; var grid_cell_size = 10; var grid = []; function create_empty_grid(){ for(var i=0;i<grid_columns;i++){ grid[i] = []; for(var j=0;j<grid_rows;j++){ grid[i][j] = 0; } } // END DOUBLE FOR LOOPS } function clear_grid(){ for(var i=0;i<grid_columns;i++){ for(var j=0;j<grid_rows;j++){ grid[i][j] = 0; } } // END DOUBLE FOR LOOPS } var x = 0; var y = 0; var w = 2; var h = 3; var block = []; block[0] = [ [1,0,0,0], [1,1,0,0], [0,1,0,0], [0,0,0,0] ]; function add_block(num){ var b = block[num]; for(var i=0;i<w;i++){ for(var j=0;j<h;j++){ if(i >= x && j >= y && i <= w && j <= h){ grid[i][j] = b[i][j]; } } } // END DOUBLE FOR LOOPS } function draw(){ for(var i=0;i<grid_columns;i++){ for(var j=0;j<grid_rows;j++){ ctx.fillStyle = "black"; if(grid[i][j] === 1){ ctx.fillStyle = "red"; }else if(grid[i][j] === 0){ ctx.fillStyle = "green"; } ctx.fillRect(i*grid_cell_size,j*grid_cell_size,grid_cell_size-1,grid_cell_size-1); } } // END DOUBLE FOR LOOP } function update(){ } function tick(){ clearRect(0,0,canvas.width,canvas.height); clear_grid(); draw(); update(); } create_empty_grid(); add_block(0); draw(); View in jsfiddle
It seems like you're using i and j to represent "block" coordinates, and x and y to represent "grid" coordinates. So I think this condition is wrong: if(i >= x && j >= y && i <= w && j <= h){ grid[i][j] = b[i][j]; } I think all you really need here is to replace the if statement with something like: grid[i+x][j+y] = b[i][j]; But as #Arnauld pointed out, there is also a bit of confusion about whether i,j denotes "row, column" or "column, row", and it looks like your usage is opposite from the way the arrays are initialized. In other words, you're using: grid[row][column] and b[row][column] but the way you laid out the arrays, it needs to be grid[column][row] and b[column][row] So you'll need to make a few adjustments here and there to make the code do what you want.
The "b" arrays were upside-down for some reason so i changed grid[j+x][i+y] = b[j][i] to grid[j+x][i+y] = b[i][j] this displays the full block, but i still can't visualise the arrays or be able to prevent these problems in the future. Arrays are so confusing to me. I'll figure it out eventually i guess, but a day has to go by.
scriptProcessorNode oscillator frequency
I am working on a web audio stochastic oscillator and am having trouble with the scriptProcessorNode. My algorithm uses a random walk to determine dynamic breakpoints in the waveform and then interpolates between them. As the breakpoints move on the x axis I thought the frequency of the oscillating waveform would change, but there is just a filtering effect, and the frequency seems to just be determined by the scriptProcessorNode buffer size, which must be a power of 2 between 256 and 16384. How do you change the frequency of a scriptProcessorNode oscillator? Here is my synthesis code: scriptNode.onaudioprocess = function(audioProcessingEvent) { walk(); //use random walk to generate new x/y position for each breakpoint var outputBuffer = audioProcessingEvent.outputBuffer; var lastPoint = 0; var index = 0; // linearly interpolate between the new breakpoint positions for(var i = 0; i < breakpoint.length-1; i++) { var y = breakpoint[lastPoint].y; for(var channel = 0; channel <= 0;channel++) { var outputData = outputBuffer.getChannelData(channel); if(i != 0){ if(y >= breakpoint[i].y) { while(y >= breakpoint[i].y) { y = (breakpoint[i].m*index)+breakpoint[i].b;// y = m(x)+b outputData[index] = y; index++; } } else if(y <= breakpoint[i].y) { while(y <= breakpoint[i].y) { y = (breakpoint[i].m*index)+breakpoint[i].b; outputData[index] = y; index++; } } } } lastPoint = i; } } And here is a link to a working example: http://andrewbernste.in/bernie/gendy011.html This is all based on Iannis Xenakis' GENDY stochastic synthesis program. Thanks!
I solved the problem by using an index variable outside of my scriptNode.onaudioprocess function to write the waveform to the scriptNode buffer. That way the frequency at which the waveform is written to the buffer is not tied to the size of the buffer. Here is the final code: var index = 0; var freq = 0.8; scriptNode.onaudioprocess = function(audioProcessingEvent){ var outputBuffer = audioProcessingEvent.outputBuffer; var outputData = outputBuffer.getChannelData(0); for(var j = 0; j < outputData.length;j++){ // linearly interpolate between the new breakpoint positions // get the interp point by comparing index to the x distance var lerp = (index - breakpoint[point].x) / (breakpoint[point+1].x - breakpoint[point].x) y = nx.interp(lerp,breakpoint[point].y,breakpoint[point+1].y); if(point < breakpoint.length && index >= breakpoint[point+1].x) { point++; } outputData[j] = y; index+=freq; if(index >= breakpoint[breakpoint.length-1].x){ index = 0; point = 0; walk(); } } }
Loop through imagedata in a HTM5 canvas vertically
I am trying to loop into a canvas vertically. I mean, Looping through the first column, the the 2nd, etc. My first goal is to colorize the first half of the width. My code is acting weird and the problem is... I do not know why! loopVertical = function (data, canvas){ for (var x = 0; x < canvas.width*2; x+=4) { for (var y = 0; y < canvas.height; y++) { data[x+y*canvas.width*4] = 255; } } return data; } The result: red stripes on my image. And that's not what I want. After I will need to divide the image in smaller images if I have a vertical line of transparent pixels, but this is not the topic of the question :)
I don't really know about html5 canvas and the image data, but according to this tutorial, my guess is that your outer loop is wrong. Apparently, you also need to take care of operator precedence when calculating the index of your data. Maybe something like : loopVertical = function (data, canvas){ // first half of the width for (var x = 0; x < canvas.width / 2; x++) { for (var y = 0; y < canvas.height; y++) { data[(x+y*canvas.width)*4] = 255; } } return data; }
Improve function speed
I'm doing a BattleShip game in javascript with iio engine. I'm trying to play against a computer so I have to put a random position for the ships (I hope you know the game :) ). I have 5 ships that have to be placed in a grid (10x10). The problem is that the function is pretty slow, and sometimes the page don't get load at all. I want to know if there are some emprovement for the speed of these function, I'm a little bit newbie :D function posShips(size){ // var size -> size of the ship var isOk = false; // flag var to check if the ship is in a right position var isOk2 = true; // flag var, become false if the cell is already fill with another ship var i; var j; var side; // horizontal or vertical while(!isOk){ i = iio.getRandomInt(1,11); j = iio.getRandomInt(1,11); side = iio.getRandomInt(0,2); if((side ? j : i)+size-1 < 11){ // Not out of the array for (var k = 0; k < size; k++) { // Size of the ship if(side){ if(gridHit[i][j+k].stat == "empty"){ //If is empty put the ship gridHit[i][j+k].stat = "ship"; gridHit[i][j+k].setFillStyle("red") }else{ // If not empty isOk2 = false; //Position is not good, do all the thing again. for (var a = 0; a < size; a++) { // Reset cell gridHit[i][j+a].stat = "empty"; } k = 10; } }else{ if(gridHit[i+k][j].stat == "empty"){ //If is empty put the ship gridHit[i+k][j].stat = "ship"; gridHit[i+k][j].setFillStyle("red") }else{ // If not empty isOk2 = false; //Position is not good, do all the thing again. for (var a = 0; a < size; a++) { // Reset cell gridHit[i+a][j].stat = "empty"; } k = 10; } } }; if(isOk2) isOk = true; } } }
Don't pick ship positions that will fall outside the grid. Pick the direction first, and then limit the x and y initial positions based on size. e.g. if the size is 3, there's no point going above 7 for the initial value of the varying coordinate. Don't change the array while you're searching. Do the search first, and only afterwards update the array. This avoids any "cleanup" operation. Wherever possible, eliminate repeated deep object references. If accessing grid[y][x] repeatedly for differing x, take a reference to grid[y] first, and then use that for the subsequent accesses. Break out of loops early, there's no point continuing to test a position if a previous one already failed. Place your big ships first - it's easier to fit small ships into the gaps left between the big ones. See http://jsfiddle.net/alnitak/Rp9Ke/ for my implementation, with the equivalent of your function being this: this.place = function(size) { // faster array access var g = this.grid; // initial direction, and vector var dir = rand(2); // 0 - y, 1 - x var dx = dir ? 1 : 0; var dy = dir ? 0 : 1; // or 1 - dx LOOP: while (true) { // initial position var x = dir ? rand(10 - size) : rand(10); var y = dir ? rand(10) : rand(10 - size); // test points var n = size, tx = x, ty = y; while (n--) { if (g[ty][tx]) continue LOOP; tx += dx; ty += dy; } // fill points n = size; while (n--) { g[y][x] = size; x += dx; y += dy; } break; } };