A continuació et proposo un pla pas a pas per crear un projecte d’un joc de Pong amb p5.js. Aquest enfocament project-based learning et permetrà aprendre els conceptes bàsics (i alguns avançats) mentre vas implementant funcionalitats gradualment. Cada pas inclou objectius, instruccions i exemples de codi.
index.html
que inclogui la biblioteca p5.js.
<!DOCTYPE html>
<html lang="ca">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pong Didàctic</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
sketch.js
on escriuràs tot el codi en p5.js.
setup()
per crear el canvas.draw()
, pinta el fons de color negre.function setup() {
createCanvas(windowWidth, windowHeight);
}
function draw() {
background(0);
}
Tasca addicional: Experimenta canviant la mida del canvas modificant els paràmetres de createCanvas()
.
setup()
, inicialitza aquestes variables amb les seves propietats (posició, mida, etc.).// Variables globals
let ball, paddle;
function setup() {
createCanvas(windowWidth, windowHeight);
// Inicialització de la pilota
ball = {
x: width / 2,
y: height / 2,
size: 20,
dx: 5,
dy: 5
};
// Inicialització de la pala
paddle = {
x: width / 2 - 50,
y: height - 30,
width: 100,
height: 10
};
}
function draw() {
background(0);
drawBall();
drawPaddle();
}
function drawBall() {
fill(255);
noStroke();
ellipse(ball.x, ball.y, ball.size);
}
function drawPaddle() {
fill(255);
rect(paddle.x, paddle.y, paddle.width, paddle.height);
}
Tasca addicional: Canvia la mida de la pilota i la pala per veure com es comporta el joc.
draw()
.function draw() {
background(0);
// Actualitzar la posició de la pilota
ball.x += ball.dx;
ball.y += ball.dy;
// Comprovar col·lisions amb les vores
if (ball.x < ball.size/2 || ball.x > width - ball.size/2) {
ball.dx *= -1;
}
if (ball.y < ball.size/2) {
ball.dy *= -1;
}
// Dibuixar elements
drawBall();
drawPaddle();
}
Tasca addicional: Modifica la velocitat de la pilota per fer el joc més o menys difícil.
mouseX
.function draw() {
background(0);
ball.x += ball.dx;
ball.y += ball.dy;
if (ball.x < ball.size/2 || ball.x > width - ball.size/2) {
ball.dx *= -1;
}
if (ball.y < ball.size/2) {
ball.dy *= -1;
}
// Actualitza la pala seguint el mouse, centrant-la en el cursor
paddle.x = constrain(mouseX - paddle.width / 2, 0, width - paddle.width);
drawBall();
drawPaddle();
}
Tasca addicional: Prova de moure la pala amb el teclat (per exemple, amb les fletxes esquerra/dreta).
let score = 0;
function draw() {
background(0);
ball.x += ball.dx;
ball.y += ball.dy;
if (ball.x < ball.size/2 || ball.x > width - ball.size/2) {
ball.dx *= -1;
}
if (ball.y < ball.size/2) {
ball.dy *= -1;
}
// Comprovar col·lisió amb la pala
if (ball.y + ball.size/2 >= paddle.y &&
ball.x > paddle.x && ball.x < paddle.x + paddle.width) {
ball.dy *= -1;
score++;
}
// Mostrar la puntuació
fill(255);
textSize(24);
text(`Puntuació: ${score}`, 20, 30);
paddle.x = constrain(mouseX - paddle.width / 2, 0, width - paddle.width);
drawBall();
drawPaddle();
}
Tasca addicional: Fes que la velocitat de la pilota augmenti lleugerament en cada impacte per incrementar la dificultat.
let lives = 3;
let gameOver = false;
function draw() {
background(0);
if (gameOver) {
fill(255, 0, 0);
textSize(36);
textAlign(CENTER, CENTER);
text("Game Over", width / 2, height / 2);
return;
}
ball.x += ball.dx;
ball.y += ball.dy;
if (ball.x < ball.size/2 || ball.x > width - ball.size/2) {
ball.dx *= -1;
}
if (ball.y < ball.size/2) {
ball.dy *= -1;
}
// Comprovar col·lisió amb la pala
if (ball.y + ball.size/2 >= paddle.y &&
ball.x > paddle.x && ball.x < paddle.x + paddle.width) {
ball.dy *= -1;
score++;
}
// Si la pilota cau per sota
if (ball.y - ball.size/2 > height) {
lives--;
if (lives <= 0) {
gameOver = true;
} else {
// Reset de la posició de la pilota
ball.x = width / 2;
ball.y = height / 2;
ball.dx = 5;
ball.dy = 5;
}
}
fill(255);
textSize(24);
textAlign(LEFT);
text(`Puntuació: ${score} | Vides: ${lives}`, 20, 30);
paddle.x = constrain(mouseX - paddle.width / 2, 0, width - paddle.width);
drawBall();
drawPaddle();
}
Tasca addicional: Crea un botó (o una tecla) per reiniciar el joc quan s’acaba.
setInterval
per generar bonus cada cert temps.let bonusBalls = [];
let bonusInterval;
function setup() {
createCanvas(windowWidth, windowHeight);
// Inicialitza la pilota, la pala, puntuació i vides aquí...
bonusInterval = setInterval(spawnBonusBall, 3000);
}
function spawnBonusBall() {
// Genera un bonus amb tipus aleatori
let bonus = {
x: random(0, width),
y: 0,
size: 15,
dy: 3,
type: random() < 0.5 ? "red" : "green"
};
bonusBalls.push(bonus);
}
function drawBonusBalls() {
bonusBalls.forEach((ball, i) => {
fill(ball.type);
ellipse(ball.x, ball.y, ball.size);
ball.y += ball.dy;
// Elimina el bonus si surt del canvas
if (ball.y > height) {
bonusBalls.splice(i, 1);
}
// Comprovar col·lisió amb la pala
if (ball.y + ball.size/2 >= paddle.y &&
ball.x > paddle.x &&
ball.x < paddle.x + paddle.width) {
// Si és "red": redueix la mida; si és "green": augmenta-la
if (ball.type === "red") {
paddle.width = max(50, paddle.width - 20);
} else {
paddle.width = min(200, paddle.width + 20);
}
bonusBalls.splice(i, 1);
}
});
}
function draw() {
background(0);
if (gameOver) {
fill(255, 0, 0);
textSize(36);
textAlign(CENTER, CENTER);
text("Game Over", width / 2, height / 2);
return;
}
// Actualitza la posició i dibuixa la pilota com abans...
ball.x += ball.dx;
ball.y += ball.dy;
if (ball.x < ball.size/2 || ball.x > width - ball.size/2) {
ball.dx *= -1;
}
if (ball.y < ball.size/2) {
ball.dy *= -1;
}
if (ball.y + ball.size/2 >= paddle.y &&
ball.x > paddle.x && ball.x < paddle.x + paddle.width) {
ball.dy *= -1;
score++;
}
if (ball.y - ball.size/2 > height) {
lives--;
if (lives <= 0) {
gameOver = true;
} else {
ball.x = width / 2;
ball.y = height / 2;
ball.dx = 5;
ball.dy = 5;
}
}
fill(255);
textSize(24);
textAlign(LEFT);
text(`Puntuació: ${score} | Vides: ${lives}`, 20, 30);
paddle.x = constrain(mouseX - paddle.width / 2, 0, width - paddle.width);
// Dibuixar elements
drawBall();
drawPaddle();
drawBonusBalls();
}
Tasca addicional: Permet al jugador configurar paràmetres (velocitat, mida de la pala, etc.) a través d’un petit menú inicial.
Aquest projecte-based learning es basa en:
Aquest enfocament no sols t’ajuda a entendre els conceptes bàsics de la programació amb p5.js, sinó que també et prepara per a la modularització, l’organització del codi i la resolució de problemes a mesura que el projecte creix i es fa més complex. Prova d’afegir-te petits desafiaments a cada pas per aprofundir encara més en els conceptes apresos.