How to use mouseX and mouseY to remove a sprite - javascript

Using p5.js / p5.play I'm trying to click a moving sprite, but stuck on how to get the moving sprites coords and position. At the moment when I click anywhere on the canvas a random sprite disappears. I've been trying to use mouseX and mouseY. Very new to coding and just trying to learn fundamentals.
let enemy;
let spawnTimer = 0;
function setup() {
createCanvas(900, 900);
spritegroup = new Group();
clickedgroup = new Group();
}
function draw() {
background(255, 255, 255);
spritegroup.cull(20);
clickedgroup.cull(20);
spawnSprites();
spriteClicked();
drawSprites();
}
function spawnSprites() {
if (spawnTimer === 60) {
for (var i = 0; i < 2; i++) {
var angle = random(360);
var x = random(50, 850);
var y = -5 * sin(radians(angle));
createEnemy(3, x, y);
spawnTimer = 0;
}
}
spawnTimer++;
}
function createEnemy(type, x, y) {
enemy = createSprite(x, y);
enemy[floor(random(0, 4))];
enemy.setSpeed(3.5 - type / 2, 90);
spritegroup.add(enemy);
enemy.setCollider("rectangle", 0, 0, 100, 100);
enemy.debug = true;
return enemy;
}
function spriteClicked() {
if (mouseIsPressed == true)
if (
(mouseX > enemy.position.x,
enemy.position.y && mouseY > enemy.position.x,
enemy.position.y)
) {
enemy.remove();
}
}

The easiest way is to use sprite.mouse :)
https://p5play.org/learn/input_devices.html?page=3

Related

Clicking Circle Game Javascript

