Dragging the mouse outside of a clickable area - processing

I'm trying to code a slider from scratch and I've got a basic functionality, but I'd like to be able to drag the sliders beyond the bounds I created for clicking on it.
void slide()
{
if ((x+w >= mouseX) && (mouseX >= x) && (y+h >= mouseY) && (mouseY >= y) &&
(mousePressed == true))
{
h = (mouseY - y);
}
As you can see when the mouse is dragged outside of the slider dimensions, the height value no longer changes. How can I activate only within the dimensions then drag outside of them?

I have done this trough a boolean to control the click and lock, like:
class Test {
//global
float x;
float y;
float w, h;
float initialY;
boolean lock = false;
//constructors
//default
Test () {
}
Test (float _x, float _y, float _w, float _h) {
x=_x;
y=_y;
initialY = y;
w=_w;
h=_h;
}
void run() {
float lowerY = height - h - initialY;
float value = map(y, initialY, lowerY, 100, 255);
color c = color(value);
fill(c);
rect(x, initialY, 4, lowerY);
fill(200);
rect(x, y, w, h);
float my = constrain(mouseY, initialY, height - h - initialY );
if (lock) y = my;
}
boolean isOver()
{
return (x+w >= mouseX) && (mouseX >= x) && (y+h >= mouseY) && (mouseY >= y);
}
}
//end of class
Test[] instances = new Test[3];
void setup() {
size(200, 600);
noStroke();
instances[0] = new Test(20, 20, 40, 20);
instances[1] = new Test(80, 20, 40, 20);
instances[2] = new Test(140, 20, 40, 20);
}
void draw() {
background(100);
for (Test t:instances)
t.run();
}
void mousePressed() {
for (Test t:instances)
{
if (t.isOver())
t.lock = true;
}
}
void mouseReleased() {
for (Test t:instances)
{
t.lock = false;
}
}

Related

Processing Drag-and-Drop Class/Object

I'm currently trying to make a class in Processing that allows the user to create objects that can be dragged and dropped. It's not that hard to create individual objects, but I've had some trouble implementing them into a class so that the user can create as many as they wish. Do you have any guidance?
Here is the code I have so far.
dragndrop.pde
void setup() {
size(800, 600);
}
void draw() {
background(80);
noStroke();
DragObject d = new DragObject(width/2, height/2, 50, 245);
d.run();
}
DragObject.pde
class DragObject {
int x;
int y;
int r;
color col;
DragObject(int xx, int yy, int rr, int c) {
x = xx;
y = yy;
r = rr;
col = c;
}
void run() {
if(mouseX > (x - r/2) && mouseX < (x + r/2) && mouseY > (y - r/2) && mouseY < (y + r/2)) {
if(mousePressed) {
x = mouseX;
y = mouseY;
}
}
fill(col);
circle(x, y, r);
}
}
It lets you drag the circle, but only as long as the mouse is within the circle's radius.
Thank you!
The following code will allow you to drag the object around the screen. In order to have multiple circles you will need to create an object array, eg DragObject[] d; and then initialize it for as many as you want in setup(), eg d = new DragObject[numOfObjects];
int xOffset = 0;
int yOffset = 0;
DragObject d;
void setup() {
size(800, 600);
d = new DragObject(width/2, height/2, 50, 245);
}
void draw() {
background(80);
noStroke();
d.display();
}
void mousePressed() {
if (mouseX > (d.x - d.r) && mouseX < (d.x + d.r) && mouseY > (d.y - d.r) && mouseY < (d.y + d.r)) {
xOffset = mouseX-d.x;
yOffset = mouseY-d.y;
}
}
void mouseDragged() {
d.x = mouseX - xOffset;
d.y = mouseY - yOffset;
}
class DragObject {
int x;
int y;
int r;
color col;
DragObject(int xx, int yy, int rr, int c) {
x = xx;
y = yy;
r = rr;
col = c;
}
void display() {
fill(col);
circle(x, y, r);
}
}
Revision:
There is an issue in the code above with the method used to determine if the mouse was pressed inside the circle. The demo above will also move the circle if the mouse is clicked outside (but near) the circle. A more correct way to determine if the mouse is down inside of the circle is to use Processing's dist() function. To facilitate keeping track of when the mouse is down inside of the circle a boolean msOver (mouse over) was added to the object class. There is also a misleading variable label ('r') in the initial class declaration. I suggest that this be changed to 'diam' (diameter) to reflect the fact that the third parameter of circle() is the width/height and not the radius as the 'r' implies.
A revised (and hopefully improved) demo follows:
int xOffset = 0;
int yOffset = 0;
DragObject d;
void setup() {
size(800, 600);
d = new DragObject(width/2, height/2, 50, 245);
}
void draw() {
background(80);
noStroke();
d.display();
}
void mousePressed() {
if (dist(d.x, d.y, mouseX, mouseY) <= d.diam/2) {
d.msOver = true;
xOffset = mouseX-d.x;
yOffset = mouseY-d.y;
println("inside");
} else {
d.msOver = false;
println("outside");
}
}
void mouseDragged() {
if (d.msOver) {
d.x = mouseX - xOffset;
d.y = mouseY - yOffset;
}
}
class DragObject {
int x, y, diam;
color col;
boolean msOver;
DragObject(int xx, int yy, int rr, int c) {
x = xx;
y = yy;
diam = rr;
col = c;
}
void display() {
fill(col);
circle(x, y, diam);
}
}

in Processing, how to hover over mouse to make numbers of rectangles change color?

I've finished a single rectangle code, but I'd like to know ways to make at least four rectangles change color while hovering the mouse over them. Any advice is much appreciated.
code is below:
int rectX, rectY;
int rectSize = 90;
color rectColor;
color baseColor;
boolean rectOver = false;
void setup() {
size(640, 360);
rectColor = color(0);
baseColor = color(102);
rectX = width/2;
rectY = height/2;
rectMode(CENTER);
}
void draw() {
update(mouseX, mouseY);
noStroke();
if (rectOver) {
rectColor = color(255);
}else
{
rectColor = color(0);
}
stroke(255);
fill(rectColor);
rect(rectX, rectY, rectSize, rectSize);
}
void update(int x, int y) {
if ( overRect(rectX, rectY, rectSize, rectSize) ) {
rectOver = true;}
else{rectOver = false;}
}
boolean overRect(int x, int y, int width, int height) {
if (mouseX >= x-width/2 && mouseX <= x+width/2 &&
mouseY >= y-height/2 && mouseY <= y+height/2) {
return true;
}
else {
return false;
}
}
First of all, you have to fix your overRect function since width and height are built-in variables, secondly what you need to do is to declare a rectangle class that will contain the x,y, width and height of your rectangle, plus two methods: one to check if the mouse if hovering (using your old method) and one to self draw the rectangle. Lastly, you need an array to store your rectangles. Here is the final code:
int rectX, rectY;
int rectSize = 90;
color rectColor;
color baseColor;
ArrayList<rectangle> list;
boolean rectOver = false;
class rectangle {
float x,y,w,h;
rectangle (float y, float x,float w, float h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
boolean checkInside() {
return overRect(x,y,w,h);
}
void selfDraw(){
if (this.checkInside()) {
rectColor = color(255);
}else
{
rectColor = color(0);
}
stroke(255);
fill(rectColor);
rect(x, y, w, h);
}
}
void setup() {
size(640, 360);
rectMode(CENTER);
list= new ArrayList<rectangle>();
list.add(new rectangle(40,40,50,60));
list.add(new rectangle(20,200,50,20));
list.add(new rectangle(300,200,50,50));
list.add(new rectangle(200,300,80,60));
}
void draw() {
for (int i = 0; i < list.size(); i++) {
list.get(i).selfDraw();
}
}
boolean overRect(float x, float y, float w, float h) {
if (mouseX >= x-w/2 && mouseX <= x+w/2 &&
mouseY >= y-h/2 && mouseY <= y+h/2) {
return true;
}
else {
return false;
}
}
Use inheritence. As in YOUSFI's answer, your nest net would be to build a rectangle class and write it's own mouse over function in there. Then, you can make an instance of that object in your main program and call it's mouseover function.
Instead of blindly copy pasting the code YOUSFI provided, my suggestion would be to read up on Object Oriented Programming or watch this introductory video series: https://www.youtube.com/watch?v=xG2Vbnv0wvg

How do I fix warped walls in my raycaster? (I have tried using cosine correction)

I understand that there are a number of answered questions on here asking the exact same thing. However, I have tried to implement the solution (cosine correction) and have had little success. Note: it is not implemented in this version of the code.
In terms of my code, I'll upload the whole thing but the part that likely needs fixing is the Player class. The rest is fairly boring stuff. I also know that it runs based off of images that you won't have, but for testing feel free to use any 600x600 image that is only black and white. Or contact me for mine. White denotes walls. I'll also upload a screenshot of the warped walls. Controls are WASD for movement, plus some glitchy mouse controls to change the view (will be fixed) as well as hold m to see a map of the current level.
Screenshot of it running
PImage maze;
int stepSize, renderDistance;
float viewStep, fov, moveSpeed;
float minLine, maxLine;
Player p;
boolean w, s, a, d, map;
void setup() {
size(600, 600);
background(0);
strokeWeight(3);
maze = loadImage("testmaze3.png");
stepSize = 1;
fov = PI/4;
viewStep = fov/(width/4);
renderDistance = 300;
moveSpeed = 2;
minLine = 0;
maxLine = 200;
colorMode(RGB, renderDistance);
p = new Player(width/2, height/2, 0);
w = false;
s = false;
a = false;
d = false;
}
void draw() {
maze.loadPixels();
if (map) {
pushStyle();
background(maze);
fill(255, 0, 0);
noStroke();
ellipse(p.x, p.y, 10,10);
stroke(renderDistance);
pushMatrix();
translate(p.x, p.y);
line(0, 0, renderDistance*cos(p.direction), renderDistance*sin(p.direction));
popMatrix();
popStyle();
}
pushMatrix();
translate(p.x, p.y);
if (w) {
if (maze.get(int(p.x + moveSpeed*cos(p.direction)), int(p.y + moveSpeed*sin(p.direction))) != color(renderDistance)) {
p.x += moveSpeed*cos(p.direction);
p.y += moveSpeed*sin(p.direction);
}
}
if (s) {
if (maze.get(int(p.x - moveSpeed*cos(p.direction)), int(p.y - moveSpeed*sin(p.direction))) != color(renderDistance)) {
p.x -= moveSpeed*cos(p.direction);
p.y -= moveSpeed*sin(p.direction);
}
}
if (d) {
if (maze.get(int(p.x - moveSpeed*cos(p.direction-PI/2)), int(p.y - moveSpeed*sin(p.direction-PI/2))) != color(renderDistance)) {
p.x -= moveSpeed*cos(p.direction-PI/2);
p.y -= moveSpeed*sin(p.direction-PI/2);
}
}
if (a) {
if (maze.get(int(p.x - moveSpeed*cos(p.direction+PI/2)), int(p.y - moveSpeed*sin(p.direction+PI/2))) != color(renderDistance)) {
p.x -= moveSpeed*cos(p.direction+PI/2);
p.y -= moveSpeed*sin(p.direction+PI/2);
}
}
popMatrix();
p.direction += ((float)mouseX-(float)pmouseX)/100;
if (!map) {
pushStyle();
noStroke();
fill(0, 0, renderDistance);
rect(0, 0, width, height/2);
fill(0, 0, renderDistance*0.6);
rect(0, height/2, width, height);
popStyle();
p.display();
}
}
void keyPressed() {
if (key == 'w') {
w = true;
}
if (key == 's') {
s = true;
}
if (key == 'a') {
a = true;
}
if (key == 'd') {
d = true;
}
if (key == 'm') {
map = true;
}
}
void keyReleased() {
if (key == 'w') {
w = false;
}
if (key == 's') {
s = false;
}
if (key == 'a') {
a = false;
}
if (key == 'd') {
d = false;
}
if (key == 'm') {
map = false;
}
}
class Player {
float x, y, direction;
Player(int x, int y, float direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
void display() {
maze.loadPixels();
for (float i = direction - fov; i < direction + fov; i += viewStep) {
FloatList line = new FloatList();
line = rayCast(i);
float length_ = (height - maxLine - minLine - map(line.get(2), 0, renderDistance, minLine, maxLine));
stroke(renderDistance - line.get(2), 0, 0);
if (line.get(3) == 1){
stroke(renderDistance - line.get(2));
}
if (renderDistance - line.get(2) > 1) {
line(map(i, direction - fov/2, direction + fov, 0, width), height/2 + length_/2, map(i, direction - fov/2, direction + fov, 0, width), height/2 - length_/2);
}
}
}
FloatList rayCast(float direction) {
FloatList out = new FloatList();
float rayx = x;
float rayy = y;
int steps = 0;
for (int i = 0; i < renderDistance; i++) {
if (maze.get(int(rayx), int(rayy)) != color(0)) {
break;
}
rayx += stepSize * cos(direction);
rayy += stepSize * sin(direction);
steps++;
}
out.append(rayx);
out.append(rayy);
out.append(steps);
if (rayx < 0 || rayx > width || rayy > height || rayy < 0) {
out.append(1);
} else {
out.append(0);
}
return out;
}
}
Your raycasting algorithm calculates the distance from the wall to an infinitely small focus point in the camera. When we try to project this onto our screen we get a distorted image because our screen is a plane and not a point or sphere.
To fix the distortion we have to calculate the distance from the wall to our screen instead of the focus point. This can be done with simple trigonometry:
multiply the raw (euclidean) distance by cos(angle) and you get the distance to the screen.
drawing
So after cleaning up the code and adding the correction it looks like this:
void display() {
maze.loadPixels();
float wallHalfHeight = 50;
float distanceFocusProjection = (height / 2) / tan(fov);
for (float angle = -fov; angle < fov; angle += viewStep) {
float euclideanDist = rayCast(direction + angle);
if (euclideanDist < renderDistance) {
float distToScreen = euclideanDist * cos(angle);
float scanLineHalfHeight = wallHalfHeight * (distanceFocusProjection / distToScreen);
float scanLineX = map(angle, -fov, fov, 0, width);
stroke(renderDistance - distToScreen, 0, 0);
line(scanLineX, height/2 + scanLineHalfHeight, scanLineX, height/2 - scanLineHalfHeight);
}
}
}
float rayCast(float angle) {
PVector position = new PVector(x, y);
PVector direction = PVector.fromAngle(angle); //new PVector(cos(angle), sin(angle));
int distance;
for(distance = 0; distance < renderDistance; distance++) {
if (maze.get(round(position.x), round(position.y)) != color(0)) {
break;
}
position.add(direction);
}
return distance;
}

Traffic Light sequence in Processing

I am trying to get this bit of code I have got and add another traffic light and car but going from right to left not from bottom to top. The car only moves when the light is amber or green and stops when red. I have tried copying the code and changing the names of the values but it just will not work. I have tried naming them all different names but it won't even show the other image I tried to put in for the other car. Can someone please tell/show me how I could add another traffic light and car but they move at different times?
TrafficLight light1 = new TrafficLight(100, 40);
int onTime = 2000;
int startTime = millis();
PImage car;
int carX, carY;
void setup() {
size(800, 600);
light1.changeColour("red");
light1.display();
car = loadImage("Car.png");
carX = 150;
carY = 300;
}
void draw() {
background(255);
if (millis() - startTime > onTime && light1.lightOn == "red") {
light1.changeColour("amber");
startTime = millis();
}
if (millis() - startTime > onTime && light1.lightOn == "amber") {
light1.changeColour("green");
startTime = millis();
}
if (millis() - startTime > onTime && light1.lightOn == "green") {
light1.changeColour("red");
startTime = millis();
}
light1.display();
image(car, carX, carY);
if (light1.lightOn == "green") {
carY -= 2;
}
{
}
if (light1.lightOn == "red") {
carY -= 0;
}
{
}
if (light1.lightOn == "amber") {
carY -= 1;
}
{
}
if (carY <= -200) {
carY = 500;
}
}
class TrafficLight {
int xpos;
int ypos;
String lightOn = "red";
TrafficLight(int x, int y) {
xpos = x;
ypos = y;
}
void changeColour(String lightColour) {
lightOn = lightColour;
}
void display() {
String lightColour = lightOn;
fill(0, 0, 0);
rect(xpos, ypos, 100, 220);//back panel
if (lightColour == "red") {
fill(255, 0, 0);
lightOn = "red";
} else {
fill(100, 0, 0);
}
ellipse(xpos + 50, ypos + 40, 60, 60);//red
if (lightColour == "amber") {
fill(255, 255, 0);
lightOn = "amber";
} else {
fill(100, 100, 0);
}
ellipse(xpos + 50, ypos + 110, 60, 60);//amber
if (lightColour == "green") {
fill(0, 255, 0);
lightOn = "green";
} else {
fill(0, 100, 0);
}
ellipse(xpos + 50, ypos + 180, 60, 60);//green
}
}
The code you've posted only contains one car, which makes this question hard to answer. Stack Overflow isn't really designed for general "how do I do this" type questions. It's more designed for specific "I tried X, expected Y, but got Z instead" type questions. That being said, I'll try to answer in a general sense:
Here's the short answer: you need to create a state for a second car, and then work with that state exactly how you work with the state of the first car. This might be easier if you encapsulate that state into a class, and then use two instances of that class.
Let's start out with a simpler example of a circle that moves vertically, and stops when we press the mouse:
MovingCircle verticalCircle;
void setup() {
size(600, 600);
verticalCircle = new MovingCircle(250, 250, 0, 5);
}
void mousePressed() {
verticalCircle.moving = !verticalCircle.moving;
}
void draw() {
background(0);
verticalCircle.step();
}
class MovingCircle {
float x;
float y;
float xSpeed;
float ySpeed;
boolean moving = true;
public MovingCircle(float x, float y, float xSpeed, float ySpeed) {
this.x = x;
this.y = y;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
}
void step() {
if (moving) {
x+=xSpeed;
y+=ySpeed;
if (x > width) {
x = 0;
}
if (y > height) {
y = 0;
}
}
ellipse(x, y, 25, 25);
}
}
This program creates a circle that moves down the screen, and stops and starts when you click the mouse. Notice that I've encapsulated all of the information I need inside the MovingCircle class, so now if I want to add another one, I can just create another instance of that class and interact with it however I want.
Here's how I would add a horizontally moving circle:
MovingCircle verticalCircle;
MovingCircle horizontalCircle;
void setup() {
size(600, 600);
verticalCircle = new MovingCircle(250, 250, 0, 5);
horizontalCircle = new MovingCircle(250, 250, 5, 0);
}
void mousePressed() {
verticalCircle.moving = !verticalCircle.moving;
}
void keyPressed() {
horizontalCircle.moving = !horizontalCircle.moving;
}
void draw() {
background(0);
verticalCircle.step();
horizontalCircle.step();
}
This is just an example, but the principle is the same in your code: you need to encapsulate your state into a class, and then you can work with two instances of that class in order to have two moving cars.
Also, you should never use == to compare String values! Use the .equals() function instead!
if(lightColour.equals("red")){

Use an object with this code? Processing

How can I use the code I have now with an object where I can store the number of times the ball bounces and the color (when i add random color) and speed. Any pointers or tips would be greatful. I am new to OOP and it can get confusing for me. Thanks in advance
float x;
float y;
float yspeed = 0;
float xspeed = 0;
float balldiameter = 10;
float ballradius = balldiameter/2;
void setup() {
size (400,400);
background (255);
fill (0);
ellipseMode(CENTER);
smooth();
noStroke();
x = random(400);
y = 0;
}
void draw() {
mouseChecks();
boundaryChecks();
ballFunctions();
keyFunctions();
}
void mouseChecks() {
if (mousePressed == true) {
x = mouseX;
y = mouseY;
yspeed = mouseY - pmouseY;
xspeed = mouseX - pmouseX;
}
}
void boundaryChecks() {
if (y >= height - ballradius) {
y = height - ballradius;
yspeed = -yspeed/1.15;
}
if (y <= ballradius) {
y = ballradius;
yspeed = -yspeed/1.35;
}
if (x >= width -ballradius) {
x = width -ballradius;
xspeed = -xspeed/1.10;
}
if (x <= ballradius) {
x = ballradius;
xspeed = -xspeed/1.10;
}
}
void ballFunctions() {
if (balldiameter < 2) {
balldiameter = 2;
}
if (balldiameter > 400) {
balldiameter = 400;
}
ballradius = balldiameter/2;
background(255); //should this be in here?
ellipse (x,y,balldiameter,balldiameter);
yspeed = yspeed += 1.63;
// xspeed = xspeed+=1.63;
y = y + yspeed;
x = x + xspeed;
}
void keyFunctions() {
if (keyPressed) {
if(keyCode == UP) {
balldiameter +=1;
}
if (keyCode == DOWN) {
balldiameter -=1;
}
}
}
you will probably want to do the following:
create a new file called Ball.pde
In that file write:
public class Ball {
public float x;
public float y;
public float yspeed;
public float xspeed;
public float diameter;
public float radius;
public Ball(float initial_x, float initial_y, float diam) {
this.x = initial_x;
this.y = initial_y;
this.xspeed = 0;
this.yspeed = 0;
this.diameter = diam;
this.radius = diam/2;
}
public void move() {
// movement stuff here
}
}
This will give you a very basic Ball class. You can now use this class in your main sketch file like so:
Ball my_ball = new Ball(50, 50, 10);
you can access the balls members using:
my_ball.xspeed;
my_ball.yspeed;
my_ball.anything_you_defined_in_ball;
This will allow you yo store all relevent variables for the ball within its own class. you can even create more than 1.
Ball my_ball1 = new Ball(50, 50, 10);
Ball my_ball2 = new Ball(20, 20, 5);
Just to note that in Proccesing you don't need to create a new file for that, the code can go either in the same file (very bad practice as pointed below) or in a new tab of the IDE. If you are using the Processing IDE you can choose "new tab" from the arrow menu in the right and it will create the file for you. It will have ".pde" extension.

Resources