Trying to get the Lives and Game Over portion of my game to work - processing

I'm creating a collision detection game where:
Every time I hit the wall, the number of my lives go down.
Once I get to 0 lives, the game is over.
But the game is letting me go into negative lives. Also, my click to begin once you win doesn't seem to work either... Does anybody know how to fix this?
PImage startScreen;
int gamestate=1;
int lives = 3;
class Sprite {
float x;
float y;
float dx;
float dy;
}
Sprite rect=new Sprite();
Sprite ball=new Sprite();
void setup(){
size(500,500);
rect.x = 500;
rect.y = 12;
ball.y= mouseY;
background(0);
fill(0,255,0);
text("Click to Begin", 10, 250);
}
void draw(){
if(gamestate ==0){
background(0);
fill(0, 255,0);
noStroke();
rect(0,235, 500,2.5);
rect(0,250, 500,2.5);
fill(0);
rect(0,238,rect.x,rect.y);
fill(0,255,0);
ellipse(mouseX, mouseY, 2,2);
text("lives left:"+lives, 10, 20);
if (mouseY<240 || mouseY>247){
background(0);
lives = lives-1;
if(lives <= 0){
text("Game Over. \nClick to Begin", 225,250);
gamestate=1;
}
}
if (mouseX >= 495){
background(0);
text("You Win! \nClick to Begin Again.", 225,250);
}
}
}
void mousePressed(){
if (gamestate ==1){
gamestate=0;
}
}

Keep in mind that before your mouse enters the sketch for the first time, mouseX and mouseY are both 0. So in your draw() function, when you check if mouseY < 240, that's true. You do that 60 times per second, so you lose all 3 of your lives right away.
To fix this, you might want to have a "starting rectangle" that the player has to click to start the game, that way you know the mouse is in the window.
Then after that, you have to give the player a chance to get back to the starting circle before starting the next round, otherwise you just keep losing lives 60 times per second.
That basics might look something like this:
int gamestate=1; //1 is start screen, 0 is playing, 2 is between lives, 3 wins
int lives = 3;
class Sprite {
float x;
float y;
float dx;
float dy;
}
Sprite rect=new Sprite();
Sprite ball=new Sprite();
void setup() {
size(500, 500);
rect.x = 500;
rect.y = 12;
ball.y= mouseY;
}
void draw() {
background(0);
if (gamestate ==0) {
fill(0, 255, 0);
noStroke();
rect(0, 235, 500, 2.5);
rect(0, 250, 500, 2.5);
fill(0);
rect(0, 238, rect.x, rect.y);
fill(0, 255, 0);
ellipse(mouseX, mouseY, 2, 2);
text("lives left:"+lives, 10, 20);
if (mouseY<240 || mouseY>247) {
lives = lives-1;
gamestate=2;
if (lives <= 0) {
text("Game Over. \nClick to Begin", 225, 250);
gamestate=1;
}
}
if (mouseX >= 495) {
gamestate=3;
}
}
else if(gamestate == 1 || gamestate==2){
fill(0, 255, 0);
text("Click to Begin", 10, 230);
rect(0, 240, width, 7);
}
else if(gamestate == 3){
text("You Win! \nClick to Begin Again.", 225, 250);
}
}
void mousePressed() {
if (gamestate ==1 || gamestate == 2) {
if(mouseY>240 && mouseY<247){
gamestate=0;
}
}
}
Note that I don't really understand what your game is supposed to do: your "safe area" is only 7 pixels tall, which seems pretty small. But assuming this is just an example, my answer should generalize to your real code:
Split your game up into "modes". You started to do this with your gamestate variable, but you're also mixing event code and drawing code. Instead, make every mode a state: the start screen, the playing screen, the "in between lives" screen, the game over screen. Only draw the stuff for that mode, and then change the mode based on input. Basically, instead of checking for "play mode" and then drawing "game over" when you run out of lives, just switch to "game over mode" and let that part of the code draw the "game over" to the screen.

Related

Using pushMatrix(), popMatrix(), translate(), and rotate()

