How to loop a drawLine so it repeats itself 10 times - javascript

I am currently trying to create a sudoku grid in javascript, to do this I need to set up a loop so one line re-appears 10 times with a gap of 20 pixels between each one. So far I have:
var canvas;
canvas = openGraphics();
var x;
var y;
var gap;
x = 20;
y = 20;
gap = 25;
canvas.drawLine(20, 20, 20, 245);
canvas.paint();
How would you recommend to do this?

As you already stated, you have to use a looping construct.
The Mozilla Developer Network has good documentation on these.
But honestly, I think you should rather read their JavaScript Guide before trying to write a Game, otherwise you'll end up bumping into a ton of dead ends and you will soon loose the interest in making the game at all.
Also, please stay on MDN when searching looking JavaScript help, since there are a lot of sites on the Internet that have bad, old, broken code example and help.
Especially stay away from w3schools.

There are various looping constructs available to programmers, the 2 most common ones are the for loop and the while loop.
The for loop is good for "looping" a number of times and the while loop is for looping while some value is "true".
In this case, you know the number of lines that you need to draw so the for loop is best matched
This is example code for the for loop. What happens is that the code between the { and } is run multiple time. Each time the loop runs, variable i gets larger by 1, starting from 0. This continues until the condition i<numberTimesToLoop becomes false.
for(var i=0;i<numberTimesToLoop;i++)
{
document.write("i = " + i);
document.write("<br />");
}
Not that I want to do your assignment for you, but in a lot of cases its easier to learn from seeing actual code. (I demonstrate and I find plenty of students who on seeing an answer can immediately recognise it in the future. Of course I give them the theory first and if it doesn't click I try this method...)
This modification to your current code will draw your vertical lines.
var canvas;
canvas = openGraphics();
var x;
var y;
var gap;
x = 20;
y = 20;
gap = 25;
var currentX = 20;
for(var i=0;i<10;i++)
{
canvas.drawLine(currentX, 20, currentX, 245);
currentX = currentX + gap;
}
canvas.paint();
(Not really sure what the problem with the w3schools website is)

Related

How to do a task outside of draw loop in p5js

I'm trying to convert an image into a picture that only has a certain amount of colors in p5.js. I am doing this by picking num random colors. Then, I'm going through every pixel in the image with loadPixels() and giving it a score. This score is determined by how close the color is to one of the random colors. I do this by adding the difference individually from the rgb values and then choosing the lowest score. For example, if I had num = [color(100, 100, 100), color(200, 200, 200)] and I was looking at a pixel that has color(100, 150, 110) then the score would be not 240 (the difference between the image pixel and the 200 color) but instead 60. This all works fine. Next, what I'm trying to do is make sure that every pixel has a score under scoreBoundary. Originally, this variable is set to 0. If the score of a pixel is more than scoreBoundary, I alter the closest random color to bring the pixel's score under scoreBoundary. This all should work fine. After a few loops (I haven't decided how many yet, maybe it has to do with the average pixel score or something), if there is still a pixel over scoreBoundary, I increase scoreBoundary. Eventually, I should have the best picture I can have with num colors. (If you want to know, I'm trying to make a sort of Cross-Stitch Clone.)
Now for my problem. I want to make a temporary progress bar, because this method is very slow. Originally, I tried putting text that said pixelNum + " out of " + pixels.length. However, since this process was in a for loop, this didn't show up. So, I tried putting this process in the draw loop. Now the text shows up, but it's unbearably slow. After about a minute, I was maybe 1% done with the first loop (and remember, there will be thousands) because it was only performing one calculation per frame. Now I ask you two things, and either solution helps.
One, is there a way to have a process that works as fast as it can away from the draw loop? For example, can I have this process run multiple times per frame (without just adding i < previousBoundary * howMuchFasterIWantItToBe) while still being linked to draw for the progress bar?
Two, is there another way to go about this? Another library or method that reduces the number of colors in an image to num?
You don't really show any code that is reproducible to explain what issue you are having.
In any case, what you are looking for (for your first question) is an async function.
SEIZURE WARNING FOR PHOTOSENSITIVITY
Seriously, this example sketch will wreck your eyes but you can see two ellipses working on different schedules because of the async function
Importantly, I had to append the start of the sketch with /*jshint esversion: 9 */ for the editor to allow async to be used:
/*jshint esversion: 9 */
let thing = 10;
let thing2 = 10;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
drawOther();
for(let i = 0; i < 1000; i++){
if(thing <= 400){
thing += 2;
}else{
thing = 10;
}
fill(255)
stroke(0);
ellipse(width, height, thing, thing);
}
}
const drawOther = async () => {
for(let i = 0; i < 100; i++){
if(thing2 <= 400){
thing2 += 2;
}else{
thing2 = 10;
}
fill(0);
stroke(255)
ellipse(0, 0, thing2, thing2);
}
}
You can read more about async functions here but basically, it does what you want - to launch a separate thread of activity that won't block your main loop.
If you want to return anything from an async function you would need to read about await and promises as well.

