I am learning user input through mouse in p5.js and i want to create a square by 4 line method on 4 different clicks , 1 click for each line and the last click completing the square.
below code is for 2 lines but the are both running at the same time and i cannot understand the if command to separately run them .
function setup() {
createCanvas(400, 400);
background(220);
}
function draw() {
}
function mousePressed()
{
line(width/20,height/40,mouseX,mouseY);
line(pmouseX,pmouseY,mouseX,mouseY);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
You've to store the points to a list. If the list contains 4 elements and the mouse is clicked again, clear the list:
var pts = [];
function mousePressed()
{
if (pts.length == 4) {
pts = [];
}
pts.push([mouseX, mouseY])
}
Do all the drawing continuously in draw(). Clear the background. Draw the liens between the points ins a loop. If the number of point is 4, the draw a line from the last point to the 1st point.
Additionally you can draw a "rubber" line from the last point to the current mouse position, if there is at least 1 point in the list:
function draw() {
background(220);
// draw the lines between the points
for (var i=0; i < pts.length-1; ++i) {
line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1]);
}
var close = pts.length == 4;
if (close) {
// draw line from 1st point to at point
line(pts[pts.length-1][0], pts[pts.length-1][1], pts[0][0], pts[0][1]);
}
else if (pts.length > 0) {
// draw a rubber line from last point to the mouse
line(pts[pts.length-1][0], pts[pts.length-1][1], mouseX,mouseY);
}
}
See the example
function setup() {
createCanvas(400, 400);
}
var pts = [];
function mousePressed()
{
if (pts.length == 4) {
pts = [];
}
pts.push([mouseX, mouseY])
}
function draw() {
background(220);
// draw the lines between the points
for (var i=0; i < pts.length-1; ++i) {
line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1]);
}
var close = pts.length == 4;
if (close) {
// draw line from 1st point to at point
line(pts[pts.length-1][0], pts[pts.length-1][1], pts[0][0], pts[0][1]);
}
else if (pts.length > 0) {
// draw a rubber line from last point to the mouse
line(pts[pts.length-1][0], pts[pts.length-1][1], mouseX,mouseY);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
Related
I am creating a 24a2 browser game. I want to add another area to the game where you can not only draw using the key pad, but also when clicking on the dots, the dots within the 24x24 grid fill with the corresponding color. Here is the code:
function create(game) {}
function update(game) {}
function onKeyPress(direction) {}
let seen = {};
let config = {
create: create,
update: update,
onKeyPress: onKeyPress,
onButtonPress: onButtonPress
};
let game = new Game(config);
game.run();
let player = {};
function onButtonPress(x, y) {
game.setDot(x, y, Color.Black)
}
function create(game) {
player = {
x: 5,
y: 10,
};
game.setDot(player.x, player.y, Color.Blue);
}
function update(game) {
for (var key in seen) {
let coordinates = seen[key];
game.setDot(coordinates[0], coordinates[1], Color.Indigo);
}
game.setDot(player.x, player.y, Color.Black);
}
// Drawing using the dot with a specific color
function onKeyPress(direction) {
let key = player.x + ',' + player.y; // setting a delimeter; if the position is 1,11 for example, the dot will move to 1, 11 and not '111'.
seen[key] = [player.x, player.y];
if (direction == Direction.Up) {
player.y--;
}
if (direction == Direction.Down) {
player.y++;
}
if (direction == Direction.Left) {
player.x--;
}
if (direction == Direction.Right) {
player.x++;
}
}
This code moves the black dot around to fill the grid with color. This is the code I was thinking about in order to fill the dots when clicked.
function onButtonPressed(x, y) {
game.setDot(x, y, Color.Yellow)
}
However, when I run this, the dots do not fill when I click on them. Where am I going wrong with this?
I am having trouble creating a line in p5/matter.js. My sketch is available on the p5 editor. On mousePressed and mouseDragged, the code grabs the mouse position every ten moves and uses curveVertex to draw a line between the current and last point. All of these points are stored in an array. This draws on the canvas perfectly but cannot interact with other objects.
function mouseDragged(){
if (pointCount == 0) {
points.push({x: mouseX, y: mouseY});
pointCount += 1;
} else if (pointCount == 10) {
pointCount = 0;
} else {
pointCount += 1;
}
}
function mousePressed(){
points.push({x: mouseX, y: mouseY});
}
function mouseReleased(){
line = new Line(points);
console.log(points);
}
function draw() {
background("#efefef");
circles.push(new Circle(200, 50, random(5, 10)));
Engine.update(engine);
for (let i = 0; i < circles.length; i++) {
circles[i].show();
if (circles[i].isOffScreen()) {
circles[i].removeFromWorld();
circles.splice(i, 1);
i--;
}
}
// for (let i = 0; i < boundaries.length; i++) {
// boundaries[i].show();
// // console.log(boundaries[i].body.isStatic)
// }
if (points.length > 0) {
// Loop through creating line segments
beginShape();
noFill();
// Add the first point
stroke('black');
strokeWeight(5);
curveVertex(points[0].x,points[0].y)
curveVertex(points[0].x,points[0].y)
// Draw line
points.forEach(function(p){
curveVertex(p.x,p.y);
})
vertex(points[points.length-1].x,points[points.length-1].y) // Duplicate ending point
endShape()
}
// Draw points for visualization
stroke('#ff9900')
strokeWeight(10)
// points.push({x: x, y: y})
points.forEach(function(p){
point(p.x, p.y)
})
}
I tried creating a class and passed the points array to it, thinking that the matter.vertices function would take the points and make the needed body for the falling balls to bounce off. The code does not throw an error, but no collision occurs with the line. The example provided in matter.js document for the vertices function is unavailable and I have been unable to find any examples online. Hoping someone can point me in the right direction to get the created line to interact with the falling balls.
class Line {
constructor(vertices) {
let options = {
friction:0,
restitution: 0.95,
// angle: a,
isStatic: true
}
this.body = Matter.Body.create(options);
this.v = Matter.Vertices.create(vertices, this.body)
World.add(world, this.body);
}
}
I am trying to hide the video (webcam in this case) but keep the detected points of the hand. I have tried different methods, but I am unsuccessful so far. I appreciate the help.
Main code (below) from ml5.js can be found and tested live here: https://editor.p5js.org/ml5/sketches/Handpose_Webcam
let handpose;
let video;
let predictions = [];
function setup() {
createCanvas(640, 480);
video = createCapture(VIDEO);
video.size(width, height);
handpose = ml5.handpose(video, modelReady);
// This sets up an event that fills the global variable "predictions"
// with an array every time new hand poses are detected
handpose.on("predict", results => {
predictions = results;
});
// Hide the video element, and just show the canvas
video.hide();
}
function modelReady() {
console.log("Model ready!");
}
function draw() {
image(video, 0, 0, width, height);
// We can call both functions to draw all keypoints and the skeletons
drawKeypoints();
}
// A function to draw ellipses over the detected keypoints
function drawKeypoints() {
for (let i = 0; i < predictions.length; i += 1) {
const prediction = predictions[i];
for (let j = 0; j < prediction.landmarks.length; j += 1) {
const keypoint = prediction.landmarks[j];
fill(0, 255, 0);
noStroke();
ellipse(keypoint[0], keypoint[1], 10, 10);
}
}
}
Yes, just stop drawing it to the canvas, and add a call to background to fill the canvas.
function draw() {
// image(video, 0, 0, width, height); // <- just delete this line
background(255);
// We can call both functions to draw all keypoints and the skeletons
drawKeypoints();
}
https://editor.p5js.org/Samathingamajig/sketches/BV_kqU0Ik
I want to animate a growing line based on a dataset, I want the line to grow each time the program finds DAE in a Row of the third column.
Here is my p5js code here
let data;
let font;
let direction;
let montant;
let annee;
function preload() {
data=loadTable('data/subvention.csv','csv','header',chargementOK,chargementERROR);
font = loadFont("data/opensans.ttf");
}
function setup() {
createCanvas(700, 700);
}
function draw() {
background(1);
let nbDAE=0;
for (let i = 0; i < data.getRowCount(); i++) {
direction = data.getString(i, "direction");
if (direction == "DAE") {
nbDAE++;
fill(255);
rect(350, 700- nbDAE*12, 20, 700);
}
}
}
function chargementOK(mesData){
print("chargement OK");
print(mesData);
}
function chargementERROR(){
print("BUGG");
}
The problem is I think I did everything right but I'm not getting any animation from it, the line just appears and code keeps on going forever.
I need some help to figure out how to properly animate the growing line.
The draw() loop is executed 60 times per second, and in each loop, you have another loop wich totalizes all the values.
If you want to animate, you need to use a counter and increment it each draw() loop.
Initialization of counter and nbDAE should be at the exterior of the draw() loop.
function draw() {
background(0);
direction = data.getString(compteur, "direction");
if (direction == "DAE") {
nbDAE++;
}
fill(255);
rect(350, 700- nbDAE*12, 20, 700);
compteur += 1;
if (compteur >= data.getRowCount()) {
noLoop();
}
}
I had worked on your previous question : here on the p5js web editor
And on your previous question, the problem of csv file : In french, the separator is semicolon (;) and not comma (,). So, in the loadTable() function, the extension should be 'ssv' and not 'csv' (semicolon-separated values)
I want to create a mobile web page where a shape appears on the screen, the user can only traces over the outline of the shape with his/her finger and then a new shape will appear. This library has a few good examples of what I am looking to do, just with more shapes. I have already found a couple of good examples for drawing on the canvas on a touch device here and here. The thing I don't know is how to constrain the line so you are only drawing on the path with a single continuous line. Is there something built in that will let me specify the only path you can draw, or do I have to write that logic by hand?
We can split the issue into two parts :
1) knowing if the user is on the path.
2) knowing if the user went on all path parts.
For 1), we can use the isPointInPath context2D method to know if the mouse/touch point (x,y) is on the curve. The constraint here is that you must build a closed surface, meaning a surface drawn by a fill(), not one built with a stroke(). So in case you are stroking thick lines, you have to do some little math to build the corresponding figures out of moveTo+lineTo+fill.
For 2) : build a list of 'check-points' for your shape. You might have, for instance 8 control points for a circle. Then decide of a distance at which the user will 'activate' the check point. Now the algorithm is, in pseudo-code:
mouseDown => check()
mouseMove => if mouse is down, check()
checkPointList = [ [ 10, 40, false ] , [ centerX, centerY, isChecked], ... ] ;
checked = 0;
function check() {
clear screen
draw the path
if (mouse down and mouse point on path) {
for ( checkPoint in CheckPointList) {
if (checkPoint near enough of mouse) {
checkPoint[3]=true;
checked++;
}
}
if (checked == checkPointList.length) ==>>> User DID draw all the shape.
} else
clear the flags of the checkPointList;
checked=0;
}
I did a moooost simple demo here, which quites work.
The control points are shown in red when disactivated, green when activated :
http://jsbin.com/wekaxiguwiyo/1/edit?js,output
// boilerplate
var cv = document.getElementById('cv');
var ctx = cv.getContext('2d');
function draw() {
ctx.clearRect(0,0,300,300);
drawShape();
drawCP();
}
// Shape
function drawShape() {
ctx.beginPath();
ctx.moveTo(30,5);
ctx.lineTo(80,5);
ctx.lineTo(80, 300);
ctx.lineTo(30,300);
ctx.closePath();
ctx.lineWidth= 16;
ctx.fillStyle='#000';
ctx.fill();
}
// Control points
var points = [ [50, 50, false], [50,120, false], [50, 190, false],[50,260, false ] ];
var pointsCount = 0;
function drawCP() {
for (var i=0; i<points.length; i++) {
var p = points[i];
ctx.fillStyle=p[2]?'#0F0':'#F00';
ctx.fillRect(p[0]-1, p[1]-1, 2, 2);
}
}
function resetCP() {
for (var i=0; i<points.length; i++) {
points[i][2]=false;
}
pointsCount=0;
}
function testCP(x,y) {
var d=30;
d=sq(d);
for (var i=0; i<points.length; i++) {
if (sq(points[i][0]-x)+sq(points[i][1]-y)<d) {
if (!points[i][2]) pointsCount++;
points[i][2]=true
};
}
}
function sq(x) { return x*x; }
//
draw();
// most simple event handling
addEventListener('mousemove', mouseMove);
var r = cv.getBoundingClientRect();
function mouseMove(e) {
var x = e.pageX-r.left;
var y = e.pageY-r.top;
draw();
ctx.fillStyle='#000';
if (ctx.isPointInPath(x,y)) {
ctx.fillStyle='#F00';
testCP(x,y);
} else {
resetCP();
}
ctx.fillRect(x-3,y-3,6,6);
var pathDrawn = (pointsCount == points.length);
if (pathDrawn) ctx.fillText('Shape drawn!!', 150, 150);
}