I have a program that draws a flower with 4 petals to the screen where ever you click. Instead of redoing the petals one at a time I was just going to attempt to rotate the flower by a quarter turn and have it overlay the first flower, so it appears to have 8 petals. The problem is that it draws the second flower some distance away from the first in the x and y direction, but as I get closer to (0,0) they get closer to overlapping (and do at (0, 0)). I'm not sure why this is happening and would appreciate any help. I'm using Processing 3 for this program.
int c_center = 15;
int c_petal = 20;
int petalsize = 70;
color rcol;
void setup(){
fullScreen();
background(0);
}
void draw(){
rcol = color(random(255), random(255), random(255));
}
void mouseClicked(){
pushMatrix();
flower();
translate(mouseX, mouseY);
rotate(PI/4);
flower();
popMatrix();
}
void flower(){
//left petal
make_petal(mouseX - (petalsize - c_petal), mouseY, petalsize, c_petal);
//right petal
make_petal(mouseX + (petalsize - c_petal), mouseY, petalsize, c_petal);
//top petal
make_petal(mouseX, mouseY - (petalsize - c_petal), c_petal, petalsize);
//bottom petal
make_petal(mouseX, mouseY + (petalsize - c_petal), c_petal, petalsize);
//flower center
fill(random(255), random(255), random(255));
ellipse(mouseX, mouseY, c_center, c_center);
}
void make_petal(int a, int b, int c, int d){
fill(rcol);
ellipse(a, b, c, d);
}
You're mixing two styles of drawing together: your flower() function uses mouseX and mouseY to determine where to draw the petals, but then you're also calling translate(mouseX, mouseY);. So you're drawing petals relative to the mouse, but then moving the entire canvas by the mouse position, and then drawing more petals relative to the mouse again.
Instead, you probably want to only use one style of drawing. Specifically, you probably don't want your flower() function to care about the mouse position. Treat it like a "stamp" that draws things around the origin at 0,0. Then move the origin by calling translate() and rotate the stamp by calling rotate().
I corrected the code thanks to feedback, so it works now in case anyone is interested. I condensed it a little by just making one petal then rotating it through a loop.
int c_center = 20;
int c_petal = int(random(5, 15));
int petalsize = int(random(30, 60));
color rcol;
void setup(){
fullScreen();
background(0);
}
void draw(){
rcol = color(random(255), random(255), random(255));
}
void mouseClicked(){
pushMatrix();
translate(mouseX, mouseY);
for(int r = 0; r < 360; r+=5){
rotate(radians(r));
flower();
}
popMatrix();
}
void flower(){
//petal
make_petal(0, 0 - (petalsize - c_petal), c_petal, petalsize);
//flower center
fill(random(255), random(255), random(255));
ellipse(0, 0, c_center, c_center);
}
void make_petal(int a, int b, int c, int d){
fill(rcol);
ellipse(a, b, c, d);
}

Clearing out canvas

I'm trying to program an intro. I want the canvas to erase itself after it. I already have the trigger, but I do not know how to clear the canvas. Would just changing the background work? I still want to make stuff after it.
Here is the code:
void setup () {
frameRate(10);
stroke(255, 255, 255);
noFill();
rect(100,155,300,300);
size(500, 500);
}
void square () {
for (int x = 100; x <= 300; x += 100) {
for (int y = 155; y <= 355; y += 100) {
fill(random(0, 255), random(0, 255), random(0, 255));
rect(x, y,100,100);
}
}
};
void draw () {
int time = 0;
int logoLength = 100;
if (time < logoLength) {
fill(255, 255, 255);
background(0, 0, 0);
textFont(createFont("Lucida console", 19));
textAlign(CENTER,CENTER);
text("Ghost Cube Games presents",250,59);
time++;
print(time);
square();
} else if (time == logoLength) {
background(255, 255, 255);
}
}
You can simply call the background() function.
background(0); draws a black background.
background(255); draws a white background.
background(255, 0, 0); draws a red background.
More info can be found in the reference.
For a more specific example, if you want to show an intro screen, you can simply keep track of whether the intro screen is showing in a boolean variable. If that variable is true, then draw the intro screen. If not, then draw whatever else you want to draw. If you do this from the draw() function, then you don't really have to worry about clearing the screen, since calling the background() function will do that for you:
boolean showingIntro = true;
void draw() {
background(0);
if (showingIntro) {
text("INTRO", 20, 20);
} else {
ellipse(50, 50, 25, 25);
}
}
void mouseClicked() {
showingIntro = false;
}

Stop background from refreshing?

