const pitchWidth = 1050 * 1.4;
const pitchHeight = 680 * 1.1;
var playerControlRed = false;
var playerControlBlue = false;
var redFormationIndex = 0;
var blueFormationIndex = 0;
function mousePressed() {
if (gameState == "Menu") {
if (dist(mouseX, mouseY, width / 2, height * 0.9) < 50) {
ball = new football(0, 0);
if (dist(mouseX, mouseY, width * 0.4, height * 0.15) < width * 0.1) {
playerControlRed = !playerControlRed;
if (dist(mouseX, mouseY, width * 0.6, height * 0.15) < width * 0.1) {
playerControlBlue = !playerControlBlue;
if(dist(mouseX, mouseY, width * 0.1, height * 0.55+30) < width * 0.1) {
if(redFormationIndex == formations.length) {
if(dist(mouseX, mouseY, width * 0.9, height * 0.55+30) < width * 0.1) {
if(blueFormationIndex == formations.length) {
if(gameState == "Postmatch") {
if (dist(mouseX, mouseY, width / 2, height * 0.9) < 50) {
playerControlRed = false;
playerControlBlue = false;
ball = new football(0, 0);
goalTimer = 24000000000000000;
if (gameState == "Title") {
playerControlBlue = false;
createCanvas(windowWidth, windowHeight);
ball = new football(0, 0);
if (gameState == "Thumbnail") {
translate(width / 2, height / 2);
image(redKick, 0, 0, 600, 600);
translate(-width / 2, -height / 2);
if(gameState == "Postmatch") {
if(redScore > blueScore) {
else if(blueScore > redScore) {
textAlign(CENTER, CENTER);
text(txt, width / 2, height / 4);
text("Leave a heart if you liked it!\nComment your suggestions", width/2, height * 0.6);
drawButton(width / 2, height * 0.9, 100, "OK");
if (gameState == "Title") {
camX = lerp(camX, (camZoom * -ball.x + width / 2), 0.05);
camY = lerp(camY, (camZoom * -ball.y + height / 2), 0.05);
ball = new football(0, 0);
for (var i = 0; i < floor(timeScale); i++) {
rect(width / 2, height / 4 + 35, width * 4, height / 4 + 100);
rect(width / 2, height * 0.75 + 10, width * 4, 100);
textAlign(CENTER, CENTER);
text("FOOTBALL", width / 2, height / 4);
text("RAPID", width/2, height/4 - width/18);
if (floor(frameCount / 40) % 2 == 0) text("Press any key to continue", width / 2, height * 0.75);
if (gameState == "Menu") {
drawButton(width / 2, height * 0.9, 100, "PLAY");
rect(width / 2, height * 0.4 + 30, width * 4, 150);
rect(width / 2, height * 0.55 + 30, width * 4, 150);
rect(width / 2, height * 0.7 + 30, width * 4, 150);
textAlign(CENTER, CENTER);
rect(width * 0.25, height * 0.4, 60, 60, 20);
rect(width * 0.25, height * 0.4 + 60, 60, 60, 20);
rect(width * 0.25 - 60, height * 0.4 + 60, 60, 60, 20);
rect(width * 0.25 + 60, height * 0.4 + 60, 60, 60, 20);
rect(width * 0.75, height * 0.4, 60, 60, 20);
rect(width * 0.75, height * 0.4 + 60, 60, 60, 20);
rect(width * 0.75 - 60, height * 0.4 + 60, 60, 60, 20);
rect(width * 0.75 + 60, height * 0.4 + 60, 60, 60, 20);
rect(width * 0.25, height * 0.55 + 30, 60, 60, 20);
rect(width * 0.75, height * 0.55 + 30, 60, 60, 20);
rect(width * 0.25, height * 0.7 + 30, 60, 60, 20);
rect(width * 0.75, height * 0.7 + 30, 60, 60, 20);
textAlign(CENTER, CENTER);
text("W", width * 0.25, height * 0.4);
text("S", width * 0.25, height * 0.4 + 60);
text("A", width * 0.25 - 60, height * 0.4 + 60);
text("D", width * 0.25 + 60, height * 0.4 + 60);
text("↑", width * 0.75, height * 0.4);
text("↓", width * 0.75, height * 0.4 + 60);
text("←", width * 0.75 - 60, height * 0.4 + 60);
text("→", width * 0.75 + 60, height * 0.4 + 60);
text("V", width * 0.25, height * 0.55 + 30);
text(".", width * 0.75, height * 0.55 + 30);
text("B", width * 0.25, height * 0.7 + 30);
text("/", width * 0.75, height * 0.7 + 30);
textAlign(CENTER, CENTER);
text("MOVEMENT", width * 0.5, height * 0.4 + 30);
text("PASS", width * 0.5, height * 0.55 + 30);
text("LONG PASS/SHOT\n(hold longer for more power)", width * 0.5, height * 0.7 + 30);
let p1Text = playerControlRed ? "Player\n(click to change)" : "AI\n(click to change)";
let p2Text = playerControlBlue ? "Player\n(click to change)" : "AI\n(click to change)";
text(p1Text, width * 0.4, height * 0.15);
text(p2Text, width * 0.6, height * 0.15);
text(formations[redFormationIndex] + "\nClick to change", width * 0.1, height * 0.55+30);
text(formations[blueFormationIndex]+ "\nClick to change", width * 0.9, height * 0.55+30);
text("Most goals after 180 seconds wins", width * 0.5, height * 0.25);
image(redStand, -width * 0.25, height * 0.15);
image(blueStand, width * 0.75, height * 0.15);
if (gameState == "Game") {
if(timer > 0 &&goalTimer == 0) {
ball = new football(0, 0);
for (let i = 0; i < floor(timeScale); i++) {
function drawButton(x, y, radius, txt) {
ellipse(0, 0, size, size);
if (dist(mouseX, mouseY, x, y) < size / 2) {
rotationAdd = frameCount * 0.1;
for (let i = 0; i < 5; i++) {
ellipse(0, 0, size * 0.4, size * 0.4);
textAlign(CENTER, CENTER);
if (gameState == "Game") {
if (ball.currentPlayer != null) {
if (keyCode == 66 && ball.currentPlayer.team == 1) {
ball.currentPlayer.manualShot();
if (keyCode == 191 && ball.currentPlayer.team == -1) {
ball.currentPlayer.manualShot();
function drawBackground() {
function drawGraphics() {
line(-pitchWidth / 2, (goalWidth / 2) * tiltAmount, -pitchWidth / 2 - 5, (goalWidth / 2 - goalHeight)* tiltAmount);
line(-pitchWidth / 2, -(goalWidth / 2) * tiltAmount, -pitchWidth / 2 - 5, (-goalWidth / 2 - goalHeight) * tiltAmount);
line(-pitchWidth / 2 - 5, (goalWidth / 2 - goalHeight)* tiltAmount, -pitchWidth / 2 - 5, (-goalWidth / 2 - goalHeight)* tiltAmount);
line(pitchWidth / 2, (goalWidth / 2)* tiltAmount, pitchWidth / 2 + 5, (goalWidth / 2 - goalHeight)* tiltAmount);
line(pitchWidth / 2, (-goalWidth / 2)* tiltAmount, pitchWidth / 2 + 5, (-goalWidth / 2 - goalHeight)* tiltAmount);
line(pitchWidth / 2 + 5, (goalWidth / 2 - goalHeight)* tiltAmount, pitchWidth / 2 + 5, (-goalWidth / 2 - goalHeight)* tiltAmount);
camX = lerp(camX, (camZoom * -ball.x + width / 2), 0.05);
camY = lerp(camY, (camZoom * -ball.y + height / 2), 0.05);
var zm = 2 - ball.velocity.mag();
camZoom = lerp(camZoom, zm, 0.005);
camZoom = min(camZoom, 2);
camZoom = max(camZoom, 1.2);
translate(width / 2 - 150 * 0.6, 30);
rect(0, 0, 100 * 0.6, 60 * 0.6);
rect(100 * 0.6, 0, 100 * 0.6, 120 * 0.6);
rect(200 * 0.6, 0, 100 * 0.6, 60 * 0.6);
textAlign(CENTER, CENTER);
text("RED", 50 * 0.6, 30 * 0.6);
text(redScore + " - " + blueScore, 150 * 0.6, 30 * 0.6);
text("BLU", 250 * 0.6, 30 * 0.6);
text(round(timer*10)/10, 150 * 0.6, 90 * 0.6);
translate(-width / 2 + 150 * 0.6, -30 * 0.6);
fill(255, map(goalTimer, 700, 1000, 0, 255));
text("TIME", width / 2, height / 2);
if (goalTimer >= 240 && goalTimer < 400) {
fill(255, map(goalTimer, 240, 400, 0, 255));
text("GOAL!!!", width / 2, height / 2);
if (goalTimer < 180 && goalTimer != 0) {
fill(255, map(goalTimer, 180, 120, 255, 0));
text("3", width / 2, height / 2);
if (goalTimer < 120 && goalTimer != 0) {
fill(255, map(goalTimer, 120, 60, 255, 0));
text("2", width / 2, height / 2);
if (goalTimer < 60 && goalTimer != 0) {
fill(255, map(goalTimer, 60, 0, 255, 0));
text("1", width / 2, height / 2);
function generatePitchImage() {
pitchImage = createGraphics(pitchWidth, pitchHeight);
pitchImage.translate(pitchWidth / 2, pitchHeight / 2);
for (let i = 0; i < pitchStripes; i++) {
pitchImage.rectMode(CORNER);
pitchImage.fill(53, 117, 42);
pitchImage.rect((pitchWidth / pitchStripes) * i - pitchWidth / 2, -pitchHeight / 2, pitchWidth / pitchStripes, pitchHeight);
pitchImage.strokeWeight(12);
pitchImage.rectMode(CENTER);
pitchImage.strokeWeight(5);
pitchImage.ellipse(0, 0, pitchWidth / 5);
pitchImage.rect(0, 0, pitchWidth, pitchHeight);
pitchImage.rect(0, 0, 0, pitchHeight);
pitchImage.rect(-pitchWidth / 2 * (pitchStripes - 1) / pitchStripes, 0, pitchWidth / pitchStripes, pitchHeight / 4);
pitchImage.rect(-pitchWidth / 2 * (pitchStripes - 3) / pitchStripes, 0, pitchWidth * 3 / pitchStripes, pitchHeight * 0.6);
pitchImage.rect(pitchWidth / 2 * (pitchStripes - 1) / pitchStripes, 0, pitchWidth / pitchStripes, pitchHeight / 4);
pitchImage.rect(pitchWidth / 2 * (pitchStripes - 3) / pitchStripes, 0, pitchWidth * 3 / pitchStripes, pitchHeight * 0.6);
for (var i = 0; i < 1200; i++) {
pitchImage.fill(0, random(5));
pitchImage.circle(random(-pitchWidth / 2, pitchWidth / 2), random(-pitchHeight / 2, pitchHeight / 2), random(60));
pitchImage.strokeWeight(12);
pitchImage.point(-pitchWidth / 2, goalWidth / 2);
pitchImage.point(-pitchWidth / 2, -goalWidth / 2);
pitchImage.point(pitchWidth / 2, goalWidth / 2);
pitchImage.point(pitchWidth / 2, -goalWidth / 2);
pitchImage.tint(255, 30);
pitchImage.imageMode(CENTER);
image(pitchImage, 0, 0, pitchImage.width, pitchImage.height * tiltAmount);