Picking a random item from an array? [duplicate] - javascript

This question already has answers here:
Getting a random value from a JavaScript array
(28 answers)
Closed 4 years ago.
so I'm making a small game on the HTML5 Canvas. I have an array of images which are displayed on the canvas, and a button (which is just an event listener checking if a certain area of the canvas is clicked.) When this button is clicked, I would like a random image to be selected so that I can have it perform a task (running a function, and an animation, which I will implement after the random selection is sorted).
I am assuming I can use some variant of math.random() to randomly select an image, but do I first need to assign each of the images to a value, e.g. if there was 5 images, 0 to 4?
Here is the array code:
var imageArray = new Array();
imageArray[0] = "./assets/1.png";
imageArray[1] = "./assets/2.png";
imageArray[2] = "./assets/3.png";
imageArray[3] = "./assets/4.png";
imageArray[4] = "./assets/5.png";
var box = new Image();
box.onload = function () {
ctx.drawImage(box, 50, 180, 150, 133);
ctx.drawImage(box, 220, 180, 150, 133);
ctx.drawImage(box, 390, 180, 150, 133);
ctx.drawImage(box, 50, 320, 150, 133);
ctx.drawImage(box, 220, 320, 150, 133);
ctx.drawImage(box, 390, 320, 150, 133);
ctx.drawImage(box, 50, 460, 150, 133);
ctx.drawImage(box, 220, 460, 150, 133);
ctx.drawImage(box, 390, 460, 150, 133);
};
box.src = imageArray[4];

To get a random integer, you can do the following:
Math.floor(Math.random() * max);
Where max is maximum number you want to generate, or in your case length of array. In case where max is 4 possible outputs are 0, 1, 2, 3.

you can try something like that :
Math.floor(Math.random()*imageArray.length)
it give you a random number between 0 and your array length
take a look at this, it can help you
Generating random whole numbers in JavaScript in a specific range?

Related

Create dynamic array within certain range values

