p5.js: Make a Gradient Stroke with beginShape() - vertex

The following code generates a single particle at a random position. The particle moves right, once it's completely off the screen, it appears left again.
The particle creates a nice trail. However, I'd like the trail to fade out.
I tried setting the stroke color stroke(random(255)) while setting the vertexes, but it changes the color of the entire shape instead.
You will find the relevant lines at the comment
// draw particle and history (approx. line 76)
https://codepen.io/normanwink/project/editor/XJoRYa
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="framerate"></div>
<!-- scripts -->
<script src="https://github.com/processing/p5.js/releases/download/0.5.14/p5.min.js"></script>
<script>
function setup() {
frameRate(30);
createCanvas(1000, 500, 'WEBGL');
particle = new Particle();
}
function draw() {
background(0);
particle.update();
particle.edges();
particle.show();
var output = '';
output += floor(frameRate()) + 'fps';
document.getElementById('framerate').innerHTML = output;
}
function Particle(mX = random(width), mY = random(height)) {
this.pos = createVector(mX,mY);
this.vel = createVector(8,0);
this.acc = createVector(0,0);
this.maxSpeed = 8;
this.trail = 60; // how long to track history
this.history = [];
this.update = function() {
this.vel.add(this.acc);
this.vel.limit(this.maxSpeed);
this.pos.add(this.vel);
this.acc.mult(0);
this.history.push(this.pos.copy());
if (this.history.length > this.trail) {
this.history.splice(0,1);
}
}
this.show = function() {
stroke(255);
strokeWeight(5);
// draw particle and history
beginShape();
for (var i=0; i<this.history.length; i++) {
var pos = this.history[i];
// stroke(random(255))
curveVertex(pos.x, pos.y);
}
endShape();
noStroke();
fill(255);
ellipse(this.pos.x, this.pos.y, 10);
}
// if particle hits the edge
this.edges = function() {
if (this.history[0].x > width && this.pos.x > width) {
this.pos.x = 0;
this.history = [];
return false;
}
if (this.history[0].x < 0 && this.pos.x < 0) {
this.pos.x = width;
this.history = [];
return false;
}
if (this.history[0].y > height && this.pos.y > height) {
this.pos.y = 0;
this.history = [];
return false;
}
if (this.history[0].y < 0 && this.pos.y < 0) {
this.pos.y = height;
this.history = [];
return false;
}
}
}
</script>
</body>
</html>
Unfortunately, it requires minor physics and handling the particles collision with the edges to work, so this is the most reduced version of the code.
For those who are interested, here is a full example: https://codepen.io/normanwink/pen/jLdpez

