How to make an (moving) ellipse clickable? Processing - processing

So I started learning processing since a week ago and I'm trying to get a moving ellipse clickable. I followed the processing API, but I can't figure it out. I removed all the code relating to the clickable ellipse because it was a mess.
In the section where I declare all my vars you can see me using:
int breedte = 600;
int hoogte = 600;
These are suppose to be:
int breedte = width;
int hoogte = height;
But for some reason the width and height don't output the width and height declared in:
size(600,600)
So what I'm asking is:
How can I make the (moving) ellipse clickable?
Why I can't use width and height on 'int hoogte' and 'int breedte'?
Thanks in advace.
Main file:
int x = 0;
int leftSide = 0;
int rightSide = width;
int bottomSide = height;
int totalHits = 0;
int totalMiss = 0;
boolean start = false;
int circelSize = 100;
int circelRings = 24;
int circelSpeed = 1;
int circelPositionY = 0;
int breedte = 600;
int hoogte = 600;
String[] buttonText = {"Start","Stop"};
String buttonTextActive = buttonText[0];
int[] buttonColor = {0,90};
int buttonColorActive = buttonColor[0];
int buttonHighlight = 50;
int buttonSize = 80;
int buttonY = breedte - (buttonSize /2);
int buttonX = hoogte / 2 - 40;
void setup() {
size(600, 600);
smooth();
noStroke();
}
void draw() {
if (start) {
circelPositionY = circelPositionY + circelSpeed;
drawCircel(circelPositionY);
if (circelPositionY == (width + circelSize)) {
circelPositionY = 0;
}
}
drawButton();
}
Events file:
void mousePressed() {
// Start or Stop button
if(mouseX > buttonX & mouseX < buttonX + buttonSize & mouseY > buttonY & mouseY < buttonY + (buttonSize / 2)){
if(start) {
start = false;
buttonColorActive = buttonColor[0];
buttonTextActive = buttonText[0];
println("Game stoped");
} else {
start = true;
buttonColorActive = buttonColor[1];
buttonTextActive = buttonText[1];
println("Game started");
}
}
//HERE SHOULD GO THE CLICKABLE ELLPISE
}
Functions file:
void drawCircel(int circelPositionY) {
background(204);
for (int i = 0; i < circelRings; i = i+1) {
int even = i % 2;
if (even == 0) {
fill(255,0,0);
ellipse(-(circelSize / 2) + circelPositionY, height / 2 - (circelSize / 2), circelSize - (i * (circelSize / circelRings)), circelSize - (i * (circelSize / circelRings)));
} else {
fill(255);
ellipse(-(circelSize / 2) + circelPositionY, height / 2 - (circelSize / 2), circelSize - (i * (circelSize / circelRings)), circelSize - (i * (circelSize / circelRings)));
}
}
}
void drawButton() {
fill(buttonColorActive);
rect(buttonX,buttonY, buttonSize, buttonSize / 2);
fill(255);
textAlign(CENTER, CENTER);
text(buttonTextActive, buttonX + (buttonSize / 2),buttonY + (buttonSize / 4));
}

In the future, please try to post a MCVE instead of a bunch of disconnected snippets or your whole project. Also please only ask one question per post.
To make your circle clickable, you're going to have to write code that checks whether the circle is being clicked. That's actually two separate checks. First you have to detect when the mouse is pressed. One way to do that is by defining a mousePressed() function:
void mousePressed(){
// mouse is pressed
}
Then you have to check whether the mouse is currently inside the circle. You can use the dist() function for that: if the distance between the mouse and the center of the circle is less than the radius of the circle, then the mouse is inside the circle. That might look like this:
void mousePressed(){
if(dist(mouseX, mouseY, circleX, circleY) < circleRadius){
// mouse is pressed inside the circle
}
}
Shameless self-promotion: I wrote a tutorial on collision detection in Processing, including point-circle collision, available here.
As for why you can't use width and height at the top of your sketch, that's because code at the top of your sketch is executed before the setup() function fires, and the width and height variables aren't set until after you call size() from the setup() function. So you have to move that code to after you call size().
If you have follow-up questions, please post an updated MCVE in a new question post, and we'll go from there. Good luck.

Processing does not provide an api for hit detection, so you need to implement this by yourself, which I think is a great learning exercise. You can explore the mathematics of an ellipse here.
But the general approach is to use a function like the one below to check that the point you clicked on was indeed inside the ellipse you provided.
boolean InsideEllipse(
float x, float y,
float xc, float yc,
float width, float height
) {
// First half the width and height to get the ellipse parameters
float a = width / 2;
float b = height / 2;
// Now calculate the deltas:
float xd = x - xc;
float yd = y - yd;
// Now the equation of an ellipse is given by
// x^2 / a ^ 2 + y^2 / b ^ 2 = 1
// So if we are inside the ellipse, we would expect the left hand
// side of this expression to be less than one
boolean inside = xd * xd / (a * a) + yd * yd / (b * b) <= 1.0
return inside
}

