I'm trying to rotate a rect and line using the following:
push();
rect(windowWidth / 2, windowHeight / 2, 500, 250);
line(windowWidth / 2, windowHeight / 2, windowWidth, windowHeight / 2);
rotate(45);
pop();
This code doesn't rotate the objects though. I also tried:
push();
rotate(45);
rect(windowWidth / 2, windowHeight / 2, 500, 250);
line(windowWidth / 2, windowHeight / 2, windowWidth, windowHeight / 2);
pop();
with the same result
I am using noLoop() so it only draws once, but I'd like the page to load with the shapes already rotated. How can I accomplish this?
Because in order to first rotate, you have to translate the object first.
For better understanding:
https://p5js.org/reference/#/p5/rotate
https://www.youtube.com/watch?v=o9sgjuh-CBM
Assuming you have specified angleMode() in your setup function...
translate();
rotate();
rect();
line();
Related
In P5js I want to overlay a shape to a video, but they don't share the same dom element.
Is there any way to do it?
Code test here: The video should be visible through the triangular contour that cuts the shape.
The code:
let video;
function preload() {
video = createVideo("video.mp4");
}
function setup() {
createCanvas(400, 300);
background("gray");
video.size(400,400);
video.loop();
var w = width * 0.7;
var h = height * 0.7;
translate((width/2) - (w/2), (height/2) - (h/2));
fill("lightgray");
noStroke();
beginShape();
vertex(0, 0);
vertex(w, 0);
vertex(w, h);
vertex(0, h);
beginContour();
vertex(w * 0.2, h * 0.4);
vertex(w * 0.5, h * 0.8);
vertex(w * 0.8, h * 0.4);
endContour();
endShape();
noLoop();
}
I see here that hiding the video and using image (i.e. image(video, 10, 10)) it is possible to draw a single frame. Alas I use noLoop() and in my case there would be no automatic refresh of the video in draw().
"The video should be visible through the triangular contour that cuts the shape."
Below is a result I got from a quick play-around with your code. Maybe it will be useful to you in some way (eg: gives new ideas on how to proceed).
The code's logic is to simply create 2 layers.
Bottom layer 1 is video and top layer 2 is triangle (the canvas).
Other ideas include maybe using BlendModes like Screen or Multiply:
example: canv.blendMode(SCREEN);
Where SCREEN makes whites transparent, and MULTIPLY makes blacks transparent).
The example testing code (makes two layers and also removed background("gray");)
let video; let canv;
function preload()
{ video = createVideo("video.mp4"); }
function setup()
{
translate(0, 0);
video.size(400,300);
video.style("z-index: 1"); //# is default in P5.JS
video.position(0, (width * 0.7) );
video.loop();
canv = createCanvas(400, 400);
canv.style("z-index: 2");
canv.position(0, 0); //# important to have a setting
//# Not needed ....
//background("gray");
var w = width * 1;
var h = height * 1;
translate((width/2) - (w/2), (height/2) - (h/2));
fill("lightgray");
noStroke();
beginShape();
vertex(0, 0);
vertex(w, 0);
vertex(w, h);
vertex(0, h);
beginContour();
vertex(w * 0.2, h * 0.4);
vertex(w * 0.5, h * 0.8);
vertex(w * 0.8, h * 0.4);
endContour();
endShape();
noLoop();
}
I recently started using p5.js more and noticed that when I the textAlign() function to center text, it is offset higher than the coordinates I specify when calling text(). The amount it is offset seems to be constant between different font sizes, being approximately fontSize()/12 above the y-coordinate I entered.
An example of this can be seen at this p5.js sketch, showing the default centering on the left, and the text being offset by fontSize()/12 on the right, having it be properly centered at varying text sizes.
Is there a way I could fix this issue and have all text be aligned properly without having to specify in each call of text that I want the text to be shifted down the amount of pixels needed for it to be properly centered? Is there a way I can modify the text function to have this functionality built in?
(Edit: I was able to "solve" this issue by overwriting the default text function with my own code, though I don't know if this is very good practice. A link to the fix can be found here, with the fixed text alignment in black and the default p5.js alignment in green.)
This has to do with what you think of as the vertical "center" of the glyphs. From you example it is evident that you think of the "center" as the center line of the capital letters. However, by this metric all lower case letters would appear mostly below center and it also fails to take into account glyph descent (that is, the amount of certain lower case glyphs that appear below the font baseline).
Here is an example that I think clearly demonstrates how the various vertical positioning types work.
function setup() {
createCanvas(windowWidth, windowHeight);
noLoop();
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
redraw();
}
function draw() {
let w = width / 4;
push();
stroke('blue');
line(0, height / 2, width, height / 2);
pop();
drawText(0, 0, w, height, TOP);
drawText(w, 0, w, height, CENTER);
drawText(w * 2, 0, w, height, BASELINE);
drawText(w * 3, 0, w, height, BOTTOM);
}
const str = 'Age';
const size = 48;
function drawText(x, y, w, h, valign) {
push();
textSize(size);
textAlign(LEFT, valign);
let tw = textWidth(str);
let yOff = 0;
switch (valign) {
case TOP:
yOff = -size / 2;
break;
case BOTTOM:
yOff = size / 2;
break;
case BASELINE:
yOff = size / 2 - textDescent();
}
stroke('limegreen');
rectMode(CENTER);
noFill();
rect(x + w / 2, y + h / 2, tw, size);
translate(x + w / 2 - tw / 2, height / 2 + yOff);
stroke('red');
line(0, 0, tw, 0);
strokeWeight(4);
point(0, 0);
noStroke();
fill('black');
text(str, 0, 0);
pop();
}
body, html {
margin: 0;
padding: 0;
overflow: hidden;
}
<script src="https://cdn.jsdelivr.net/npm/p5#1.3.1/lib/p5.js"></script>
I currently have a canvas container with a width of 100% width and 50% height. Whenever I draw something like lines, I have to pass x and y coordinates to it:
context.moveTo(20, 20);
context.lineTo(50, 20);
context.stroke();
Unfortunately, whenever I resize the canvas (by resizing the browser), the line still have the same dimension as before and will not adjust to it's canvas size like seen in the picture:
This is how I actually resize:
var scale = window.devicePixelRatio;
this.canvas.width = Math.floor(parseInt(this.$canvasPage.css('width')) * scale);
this.canvas.height = Math.floor(parseInt(this.$canvasPage.css('height')) * scale);
this.context.scale(scale, scale);
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.drawContent();
Does anyone have an idea how to fix this? I also thought about something like calculating x and y positions but I do not know the maximum coordinates. Or are there any better ways?
Later, it I'm planning to add rectangles, input fields, and so on...
Thank you for helping!
context.moveTo and context.lineTo takes in a number of pixels, so if you do not change the value the distance will not change. You could instead use a percentage of the canvases width:
context.moveTo(0.2 * this.canvas.width, 0.2 * this.canvas.height);
context.lineTo(0.5 * this.canvas.width, 0.2 * this.canvas.height);
context.stroke();
I'm using ctx.globalCompositeOperation = 'destination-over'. Though the text still goes behind.
Game.setup();
ctx = Game.context;
if (AllImagesLoaded === true) {
loading = false;
clearInterval(int);
BackgroundsA.push(true);
ctx.globalCompositeOperation = 'destination-over';
Interact = new text(window.innerWidth / 2, window.innerHeight / 2 - 200, 'Press F to Interact', 'white', '30px Verdana');
Sprites.push(new sprite(window.innerWidth / 2 - 275, window.innerHeight / 2 - 315, 'idle_jack/frame_1.PNG', 600, 600, 5));
Player = new component(window.innerWidth / 2, window.innerHeight / 2 - 100, 'rgba(0, 0, 0, 0)', 50, 150);
ctx.globalCompositeOperation = 'source-over';
Backgrounds.push(new background(0, 0, 'Backgrounds/Test/test2.jpg'));
ctx.globalCompositeOperation = 'destination-over';
The "new [KEYWORDS]" are functions for filling or drawing text/components/images.
Please help!
Why don't you draw everything from behind, i.e. firstly draw the backgrounds of the game, then text and at the end player and all of the game objects ?
However if you do want to draw everything like you're trying to now, then try changing global composite operation just before drawing, it's not clear if new Background() will actually draw the background or not from your code. Here is an article to read about global composite operation:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
THREE.Box3.setFromObject(*object*) returns wrong values. The best way to show you is by showing you how I work through it:
I create 2 meshes from vertices. First one with the triangle() function, the other with trapezoidForm().
var triangle = function (base, height) {
return [
new THREE.Vector2(0, -height / 2),
new THREE.Vector2(-base / 2, height / 2),
new THREE.Vector2(base / 2, height / 2)
];
}
var trapezoidForm = function (base, upperBase, height) {
return [
new THREE.Vector2(-base / 2, height / 2),
new THREE.Vector2(-upperBase / 2, -height / 2),
new THREE.Vector2(upperBase / 2, -height / 2),
new THREE.Vector2(base / 2, height / 2),
];
}
I use the returned value to create my mesh:
var material = new THREE.MeshPhongMaterial({ color: 0x666666, /*specular: 0x101010*//*, shininess: 200*/ });
var shape = new THREE.Shape(vertices);
var mesh = new THREE.Mesh(new THREE.ShapeGeometry(shape), material);
And use that to place it in the scene, and to create a boundingbox:
mesh.position.set(posX, 0, posZ);
mesh.rotation.set(-Math.PI / 2, 0, 0);
boundingBox.setFromObject(mesh);
Now, I want to find the center of my 2 shapes. Easy enough: I take the boundingbox, and calculate it. Like this:
var centerX = (boundingBox.max.x + boundingBox.min.x) * 0.5;
var centerZ = (boundingBox.max.z + boundingBox.min.z) * 0.5;
Here is where it goes wrong: For the triangle, it calculates the right spot, but for the trapezoid, it messes up.
Below is a printscreen of the console. The first 3 vertices are for the triangle, followed by the boundingbox. The next 4 are for the trapezoid, with again the bounding box. For the vertices: first number is X-coord, second one is Z-coord.
Desired result: 2nd boundingbox should return something like:
max: X: 200
Z: 200
min: X: -200
Z: -100
Image showing the current state (triangle has the minus-sign in the middle, trapezoid not):
Found the solution myself in the end:
I have to create my boundingBox before I reposition or rotate it:
//Boundingbox
boundingBox.setFromObject(mesh);
mesh.position.set(posX, 0, posZ);
mesh.rotation.set(-Math.PI / 2, 0, 0);
instead of:
mesh.position.set(posX, 0, posZ);
mesh.rotation.set(-Math.PI / 2, 0, 0);
//Boundingbox
boundingBox.setFromObject(mesh);
the reason why the triangle didn't cause problems, was because it was rendered on 0,0.