You'll have better luck if you post a MCVE showing what you've tried along with a specific techincal question. Here's an example:
function setup(){
createCanvas(200, 200);
}
function draw(){
background(220);
noFill();
stroke(255);
beginShape();
curveVertex(84, 91);
curveVertex(84, 91);
curveVertex(68, 19);
stroke(128);
curveVertex(21, 17);
stroke(0);
curveVertex(32, 100);
curveVertex(32, 100);
endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.14/p5.js"></script>
We might expect this to show a very basic gradient on a path. (Notice how much easier this is to think about than your whole project!) But if we run it, then we'll see that it only ever takes the last color, in this case black.
To get around this, we need to break your path down into multiple shapes. Here's the same path, split into multiple shapes so we can give each section of the path a different shape:
function setup() {
createCanvas(200, 200);
}
function draw() {
background(220);
noFill();
stroke(0);
beginShape();
curveVertex(84, 91);
curveVertex(84, 91);
curveVertex(68, 19);
curveVertex(21, 17);
endShape();
stroke(128);
beginShape();
curveVertex(84, 91);
curveVertex(68, 19);
curveVertex(21, 17);
curveVertex(32, 100);
endShape();
stroke(255);
beginShape();
curveVertex(68, 19);
curveVertex(21, 17);
curveVertex(32, 100);
curveVertex(32, 100);
endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.14/p5.js"></script>
If we run that, we'll see that the path does indeed have different colors.
You'd need to do something very similar where you break your path down into multiple shapes. Then you'd just need to modify the color passed into the stroke() function to create your gradient.

Related

Button for Creative Coding Asteroids project

I'm an undergrad and in one of my classes, we have this assignment to make the Asteroids game (you know, the retro one!) on Processing (which is basically a simplified Javascript program). I have the code for a button:
void setup()
{
size(1280, 720);
}
void draw()
{
background(0,0,0);
drawButton();
}
Boolean pointIsInRectangle(int left, int top, int right, int bottom, int pointX, int pointY)
{
if (pointX >= left
&& pointX <= right
&& pointY <= bottom
&& pointY >= top
)
return true;
else
return false;
}
void drawButton()
{
int left = 350;
int top = 145;
int right = 860;
int bottom = 220;
rectMode(CORNERS);
color background = color(0,0,0);
if (pointIsInRectangle(left,top,right,bottom,mouseX,mouseY))
{
background = color(255);
}
// draw outer rectangle
stroke(255);
fill(background);
rect(left,top,right,bottom);
// draw caption
fill(255);
textSize(100);
text(" ASTEROIDS", left,bottom);
}
and I have the preliminary code for the ship for the game, but I need the button to get to an "in between" page so that when the button is clicked, it leads to a new screen that says "click anywhere to play game" and when any point in the screen is clicked, the ship appears and asteroids begin appearing and the game begins. HOW DO I GET THE BUTTON TO LEAD TO A NEW PAGE, AND HOW DO I CREATE THAT PAGE? I really cannot figure it out. Crossing my fingers that someone will be able to give me some guidance!!!!!
The actual result I'm seeing is that nothing is happening when the button is clicked. This makes sense because I don't know how to add the next page that says Click to Play Game, so this is the issue I'm facing. The code I have so far can be found above.
This is not question about a button, but about a game engine with multiple scenes.
Your game is a collection of screens (scenes). Every scene have definition of visuals, definition of logic, and definition of switch for another scene.
Here is the minimal solution of Your problem.
1 - Define visuals of Your screens in .display() method,
2 - Define logic condition for next screen switch in stateCondition().
boolean mouseReleased;
GameScreen screen;
GameScreen splashScreen;
GameScreen inBetweenPage;
void setup() {
size(1280, 720);
GameScreen splashScreen = new SplashScreen();
GameScreen inBetweenPage = new InBetweenPage();
splashScreen.setNextScreen(inBetweenPage);
inBetweenPage.setNextScreen(splashScreen);
screen = splashScreen;
mouseReleased = false;
}
void draw() {
screen.display();
if (screen.stateCondition()) {
screen = screen.getNextScreen();
}
}
interface GameScreen {
/**
** screen visual definition
**/
void display();
/**
** screen change state condition
**/
boolean stateCondition();
void setNextScreen(GameScreen scr);
GameScreen getNextScreen();
}
class SplashScreen implements GameScreen {
GameScreen nextScreen;
int left = 350;
int top = 145;
int right = 860;
int bottom = 220;
void display() {
background(0, 0, 0);
rectMode(CORNERS);
color background = color(0, 0, 0);
if (pointIsInRectangle(left, top, right, bottom, mouseX, mouseY)) {
background = color(255, 255, 255, 160);
}
// draw outer rectangle
stroke(255);
fill(background);
rect(left, top, right, bottom);
// draw caption
fill(255);
textSize(100);
textAlign(CENTER, CENTER);
text("ASTEROIDS", (left+right)/2, (top+bottom)/2-16);
}
boolean stateCondition() {
if (mouseReleased && (mouseButton == LEFT)) {
mouseReleased = false;
return pointIsInRectangle(left, top, right, bottom, mouseX, mouseY);
}
return false;
}
GameScreen getNextScreen() {
return nextScreen;
}
void setNextScreen(GameScreen target) {
this.nextScreen = target;
}
}
class InBetweenPage implements GameScreen {
GameScreen nextScreen;
int left = 0;
int top = 0;
int right = width;
int bottom = height;
void display() {
background(0, 0, 0);
// draw caption
fill(255);
textSize(24);
textAlign(CENTER, CENTER);
text("< click anywhere to play game >", width/2, height/2);
}
boolean stateCondition() {
if (mouseReleased && (mouseButton == LEFT)) {
mouseReleased = false;
return pointIsInRectangle(left, top, right, bottom, mouseX, mouseY);
}
return false;
}
GameScreen getNextScreen() {
return nextScreen;
}
void setNextScreen(GameScreen target) {
this.nextScreen = target;
}
}
Boolean pointIsInRectangle(int left, int top, int right, int bottom, int pointX, int pointY) {
if (pointX >= left && pointX <= right && pointY <= bottom && pointY >= top) {
return true;
} else
return false;
}
void mouseReleased() {
mouseReleased = true;
}
There is a relatively simple solution to this problem, which would be to make some space for a special "splashscreen" state in your code. It would almost be ninja coding to implement it, although in this case as you are learning it's not taking shortcuts but more like climbing a new step in the learning stairwell. Here's a proof of concept which shows what I'm speaking about:
// this boolean keeps track of the current game state: splashscreen or not
boolean splashScreen = true;
void setup() {
size(600, 400);
}
void draw() {
background(0);
// if the game has yet to start, show the splashscreen
if (splashScreen) {
drawSplashScreen();
} else {
playGame();
}
}
// this method draws the splashScreen
// it could be coded in the 'draw()' method, but it's easier to read this way
void drawSplashScreen() {
textAlign(CENTER);
textSize(30);
fill(255);
text("THIS IS THE SPLASHSCREEN \n click anywhere to play the game", width/2, height/2);
}
// this method contains everything your game loop needs to work
void playGame() {
textAlign(CENTER);
textSize(40);
fill(200, 0, 200);
text("YOU ARE CURRENTLY \n PLAYING THE GAME", width/2, height/2);
}
void mouseClicked() {
if (splashScreen) {
splashScreen = !splashScreen;
}
}
Here you have 2 game states: the splash screen and the game itself, but you could implement more than just these two. There's a design pattern called Finite State Machine that would be just perfect for your needs. Although you already have everything you need to code your assignment, let me explain a little further:
A FSM let you determine the context which can lead to another context and limit some actions to it's own context. A good example of this is Mario in the original Super Mario Bros game: when he's small, getting a magic mushroom will transform him into Super Mario. When he's Super, getting a flower will transform him into Fire Mario. But while small, getting a flower will only make him into Super Mario, not Fire Mario (in the ooold first game at least). That's because each one of these states have rules, and he cannot just jump from one to the other without regard for these.
Your game's logic has it's own rules too: you have the first screen with the "start" button. When this button is clicked, there's a second state where it says "click anywhere to play the game". If the user clicks, then the game itself starts. That makes for 3 states (3 screens if you like) where every state has it's own set of rules - which we often call 'business rules'.
We could schematize this assignment like this:
And here's the skeleton code that would implement such a game, including a bonus rectangle collision detection method:
// the game states are as follow:
// 0 is welcome screen with button
// 1 is click anywhere screen
// 2 is the game itself
int gameState = 0;
void setup() {
size(600, 400);
}
void draw() {
background(0);
// let's use the right game state here
switch(gameState) {
case 0:
drawWelcomeScreen();
break;
case 1:
drawClickAnywhereScreen();
break;
case 2:
playGame();
break;
}
}
void drawWelcomeScreen() {
fill(0, 0, 100);
rect(100, 100, 400, 100);
textAlign(CENTER);
textSize(30);
fill(255);
text("Click here to play", 300, 150);
text("THIS IS THE WELCOME SCREEN", width/2, 50);
}
void drawClickAnywhereScreen() {
textAlign(CENTER);
textSize(30);
fill(255);
text("Click anywhere to play the game", width/2, height/2);
}
void playGame() {
textAlign(CENTER);
textSize(40);
fill(200, 0, 200);
text("YOU ARE CURRENTLY \n PLAYING THE GAME \n click anywhere to go \n back to the welcome screen", width/2, height/2);
}
void mouseClicked() {
// now this will be more complicated, because you'll want to deal with clicks differently depending on the game state
// which kinda answers the question as how we'll deal with this issue: same as in the 'draw()' method
switch(gameState) {
case 0:
// if the click's coordinates are in the rectangle's coordinates (use math here, or a collision method)
// (in fact, use math pretty much everywhere)
// (I hope you like math)
// anyway here's an old collision method I paste everywhere on SO, feel free to steal it and improve on it!
// I wrote it as a student to deal with pretty much the same stuff that you're going through
if (intersect(100, 100, 400, 100, mouseX, mouseY, 1, 1)) {
gameState = 1;
}
break;
case 1:
gameState = 2;
break;
case 2:
gameState = 0;
break;
}
}
// enter the xy coordinates, the width and the heigh of 2 rectangle shapes and it'll return true if they intersect
boolean intersect(float x1, float y1, float w1, float h1, float x2, float y2, float w2, float h2) {
boolean checkX = false;
boolean checkY = false;
if ( (x1<x2 && (x1+w1)>x2) || (x1<(x2+w2) && (x1+w1)>x2+w2) || (x1>x2 && (x1+w1)<(x2+w2)) ) {
checkX = true;
}
if ( (y1<y2 && (y1+h1)>y2) || (y1<(y2+h2) && (y1+h1)>y2+h2) || (y1>y2 && (y1+h1)<(y2+h2)) ) {
checkY = true;
}
return checkX && checkY;
}
I hope I'm not confusing you with all this material. I'll try and keep an eye out for any question you may have about these things.
Good luck and have fun!

How to Calculate a particular area using MouseClicked () method in Processing?

In my window there is a circle. I have implemented the void MouseClicked() method to take effect on the mouse click event. That means only clicking inside the circle should change the color of the circle and do the corresponding operation.
But the problem is wherever I click (even outside the circle), it changes the color of the circle. So I understand that the mouseClicked() method isn't stable. How do I fix this?
My code in processing:
int colorValue = 0;
void setup() {
size(450, 255);
background(204);
}
void draw() {
fill(colorValue);
ellipse(56, 46, 55, 55);
}
void mouseClicked() {
if (colorValue == 0) {
colorValue = 255;
} else {
colorValue = 0;
}
}
You aren't doing any check for whether the mouse is in the circle. You could use the dist() function to help with that:
int colorValue = 0;
float circleX = 56;
float circleY = 46;
float circleR = 55;
void setup() {
size(450, 255);
background(204);
ellipseMode(RADIUS);
}
void draw() {
fill(colorValue);
ellipse(circleX, circleY, circleR, circleR);
}
void mouseClicked() {
if(dist(mouseX, mouseY, circleX, circleY) < circleR){
if (colorValue == 0) {
colorValue = 255;
} else {
colorValue = 0;
}
}
}

Want a paddle at bottom x-axis in this animation

I am making an animation of ball and paddle. Ball is bouncing well.
After this i want a paddle or a <div> element shaped "paddle" at x-axis.
This paddle must be moving only by x-axis and should be moving when i active cursor at any position to x-axis.
Any help?
Here is my code:
var x=150;
var y=150;
var dx=2;
var dy=4;
var WIDTH;
var HEIGHT;
var ctx=document.getElementById("canvas").getContext("2d");
ctx.beginPath();
ctx.arc(150,150,10,0,2*Math.PI,true);
ctx.closePath();
ctx.fill();
function init() {
var ctx=document.getElementById("canvas").getContext("2d");
return setInterval(draw,10);
}
function draw() {
ctx.clearRect(0,0,300,300);
ctx.beginPath();
ctx.arc(x,y,10,0,2*Math.PI,true);
ctx.closePath();
ctx.fill();
x+=dx;
y+=dy;
bounce();
}
function bounce(){
if(x+dx>300||x+dx<0)
dx=-dx;
if(y+dy>300||y+dy<0)
dy=-dy;
}
init();
And in a Fiddle, here.
Try this code:
In your var declarations:
var mouseX = 150;
In your init() function:
document.getElementById("canvas").addEventListener('mousemove', moveHandler);
In your draw() function:
ctx.rect(mouseX-20,280,40,5); // rect( x , y , width , height )
ctx.fillStyle = 'black'; // ^ This is the mouse's X position, minus half the paddle width.
ctx.fill();
And finally, add this function:
function moveHandler(e){
e = e || window.event; // Compatibility.
mouseX = e.offsetX;
}
So, your resulting code Will look like this:
var x=150;
var y=150;
var dx=2;
var dy=4;
var WIDTH;
var HEIGHT;
var mouseX = 150;
var mouseY;
var ctx=document.getElementById("canvas").getContext("2d");
ctx.beginPath();
ctx.arc(150,150,10,0,2*Math.PI,true);
ctx.closePath();
ctx.fill();
function init() {
document.getElementById("canvas").addEventListener('mousemove', moveHandler);
return setInterval(draw,10);
}
function moveHandler(e){
mouseX = e.offsetX;
}
function draw() {
ctx.clearRect(0,0,300,300);
ctx.rect(mouseX-20,280,40,5);
ctx.fillStyle = 'black';
ctx.fill();
ctx.beginPath();
ctx.arc(x,y,10,0,2*Math.PI,true);
ctx.closePath();
ctx.fill();
x+=dx;
y+=dy;
bounce();
}
function bounce(){
if(x+dx>300||x+dx<0)
dx=-dx;
if(y+dy>300||y+dy<0)
dy=-dy;
}
init();

Why does the x value change in this program?

I have created this code, and when I run it, don't get any errors until the arrow leaves the screen (ie: (*I)->x>maxx), after which the O will randomly teleport (Well, I'm guessing its not random, but I'm trying to find a pattern to it).
EDIT: the random teleportation don't seem to occur if I move up, and if I move down, the O is teleported directly to the bottom. Also, a glitch has occured where the O becomes a '>'. (I am trying to figure out how that happens)
EDIT: the transform-into-'>' glitch occurs if the O is at the bottom right of the screen (player.x=9;player.y=9) and the sequence "wqs" is entered.
EDIT: I've removed the class declarations because I am fairly sure that the error is within the _move()s and check().
EDIT: The transform glitch appears to occur when 'wq' is typed, then any other character is entered (ie "skiping" the next move)
EDIT: The tranform glitch occurs when player.x=9; player.y=8; and then 'q' is pressed, the next move the player tranforms into a '>'
This is the code:
#include<vector>
#include<iostream>
#include<string>
using namespace std;
const int maxx = 10, maxy = 10; //two constants that show the size of the sector
char sector[maxx][maxy]; //array of characters used to display the sector
prgm player(0, 0, 'O'); //player definition at x0,y0,and displayed with 'O'
const int vsize = 1; //size of the enemy array (ie: how many enemies there will be
X1 a(9, 5, 'X', 10); //enemy "a", has a move function that moves it back and forth
virus * viral_data[vsize] = {&a}; //array of enemies used to set the sector
vector<antivirus*> antiviral_data; //vector of pointers to "antivirus" the weapon used
vector<antivirus*>::iterator I; //iterator for previous vector
void display() //function to display the sector
{
for(int i = 0; i < maxy; i++)
{
for(int j = 0; j < maxx; j++)
{
cout<<sector[j][i];
}
cout<<endl;
}
return;
}
void p_move() //function to get players input, then move the player or create "antivirus"
{
char dir;
cin>>dir;
switch(dir)
{
case 'w':
player.y--;
break;
case 'a':
player.x--;
break;
case 's':
player.y++;
break;
case 'd':
player.x++;
break;
case 'q':
antiviral_data.push_back(new aX1(player.x, player.y, '>')); //creates a new aX1 at the players position
break;
}
return;
}
void v_move() //uses the enemies move
{
for(int i = 0; i < vsize; i++)
{
viral_data[i]->move();
}
return;
}
void a_move() //uses the weapon (ie: moves the weapon forward)
{
for(I = antiviral_data.begin(); I < antiviral_data.end(); I++)
{
(*I)->move();
}
return;
}
void set() //sets the sector array (char)
{
for(int i = 0; i < maxy; i++)
{
for(int j = 0; j < maxx; j++)
{
sector[j][i] = ' '; makes the entire sector blank
}
}
sector[player.x][player.y]=player.sym; //sets the sector at the player's position to 'O'
for(int i = 0; i < vsize; i++)
{
sector[viral_data[i]->x][viral_data[i]->y] = viral_data[i]->sym; //sets the sector at each enemy's position to be 'X'
}
for(I = antiviral_data.begin(); I < antiviral_data.end(); I++)
{
sector[(*I)->x][(*I)->y] = (*I)->sym; //sets the sector at each weapon's position to be '>'
}
return;
}
void check() //prevents the player from moving off the screen, erases bullet if it moves of the screen (to prevent access to non-allocated memory)
{
if(player.x < 0)
{
player.x = 0;
}
if(player.y < 0)
{
player.y = 0;
}
if(player.x > (maxx-1))
{
player.x = (maxx-1);
}
if(player.y > (maxy-1))
{
player.y = (maxy-1);
}
//PROBLEM APPEARS TO OCCUR HERE
for(I = antiviral_data.begin(); I! = antiviral_data.end();)
{
if((*I)->x > maxx)
{
I = antiviral_data.erase(I);
}
else
{
I++;
}
}
//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
return;
}
int main()
{
while(true)
{
set(); //set sector
display(); //display sector
p_move(); //player's move
v_move(); //enemy's move
a_move(); //bullet's move
check();//check moves
}
return 0;
}
In check(), the test
((*I)->x > maxx)
should be
((*I)->x >= maxx)
. This is an off-by-one error that lets the > get one square off the screen. When the display routine tries to display it, it clobbers the display symbol for the X.

Jogl making balls disappear

At the moment am using JOGL for a ball detection program I have been told to make the balls disappear once they get to close to one another.
//this is the method from the main class
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glColor3f(1.0f, 1.0f, 1.0f);
glut.glutWireCube(2.0f * limit);
for (int i = 0; i < ball.length; ++i)
{
ball[i].display(gl);
}
for (int i = 0; i < ball.length; ++i)
{
ball[i].moveRandomly();
}
//this is the method from the auxiliary class
for (int i = 0; i < ball.length; ++i)
{
for (int j = 0; j < ball.length; ++j)
{
if (ball[i].distanceFrom(ball[j]) <= 10)
{
}
}
}
}
void display(GL gl) {
gl.glLoadIdentity();
gl.glTranslatef(position[0], position[1], position[2]);
gl.glColor3fv(colour, 0);
glut.glutSolidSphere(radius, 10, 10);
//glut.glutSolidTeapot(radius);
}
I tried doing this to no avail the balls disappear all at once, I also tried decreasing the radius with the same results, any sort of point in the right direction would be much appreciated.
The reason they're all disappearing is that each ball is being compared to itself.
Add this in the inner loop before the if statement (this is a quick fix):
if (i == j) continue;
I have more questions than help at the moment.
First, how many balls do you have?
This line bothers me:
if(ballGone == false)
{
glut.glutSolidSphere(radius, 10, 10);
}
If ballGone is false then the ball isn't displayed, but that would imply there is only one ball, so when it is set to false no balls will be displayed.
According to here: http://www.cs.umd.edu/~meesh/kmconroy/JOGLTutorial/ my concern should be justified:
Display is very similar to
java.awt.Component.paint() in that it
is called each time the canvas needs
to be redraw/repainted/redisplayed
So, you may want to look at how you will redraw and make certain that each object that doesn't have a state set to false will be drawn.

Resources