I'm trying to make a simple interactive game where there are circles of different colours moving in the canvas and when the user clicks on the blue circles, it logs the number of clicks on the screen. When clicking circles with any other colour, the animation stops.
I'm very new to javascript but this is what I have for now. I've made a function with random coloured circles and a function with blue circles moving but I'm totally stuck on how to stop the animation when clicking on the function with a random coloured circles and logging the amount of clicks on the blue circles. If someone could help me move forward with it in any way (doesn't have to be the full thing), that would be awesome, thanks.
JS
var canvas;
var ctx;
var w = 1000;
var h = 600;
var colours = ["red", "blue"];
var allCircles = [];
for(var i=0; i<1; i++){
setTimeout(function(){console.log(i)},1000);
}
document.querySelector("#myCanvas").onclick = click;
createData(2);
createDataTwo(20);
setUpCanvas();
animationLoop();
function animationLoop(){
clear();
for(var i = 0; i<allCircles.length; i++){
circle(allCircles[i]);
forward(allCircles[i], 5)
turn(allCircles[i], randn(30));
collisionTestArray(allCircles[i],allCircles)
bounce(allCircles[i]);
}
requestAnimationFrame(animationLoop);
}
function collisionTestArray(o, a){
for(var i=0; i<a.length; i++){
if(o !=a[i]){
collision(o,a[i]);
}
}
}
function collision(o1,o2){
if(o1 && o2){
var differencex = Math.abs(o1.x-o2.x);
var differencey = Math.abs(o1.y-o2.y);
var hdif = Math.sqrt(differencex*differencex+differencey*differencey);
if(hdif<o1.r+o2.r){
if(differencex < differencey){
turn(o1, 180-2*o1.angle);
turn(o2, 180-2*o2.angle);
}else{
turn(o1, 360-2*o1.angle);
turn(o2, 360-2*o2.angle);
}
turn(o1, 180);
turn(o2, 180);
console.log("collision");
};
}
}
function click(event){
clear()
}
function bounce (o){
if(o.x > w || o.x < 0){
turn(o, 180-2*o.angle);
};
if(o.y > h || o.y < 0){
turn(o, 360-2*o.angle);
}
}
function clear(){
ctx.clearRect(0,0,w,h);
}
function stop (){
o1.changex = 0;
o1.changey = 0;
o2.changex = 0;
o2.changey = 0;
}
function circle (o){
var x = o.x;
var y = o.y;
var a = o.angle;
var d = o.d;
ctx.beginPath();
ctx.arc(o.x,o.y,o.r,0,2*Math.PI);
ctx.fillStyle = "hsla("+o.c+",100%,50%, "+o.a+")";
ctx.fill();
o.x = x;
o.y = y;
o.angle = a;
o.d = d;
}
function createData(num){
for(var i=0; i<num; i++){
allCircles.push({
"x": rand(w),
"changex": rand(10),
"y":rand(h),
"changex": rand(10),
"w": randn(w),
"h": randn(h),
"d": 1,
"a": 1,
"angle": 0,
"changle":15,
"c":216,
"r": 50
}
)
}
}
function createDataTwo(num){
for(var i=0; i<num; i++){
allCircles.push({
"x": rand(w),
"changex": rand(10),
"y":rand(h),
"changex": rand(10),
"w": randn(w),
"h": randn(h),
"d": 1,
"a": 1,
"angle": 0,
"changle":15,
"c":rand(90),
"r": 50
}
)
}
}
function turn(o,angle){
if(angle != undefined){
o.changle=angle;
};
o.angle+=o.changle;
}
function forward(o,d){
var changeX;
var changeY;
var oneDegree = Math.PI/180;
if(d != undefined){
o.d = d;
};
changeX= o.d*Math.cos(o.angle*oneDegree);
changeY = o.d*Math.sin(o.angle*oneDegree);
o.x+=changeX;
o.y+=changeY;
}
function randn(r){
var result = Math.random()*r - r/2
return result
}
function randi(r) {
var result = Math.floor(Math.random()*r);
return result
}
function rand(r){
return Math.random()*r
}
function setUpCanvas(){
canvas = document.querySelector("#myCanvas");
ctx = canvas.getContext("2d");
canvas.width = w;
canvas.height = h;
canvas.style.border = "5px solid orange"
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, w, h);
}
console.log("assi4")
HTML
<html>
<head>
<link rel="stylesheet" type="text/css" href="../modules.css">
</head>
<body>
<div id="container">
<h1>Click the Blue Circles Only</h1>
<canvas id = "myCanvas"></canvas>
</div>
<script src="assi5.js"></script>
</body>
</html>
CSS
#container {
margin: auto;
width: 75%;
text-align: center;
}
You can use cancelAnimationFrame to stop the animation when a non-blue circle is clicked
You need to pass it a reference to the frame ID returned from requestAnimationFrame for it to work.
In order to tell if a circle was clicked, you need to check the coordinates of each circle against the coordinates of the click.
I have an example below if you had your blue circles in an array "blue", and other circles in array "other", the ID returned by requestAnimationFrame as "frame".
The check function returns the number of blue circles hit (the points scored) and if any other circles were hit, it stops the animation.
getCoords returns the coordinates of the click on the canvas from the click event.
canvas.addEventListener('click', event=>{
points += check(getCoords(event), blue, other, frame);
document.getElementById('points').textContent = points;
})
function check({x, y}, blue, other, frame) {
other.filter(circle=>circle.isWithin(x, y))
.length && cancelAnimationFrame(frame); // This is where animation stops
return blue.filter(circle=>circle.isWithin(x, y)).length;
}
function getCoords(event) {
const canvas = event.target;
const rect = canvas.getBoundingClientRect()
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
return { x, y };
}
I have an example that works below where I changed the circles to the result of a function rather than an inline object, and moved the functions you use on them into their own class. You don't have to do this, but I find it a lot easier to understand.
function main() {
const canvas = document.getElementById('canvas');
const context = canvas.getContext("2d");
const clear = () => context.clearRect(0, 0, canvas.width, canvas.height);
const blue = new Array(2).fill().map(() => new Circle(context, 216));
const other = new Array(10).fill().map(() => new Circle(context));
let circles = [...blue, ...other];
let frame = 0;
let points = 0;
// Move the circle a bit and check if it needs to bounce
function update(circle) {
circle.forward(1)
circle.turn(30, true)
circle.collisionTestArray(circles)
circle.bounce();
}
// Main game loop, clear canvas, update circle positions, draw circles
function loop() {
clear();
circles.filter(circle => circle.free).forEach(update);
circles.forEach(circle => circle.draw());
frame = requestAnimationFrame(loop);
}
loop();
canvas.addEventListener('click', event => {
points += check(getCoords(event), blue, other, frame, circles);
document.getElementById('points').textContent = points;
})
}
function check({ x, y }, blue, other, frame) {
other.filter(circle => circle.isWithin(x, y))
// .map(circle=>circle.toggle())
.length && cancelAnimationFrame(frame); // This is where animation stops
return blue.filter(circle => circle.isWithin(x, y)).length;
}
function getCoords(event) {
const canvas = event.target;
const rect = canvas.getBoundingClientRect()
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
return { x, y };
}
main();
function Circle(context, c) {
const randn = r => rand(r) - r / 2;
const randi = r => Math.floor(randi(r));
const rand = r => Math.random() * r;
// These are for easily stopping and starting a circle;
this.free = true;
this.stop = () => this.free = false;
this.release = () => this.free = true;
this.toggle = () => this.free = !this.free;
const {
width,
height
} = context.canvas;
// These are the same properties you were using in your code
this.x = rand(width);
this.changex = rand(10);
this.y = rand(height);
this.changey = rand(10);
this.w = randn(width);
this.h = randn(height);
this.d = 1;
this.a = 1;
this.angle = 0;
this.changle = 15;
this.c = c || rand(90); // This is the only difference between blue and other circles
this.r = 50;
// These next functions you had in your code, I just moved them into the circle definition
this.draw = () => {
const { x, y, r, c } = this;
context.beginPath();
context.arc(x, y, r, 0, 2 * Math.PI);
context.fillStyle = "hsla(" + c + ",100%,50%, 1)";
context.fill();
}
this.bounce = () => {
const { x, y, angle } = this;
if (x > width || x < 0) {
this.turn(180 - 2 * angle);
}
if (y > height || y < 0) {
this.turn(360 - 2 * angle);
}
}
this.turn = (angle, random = false) => {
this.changle = random ? randn(angle) : angle;
this.angle += this.changle;
}
this.forward = d => {
this.d = d;
this.x += this.d * Math.cos(this.angle * Math.PI / 180);
this.y += this.d * Math.sin(this.angle * Math.PI / 180);
}
this.collisionTestArray = a => a
.filter(circle => circle != this)
.forEach(circle => this.collision(circle));
this.collision = circle => {
var differencex = Math.abs(this.x - circle.x);
var differencey = Math.abs(this.y - circle.y);
var hdif = Math.sqrt(differencex ** 2 + differencey ** 2);
if (hdif < this.r + circle.r) {
if (differencex < differencey) {
this.turn(180 - 2 * this.angle);
circle.turn(180 - 2 * circle.angle);
} else {
this.turn(360 - 2 * this.angle);
circle.turn(360 - 2 * circle.angle);
}
this.turn(180);
circle.turn(180);
}
}
// These 2 functions I added to check if the circle was clicked
this.distanceFrom = (x, y) => Math.sqrt((this.x - x) ** 2 + (this.y - y) ** 2);
this.isWithin = (x, y) => this.r > this.distanceFrom(x, y);
}
#canvas {
border: 5px solid orange;
}
#container {
margin: auto;
width: 75%;
text-align: center;
}
<div id="container">
<h1>Click the Blue Circles Only</h1>
<canvas id="canvas" width="1000" height="600"></canvas>
<p>
Points: <span id="points">0</span>
</p>
</div>
using OOP is better in this situation and will save you a lot of time
I have written the OOP version of your game, I wrote it in harry so you may find some bugs but it is good as a starting point
const canvas = document.querySelector("canvas")
const ctx = canvas.getContext("2d")
let h = canvas.height = 600
let w = canvas.width = 800
const numberOfCircles = 20
let circles = []
// running gameover
let gameStatus = "running"
let score = 0
canvas.addEventListener("click", (e) => {
if(gameStatus === "gameOver") {
document.location.reload()
return;
}
const mouse = {x: e.offsetX, y: e.offsetY}
for(let circle of circles) {
if(distance(mouse, circle) <= circle.radius) {
if(circle.color == "blue") {
gameStatus = "running"
score += 1
} else {
gameStatus = "gameOver"
}
}
}
})
class Circle {
constructor(x, y, color, angle) {
this.x = x
this.y = y
this.color = color
this.radius = 15
this.angle = angle
this.speed = 3
}
draw(ctx) {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fill();
}
move(circles) {
this.check(circles)
this.x += Math.cos(this.angle) * this.speed
this.y += Math.sin(this.angle) * this.speed
}
check(circles) {
if(this.x + this.radius > w || this.x - this.radius < 0) this.angle += Math.PI
if(this.y + this.radius > h || this.y - this.radius < 0) this.angle += Math.PI
for(let circle of circles) {
if(circle === this) continue
if(distance(this, circle) <= this.radius + circle.radius) {
// invert angles or any other effect
// there are much better soultion for resolving colliusions
circle.angle += Math.PI / 2
this.angle += Math.PI / 2
}
}
}
}
}
setUp()
gameLoop()
function gameLoop() {
ctx.clearRect(0,0,w,h)
if(gameStatus === "gameOver") {
ctx.font = "30px Comic"
ctx.fillText("Game Over", w/2 - 150, h/2 - 100)
ctx.fillText("you have scored : " + score, w/2 - 150, h/2)
return;
}
ctx.font = "30px Comic"
ctx.fillText("score : " + score, 20, 30)
for (let i = 0; i < circles.length; i++) {
const cirlce = circles[i]
cirlce.draw(ctx)
cirlce.move(circles)
}
requestAnimationFrame(gameLoop)
}
function random(to, from = 0) {
return Math.floor(Math.random() * (to - from) + from)
}
function setUp() {
gameStatus = "running"
score = 0
circles = []
for (var i = 0; i < numberOfCircles; i++) {
const randomAngle = random(360) * Math.PI / 180
circles.push(new Circle(random(w, 20), random(h, 20), randomColor(), randomAngle))
}
}
function randomColor() {
const factor = random(10)
if(factor < 3) return "blue"
return `rgb(${random(255)}, ${random(255)}, ${random(100)})`
}
function distance(obj1, obj2) {
const xDiff = obj1.x - obj2.x
const yDiff = obj1.y - obj2.y
return Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2))
}