Related

Any idea why this Processing sketch runs so slow?

I'm using processing 2.1.
Any idea why my simple sketch is running slow on my (powerful) machine?
I'm simply drawing some quads in a grid, and when pressing the mouse I was trying to animate them (via Ani library), but the animation is sloppy and superslow....Any hint?
import de.looksgood.ani.*;
import de.looksgood.ani.easing.*;
int quadSize = 30;
int spacing = 10;
int numRows = 11;
int numColumns = 22;
float angleRotationIncrease = 3;
void setup () {
size (900, 600, P3D);
background (0);
fill (255);
stroke (255);
Ani.init(this);
frameRate (60);
}
void draw () {
text(frameRate,20,20);
// println (angleRotationIncrease);
background (0);
int posX = 0;
int posY = 0;
int angleRotation = 0;
float scaleFactor = 1;
float scaleFactorIncrease = -0.045;
for (int i=0; i<numRows; i++) {
for (int j=0; j<numColumns; j++) {
pushMatrix();
translate (posX + quadSize/2, posY + quadSize/2);
// println (radians(angleRotation));
rotate(radians(angleRotation));
if (scaleFactor > 0) {
rect (-quadSize/2 * scaleFactor, -quadSize/2* scaleFactor, quadSize* scaleFactor, quadSize* scaleFactor);
}
popMatrix ();
posX += (quadSize + spacing);
angleRotation += angleRotationIncrease;
scaleFactor += scaleFactorIncrease;
}
// for each new line, reset or change params
scaleFactorIncrease -= 0.002;
scaleFactor = 1;
angleRotation = 0;
posX = 0;
posY += (quadSize + spacing);
}
}
void mousePressed() {
Ani.to(this, 20, "angleRotationIncrease", -3);
}
Solved. it was a casting problem. Anglerotation is an int, so when subtracting the value I'm animating via Ani, it gets rounded
Because you are animating low range of values over very long period of time
Ani.to(this, 20, "angleRotationIncrease", -3);
Your range is [3,-3] and time is 20 seconds. Just try to decrease time and increase range an you will see more fluent animation on your powerful machine :) like this:
Ani.to(this, 2, "angleRotationIncrease", -30);
But at the end of animation is some kind of slowing what should be specified by default by Ani library so for more information read documentation here

Get shapes on screen

I have created a grid of thumbs. When a certain thumb is pressed I want the image that is linked to the thumb added on screen. I know i'm supposed to write the loadImages in setup(), but i'm a bit confused on how to do this.
PShape[] Quotes = new PShape[6];
int qLength = Quotes.length;
setup() {
size(1024, 768);
}
draw() {
stroke(bruin);
strokeWeight(5);
fill(wit);
rectMode(CORNER);
rect(guide, 280, bBorder, 145);
noStroke();
fill(bruin);
rect(guide, 280, bBorder, 40);
textFont(kaffeesatzFont);
textSize(30);
fill(wit);
text("Quotes", 80, 308);
createGridQ();
}
void createGridQ(){
xOffset = 30;
yOffset = 325;
xSize = 50;
ySize = 38;
padding = 10;
xPos = padding + xOffset;
yPos = yOffset;
cols = 3;
for(int j = 0; j < qLength; j++){
// Grid
xPos = xOffset + ((j % cols) * (xSize+padding));
yPos = yOffset + ((j / cols) * (ySize+padding));
Quotes[j] = loadShape("Q" + j + ".svg");
shape(Quotes[j], xPos, yPos);
if((mouseX >= xPos) && (mouseX <= xPos+xSize) &&
(mouseY >= yPos) && (mouseY <= yPos+ySize)){
cursor(HAND);
if (mousePressed){
cursor(HAND);
Quotes[j] = loadShape("Q" + j + "groot" + ".svg");
shape(Quotes[j], width/5, height/2-200);
}
}
}
}
You can load an image by declaring a PImage and loading it from a web url or by placing it into your data or source directory (where your .pde files are) and then loading it from there.
PImage img;
img = loadImage("laDefense.jpg");
Processing loadImage Reference
So, replace "laDefense.jpg" with the name of the image you want to use and place that image into your data folder. After that, you can place the image in the scene and manipulate it as you would a shape.

Fill background with color from array when clicked on rectangle

