How do I make a object move towards the mouse in p5.js? - p5.js

I'm making a zombie game in p5js, does anyone have any recommendations on to make a shape or object move towards the mouse(this will be used to make the gun)? and if anyone knows how to make more enemies spawn more often each round that would be nice to!:)
Sorry if the solution is super simple, I still kinda new!
code:
let dogmode;
let round;
let zombie, player;
let x, y;
let health, speed, damage, playerhealth;
function setup() {
dogmode=false;
createCanvas(400,400);
round = 1;
bullet ={
damage:20
};
//Player and zombie parameters
zombie = {
pos: createVector(500, 200),
//increase by 100 each round until round 9
health: 150,
speed: 1,
};
player = {
pos: createVector(200, 200),
//default
health: 100,
};
fill(0);
}
function draw() {
if( dogmode===true){
player.health=player.health+100;
}
background(220);
stroke(0);
line(player.pos.x,player.pos.y,mouseX,mouseY);
fill('gray')
ellipse(mouseX,mouseY,10,10);
push();
//player
fill("green");
ellipse(player.pos.x, player.pos.y, 20, 20);
//HUD or something
fill("black");
text("" + player.health, 10, 10);
//zombie(s)
fill("gray");
rect(zombie.pos.x, zombie.pos.y, 20, 20);
//Damage system
if (p5.Vector.sub(player.pos, zombie.pos).mag() <= 30) {
player.health = player.health - 1;
}
//Health detection
if (player.health <= 0) {
background(0);
textSize(20);
text("You died \n Round " + round, 165, 200);
}
if (keyIsDown(87)) {
player.pos.y -= 2;
}
if (keyIsDown(83)) {
player.pos.y += 2;
}
if (keyIsDown(65)) {
player.pos.x -= 2;
}
if (keyIsDown(68)) {
player.pos.x += 2;
}
zombie.pos.add(p5.Vector.sub(player.pos, zombie.pos).limit(zombie.speed))
pop();
//Create bullet
if(mouseIsPressed ){
fill('yellow')
ellipse(mouseX,mouseY,5,5);
//Shoots bullet
}
}

