Right, so I found some of my older functions that are useful for this that come in pairs and output only 1 number, while they should output PVector
instead or something. In any case, I used them as is to create pretty horrific code that makes your final ideal output possible.
Move mouse left/right to give the tower a tilt. Hold mouse to set the second tilt used more at the top parts of the tower. Move mouse up/down to set the steepness between the first and second tilt.
int sign(float in){
//Tells the sign of the input number.
if(in<0){return -1;}
if(in>0){return 1;}
return 0;
}
float mix(float in1,float in2,float mix){
//Blends between 2 values - 0 mix equals in1, 1 mix equals in2, 0.5 mix equals half of both i.e. average.
return in1+(in2-in1)*mix;
}
float angle(float x, float y){
//If you were to draw an arrow going from 0,0 to x,y coordinates in 2D space, considering up is 0 degrees and right is 90 degrees, this is the angle of that arrow.
if(x==-0){x=0;}
if(y==-0){y=0;}
return y!=0?(x<0?(180*sign(y)-(atan(y/abs(x))/(PI)*180)):atan(y/abs(x))/(PI)*180):sign(x)<0?(180):0;
//return y!=0?(-sign(x)*(180*sign(y)-(atan(y/abs(x))/(PI)*180))/(PI)*180):sign(x)<0?(180):0;
}
float rotX(float x, float y, float degrees){
//Takes current x,y on 2D space, rotates them around the 0,0 pivot point at degrees degrees, and outputs X of the result.
return sqrt(x*x+y*y)*cos((angle(x,y)+degrees)/180*PI);
}
float rotY(float x, float y, float degrees){
//Takes current x,y on 2D space, rotates them around the 0,0 pivot point at degrees degrees, and outputs Y of the result.
return sqrt(x*x+y*y)*sin((angle(x,y)+degrees)/180*PI);
}
float rotX(float originx, float originy, float x, float y, float degrees){
//Takes current x,y on 2D space, rotates them around the originx, originy pivot point at degrees degrees, and outputs X of the result.
return rotX(x-originx,y-originy,degrees)+originx;
}
float rotY(float originx, float originy, float x, float y, float degrees){
//Takes current x,y on 2D space, rotates them around the originx, originy pivot point at degrees degrees, and outputs Y of the result.
return rotY(x-originx,y-originy,degrees)+originy;
}
float offset=-50;
float sideSizeL = 25;
float sideSizeR = 25;
int count = 10;
float angle = 0;
float angle2 = 0;
float angleMixSteepness = 0.5;
int oddSegment = 5;
//At which shape it should change which side of the tower zigzags.
void setup(){size(480,640,P2D);}
void draw(){
if(mousePressed) angle2 = (mouseX-width/2)*0.1;
else angle = (mouseX-width/2)*0.1;
angleMixSteepness = (float)mouseY*2/height;
background(255);
float currentX=width/2;
float currentY=height-10;
float currentAngle = 0;
// line(width/2,height-10,rotX(width/2,height-10,width/2,height-60,angle),rotY(width/2,height-10,width/2,height-60,angle));
for(int i=0;i<count;i++){
float nextAngle=currentAngle+mix(angle,angle2,pow((float)i/count,angleMixSteepness));
float nextX=rotX(currentX,currentY,currentX,currentY+offset,nextAngle);
float nextY=rotY(currentX,currentY,currentX,currentY+offset,nextAngle);
//Current coordinates:
//currentX currentY currentAngle - starting position and angle of this current segment.
//nextX nextY nextAngle - ending position of this current segment - these values will be used for the start of the next segment.
//All lines are based around these coordinates and rotating them around these angles.
float sideSizeLeftCurrent = sideSizeL;
float sideSizeLeftNext = sideSizeL;
float sideSizeRightCurrent = sideSizeR;
float sideSizeRightNext = sideSizeR;
//sideSizeLeft/RightCurrent - Offsets from the starting point to the left/right to form the base of this segment.
//sideSizeLeft/RightCurrent - Offsets from the starting point to the left/right to form the roof of this segment or base of the next segment.
//Make them do the zig-zag thing.
if(i<oddSegment){
if(i%2==1) sideSizeLeftCurrent-=30;
else sideSizeLeftNext-=30;
}else if(i==oddSegment){
sideSizeLeftCurrent-=30;
}else if(i>oddSegment){
if(i%2==1) sideSizeRightCurrent-=30;
else sideSizeRightNext-=30;
}
line(rotX(currentX,currentY,currentX-sideSizeLeftCurrent,currentY,currentAngle),rotY(currentX,currentY,currentX-sideSizeLeftCurrent,currentY,currentAngle),
rotX(currentX,currentY,currentX+sideSizeRightCurrent,currentY,currentAngle),rotY(currentX,currentY,currentX+sideSizeRightCurrent,currentY,currentAngle));
//Line going below the segment. Makes the base.
//line(lastX,lastY,lastX1,lastY1);
//Line going through the middle of the segment.
beginShape(QUADS);
vertex(rotX(currentX,currentY,currentX-sideSizeLeftCurrent,currentY,currentAngle),rotY(currentX,currentY,currentX-sideSizeLeftCurrent,currentY,currentAngle));
//Top left
vertex(rotX(currentX,currentY,currentX+sideSizeRightCurrent,currentY,currentAngle),rotY(currentX,currentY,currentX+sideSizeRightCurrent,currentY,currentAngle));
//Top right
vertex(rotX(nextX, nextY, nextX+sideSizeRightNext, nextY, nextAngle) ,rotY(nextX ,nextY ,nextX+sideSizeRightNext ,nextY ,nextAngle));
//Bottom right
vertex(rotX(nextX ,nextY ,nextX-sideSizeLeftNext ,nextY ,nextAngle) ,rotY(nextX ,nextY ,nextX-sideSizeLeftNext ,nextY ,nextAngle));
//Bottom left
endShape();
currentAngle+=mix(angle,angle2,pow((float)i/count,angleMixSteepness));
currentX = nextX; currentY = nextY;
}
}
P.S. Forgive me for these long names - I named them like X1
Y4
and so on and it was pretty confusing. If you want to have a bit less horrific experience with my code, I suggest to right-click values, “Rename…”, and set them to something shorter… ._.