I am trying to get my gif to do something similar to this gif.
I have been able to get the line to draw, and the 'planets' to orbit, but can't figure out how to keep the line connecting the two circles, like the gif does.
Here's the basic code:
int x = 500;
int y = 500;
int radius = y/2;
int cX = x/2;
int cY = y/2;
String text1;
int lg_xBall;
int lg_yBall;
int sm_xBall;
int sm_yBall;
void setup() {
size(x, y);
smooth();
colorMode(RGB);
}
void draw() {
background(0);
stroke(255);
float t = millis()/1000.0f;
drawSmBallOrbit(100);
drawLgBallOrbit(100);
moveSmBall(t);
moveLgBall(t);
sun();
// showMouse();
connectingLines();
}
void drawCircle() { // This will draw a simple circle
stroke(1);
// x1=a+r*cos t, y1=b+r*sin t
ellipse(x/2, y/2, x/2, y/2);
}
void drawLines() { // This will draw lines from the center of the circle.
stroke(1);
line(x/2, y/2, radius/2, radius); // line from 6 to center
line(x/2, y/2, x/2, y/4); // line from 12 to center
for (int i = 0; i <= 5; i+=2.5) {
float x1 = x/2+radius/2*cos(i);
float y1 = y/2+radius/2*sin(i);
line(x/2, y/2, x1, y1);
}
}
void moveSmBall(float ky) { // This will create, and move, a small 'planet'
pushStyle();
stroke(100);
sm_xBall = (int)(cX+radius*cos(ky));
sm_yBall = (int)(cY+radius*sin(ky));
fill(190, 0, 0);
// background(0);
ellipse(sm_xBall, sm_yBall, 10, 10);
popStyle();
}
void drawSmBallOrbit(float opacity) {
pushStyle();
stroke(255, opacity);
strokeWeight(1);
noFill();
ellipse(x/2, y/2, cX+radius, cY+radius);
popStyle();
}
void moveLgBall(float kx) {
kx = kx/.7;
pushStyle();
lg_xBall = (int)(cX+radius*cos(kx)*.6);
lg_yBall = (int)(cY+radius*sin(kx)*.6);
fill(0, 0, 230);
ellipse(lg_xBall, lg_yBall, 30, 30);
popStyle();
}
void drawLgBallOrbit(float opacity) {
pushStyle();
stroke(255, opacity);
strokeWeight(1);
noFill();
ellipse(x/2, y/2, (cX+radius)*.6, (cY+radius)*.6);
popStyle();
}
void sun() {
pushStyle();
fill(250, 250, 0);
ellipse(cX, cY, 40, 40);
popStyle();
}
void connectingLines() {
line(sm_xBall, sm_yBall, lg_xBall, lg_yBall);
}
void showMouse() {
text("X: " + mouseX, x/2, y/2-30);
text("Y: " + mouseY, x/2, y/2-50);
}
Thanks for any help/advice!
The problem is that you're calling background() during every frame, which will clear away anything you've already drawn.
So you either need to stop calling background(), or you need to redraw the old lines every frame.
If you simply move the call to background() out of your draw() function and into your setup() function, you're about 50% there already:
void setup() {
size(x, y);
smooth();
colorMode(RGB);
background(0);
}
void draw() {
// background(0);
stroke(255);
float t = millis()/1000.0f;
drawSmBallOrbit(100);
drawLgBallOrbit(100);
moveSmBall(t);
moveLgBall(t);
sun();
// showMouse();
connectingLines();
}
However, the original animation does not show the previous positions of the ellipses. So you need to clear away the previous frame by calling the background() function, and then redraw previous line positions. You'd do that by having an ArrayList that holds those previous positions.
Here's a simple example that uses an ArrayList to redraw anywhere the mouse has been:
ArrayList<PVector> points = new ArrayList<PVector>();
void setup() {
size(500, 500);
}
void draw() {
background(0);
stroke(255);
points.add(new PVector(mouseX, mouseY));
for(PVector p : points){
ellipse(p.x, p.y, 10, 10);
}
}
You would need to do something very similar, but you'd have to keep track of two points at a time instead of one, since you're tracking two ellipses and not just the mouse position.

Understanding void draw() in processing