I've made several rectangles by using a loop.
The color of the rectangles are provided from an array.
I want on clicking one of the rectangles, that background fills with the color I selected.
I'm new to processing so i'm a bit confused on how to do it.
color[] backgrounds = {#e8be55, #ff8827, #eb5051, #00b4cc, #005f6b, #7c6753, #edeaee};
int bgLength = backgrounds.length;
int xPos;
int yPos;
int size;
void setup(){
background(255);
size(1024, 768);
}
void draw(){
size = 40;
xPos = guide + 10;
yPos = 167;
for(int i = 0; i < bgLength; i++) {
noStroke();
fill(backgrounds[i]);
rect(xPos, yPos, size, size);
xPos = xPos + size + 4;
if(xPos>180){
xPos = guide + 10;
yPos += size + 4;
}
}
}
Thanks.
You need to check the bounds. First I suggest you organize the variables a bit.
For example some variables never change(so there's no reason to assign them in draw()).
This should make it easier to see what the coordinates are.
I suggest this:
color[] backgrounds = {#e8be55, #ff8827, #eb5051, #00b4cc, #005f6b, #7c6753, #edeaee};
int bgLength = backgrounds.length;
int xOffset = 10;
int yOffset = 167;
int xPos;
int yPos;
int size = 40;
int guide = 10;
int cols = 4;//4 columns
color selectedBackground = backgrounds[backgrounds.length-1];//default to last element in the list/array
void setup(){
background(255);
size(1024, 768);
noStroke();
}
void draw(){
background(selectedBackground);
for(int i = 0; i < bgLength; i++) {
xPos = xOffset + ((i % cols) * (size+guide));//since % is returns the remainder of division, we use it to compute x position in the grid
yPos = yOffset + ((i / cols) * (size+guide));//and we divide by the number of columns to compute the y position in the grid
fill(backgrounds[i]);
//check if a box is clicked
if((mouseX >= xPos && mouseX <= xPos+size) && //check horizontal bounds(left/right)
(mouseY >= yPos && mouseY <= yPos+size)){ //check vertical bounds(top/bottom)
if(mousePressed){//if mouse is over/within a boxes bounds and clicked
selectedBackground = backgrounds[i];//set the colour based on id
}else{//just hovering
fill(backgrounds[i],127);//draw transparent colour, just to high light selection, not actually needed, but now an easy option
}
}
rect(xPos, yPos, size, size);//we draw at the end because the fill colour might have changed if a box was hovered
}
}
You can run a javascript demo bellow. (Although there are minor differences in syntax, the core concept is the same):
var backgrounds;// = [color('#e8be55'), color('#ff8827'), color('#eb5051'), color('#00b4cc'), color('#005f6b'), color('#7c6753'), color('#edeaee')];
var bgLength;// = backgrounds.length;
var xOffset = 10;
var yOffset = 67;
var xPos = 0;
var yPos = 0;
var ssize = 40;
var guide = 10;
var cols = 4;//4 columns
var selectedBackground;// = backgrounds[backgrounds.length-1];//default to last element in the list/array
function setup(){
createCanvas(1024, 768);noStroke();
backgrounds = [color('#e8be55'), color('#ff8827'), color('#eb5051'), color('#00b4cc'), color('#005f6b'), color('#7c6753'), color('#edeaee')];
bgLength = backgrounds.length;
selectedBackground = backgrounds[backgrounds.length-1];//default to last element in the list/array
}
function draw(){
background(selectedBackground);
for(var i = 0; i < bgLength; i++) {
xPos = xOffset + ((i % cols) * (ssize+guide));//since % is returns the remainder of division, we use it to compute x position in the grid
yPos = yOffset + (floor(i / cols) * (ssize+guide));//and we divide by the number of columns to compute the y position in the grid
fill(backgrounds[i]);
//check if a box is clicked
if((mouseX >= xPos && mouseX <= xPos+ssize) && //check horizontal bounds(left/right)
(mouseY >= yPos && mouseY <= yPos+ssize)){ //check vertical bounds(top/bottom)
if(isMousePressed){//if mouse is over/within a boxes bounds and clicked
selectedBackground = backgrounds[i];//set the colour based on id
}else{//just hovering
fill(backgrounds[i].rgba[0]+50,backgrounds[i].rgba[1]+50,backgrounds[i].rgba[2]+50);//draw transparent colour, just to high light selection, not actually needed, but now an easy option
}
}
rect(xPos, yPos, ssize, ssize);//we draw at the end because the fill colour might have changed if a box was hovered
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>

Processing PVector rotations

The issue is i got an array of PVectors placed around my main PVector which is in the middle. I want my array of PVectors to rotate around my main PVector based on a rotation variable. Is there any way to do this?
Right now I have this code but it does not rotate the PVectors, just places them farther away based on the rotation var.
class Box {
PVector location;
PVector[] points;
float rotation = random(360);
Box() {
location = new PVector(random(width), random(height));
points = new PVector[4];
for(a = 0; a < points.length; a ++) {
points[a] = new PVector(0,0);
}
}
void update() {
points[0].x = location.x + 10 * sin(rotation);
points[0].y = location.y + 10 * sin(rotation);
points[1].x = location.x + 10 * sin(rotation);
points[1].y = location.y - 10 * sin(rotation);
points[2].x = location.x - 10 * sin(rotation);
points[2].y = location.y + 10 * sin(rotation);
points[3].x = location.x - 10 * sin(rotation);
points[3].y = location.y - 10 * sin(rotation);
}
To rotate the vectors, you do need to use trig functions like sin and cos like you have in your code. However, your approach isn't really the best. Adding onto the existing (x,y) coordinates on each update isn't really feasible, since the number you have to add on is changing every time. It's easier just to overwrite and calculate new values for each update. The x and y coordinates for a given angle are given by the unit circle:
So, the x of a given PVector varies with cos(theta) and the y varies with sin(theta). Check the following code:
Box b;
void setup(){
size(300,300);
b = new Box();
}
void draw(){
background(255);
b.update(mouseX, mouseY);
b.display();
}
class Box {
PVector location;
PVector[] points;
float rotation;
float radius;
Box() {
location = new PVector(width/2,height/2);
points = new PVector[7];
rotation = 0;
radius = 50;
for(int i = 0; i < points.length; i ++) {
//this centers the points around (0,0), so you need to add in
//the box coordinates later on.
points[i] = new PVector(radius*cos(rotation + i*TWO_PI/points.length),
radius*sin(rotation + i*TWO_PI/points.length));
}
}
void update(int x, int y) {
location.set(x,y);
rotation += 0.08; // change for different rotation speeds.
for(int i = 0; i < points.length; i++){
points[i].set(radius*cos(rotation + i*TWO_PI/points.length),
radius*sin(rotation + i*TWO_PI/points.length));
}
}
void display(){
stroke(0);
for(int i = 0; i < points.length; i++){
//points are treated as offsets from the center point:
line(location.x,location.y,location.x+points[i].x,location.y+points[i].y);
ellipse(location.x+points[i].x,location.y+points[i].y,10,10);
}
}
}
For every update() call, it increments the rotation variable and calculates the new x and y values for each point in the array. You can change the speed and direction of rotation by changing 0.08 to bigger/smaller/positive/negative numbers.
To rotate a point around location:
double x = cos(rotation) * (point.x-location.x) - sin(rotation) * (point.y-location.y) + location.x;
double y = sin(rotation) * (point.x-location.x) + cos(rotation) * (point.y-location.y) + location.y;
point.x = x;
point.y = y;
See Rotate a point by an angle

Rotate some elements in an ellipse path

I am trying to make some objects, say 12, to rotate in an ellipse path continuously in Processing. I got a sketch which does rotation in a circle and I want to make it to rotate in a ellipse. I have some pointer from processing forum but the code from the pointer is different from the code that I posted and I couldn't understand yet (weak in trigonometry).
I googled a bit and found a post trying to achieve this with this algorithm:
You need to define your ellipse with a few parameters:
x, y: center of the ellipse
a, b: semimajor and semiminor axes
If you want to move on the elipses this means that you change the
angle between the major axes and your position on the ellipse. Lets
call this angle alpha.
Your position (X,Y) is:
X = x + (a * Math.cos(alpha));
Y = y + (b * Math.sin(alpha));
In order to move left or right you need to increase/decrease alpha and
then recalculate your position. Source:
http://answers.unity3d.com/questions/27620/move-object-allong-an-ellipsoid-path.html
How do I integrate it into my sketch? Thank you.
Here's my sketch:
void setup()
{
size(1024, 768);
textFont(createFont("Arial", 30));
}
void draw()
{
background(0);
stroke(255);
int cx = 500;
int cy = 350;
int r = 300; //radius of the circle
float t = millis()/4000.0f; //increase to slow down the movement
ellipse(cx, cy, 5, 5);
for (int i = 1 ; i <= 12; i++) {
t = t + 100;
int x = (int)(cx + r * cos(t));
int y = (int)(cy + r * sin(t));
line(cx, cy, x, y);
textSize(30);
text(i, x, y);
if (i == 10) {
textSize(15);
text("x: " + x + " y: " + y, x - 50, y - 20);
}
}
}
Replace
int r = 300; //radius of the circle
with
int a = 350; // major axis of ellipse
int b = 250; // minor axis of ellipse
and replace
int x = (int)(cx + r * cos(t));
int y = (int)(cy + r * sin(t));
with
int x = (int)(cx + a * cos(t));
int y = (int)(cy + b * sin(t));

Resources