I'm trying to add a light effect, like a lantern, on a simple game using p5.js.
So, I have a background image and a player who is the source of the light (so it will go a radius from him).
I used a circle with RGBA color to make this effect, so it lights the background close to the player, but the problem is that the rest of the background is still visible, when it should be all dark, and I couldn't find a method in p5.js to handle that.
As an example of what I want to achieve, there's this game on itch.io that does exactly that.
You may try to give the circle pixels of the "background" image
As i cannot comment right now, I suggest you color few background pixels by some shape,
You would not find, i think so to open a hole to the front dark image.
Although this tool
pixC = color(yourBImagePlace.get(x, y));
will not give your perfect result
Class fireParticle{ ...
show() {
noStroke();
fill(this.pixC);
ellipse(this.x, this.y, this.radius);
}
move() {
this.x += random(-5, 5);
this.y -= random(1, 3);
}
}
you can always try some
kernels
|| convolution
(computer vision techniques)
Related
In my game there are enemies wandering around, their draw() method is simple:
core.displayBuffer is a PGraphics object that is draw onto the screen at the end of draw().
if(facingRight) {
core.displayBuffer.image(image,
x, y + offsetY, 80, 80);
} else {
float tX = -core.camera.x+core.game.width/2f + x;
float tY = -core.camera.y+core.game.height/2f+ y;
core.displayBuffer.pushMatrix();
core.displayBuffer.translate(core.camera.x-core.game.width/2f,
core.camera.y-core.game.height/2f);
core.displayBuffer.translate(tX, tY);
core.displayBuffer.scale(-1, 1);
core.displayBuffer.image(image,
-80, offsetY, 80, 80);
core.displayBuffer.popMatrix();
}
Then when we are going to draw walls, we just draw a coloured rectangle like this:
core.displayBuffer.noStroke();
if(destroyed) {
core.displayBuffer.fill(0, 0, 0, 16);
core.displayBuffer.rect(x, y, w, h);
} else {
core.displayBuffer.fill(64);
core.displayBuffer.rect(x, y - WALL_HEIGHT, w, h);
core.displayBuffer.fill(32);
core.displayBuffer.rect(x, y + h - WALL_HEIGHT, w, WALL_HEIGHT);
}
But for some reason, the walls have the texture of the enemies? Here's the loop in which the objects are drawn:
PMatrix displayMatrix = displayBuffer.getMatrix();
PMatrix bloomMatrix = bloomLayer.getMatrix();
PStyle displayStyle = displayBuffer.getStyle();
PStyle bloomStyle = bloomLayer.getStyle();
onScreenObjects.forEach(o -> {
displayBuffer.setMatrix(displayMatrix);
bloomLayer.setMatrix(bloomMatrix);
displayBuffer.style(displayStyle);
bloomLayer.style(bloomStyle);
o.draw(this);
});
displayBuffer.setMatrix(displayMatrix);
bloomLayer.setMatrix(bloomMatrix);
displayBuffer.style(displayStyle);
bloomLayer.style(bloomStyle);
Here's example of the results, red rectangles are around the walls, that are drawn incorrectly.
Also the bullets are flickering for some reason? These 2 bugs don't appear when I don't draw the enemies onto the screen (or I draw just rectangles instead), so that means, that the image() is doing something weird in the background?
Project's source code is at https://github.com/Matrx007/TheLostBits
Ask for additional info if needed!
Nvidia Quadro 4000.
Graphics card driver is from 2016, can't upgrade it, all other games are working fine tho.
Processing version: 3.5.3 (Library)
Operating System and OS version: Windows 10 build 17134
Possible Causes / Solutions:
Maybe that the image() manipulates the current texture being used and rect() uses the texture?
SOLVED
The solution was, that Processing can't draw onto more than one PGraphics at a time. I had beginDraw() called on two PGraphics and I was drawing to both of them at the same time, now I separated them, and the bug is gone! Better explanation here: https://github.com/processing/processing/issues/5863
I have a program where a box ( player ) can land on the ground ( environment ), move and jump around. In the process of trying to make the boxes forward direction independent from the environment I used a couple or translations and rotations. this works fine for the boxes movement but now i do not know the coordinates of the box to use the camera function to focus on it.
void setup() {
size(600,600,P3D);
PVector eye = new PVector(0,0,0);
PVector translations = new PVector(0,0,0);
background(200);
translate(width/2, height/2);
rotateZ(mouseX/(width/PI));
//ground would be drawn here
translate(0,0,-400);
translate(50, 100 ,490);
rotateZ(-mouseX/(width/PI));
box(150);
translations.add(0,0,0);//translations occurring from rotations and translation
eye.add(translations);
eye.add(500, 1000, 500); //translate the eye away from the point its looking at
camera(eye.x, eye.y, eye.z, translations.x, translations.y, translations.z, 0, 0, -1);
eye.mult(0);
translations.mult(0);
}
How can I find the position of the box after the translations? I know that the use of sin and cos is necessary but i cannot for the life of me get an algorithm that works perfectly.
edit: I changed the code to be complete and verifiable
I have this codepen: https://codepen.io/giorgiomartini/pen/OjQpKd?editors=0010
Where I paint some shapes and some text, now I want to add a radial overlay between the shapes and the text.
So I created a drawgradient function and call it between the shapes and the text:
function drawGradient() {
blendMode(MULTIPLY)
for (let r = canvasX; r > 0; --r) {
let lightnes = map(r,0,canvasX,255,0)
fill(0, 0, lightnes)
ellipse(0, 0, r*1.8, r*2)
}
}
I want this gradient to have a multiply blend mode, so that it makes the whole thing a bit darker where the pixels are darker in the gradient.
But all i get is a full black overlay...
In photoshop or gimp, if you add a black and white radial gradient with a multiply blend mode it makes the background darker where there are darker pixles in the gradient.. but here in p5js it just makes everything black.
any ideas what am I doing wrong?
This is the mouseClicked function, and at the bottom, you can see the gradient function being called:
function mouseClicked(){
blendMode(BLEND)
const colsArray = randomColor({luminosity: 'light', format: 'hsl',count: 4})
background(colsArray[0])
translate(width/2, height/2)
////////////////////////////////////////////////////////////////// amt initial range
const arrayOfRandomNumsOfFirstProbStepX = createArrayOfRandomNums(amtOfSpotsInFirstProb,startProbStep,firstProbStepX)
const arrayOfRandomNumsOfFirstProbStepY = createArrayOfRandomNums(amtOfSpotsInFirstProb,startProbStep,firstProbStepY)
const arrayOfRandomNumsOfSecondProbStepX = createArrayOfRandomNums(amtOfSpotsInSecondProb,startProbStep,secondProbStepX)
const arrayOfRandomNumsOfSecondProbStepY = createArrayOfRandomNums(amtOfSpotsInSecondProb,startProbStep,secondProbStepY)
drawLinesAtRandomspots(6,random(50),colsArray)
//args => element, arrayOfRandomNumsOfProbStepX, arrayOfRandomNumsOfProbStepY, elmntSizeMin, elmntSizeMax,rot, colors
drawElmntsOnSomeProbabilityStep('ellipse',arrayOfRandomNumsOfFirstProbStepX, arrayOfRandomNumsOfFirstProbStepY , 10, 80, true, colsArray )
drawElmntsOnSomeProbabilityStep('rect',arrayOfRandomNumsOfSecondProbStepX, arrayOfRandomNumsOfSecondProbStepY, 5, 30, true, colsArray)
drawGradient()
addText()
}
Placing clear() at the beginning of the draw() function will clear the pixels within a buffer. This lets you use blendMode(MULTIPLY) without your overlapping shapes turning black after the first few frames.
If the effect you're going for is a linear gradient, it seems a little weird that you're drawing a bunch of ellipses to the screen.
ellipse(0, 0, r*1.8, r*2)
What do you expect this line to do?
Instead, I would think it would make more sense if you would draw a series of lines, a little bit darker or lighter each time. Here's an example:
function drawGradient() {
blendMode(MULTIPLY);
for (let lineX = 0; lineX < width; lineX++) {
let lightness = map(lineX, 0, width, 0, 255);
stroke(0, lightness)
line(lineX, 0, lineX, height)
}
}
This creates a horizontal gradient that fades from light to dark.
Edit: If you want a radial gradient, right now you're drawing a ton of dark circles on top of each other, so they're "stacking" to just become entirely black. You need to do a combination of drawing fewer circles (every 10 pixels instead of every 1 pixel, for example) and drawing them lighter. Here's an example:
function drawGradient() {
blendMode(MULTIPLY);
for (let r = 600; r > 0; r-=10) {
let lightness = map(r, 0, 600, 20, 0);
fill(0, lightness);
noStroke();
ellipse(0, 0, r, r);
}
}
This code draws circles every 10 pixels, and the darkest circle has an alpha of 20 instead of 255. This causes a much lighter gradient. You'll have to play with the exact values to get the effect you're going for.
If you have a follow-up question, please post a MCVE instead of your whole project. Just a couple of hard-coded shapes and a single gradient function would be enough, as long as we can run it. As of now your code is a little hard to debug because it contains a bunch of stuff not directly related to the problem. Good luck.
I have stuck up in a problem. This question is with respect to processing. I have to draw a scratch on an image using this function
line(pmouseX, pmouseY, mouseX, mouseY);
How do I achieve this? I mean, wherever I draw a scratch, pixel corresponding to that image has to be updated.
Thanks for any assistance
I'm not sure what kind of effect do you want to achieve so here is basic usage of drawing line according to mouse position.
PImage img; //global variable for storing image
void setup(){
img = loadImage("image.jpg"); //loading image
size(img.width, img.height); //setting size of sketch
}
void draw(){
image(img, 0, 0); //each time redraw background with Image
line(pmouseX, pmouseY, mouseX, mouseY); //draw line acc to mouse
}
If you want to draw big line just move image() function into setup().
If you want more complicated lines you will have to use mouse events.
This is for the programing language Processing (2.0).
Say I wish to load a not square image (lets use a green circle for the example). If I load this on a black background you can visibly see the white square of the image(aka all parts of image that aren't the green circle). How would I go about efficiently removing them?
It can not think of an efficient way to do it, I will be doing it to hundreds of pictures about 25 times a second(since they will be moving).
Any help would be greatly appreciated, the more efficient the code the better.
As #user3342987 said, you can loop through the image's pixels to see if each pixel is white or not. However, it's worth noting that 255 is white (not 0, which is black). You also shouldn't hardcode the replacement color, as they suggested -- what if the image is moving over a striped background? The best approach is to change all the white pixels into transparent pixels using the image's alpha channel. Also, since you mentioned you would be doing it "about 25 times a second", you shouldn't be doing these checks more than once-- it will be the same every time and would be wasteful. Instead, do it when the images are first loaded, something like this (untested):
PImage[] images;
void setup(){
size(400,400);
images = new PImage[10];
for(int i = 0; i < images.length; i++){
// example filenames
PImage img = loadImage("img" + i + ".jpg");
img.beginDraw();
img.loadPixels();
for(int p = 0; p < img.pixels.length; p++){
//color(255,255,255) is white
if(img.pixels[p] == color(255,255,255)){
img.pixels[p] = color(0,0); // set it to transparent (first number is meaningless)
}
}
img.updatePixels();
img.endDraw();
images[i] = img;
}
}
void draw(){
//draw the images as normal, the white pixels are now transparent
}
So, this will lead to no lag during draw() because you edited out the white pixels in setup(). Whatever you're drawing the images on top of will show through.
It's also worth mentioning that some image filetypes have an alpha channel built in (e.g., the PNG format), so you could also change the white pixels to transparent in some image editor and use those edited files for your sketch. Then your sketch wouldn't have to edit them every time it starts up.
Pixels are stored in the Pixels[] array, you can use a for loop to check to see if the value is 0 (aka white). If it is white load it as the black background.