Global color variable

I have been working on an internship. The application I need to make needs to have different colors in the intersecting areas. I made a global variable of color. I am changing its values in the buttons I have created. But whenever I press the button it changes color of each intersecting area even though I have pushed it in array with its own color. How can I solve this issue
let squares = [];
let overlappingsquares = []; //variable to hold squares drawn in intersecting area
let dragObject = null; // variable to hold the object being dragged
var myColour = (255);
function setup() {
createCanvas(600, 520);
button1 = createButton("Alpha");
button2 = createButton("Bravo");
button3 = createButton("Charlie");
button4 = createButton("Delta");
button5 = createButton("Echo");
button6 = createButton("Foxtrot");
button7 = createButton("Golf");
button8 = createButton("Hotel");
button9 = createButton("India");
button10 = createButton("Juliet");
button1.mousePressed(fun1);
button2.mousePressed(fun2);
button3.mousePressed(fun3);
button4.mousePressed(fun4);
button5.mousePressed(fun5);
button6.mousePressed(fun6);
button7.mousePressed(fun7);
button8.mousePressed(fun8);
button9.mousePressed(fun9);
button10.mousePressed(fun10);
//frameRate(1);
}
function draw() {
background(135,206,250);
//myColour = (255);
// if a square is being dragged, update its position
if (this.dragObject != null) {
this.dragObject.position.x = mouseX;
this.dragObject.position.y = mouseY;
}
//draw all squares
for (let i = 0; i < squares.length; i++) {
let s = squares[i];
s.show();
}
for (let i = 0; i < squares.length; i++) {
for (let j = i + 1; j < squares.length; j++) {
//block checking collision
if (i != j && squares[i].collides(squares[j])) {
squares[i].changecolor();
//set intersection color
//fill(myColour);
//calculate parameters
newX = Math.max(squares[i].position.x, squares[j].position.x);
newY = Math.max(squares[i].position.y, squares[j].position.y);
newW = Math.min(squares[i].position.x + squares[i].w, squares[j].position.x + squares[j].w) - newX;
newH = Math.min(squares[i].position.y + squares[i].h, squares[j].position.y + squares[j].h) - newY;
//draw rectangle
let col = myColour
let Osquare = new OverlappingSquares(newX, newY, newW, newH, col);
overlappingsquares.push(Osquare);
}
}
}
}
function mousePressed() {
if (this.dragObject == null) {
//ask every square if they are being "hit"
for (let i = 0; i < squares.length; i++) {
let s = squares[i];
if (s.hitTest()) {
//if so, set the drag object as this square and return
this.dragObject = s;
return;
}
}
//no squares are hit, create a new square.
let square = new Square(mouseX, mouseY);
squares.push(square);
}
}
//mouse is released, release the current dragged object if there is one
function mouseReleased() {
this.dragObject = null;
}
class Square {
constructor(InitialX, InitialY) {
this.w = 60;
this.h = 60;
this.position = {
x: InitialX,
y: InitialY
};
}
//basic test of mouse position against square position and if its inside the rectangle
hitTest() {
let x = mouseX - this.position.x;
let y = mouseY - this.position.y;
return (x > 0 && x < this.w) && (y > 0 && y < this.h);
}
show() {
fill(50);
rect(this.position.x, this.position.y, this.w, this.h);
}
collides(sqr) {
if (this.position.x < sqr.position.x + sqr.w &&
this.position.x + this.w > sqr.position.x &&
this.position.y < sqr.position.y + sqr.h &&
this.position.y + this.h > sqr.position.y) {
return true;
}
return false;
}
changecolor() {
for (let i = 0; i < squares.length; i++) {
let s = squares[i];
s.show();
}
for (let i = 0; i < overlappingsquares.length; i++) {
let s = overlappingsquares[i];
s.show();
}
}
}
//Overlapping sqaures class
class OverlappingSquares {
constructor(X, Y, W, H, C) {
this.w = W;
this.h = H;
this.col = C
this.position = {
x: X,
y: Y
};
}
show() {
fill(this.col)
rect(this.position.x, this.position.y, this.w, this.h);
}
}
function fun1() {
myColour = color(0,255, 0); //green
}
function fun2() {
myColour = color(255, 0, 0); //red
}
function fun3() {
myColour = color(0, 0, 200); //blue
}
function fun4() {
myColour = color(250, 0, 150); //pink
}
function fun5() {
myColour = color(128, 0, 128); //purple
}
function fun6() {
myColour = color(255, 255, 0); //yellow
}
function fun7() {
myColour = color(128, 0, 0); //marroon
}
function fun8() {
myColour = color(255, 128, 0); //orange
}
function fun9() {
myColour = color(192, 105, 50); //brown
}
function fun10() {
myColour = color(255,228,196); //bisque
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.js"></script>
I went through your code and spotted this snippet
//draw rectangle
let col = myColour
let Osquare = new OverlappingSquares(newX, newY, newW, newH, col);
overlappingsquares.push(Osquare);
It's within the loop that you are calling on every single cycle. When ever you select a button, it sets the new value for 'myColour', and within the next loop it will color all overlapping elements. You don't really tell in detail what's your goal. But some how you will need to add another color variable and identify which button intersection you want to color which way...
I think it would be better to solve this in a different way. Looping over all elements will make your program lag.

How to see through a rectangle in p5.js?

I am trying to create an effect where you can hover over the webpage with your mouse and it will have a drawing and when you get to an area, you unveil an image. I thought about doing it this way:
Have an image in the back
Have a rectangle over it (to hide it)
Have an element (your mouse) be able to go over the rectangle and delete the portion that your mouse is hovered over on.
How can I do this with p5.js?
I have it on my screen at the moment:
let img;
// function preload() {
// }
function setup() {
var canvas = createCanvas(
document.getElementById("myCanvas").offsetWidth,
document.getElementById("myCanvas").offsetHeight
);
canvas.parent("myCanvas");
// background(32);
loadImage("../img/monalisa.png", img => {
image(img, 0, 0);
});
}
function draw() {
// monaLisa();
rect(0, 0, 300, 300);
circles();
}
// function monaLisa() {
// image(img, 0, 0);
// }
function circles() {
// fill(255);
ellipse(mouseX, mouseY, 25, 25);
}
Simply push that rectangle to the right by such amount of pixels mouse is positioned from left side.
let img;
let edgeX = 0;
function setup() {
createCanvas(300,400)
img = loadImage("https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/300px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg")
}
function draw() {
// variable updates
if (mouseX > edgeX &&
mouseX >= 0 && mouseX <= 300 && // mouse within limits of picture
mouseY >= 0 && mouseY <= 400
) {
edgeX = mouseX;
}
// actual rawing
image(img, 0, 0);
fill('rgba(50,255,150, 0.5)');
rect(edgeX, 0, 300, 400);
}
p5 demo
EDIT
If you want to uncover just a small segment of picture under the mouse position, then algo may be this:
Create 2D rectangle array
Loop through rectangles and draw them on top of image
If mouse intersects with some rectangle - mark it as undrawable
Code:
let canvW = 300
let canvH = 400
let img
let dx = 20
let dy = 40
let diff = 3
let blocks
function setup() {
cursor(CROSS);
mouseX = -10;
mouseY = -10;
createCanvas(canvW,canvH)
img = loadImage("https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/300px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg")
blocks = new Array(canvH/dy);
for (var i=0; i < blocks.length; i++) {
blocks[i] = new Array(canvW/dx);
}
}
function draw() {
// variable updates
for (var y=0; y < blocks.length; y++) {
for (var x=0; x < blocks[y].length; x++) {
if (mouseX >= dx*x &&
mouseX <= dx*x+dx &&
mouseY >= dy*y &&
mouseY <= dy*y+dy
) {
blocks[y][x] = false;
}
}
}
// actual drawing
image(img, 0, 0)
stroke(70,127,240, 100)
strokeWeight(3)
for (var y=0; y < blocks.length; y++) {
for (var x=0; x < blocks[y].length; x++) {
if (blocks[y][x] !== false) {
// outer rectangle
fill(`rgba(50,127,240, 0.5)`)
rect(dx*x, dy*y, dx, dy)
// inner rectangle
fill(`rgba(70,127,240, 0.8)`)
rect(dx*x+diff, dy*y+diff, dx-2*diff, dy-2*diff)
}
}
}
}
p5 uncover segment demo
Visuals: partly uncovered Mona Lisa if somebody is lazy to check demo:

How to trigger animations in correct order in p5.js?

I'm trying to trigger animations in a simple pong game when the ball bounces off each edge. However, I'm struggling to get the animations to appear the way I want them to. I want the ellipses to draw on top of each other in the order that the edges are hit. This sometimes happens, but I believe the problem is that when two animation booleans are true at the same time, whichever animation appears later in the program flow will draw over the other. So the way I've laid it out below, the blue will always draw over the yellow if both are true, and the red will always draw over both blue and yellow if both are true.
Any assistance with this would be much appreciated! Thanks.
var bg = 220;
var x = 0;
var y = 200;
var speed = 3;
var speedY = 4;
var leftAnim = false;
var leftX;
var leftY;
var leftDiam = 40;
var rightAnim = false;
var rightX;
var rightY;
var rightDiam = 40;
var topAnim = false;
var topX;
var topY;
var topDiam = 40;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(bg);
noStroke();
edgeAnimation();
fill("white");
ellipse(x, y, 40, 40);
x += speed;
y += speedY;
if (x > width) {
//set rightAnim boolean to true to trigger right edge animation
rightAnim = true;
//update animating ellipse position variables to draw it at the same point where ball bounced
rightX = x;
rightY = y;
//reverse x direction of ball
speed *= -1;
}
if (x < 0) {
leftAnim = true;
leftX = x;
leftY = y;
speed *= -1;
}
// if the ball hits the top of the canvas, reverse the y direction of the ball
if (y < 0) {
topAnim = true;
topX = x;
topY = y;
speedY *= -1;
}
//if ball hits bottom of the canvas, stop the ball's motion
if (y > height) {
speed = 0;
speedY = 0;
}
//conditional to check for collision with paddle
if (x > mouseX && x < mouseX + 100 && y == height - 60) {
speedY *= -1;
}
// Paddle
rect(mouseX, height - 40, 100, 30);
}
function edgeAnimation() {
if (leftAnim == true) {
fill("gold");
ellipse(leftX, leftY, leftDiam);
leftDiam += 20;
//if animating ellipse fills the canvas, change the background color to the ellipse color, change leftAnim boolean to false and reset the diameter's size
if (leftDiam > 1150) {
bg = "gold";
leftAnim = false;
leftDiam = 40;
}
}
if (rightAnim == true) {
fill("RoyalBlue");
ellipse(rightX, rightY, rightDiam);
rightDiam += 20;
if (rightDiam > 1150) {
bg = "RoyalBlue";
rightAnim = false;
rightDiam = 40;
}
}
if (topAnim == true) {
fill("crimson");
ellipse(topX, topY, topDiam);
topDiam += 20;
if (topDiam > 1150) {
bg = "crimson";
topAnim = false;
topDiam = 40;
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.js"></script>
Don't use boolean states, but use list of animations.
var animation = []
Is a new edge is hit the append a new animation data set at the end (.push) of the animation list:
function draw() {
// [...]
if (x > width) {
animation.push( {color: "RoyalBlue", x: x, y: y, diam:40} );
speed *= -1;
}
if (x < 0) {
animation.push( {color: "gold", x: x, y: y, diam: 40} );
speed *= -1;
}
if (y < 0) {
animation.push( {color: "crimson", x: x, y: y, diam: 40} );
speedY *= -1;
}
// [...]
}
The animations can be drawn in a loop. Keep only that animations which doesn't exceed the limit:
function edgeAnimation() {
var keepAnimation = []
for (let i = 0; i < animation.length; ++i) {
fill( animation[i].color );
ellipse( animation[i].x, animation[i].y, animation[i].diam );
animation[i].diam += 20;
if (animation[i].diam > 1150) {
bg = animation[i].color;
} else {
keepAnimation.push(animation[i]);
}
}
animation = keepAnimation;
}
See the example, wher I applied the suggestions to the code of the question:
var bg = 220;
var x = 0;
var y = 200;
var speed = 3;
var speedY = 4;
var animation = []
function setup() {
createCanvas(400, 400);
}
function draw() {
background(bg);
noStroke();
edgeAnimation();
fill("white");
ellipse(x, y, 40, 40);
x += speed;
y += speedY;
if (x > width) {
animation.push( {color: "RoyalBlue", x: x, y: y, diam:40} );
speed *= -1;
}
if (x < 0) {
animation.push( {color: "gold", x: x, y: y, diam: 40} );
speed *= -1;
}
if (y < 0) {
animation.push( {color: "crimson", x: x, y: y, diam: 40} );
speedY *= -1;
}
//if ball hits bottom of the canvas, stop the ball's motion
if (y > height) {
x = random(20, width-20);
y = 20;
speed = random(2,4);
speedY = 6 - speed;
}
//conditional to check for collision with paddle
if (x > mouseX && x < mouseX + 100 && y < height - 59 + speedY && y > height - 60) {
speedY *= -1;
y = height - 60
}
// Paddle
rect(mouseX, height - 40, 100, 30);
}
function edgeAnimation() {
var keepAnimation = []
for (let i = 0; i < animation.length; ++i) {
fill( animation[i].color );
ellipse( animation[i].x, animation[i].y, animation[i].diam );
animation[i].diam += 20;
if (animation[i].diam > 1150) {
bg = animation[i].color;
} else {
keepAnimation.push(animation[i]);
}
}
animation = keepAnimation;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.js"></script>

JavaScript Pong game. I can't move 2 players at once

I stuck in one place for few hours, so I decided to go for help here. I'm beginner and i wish to try write a simple pong game.
At this link in Khan Academy you'll see result.
KHAN ACADEMY my pong game
My issue is:
I can't move two players at once. Only player can move - who hit last the keyboard. Last hit key win.
I know there are few ready pong games, but a lot of it is in Java, or all different logic. Can you help me good people? :)
//THIS IS GAME FOR 2 PEOPLE
//PLAYER 1 CONTROLS: UP ARROW (MOVE UP), DOWN ARROW (MOVE DOWN)
//PLAYER 2 CONTROLS: W KEY (MOVE UP), S KEY (MOVE DOWN)
var player1Y = height/2;
var player2Y = height/2;
var player1Score = 0;
var player2Score = 0;
var ball;
var gameStarted = false;
var t = 0;
//Constants
var PAUSE_TIME = 60;
var PLAYER_MOVE_SPEED = 2;
var BALL_SPEED = 3;
var PADDLE_HEIGHT = 80;
var PADDLE_WIDTH = 8;
angleMode = "degrees";
var Ball = function(position, speed) {
this.position = position;
this.speed = speed || BALL_SPEED;
this.radius = 6;
this.resetVelocity = function() {
this.theta = random(0, 75);
this.velocity = new PVector(
this.speed*cos(this.theta), -this.speed*sin(this.theta));
};
this.resetVelocity();
this.draw = function() {
fill(0, 0, 0);
noStroke();
ellipse(this.position.x, this.position.y,
this.radius*2, this.radius*2);
};
this.collideWithPaddle = function(x, y) {
if (this.position.x - this.radius < x + PADDLE_WIDTH/2 &&
this.position.x + this.radius > x - PADDLE_WIDTH/2) {
if (dist(0, this.position.y, 0, y) <
PADDLE_HEIGHT/2 + this.radius) {
if (this.position.x > x) {
this.position.x = x +
this.radius + PADDLE_WIDTH/2;
}
else if (this.position.x < x) {
this.position.x = x -
this.radius - PADDLE_WIDTH/2;
}
this.velocity.mult(new PVector(-1, 1));
}
}
};
this.update = function() {
//Handle wall collisions
if (this.position.x < 0) {
player2Score++;
this.position = new PVector(width/2, height/2);
gameStarted = false;
this.resetVelocity();
}
else if (this.position.x > width) {
player1Score++;
this.position = new PVector(width/2, height/2);
gameStarted = false;
this.resetVelocity();
}
if (this.position.y < 0) {
this.position.y = 0;
this.velocity.mult(new PVector(1, -1));
}
else if (this.position.y > height) {
this.position.y = height;
this.velocity.mult(new PVector(1, -1));
}
//Handle paddle collisions
this.collideWithPaddle(20, player1Y);
this.collideWithPaddle(width-20, player2Y);
this.position.add(this.velocity);
};
};
ball = new Ball(new PVector(width/2, height/2));
var drawScores = function() {
var s;
fill(0, 0, 0);
textSize(16);
s = "Player 1: " + player1Score;
text(s, width*0.25-textWidth(s)/2, 25);
s = "Player 2: " + player2Score;
text(s, width*0.75-textWidth(s)/2, 25);
};
//Move the player1 up
var movePlayer1Up = function() {
player1Y -= PLAYER_MOVE_SPEED;
};
//Move the player1 down
var movePlayer1Down = function() {
player1Y += PLAYER_MOVE_SPEED;
};
//Move the player2 up
var movePlayer2Up = function() {
player2Y -= PLAYER_MOVE_SPEED;
};
//Move the player2 down
var movePlayer2Down = function() {
player2Y += PLAYER_MOVE_SPEED;
};
var drawPlayers = function() {
//Constrain the player movement
player1Y = constrain(player1Y, 0, 400);
player2Y = constrain(player2Y, 0, 400);
rectMode(CENTER);
fill(0, 0, 0);
rect(20, player1Y, PADDLE_WIDTH, PADDLE_HEIGHT);
rect(width-20, player2Y, PADDLE_WIDTH, PADDLE_HEIGHT);
};
draw = function() {
//Control Player 1
if (keyIsPressed) {
if (keyCode===38){
movePlayer1Up();
}
else if(keyCode===40) {
movePlayer1Down();
}
}
//Control Player 2
if (keyIsPressed) {
if (key.toString()==="w"){
movePlayer2Up();
}
else if(key.toString()==="s"){
movePlayer2Down();
}
}
//Draw the environment
background(255, 255, 255);
drawPlayers();
drawScores();
stroke(100, 100, 100);
line(width/2, 0, width/2, height);
//Draw the ball
ball.draw();
if (!gameStarted) {
t++;
if (t >= PAUSE_TIME) {
t = 0;
gameStarted = true;
}
return;
}
ball.update();
};
You should be watching the onkeyup, onkeydown events for moving players, see this related question here. JavaScript multiple keys pressed at once
Now I understand concept, and I just did something like that:
Scope for multiple keys:
var keys = [];
var keyPressed = function(){
keys[keyCode] = true;
};
var keyReleased = function(){
keys[keyCode] = false;
};
and drawing function:
//Controls
if (keys[87]) {
movePlayer2Up();
}
if (keys[83]) {
movePlayer2Down();
}
if (keys[38]) {
movePlayer1Up();
}
if (keys[40]) {
movePlayer1Down();
}
And now it's working! The same link to the Khan Academy - there's the effect. Thank you one more time.

Categories