In order to fire a bullet you need to:
Determine the direction of motion at the time the bullet is fired.
Save that vector so that the direction remains constant for the life of the bullet.
Update the position of the bullet each frame after it is fired.
Determining the direction of motion is simple vector arithmetic if you have two vectors, A and B, and subtract A - B you will get a vector representing the offset from B to A (i.e. pointing in the direction of A from B):
It is important to save this direction vector, because as the player, mouse, and bullet move the result of this computation will continually change; and bullets don't usually change direction once fired.
const BULLET_SPEED = 5;
let player;
let bullet;
function setup() {
createCanvas(windowWidth, windowHeight);
bullet = {
damage: 20,
};
player = {
pos: createVector(width / 2, height / 2),
//default
health: 100,
};
}
function draw() {
background(220);
stroke(0);
// By taking the difference between the vector pointing to the mouse and the
// vector pointing to the player we get a vector from the player to the mouse.
let mouseDir = createVector(mouseX, mouseY).sub(player.pos);
// Limit the length to display an indicator of the bullet direction
mouseDir.setMag(30);
// Because we want to draw a line to the point mouseDir offset away from
// player, we'll need to add mouseDir and player pos. Do so using the static
// function so that we don't modify either one.
let dirOffset = p5.Vector.add(player.pos, mouseDir);
// direction indicator
line(player.pos.x, player.pos.y, dirOffset.x, dirOffset.y);
fill("gray");
ellipse(dirOffset.x, dirOffset.y, 10, 10);
//player
fill("green");
ellipse(player.pos.x, player.pos.y, 20, 20);
if (keyIsDown(87)) {
player.pos.y -= 2;
}
if (keyIsDown(83)) {
player.pos.y += 2;
}
if (keyIsDown(65)) {
player.pos.x -= 2;
}
if (keyIsDown(68)) {
player.pos.x += 2;
}
//Create bullet
if (mouseIsPressed) {
// Notice there can be only one bullet on the screen at a time, but there's
// no reason you couldn't create multiple bullets and add them to an array.
// However, if you did, you might want to create bullets in a mouseClicked()
// function instead of in draw() lets you create too many bullets at a time.
bullet.firing = true;
// Save the direction of the mouse;
bullet.dir = mouseDir;
// Adjust the bullet speed
bullet.dir.setMag(BULLET_SPEED);
// Position the bullet at/near the player
bullet.initialPos = dirOffset;
// Make a copy so that initialPos stays fixed when pos gets updated
bullet.pos = bullet.initialPos.copy();
//Shoots bullet
}
if (bullet.firing) {
fill('yellow');
ellipse(bullet.pos.x, bullet.pos.y, 5, 5);
// move the bullet
bullet.pos.add(bullet.dir);
if (bullet.pos.dist(bullet.initialPos) > 500) {
bullet.firing = false;
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

Related

How can add interaction and animation to shapes drawn in Processing?

I'm trying to code a canvas full of shapes(houses) and animate them in processing.
Here's an example of shape:
void house(int x, int y) {
pushMatrix();
translate(x, y);
fill(0, 200, 0);
triangle(15, 0, 0, 15, 30, 15);
rect(0, 15, 30, 30);
rect(12, 30, 10, 15);
popMatrix();
}
By animation I mean moving them in random directions.
I would also like to add basic interaction: when hovering over a house it's colour would change.
At the moment I've managed to render a canvas full of houses:
void setup() {
size(500, 500);
background(#74F5E9);
for (int i = 30; i < 500; i = i + 100) {
for (int j = 30; j < 500; j = j + 100) {
house(i, j);
}
}
}
void house(int x, int y) {
pushMatrix();
translate(x, y);
fill(0, 200, 0);
triangle(15, 0, 0, 15, 30, 15);
rect(0, 15, 30, 30);
rect(12, 30, 10, 15);
popMatrix();
}
Without seeing source code: your attempted sketch it's very hard to tell.
They can be animated in many ways and it's unclear what you mean. For example, is that the position/rotation/scale of each square, is it the corners/vertices of each square, both ?
You might have a clear idea in your mind, but the current form of the question is ambiguous. We also don't know you're comfort level with various notions such as classes/objects/PVector/PShape/etc. If you were to 'story board' this animation what would it look like ? Breaking the problem down and explaining it in a way that anyone can understand might actually help you figure out a solution on your own as well.
Processing has plenty of examples. Here are a few I find relevant based on what my understanding is of your problem.
You can have a look at the Objects and Create Shapes examples:
File > Examples > Basics > Objects > Objects: Demonstrates grouping drawing/animation (easing, damping). You can tweak this example draw a single square and once you're happy with the look/motion you can animate multiple using an array or ArrayList
File > Examples > Topics > Create Shapes > PolygonPShapeOOP3: Great example using PShape to animate objects.
File > Examples > Topics > Create Shapes > WigglePShape: This example demonstrates how to access and modify the vertices of a PShape
For reference I'm simply copy/pasting the examples mentioned above here as well:
Objects
/**
* Objects
* by hbarragan.
*
* Move the cursor across the image to change the speed and positions
* of the geometry. The class MRect defines a group of lines.
*/
MRect r1, r2, r3, r4;
void setup()
{
size(640, 360);
fill(255, 204);
noStroke();
r1 = new MRect(1, 134.0, 0.532, 0.1*height, 10.0, 60.0);
r2 = new MRect(2, 44.0, 0.166, 0.3*height, 5.0, 50.0);
r3 = new MRect(2, 58.0, 0.332, 0.4*height, 10.0, 35.0);
r4 = new MRect(1, 120.0, 0.0498, 0.9*height, 15.0, 60.0);
}
void draw()
{
background(0);
r1.display();
r2.display();
r3.display();
r4.display();
r1.move(mouseX-(width/2), mouseY+(height*0.1), 30);
r2.move((mouseX+(width*0.05))%width, mouseY+(height*0.025), 20);
r3.move(mouseX/4, mouseY-(height*0.025), 40);
r4.move(mouseX-(width/2), (height-mouseY), 50);
}
class MRect
{
int w; // single bar width
float xpos; // rect xposition
float h; // rect height
float ypos ; // rect yposition
float d; // single bar distance
float t; // number of bars
MRect(int iw, float ixp, float ih, float iyp, float id, float it) {
w = iw;
xpos = ixp;
h = ih;
ypos = iyp;
d = id;
t = it;
}
void move (float posX, float posY, float damping) {
float dif = ypos - posY;
if (abs(dif) > 1) {
ypos -= dif/damping;
}
dif = xpos - posX;
if (abs(dif) > 1) {
xpos -= dif/damping;
}
}
void display() {
for (int i=0; i<t; i++) {
rect(xpos+(i*(d+w)), ypos, w, height*h);
}
}
}
PolygonPShapeOOP3:
/**
* PolygonPShapeOOP.
*
* Wrapping a PShape inside a custom class
* and demonstrating how we can have a multiple objects each
* using the same PShape.
*/
// A list of objects
ArrayList<Polygon> polygons;
// Three possible shapes
PShape[] shapes = new PShape[3];
void setup() {
size(640, 360, P2D);
shapes[0] = createShape(ELLIPSE,0,0,100,100);
shapes[0].setFill(color(255, 127));
shapes[0].setStroke(false);
shapes[1] = createShape(RECT,0,0,100,100);
shapes[1].setFill(color(255, 127));
shapes[1].setStroke(false);
shapes[2] = createShape();
shapes[2].beginShape();
shapes[2].fill(0, 127);
shapes[2].noStroke();
shapes[2].vertex(0, -50);
shapes[2].vertex(14, -20);
shapes[2].vertex(47, -15);
shapes[2].vertex(23, 7);
shapes[2].vertex(29, 40);
shapes[2].vertex(0, 25);
shapes[2].vertex(-29, 40);
shapes[2].vertex(-23, 7);
shapes[2].vertex(-47, -15);
shapes[2].vertex(-14, -20);
shapes[2].endShape(CLOSE);
// Make an ArrayList
polygons = new ArrayList<Polygon>();
for (int i = 0; i < 25; i++) {
int selection = int(random(shapes.length)); // Pick a random index
Polygon p = new Polygon(shapes[selection]); // Use corresponding PShape to create Polygon
polygons.add(p);
}
}
void draw() {
background(102);
// Display and move them all
for (Polygon poly : polygons) {
poly.display();
poly.move();
}
}
// A class to describe a Polygon (with a PShape)
class Polygon {
// The PShape object
PShape s;
// The location where we will draw the shape
float x, y;
// Variable for simple motion
float speed;
Polygon(PShape s_) {
x = random(width);
y = random(-500, -100);
s = s_;
speed = random(2, 6);
}
// Simple motion
void move() {
y+=speed;
if (y > height+100) {
y = -100;
}
}
// Draw the object
void display() {
pushMatrix();
translate(x, y);
shape(s);
popMatrix();
}
}
WigglePShape:
/**
* WigglePShape.
*
* How to move the individual vertices of a PShape
*/
// A "Wiggler" object
Wiggler w;
void setup() {
size(640, 360, P2D);
w = new Wiggler();
}
void draw() {
background(255);
w.display();
w.wiggle();
}
// An object that wraps the PShape
class Wiggler {
// The PShape to be "wiggled"
PShape s;
// Its location
float x, y;
// For 2D Perlin noise
float yoff = 0;
// We are using an ArrayList to keep a duplicate copy
// of vertices original locations.
ArrayList<PVector> original;
Wiggler() {
x = width/2;
y = height/2;
// The "original" locations of the vertices make up a circle
original = new ArrayList<PVector>();
for (float a = 0; a < radians(370); a += 0.2) {
PVector v = PVector.fromAngle(a);
v.mult(100);
original.add(new PVector());
original.add(v);
}
// Now make the PShape with those vertices
s = createShape();
s.beginShape(TRIANGLE_STRIP);
s.fill(80, 139, 255);
s.noStroke();
for (PVector v : original) {
s.vertex(v.x, v.y);
}
s.endShape(CLOSE);
}
void wiggle() {
float xoff = 0;
// Apply an offset to each vertex
for (int i = 1; i < s.getVertexCount(); i++) {
// Calculate a new vertex location based on noise around "original" location
PVector pos = original.get(i);
float a = TWO_PI*noise(xoff,yoff);
PVector r = PVector.fromAngle(a);
r.mult(4);
r.add(pos);
// Set the location of each vertex to the new one
s.setVertex(i, r.x, r.y);
// increment perlin noise x value
xoff+= 0.5;
}
// Increment perlin noise y value
yoff += 0.02;
}
void display() {
pushMatrix();
translate(x, y);
shape(s);
popMatrix();
}
}
Update
Based on your comments here's an version of your sketch modified so the color of the hovered house changes:
// store house bounding box dimensions for mouse hover check
int houseWidth = 30;
// 30 px rect height + 15 px triangle height
int houseHeight = 45;
void setup() {
size(500, 500);
}
void draw(){
background(#74F5E9);
for (int i = 30; i < 500; i = i + 100) {
for (int j = 30; j < 500; j = j + 100) {
// check if the cursor is (roughly) over a house
// and render with a different color
if(overHouse(i, j)){
house(i, j, color(0, 0, 200));
}else{
house(i, j, color(0, 200, 0));
}
}
}
}
void house(int x, int y, color fillColor) {
pushMatrix();
translate(x, y);
fill(fillColor);
triangle(15, 0, 0, 15, 30, 15);
rect(0, 15, 30, 30);
rect(12, 30, 10, 15);
popMatrix();
}
// from Processing RollOver example
// https://processing.org/examples/rollover.html
boolean overRect(int x, int y, int width, int height) {
if (mouseX >= x && mouseX <= x+width &&
mouseY >= y && mouseY <= y+height) {
return true;
} else {
return false;
}
}
// check if the mouse is within the bounding box of a house
boolean overHouse(int x, int y){
// offset half the house width since the pivot is at the tip of the house
// the horizontal center
return overRect(x - (houseWidth / 2), y, houseWidth, houseHeight);
}
The code is commented, but here are the main takeaways:
the house() function has been changed so you can specify a color
the overRect() function has been copied from the Rollover example
the overHouse() function uses overRect(), but adds a horizontal offset to take into account the house is drawn from the middle top point (the house tip is the shape's pivot point)
Regarding animation, Processing has tons of examples:
https://processing.org/examples/sinewave.html
https://processing.org/examples/additivewave.html
https://processing.org/examples/noise1d.html
https://processing.org/examples/noisewave.html
https://processing.org/examples/arrayobjects.html
and well as the Motion / Simulate / Vectors sections:
Let's start take sine motion as an example.
The sin() function takes an angle (in radians by default) and returns a value between -1.0 and 1.0
Since you're already calculating positions for each house within a 2D grid, you can offset each position using sin() to animate it. The nice thing about it is cyclical: no matter what angle you provide you always get values between -1.0 and 1.0. This would save you the trouble of needing to store the current x, y positions of each house in arrays so you can increment them in a different directions.
Here's a modified version of the above sketch that uses sin() to animate:
// store house bounding box dimensions for mouse hover check
int houseWidth = 30;
// 30 px rect height + 15 px triangle height
int houseHeight = 45;
void setup() {
size(500, 500);
}
void draw(){
background(#74F5E9);
for (int i = 30; i < 500; i = i + 100) {
for (int j = 30; j < 500; j = j + 100) {
// how fast should each module move around a circle (angle increment)
// try changing i with j, adding i + j or trying other mathematical expressions
// also try changing 0.05 to other values
float phase = (i + frameCount) * 0.05;
// try changing amplitude to other values
float amplitude = 30.0;
// map the sin() result from it's range to a pixel range (-30px to 30px for example)
float xOffset = map(sin(phase), -1.0, 1.0, -amplitude, amplitude);
// offset each original grid horizontal position (i) by the mapped sin() result
float x = i + xOffset;
// check if the cursor is (roughly) over a house
// and render with a different color
if(overHouse(i, j)){
house(x, j, color(0, 0, 200));
}else{
house(x, j, color(0, 200, 0));
}
}
}
}
void house(float x, float y, color fillColor) {
pushMatrix();
translate(x, y);
fill(fillColor);
triangle(15, 0, 0, 15, 30, 15);
rect(0, 15, 30, 30);
rect(12, 30, 10, 15);
popMatrix();
}
// from Processing RollOver example
// https://processing.org/examples/rollover.html
boolean overRect(int x, int y, int width, int height) {
if (mouseX >= x && mouseX <= x+width &&
mouseY >= y && mouseY <= y+height) {
return true;
} else {
return false;
}
}
// check if the mouse is within the bounding box of a house
boolean overHouse(int x, int y){
// offset half the house width since the pivot is at the tip of the house
// the horizontal center
return overRect(x - (houseWidth / 2), y, houseWidth, houseHeight);
}
Read through the comments and try to tweak the code to get a better understanding of how it works and have fun coming up with different animations.
The main changes are:
modifying the house() function to use float x,y positions (instead of int): this is to avoid converting float to int when using sin(), map() and get smoother motions (instead of motion that "snaps" to whole pixels)
Mapped sine to positions which can be used to animate
Wrapping the 3 instructions that calculate the x offset into a reusable function would allow you do further experiment. What if you used a similar technique the y position of each house ? What about both x and y ?
Go through the code step by step. Try to understand it, change it, break it, fix it and make new sketches reusing code.

How to detect collisions between a moving point and the stroke of an arbitrary boundary shape?

I want to draw a circle(for example) and create a couple of points inside that circle. The points are moving randomly, but when they hit the circle's stroke, they should either stop or go inverse or react in some way (it's not that important). I know it would be easy to do with rect-like shapes, but I want to draw inside custom shapes like stars or flower.
To find out if point inside the circle or not you just need to calculate distance from center of circle to point itself. If that distance less then radius - point inside circle.
Fun example:
let c, r;
let points = [];
function setup()
{
createCanvas(200, 200);
r = 50;
c = createVector(100, 100);
let pos = createVector(95, 110);
let v = p5.Vector.random2D();
points.push({p: pos, v: v});
}
function draw()
{
background(0);
points.forEach(point => {
point.p.add(point.v);
if(point.p.dist(c) > r) {
let n = point.p.copy().sub(c).normalize();
let d_n = point.v.dot(n);
point.v = p5.Vector.sub(n.mult(2).mult(d_n), point.v).mult(-1);
//pv.mult(-1);
}
circle(point.p.x,point.p.y,5);
});
noFill();
stroke(255);
circle(c.x,c.y, r*2);
}
function mouseClicked() {
let p = createVector(mouseX, mouseY);
if (p.dist(c) < r) {
points.push({
p: p,
v: p5.Vector.random2D(),
});
}
// prevent default
return false;
}
<script src="https://github.com/processing/p5.js/releases/download/v1.4.0/p5.min.js"></script>
click inside circle
Boring example:
let c, radius;
function setup()
{
createCanvas(200, 200);
c = createVector(100, 100);
radius = 50;
}
function draw()
{
background(0);
let point = createVector(mouseX, mouseY);
let distance = c.dist(point);
if (distance > radius) {
fill("red");
} else {
fill("green");
};
circle(c.x, c.y, radius * 2);
// just rendering text :)
stroke(255);
line(point.x,point.y, c.x,c.y);
stroke(0);
fill(200)
push()
translate(p5.Vector.add(c, p5.Vector.sub(point, c).div(2)));
text(distance.toFixed(2),0,0)
pop()
text("Move your mouse",20,10);
}
<script src="https://github.com/processing/p5.js/releases/download/v1.4.0/p5.min.js"></script>

How to track sphere with camera in p5.js?

I'm trying to replicate the game "slope" using p5.js web editor because I'm on a school Chromebook and no other way of coding. So far I have the camera following the sphere but it seems that once the sphere goes so far the camera retracts and the sphere disappears. The cube is there as a reference to see if the sphere is moving which it is but then it gets buggy after 10 seconds. Any ideas on how to fix this and have the camera continuously following the sphere as it travels down the z-axis. Once the sphere reaches a certain point the whole thing seems to invert.
let cam;
//let delta = 0.01
var ballX = 0;
var ballY = 0;
var ballZ = 0;
var score = 1;
var speed = 3;
//var speedZ = 2;
function setup() {
createCanvas(500, 500, WEBGL);
translate(0, 0, 0)
cam = createCamera()
}
function draw() {
background(200);
normalMaterial();
//camera
camera(ballX, ballY, ballZ - 500, ballX, ballY, 0, 0, 50, 0);
//test
box(20);
if (keyIsDown(RIGHT_ARROW)) {
ballX -= speed;
} else if (keyIsDown(LEFT_ARROW)) {
ballX += speed;
}
push();
translate(ballX, ballY, ballZ);
sphere(50);
pop();
ballZ += speed;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
The fourth, fifth and sixth argument that the camera() function receives, mark the point that the camera is pointing to. In your case, the camera is always pointing to z = 0 which is why when the camera's z coordinate reaches zero, the sphere "disappears" (figuratively, the camera rotates 180 degrees).
Modify the camera's position like this:
camera(ballX, ballY, ballZ - 500, ballX, ballY, ballZ, 0, 50, 0);
so it's set to always point towards the sphere.
Here's your code lightly modified and with a small function that allows to check the "review mirror" when pressing backspace by alternating the cameras z-axis target between the sphere's position and 0
var ballX = 0;
var ballY = 0;
var ballZ = 0;
var speed = 3;
function setup() {
createCanvas(500, 500, WEBGL);
translate(0, 0, 0)
}
function draw() {
background(200);
//camera
camera(ballX, ballY, ballZ -500, ballX, ballY, mirror ? 0 : ballZ, 0, 50, 0);
//test
fill('red');
box(20);
normalMaterial();
if (keyIsDown(RIGHT_ARROW)) {
ballX -= speed;
} else if (keyIsDown(LEFT_ARROW)) {
ballX += speed;
}
push();
translate(ballX, ballY, ballZ);
sphere(50);
pop();
ballZ += speed;
}
let mirror = false;
function keyPressed(){
if(keyCode === BACKSPACE)
mirror =!mirror;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>

Moving an objects while others stay static in a click controlled sketch

So I'm trying to build an animation that I can step through with mouse clicks. Adding individual objects click by click is easy. Sequence I want is as follows:
One object(a) drawn initially.
First mouse click adds an object(b).
Second mouse click adds an object(c).
Third mouse click, object(c) should move across the screen and disappear.
I'm having a problem on the last part of the sequence. I can't figure out how to make the object move and still maintain the static part of the sketch. The normal way of doing movement is to change the coordinates of the object with each loop through the draw() function, and use the background to cover up the previous objects. Can't do that in this case because I need object(a) and object(b) to be persistent.
Code below. Thanks for your help!
var count = 0;
function setup() {
createCanvas(200, 200);
a = new Object1(20, 40);
b = new Object1(20, 85);
c = new Object1(20, 130);
}
function draw() {
background(200);
a.display();
if (count == 1) {
b.display();
}
if (count == 2) {
b.display();
c.display();
}
if (count == 3) { //this is where I have a problem
}
if (count > 3) {
count = 0;
}
}
function Object1(ix, iy, itext) {
this.x = ix;
this.y = iy;
this.text = itext;
this.display = function() {
fill(160);
rect(this.x, this.y, 40, 40);
}
}
function mousePressed() {
count++;
}
Generally how you'd do this is by drawing the static part of your scene to an off-screen buffer, which you can create using the createGraphics() function. From the reference:
var pg;
function setup() {
createCanvas(100, 100);
pg = createGraphics(100, 100);
}
function draw() {
background(200);
pg.background(100);
pg.noStroke();
pg.ellipse(pg.width/2, pg.height/2, 50, 50);
image(pg, 50, 50);
image(pg, 0, 0, 50, 50);
}
You'd draw the static part to the buffer, then draw the buffer to the screen, then draw the dynamic stuff on top of it each frame.
This has been discussed before, so I'd recommend doing a search for stuff like "processing pgraphics" and "p5.js buffer" to find a bunch more information.

Ball should bounce off the paddles and game should restart once it is gameover

So this is my entire code and what it does not do, but should definitely do is first bounce off when colliding with the paddles and second if it does not do so then once the game enters in gameover mode once a key is pressed it should restart the game. Now I've tried several things and nothing seems to work.
Can someone please find a solution and try to explain what I did wrong?
// variables for the ball
int ball_width = 15, ball_height = 15;
int ballX = width/2, ballY = height/2;
//
// variables for the paddles
int paddle_width = 20, paddle_height = 150;
int paddle1 = 60, paddle2;
//
// direction variables
int directionX = 15, directionY = 15;
//
// variables for the score
int scorecounter = 0;
//
//game states
boolean playing = false, gameover = false, finalscore = false, score = true;
void setup () {
size (1900, 1300); // the field game is going to be 1900x1300 px big
rectMode (CENTER);
paddle2 = width - 60;
}
void draw () {
background (0); // black background
playing ();
gameover ();
finalscore();
}
//
void playing () {
if (keyPressed) {
playing = true;
}
if (!playing) { // playing = false
fill(255);
textSize(80);
textAlign(CENTER);
text("Press Space to Play", width/2, height/4);
fill (255);
ellipse (width/2, height/2, ball_width, ball_height); // this is the starting point of the ball
fill (255, 10, 20);
rect(paddle1, (height/2), paddle_width, paddle_height); // red pong
fill (60, 255, 0);
rect(paddle2, (height/2), paddle_width, paddle_height); // green pong
}
if (playing) { // playing = true
score();
ballX = ballX + directionX;
ballY = ballY + directionY;
fill (255);
ellipse (ballX, ballY, ball_width, ball_height);
fill ( 255, 10, 20 );
rect(paddle1, mouseY, paddle_width, paddle_height); // red pong
fill ( 60, 255, 0 );
rect(paddle2, mouseY, paddle_width, paddle_height); // green pong
if ( ballY > height ) {
directionY = -directionY;
} // if the ball reaches the lower wall it will bounce off
if ( ballY < 0 ) {
directionY = -directionY;
} // if the ball reaches the upper wall it will bounce off
if ( ballX > width || ballX < 0 ) {
gameover = true; }
}
if (ballX == paddle1 && ballY <= paddle_height) {
directionX = -directionX;
directionY = -directionY;
}
if (ballX == paddle2 && ballY <= paddle_height) {
directionX = -directionX;
directionY = -directionY;
}
}
void gameover () {
if (gameover) {
background (0);
}
finalscore ();
score = false;
if (keyPressed) {
playing = true;
}
}
void score () {
if (playing) {
fill(255);
textSize(45);
textAlign(CENTER);
text ( scorecounter, width/2, height/4);
if (ballX == paddle1 && ballY <= paddle_height) {
scorecounter = scorecounter + 10;
}
if (ballX == paddle2 && ballX <= paddle_height) {
scorecounter = scorecounter + 10;
}
}
if (!playing) {
score = false;
}
}
void finalscore () {
if (gameover) {
score = false;
fill(255);
textSize(45);
textAlign(CENTER);
text("Game Over. Press a key to play again.", width/2, height/4);
fill(255);
textSize(80);
textAlign(CENTER);
text("You scored " + scorecounter + " points", width/2, (height/4) * 3);
if (keyPressed) {
playing = playing;
}
}
}
Not sure if that's the problem, but
if (keyPressed) {
playing = playing;
}
looks not very useful. You have both a function and a variable named playing. Reusing identifiers is usually a recipe for confusion.
For your first issue of the ball not bouncing off the paddle, take a look at these lines:
if (ballX == paddle1 && ballY <= paddle_height) {
directionX = -directionX;
directionY = -directionY;
}
if (ballX == paddle2 && ballY <= paddle_height) {
directionX = -directionX;
directionY = -directionY;
}
Notice that you're checking whether ballX == paddle1 or ballX == paddle2. You're checking whether the exact pixel position of the ball matches either of the paddles.
However, also notice that you're moving the ball by 15 pixels each time, so the chances of it hitting an exact pixel are pretty low. In other words, your ball is going to move through the exact pixel position and be inside your paddles. That is what you have to check for.
Furthermore, you're only checking whether the ball's y position is less than paddleHeight. That's not enough. You also have to check whether it's greater than the paddle position!
Even after that, I'm not sure you want to reverse directionY when it hits a paddle, but I'll let you decide that for yourself.
For your other question about the gameover not reseting, notice that you never reset the ball position! That means you start playing, but then instantly get a game over. You need to reset the position of the ball before you restart the game.
Honestly, if I were you, I would start with a more basic sketch. Your code has a lot of extra stuff in it that doesn't make a lot of sense, so I'm not surprised that you're getting confused. Start with something much simpler: can you create a sketch that simply detects when the mouse is inside a rectangle? Start from there (or even simpler!) and take small steps instead of trying to program your end goal all at once. Good luck.
The reason why this is not reseting is because you are never updating the ballX o gameover variable. Every time you press a key you are falling into this conditional.
if ( ballX > width || ballX < 0 ) {
gameover = true;
}
I got around this by adding your inital values to the playing method:
void playing () {
if (keyPressed) {
playing = true;
gameover = false;
ballX = width/2;
ballY = height/2;
}
// rest of playing() code
}

Resources