I am trying to find the best way to generate an array that has the following output:
[135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 275, 276, 277 , 278, 279, 280, 281, 282, 283, 284, 285, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 675, 676, 677, 678, 679, 700, 701, 702, 703, 704, 705 ...
As you can see it has a set of limits from 140 - 280 - 420 - 560 - 700 ( adds 148 to each value)
and then there's an interval with minus 5 and plus 5 for each value.
I already tried this approach
scrollFrom = Array.from(Array(bytesIndexTo).keys()).map(i => 140 + i * 140);
That returns me:
[140, 280, 420, 560, 700, ...
However I also need the plus and minus 5 values intervals...
I also noticed it uses to much resources.
const prev = [
[135,136,137,138,139],
[275,276,277,278,279],
];
const after = [
[141,142,143,144,145],
[281,282,283,284,285],
];
for (let i = 0; i < scrollFrom.length; i++) {
scrollFrom.push( scrollFrom[i] );
}
The purpose of this array is to have a set of values that will help me to identify a certain scroll position in order to execute a function, the addition of this intervals will help me to figure the scroll position even if the user scrolls fast.
Maybe I could load the values inside a .json and load them ?
What do you think ? thanks in advance
Once you create an array of central values (eg [140, 280, 420, 560, 700]), you can use flatMap to iterate over each item and construct another array of the 5 values below and above it:
const bytesIndexTo = 4;
const result = Array.from(
{ length: bytesIndexTo },
(_, i) => (i + 1) * 140
)
.flatMap(num => Array.from(
{ length: 11 },
(_, j) => num - 5 + j
));
console.log(result);
So, if you all you really want to do is to be able to test if a number is within 5 of a sentinel multiple, then I don't think you really want to be generating a giant array and using .includes(). That would be slow. If you were going to pre-generate values, you should use a Set and then use .has() which should be a lot faster than .includes() for a large set of data.
But, it seems to be that you can just calculate a lot faster without doing any pre-generation at all.
In the code below, we divide by the multiple (140) and then look at the remainder. If the remainder is <=5 or >= 135, then it's within 5 of the multiple, otherwise not. It's really that simple. Since it appears you don't want the numbers 0-5 (around the zero multiple) to be counted as true, we add a special case for those.
// tests to see if a value is within 5 of a multiple of 140
const multiple = 140;
const over = 5;
const below = multiple - over;
function testValue(val) {
if (val < below) return false;
const delta = val % multiple; // divide by multiple, get remainder
return (delta <= over || delta >= below); // see if remainder in right range
}
// run some tests on numbers at edges of the interval ranges
[
0, 1,
134, 135, 140, 144, 145, 146, // around 140
274, 275, 280, 284, 285, 286, // around 280
414, 415, 420, 424, 425, 426, // around 420
554, 555, 560, 564, 565, 566 // around 560
].forEach(num => {
console.log(`${num}: ${testValue(num)}`);
});

Creating a piano in p5.js

I am creating a piano using p5.js. I need help with the color change. When a user presses a key, I want the key to flash a quick color change to let them know that they pressed the key.
In my code, the color does change when you click on the first key, however, when I click a little bit outside the first key, the first key still changes color.
Is my distance a little off? Or is there a more effective way to do this?
function setup() {
createCanvas(990, 600);
}
function draw() {
background(220);
fill(255);
rect(0, 300, 70, 400);
rect(70, 300, 70, 400);
rect(140, 300, 70, 400);
rect(210, 300, 70, 400);
rect(280, 300, 70, 400);
rect(350, 300, 70, 400);
rect(420, 300, 70, 400);
rect(490, 300, 70, 400);
rect(560, 300, 70, 400);
rect(630, 300, 70, 400);
rect(700, 300, 70, 400);
rect(770, 300, 70, 400);
rect(840, 300, 70, 400);
rect(910, 300, 70, 400);
fill(0);
rect(50, 300, 38, 180);
rect(120, 300, 38, 180);
rect(260, 300, 38, 180);
rect(330, 300, 38, 180);
rect(400, 300, 38, 180);
rect(540, 300, 38, 180);
rect(610, 300, 38, 180);
rect(750, 300, 38, 180);
rect(820, 300, 38, 180);
rect(890, 300, 38, 180);
text("mouse x: "+mouseX+" mouse y:"+mouseY, width/2,height-30);
}
function mousePressed() {
cursor(HAND);
}
function mouseReleased() {
cursor(ARROW);
let d = dist(mouseX, mouseY, 0, 300);
if (d < 300) {
fill(0);
rect(0, 300, 70, 400);
}
}
You're checking whether the mouse position is withing 300 pixels of the point 0,300. This sets up a circle with a center of 0,300 and a radius of 300. Try drawing that in your scene to see where your clickable area is.
Your keys are rectangles, so you should be using point-rectangle intersection to check whether the mouse is inside a particular key. Google is your friend here, but basically you want to check whether mouseX is between the left and right edges, and mouseY is between the top and bottom edges.
Finally, note that you're only ever showing the "flash" for a single frame. I personally can't even see it. You probably want to show the flash for longer, using the millis() function or the frameCount variable for timing. (Again, Google is your friend!)
Shameless self-promotion: here is a tutorial on collision detection, including point-rectangle intersection. It's for Processing, but the ideas are the same in P5.js.

Add a background image to an SVG

I am using Snap.svg and trying to add a background image to a polygon.
The polygon is as follows:
<svg id="test" height="600" width="600" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="" class=""></svg>
var polygon = s.polyline(200, 286, 250, 200, 350, 200, 400, 286, 350, 373, 250, 373);
I have tried a bunch of different ways to make the background image but none of them work:
polygon.attr(
{
fill: 'url(http://csshexagon.com/img/meow.jpg)'
});
polygon.attr('xlink:href', 'url(http://csshexagon.com/img/meow.jpg)');
Any ideas? Thanks.
There's a couple of bits you need to do. If using Snap, make sure you are using the latest version, so 'toPattern()' works.
Then we can draw the image, convert it to a pattern, and then fill the polygon with the pattern.
var polygon = paper.polyline(200, 286, 250, 200, 350, 200, 400, 286, 350, 373, 250, 373);
var img = paper.image('https://i.imgur.com/LQIsf.jpg', 150, 200, 250, 250)
var p = img.toPattern( 0,0,400,400 );
polygon.attr({ fill: p })
jsfiddle

fabric js: Polygon perPixelTargetFind

I'm creating a Polygon with fabric.js and set its value "perPixelTargetFind" true.
When you click, for example, on the right top end (not inside the polygon, inside its bounding box), the polygon gets selcected, although "perPixelTargetFind" is set ( I though with this value it is only possible to select an object by directly clicking on it).
The polygon should only be selected, if you click directly on it, is this possible?
Here is a link to the issue on jsfiddle: Polygon perPixelTargetFind
And here is my code so far:
var canvas = new fabric.Canvas('canvas');
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
document.getElementById("canvas").tabIndex = 1000;
var pol = new fabric.Polygon([
{x: 200, y: 0},
{x: 250, y: 50},
{x: 250, y: 100},
{x: 150, y: 100},
{x: 150, y: 50} ], {
left: 250,
top: 150,
fill: 'green',
perPixelTargetFind: true
}
);
canvas.add(pol);
thank you for your help! :)

Place an Image inside a Polygon with Snap.svg

I have a polygon (in fact it's a hexagon) painted with Adobe's Snap.svg:
var s = Snap('#test');
var hexagon = s.paper.polygon([
0, 50,
50, 0,
100, 0,
150, 50,
100, 100,
50, 100,
0, 50
]);
hexagon.attr({
stroke: '#fff',
strokeWidth: 1
});
Instead of filling the polygon with some paint, I want to place an image inside of it. The only thing I have found in the docs is the image function, but I don't know how to insert it. Anyone any idea?
======
Final Solution:
var image = s.paper.image('http://placekitten.com/g/200/300', 0, 0, 150, 150);
image = image.pattern(0, 0, 150, 150);
...
hexagon.attr({
stroke: '#fff',
strokeWidth: 1,
fill: image
});
You can't directly fill an element with an image you have to go via a pattern.
What this means is that you need to create a pattern that contains an image and then fill the shape with the pattern.

Categories

Resources