I am tinkering with Processing and cannot figure out how to write text over an image I created using the image buffer (rotating squares)...when the square becomes smaller than the text, the changing digits wrote on top of each other. Cannot use resetting the bkg as a solution because that erases the overlapping images. Still having a hard time understanding this area...
Question: How to get the text to appear on top of the rotating squares without resetting the bkg and without the text writing over itself
Code below
Thank you!
float rotateAmount;
int boxColorR = 255;
int boxColorG = 255;
int boxColorB = 255;
int boxW = 480;
void setup () {
size(640,480);
rectMode(CENTER);
}
void drawText() {
//translate(width/2,height/2);
textAlign(LEFT, CENTER);
fill(255, 255, 255);
textSize(32);
text("RED: " + boxColorR,width/2,height/2);
text("GREEN: " + boxColorG,width/2,height/2+30);
text("BLUE: " + boxColorB,width/2,height/2+60);
text("Box Width: " + boxW,width/2,height/2+90);
}
void drawBox() {
translate(width/2,height/2);
rotateAmount += 12;
if (boxColorR <= 0) {
boxColorG--;
}
if (boxColorG <= 0) {
boxColorB--;
}
boxColorR--;
boxW--;
rotateAmount += .05;
rotate(rotateAmount);
fill(boxColorR,boxColorG,boxColorB);
rect(0,0,boxW,boxW);
resetMatrix();
}
void draw() {
//rect(width/2,height/2,640,480); //this solves the text overlapping but erases the cool effect
drawBox();
drawText();
}
Most Processing sketches use a call to the background() function as the first line in the draw() function. This clears out anything drawn in previous frames.
However, you want to keep the stuff drawn in previous frames, so you don't want to clear them out. The problem with this is that since your text isn't cleared out either, your text ends up looking garbled.
The solution to this is to use the PGraphics class to create an off-screen buffer. You draw the squares to the buffer instead of to the screen. Then you draw the buffer to the screen, and finally, you draw the text on top of the buffer.
Since you draw the buffer to the screen each frame, it clears away the old text, but the squares you've previously drawn are maintained in the buffer.
Code speaks louder than words:
float rotateAmount;
int boxColorR = 255;
int boxColorG = 255;
int boxColorB = 255;
int boxW = 480;
//create a buffer to draw boxes to
PGraphics buffer;
void setup () {
size(640, 480);
buffer = createGraphics(640, 480);
}
void drawText() {
//translate(width/2,height/2);
textAlign(LEFT, CENTER);
fill(255, 255, 255);
textSize(32);
text("RED: " + boxColorR, width/2, height/2);
text("GREEN: " + boxColorG, width/2, height/2+30);
text("BLUE: " + boxColorB, width/2, height/2+60);
text("Box Width: " + boxW, width/2, height/2+90);
}
//draw boxes to buffer
void drawBox() {
buffer.beginDraw();
buffer.rectMode(CENTER);
buffer.translate(width/2, height/2);
rotateAmount += 12;
if (boxColorR <= 0) {
boxColorG--;
}
if (boxColorG <= 0) {
boxColorB--;
}
boxColorR--;
boxW--;
rotateAmount += .05;
buffer.rotate(rotateAmount);
buffer.fill(boxColorR, boxColorG, boxColorB);
buffer.rect(0, 0, boxW, boxW);
buffer.resetMatrix();
buffer.endDraw();
}
void draw() {
//draw the boxes to the buffer
drawBox();
//draw the buffer to the screen
image(buffer, 0, 0);
//draw the text on top of the buffer
drawText();
}

How can i register when text and shapes has been clicked on?

rect(x, y, 100, 100)
text("click here", 50, 50)
Is there a way to use mousePressed() so it registers when these two items have been clicked on?
It sounds like you're looking for collision detection. Specifically, you're probably looking for point-rectangle collision detection, to determine whether the mouse is inside a rectangle.
Google is your friend, but here's an example:
float rectX;
float rectY;
float rectWidth;
float rectHeight;
void setup() {
size(300, 300);
rectX = 50;
rectY = 100;
rectWidth = 200;
rectHeight = 100;
}
void draw() {
background(64);
if (mouseX > rectX && mouseX < rectX + rectWidth && mouseY > rectY && mouseY < rectY + rectHeight) {
fill(255, 0, 0);
}
else {
fill(0, 255, 0);
}
rect(rectX, rectY, rectWidth, rectHeight);
}
Shameless self-promotion: here is a tutorial on collision detection in Processing.

Resources