draw function not looping as expected

I'm a beginner on here, so apologies in advance for naivety. I've made a simple image on Brackets using Javascript, trying to generate circles with random x and y values, and random colours. There are no issues showing when I open the browser console in Developer Tools, and when I save and refresh, it works. But I was expecting the refresh to happen on a loop through the draw function. Any clues as to where I've gone wrong?
Thanks so much
var r_x
var r_y
var r_width
var r_height
var x
var y
var z
function setup()
{
r_x = random()*500;
r_y = random()*500;
r_width = random()*200;
r_height = r_width;
x = random(1,255);
y= random(1,255);
z= random(1,255);
createCanvas(512,512);
background(255);
}
function draw()
{
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
Brackets.io is just your text editor (or IDE if you want to be technical) - so we can remove that from the equation. The next thing that baffles me is that something has to explicitly call your draw() method as well as the setup() method -
I'm thinking that you're working in some sort of library created to simplify working with the Canvas API because in the setup() method you're calling createCanvas(xcord,ycord) and that doesn't exist on it's own. If you want to rabbit hole on that task check out this medium article, it walks you thru all the requirements for creating a canvas element and then drawing on that canvas
Your also confirming that you're drawing at least 1 circle on browser refresh so i think all you need to focus on is 1)initiating your code on load and 2)a loop, and we'll just accept there is magic running in the background that will handle everything else.
At the bottom of the file you're working in add this:
// when the page loads call drawCircles(),
// i changed the name to be more descriptive and i'm passing in the number of circles i want to draw,
// the Boolean pertains to event bubbling
window.addEventListener("load", drawCircles(73), false);
In your drawCircles() method you're going to need to add the loop:
// im using a basic for loop that requires 3 things:
// initialization, condition, evaluation
// also adding a parameter that will let you determine how many circles you want to draw
function drawCircles(numCircles) {
for (let i = 0; i < numCircles; i++) {
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
}
here's a link to a codepen that i was tinkering with a while back that does a lot of the same things you are
I hope that helps - good luck on your new learning venture, it's well worth the climb!
Thank you so much for your help! What you say makes sense - I basically deleted the equivalent amount of code from a little training exercise downloaded through coursera, thinking that I could then essentially use it as an empty sandpit to play in. But there's clearly far more going on under the hood!
Thanks again!

Should this For-Loop, in theory, work?

I have a question over at collision-detection about a similar issue, but it's not exactly the same. I had an issue with a new game project (I'm trying to learn more about HTML5 Canvases and Socket.io) in which my collisions weren't working. I thought that my issue was centered on collisions, but now I'm starting to think something different. The reason I have a different issue posted here at the for-loop area is because I'm not sure if my issue is for-loop related or collision-detection related. Either way, I'd be happy to take one of my questions down.
This code is looping every frame to get the active positions of bullets and ships. If the bullet touches the ship, it'll be removed and some health points will be removed from the ship.
Tutorial I was using: http://jlongster.com/Making-Sprite-based-Games-with-Canvas
That aside, here's my checkCollisions code. It seems that the collision function is working, because when I started to log all the positions every time we had an iteration, it seemed that the position of my object was changing every single time. Is this one of those for-loop issues where I'm going to need a callback?
Thank you so much in advance for all your help. I'll be sure to upvote/select every response that helps out! :)
SOLVED! Turns out one of my arrays wasn't being passed in correctly. I'd like to thank you guys for telling me to always split it into multiple functions, that really helped me figure that one out!
// Let's start out here: I have a players[] array
//that's essentially a list of all players on the server
// and their positions. I omitted server connection functionality since that's not my error
// source.
function checkCollisions() {
for (var i = 0; i < players.length; i++) { // Iterating through all players
var pos = [players[i].posX, players[i].posY];
var size = [SHIP_WIDTH, SHIP_HEIGHT]; // This is the size of each player, it's a ship game. So these are constants.
if (players[i].userId != PLAYER.userId) { // Each player has a userId object, this is just doublechecking if we're not uselessly iterating
for (var j = 0; j < bullets.length; j++) { // We're now looping through bullets, an array of all the bullets being shot by players
var pos2 = bullets[j].pos;
var size2 = BULLET_SIZE;
var sender = bullets[j].sender;
if (boxCollides(pos, size, pos2, size2)) { // Collision code
if (sender != players[i].userId) {
bullets.splice(j, 1);
i--; // Tried here with j--, and by removing the entire line. Unfortunately it doesn't work :(
break;
}
}
}
}
}
}
Have you tried using console.log to see where the program is breaking? This might help you determine if there are multiple bugs or if it's just this one. If there's something wrong in a previous statement, you may not know it if you've fixed the i-- / j-- ...?
Edit: AH I see that you've fixed things, after I'd posted this. Well congrats and good job!

Detecting a Fist with Leap Motion SDK V2

I want to check if a Hand in a Leap Motion Frame is currently a Fist.
The usually suggested method is to look for hand.grabStrength with a value of 1. The problem is that the value jumps to 1 even with a "Claw-Like" Hand, or anything else with very slightly curled fingers.
Another approach would be to check on each finger if it is extended. But this has a similiar issue, Fingers only count as extended if they are completely straight. So even if i check for all fingers to be not extended, the same issue as above occurs (claw-like hands get recognized as grabbed).
Combining these two methods also does not solve the issue, which is not surprising given that they both suffer from the same problems.
Now, we do have all the bones of each finger available, with positions and everything. But I have no idea where to start with the math to detect if a finger is curled.
Basically I have this setup for now:
var controller = Leap.loop(function(frame){
if(frame.hands.length>0){
//we only look at the first available hand
var hand = frame.hands[0];
//we get the index finger only, but later on we should look at all 5 fingers.
var index = hands.fingers[1];
//after that we get the positions of the joints between the bones in a hand
//the position of the metacarpal bone (i.e. the base of your hand)
var carp = index.carpPosition;
//the position of the joint on the knuckle of your hand
var mcp = index.mcpPosition;
//the position of the following joint, between the proximal and the intermediate bones
var pip = index.pipPosition;
//the position of the distal bone (the very tip of your finger)
var dip = index.dipPosition;
//and now we need the angle between each of those positions, which is where i'm stuck
}
});
So, how do I get the angle between two of those positions (carp to mcp, mcp to pip, pip to dip)? Any ideas?
Alright, I think I found a sort of working approach to detect an actual fist, and not a claw.
First off, instead of the positions of the joints, we need the distance Vectors for each Bone.
Then we calculate the Dot product between the Metacarpal and the Proximal bone, as well as the dot Product between the Proximal and the Intermediate Bone. We can ignore the Distal bone, it doesn't change the result too much.
We sum all the calculated dot products (10 in total) and calculate the average out (we divide by 10). This will give us a value between 0 and 1. A Fist is beneath 0.5 and everything above that is basically not a fist.
Additionally you might also want to check for the amount of extended fingers on a Hand and check if it is 0. This will ensure that a "Thumbs-up" and similiar 1-digit poses do not get recognized as a Fist.
Here is my implementation:
const minValue = 0.5;
var controller = Leap.loop(function(frame){
if(frame.hands.length>0)
{
var hand = frame.hands[0];
var isFist = checkFist(hand);
}
});
function getExtendedFingers(hand){
var f = 0;
for(var i=0;i<hand.fingers.length;i++){
if(hand.fingers[i].extended){
f++;
}
}
return f;
}
function checkFist(hand){
var sum = 0;
for(var i=0;i<hand.fingers.length;i++){
var finger = hand.fingers[i];
var meta = finger.bones[0].direction();
var proxi = finger.bones[1].direction();
var inter = finger.bones[2].direction();
var dMetaProxi = Leap.vec3.dot(meta,proxi);
var dProxiInter = Leap.vec3.dot(proxi,inter);
sum += dMetaProxi;
sum += dProxiInter
}
sum = sum/10;
if(sum<=minValue && getExtendedFingers(hand)==0){
return true;
}else{
return false;
}
}
While this works like it should, I doubt that this is the correct and best approach to detect a Fist. So please, if you know of a better way, post it.
Solution works perfect, any chance you could explain why you divide by 10 and why the minValue is 0.5? Thanks!
Well, it doesn't work that good, to be honest. I'll soon start to work on a little project that has the goal to improve the detection of fists with Leap Motion.
Regarding your questions, We divide the sum by 10 because we have 2 Bone Joints per finger, with 5 fingers. We want the average value from the sum of all those calculations, because not all fingers will be angled in the same way. So we want some value that encompasses all of these values into a single one: the average value. Given that we have 10 calculations in total (2 per each finger, 5 fingers), we divide the sum of those calculations and there we go. We will get a value between 0 and 1.
Regarding the minValue: Trial&Error. In a project of mine, I used a value of 0.6 instead.
This is another problem of this approach: ideally a flat hand should be a value of nearly 0, while a fist should be 1.
I know it is an old topic but if you guys still around the answer could be simpler just by using sphereRadius() ;
I found "grabStrength" is good

Javascript: Simple Particle Motion, Particle Elastically Bouncing Off Other Particle

I've created this rather simple javascript; balls or 'molecules' moving around the screen. I was hoping to add to the functionality that when one ball comes into contact with another, they swap velocities. We don't need to worry about any angles, just when they come into contact with each other, the velocities swap. (Instead of changing the velocities though, in the code linked I've just coded a colour change)
I've been trying to call the function 'someplace' to recognise when the molecules touch, but I've had no luck with that. I don't really understand why.
Link to code:
http://jsbin.com/arokuz/5/
There seems to be three main problems:
The molecules seem to be randomly changing, rather than when two molecules touch.
When one sets the array to have say, 3 molecules, only two appear, the first is actually there, but unresponsive to .fillstyle changes, so invisible against the canvas
With the function method I would only be able to recognise when molecules in series (1 and 2 or 4 and 5) in the array touch...how could I check all the molecules?
You are only comparing a molecule with 2 other ones, which in fact might be anywhere.
Collision detection is a topic quite hard to solve, but if you want to have your idea
working quickly you might go for a n^2 algorithm with 2 nested for loops.
the code is quite expected :
// collision
for(var t = 0; t < molecules.length-1; t++)
for(var tt = t+1; tt < molecules.length; tt++) {
var p1 = molecules[t];
var p2 = molecules[tt];
if (sq(p1.x-p2.x) +sq(p1.y-p2.y) < sq(p1.radius+p2.radius) )
{
p1.collided = 8; // will diplay for next 8 frames
p2.collided = 8; // .
}
}
the fiddle is here :
http://jsbin.com/arokuz/10
The reason only two appear when three are made isn't because the first one doesn't render it is rather the last one doesn't, this is because of how you draw them by comparing its distance with the next one in the list - as it is the last there is no next and thus throws a null error and continues (check the console).
The reason why they seem to "randomly" detect collisions or not is because they are not checking against all other molecules - only the next in the list, unfortunately the only simply way to do it would be to go through all other balls for every ball and checking.
To get the molecules to detect distance you could use the pythagorean theorem, I typically use it such as:
var distx = Math.abs(molecule1.x - molecule2.x);
var disty = Math.abs(molecule1.x - molecule2.y);
var mindist = molecule1.radius + molecule2.radius;
return Math.sqrt(distx*distx+disty*disty) < mindist;

Categories