Basics: toggling colors of a grid when traveling ball hits cells?

Hi! I am trying to create a grid like a checkerboard. When players click a button, a ball shoots out of the character. My goal is that when a ball strikes a cell, it changes the color of the cell to match the ball, then rebounds off like a hockey puck. Balls only last a few bounces before expiring.

However, if a ball strikes a cell that’s already the same color, it continues moving in the same direction. I can’t understand how to code this interaction.

The goal is that after a few shots, the grid cells will match the color of the ball and can travel ffurther and eventually strike the enemy base.

The goal is that it should be sort of like minesweeper or breakout, and can continue over ‘safe’ terrain, but basically the ball just keeps bouncing back and forth!

Here’s what I have so far:

var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: {
        preload: preload,
        create: create,
    },
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 0 }, // No gravity in this example
        },
    },
};

var game = new Phaser.Game(config);

function preload() {
    // Load your ball and grid cell images here
    this.load.image('ball', 'ball.png');
    this.load.image('tile', 'cell.png');
}

var grid;
var ball;

function create() {
    const tileSize = 75; // Set the size of each tile
    const rows = 8; // Number of rows
    const cols = 10; // Number of columns
    const tileColor = 0x77FFFF; // Initial tile color
  
    // this.physics.createCheckerboard()
    // Create a group to hold the tiles
    const tilesGroup = this.add.group();
    for (let i = 0; i < rows; i++) {
        for (let j = 0; j < cols; j++) {
          const x = j * tileSize;
          const y = i * tileSize;
          const tile = this.physics.add.sprite(x, y, 'tile');
          tile.onCollide=true;
          tile.setTint(tileColor);
          tilesGroup.add(tile);
          tile.setImmovable(true); // Make the tiles immovable
        }
      }
    

    const ball = this.physics.add.sprite(50, 50, 'ball');
    ball
        .setScale(0.1)
        .setBounce(1)
        .setVelocity(400, 200);
        // .setCollideWorldBounds(true);
    
    ball.onCollide=true;
    // tilesGroup.onCollide=true;
    this.physics.world.setBounds(0, 0, 800, 600); // Set world bounds
    this.physics.add.collider(ball, tilesGroup, onCollision); // Add collision with tiles
  
  }

// function createGrid(group, rows, cols) {
//     for (var row = 0; row < rows; row++) {
//         for (var col = 0; col < cols; col++) {
//             var cell = group.create(col * 16, row * 16, 'gridCell');
//             cell.onCollide=true;
//             cell.setScale=0.3;
//             tile.hasBeenHit = false; 
//                         cell.setAlpha(0.5); // Set initial alpha to make the cells semi-transparent
//         }
//     }
// }

function onCollision(ball, tile) {
    if (!tile.hasBeenHit) {
        console.log("tile has not been hit");
      tile.setTint(0x0000FF);
      tile.onCollide=false;
      tile.hasBeenHit = true; // Mark the tile as hit
      // Make the ball bounce off only if it's the first hit
      ball.setVelocityX(-ball.body.velocity.x); // Reverse the ball's X velocity
      ball.setVelocityY(-ball.body.velocity.y); // Reverse the ball's Y velocity

    }
    console.log("ball hit tile");
    return true;
}

function changeTileColor(ball, tile) {

    if (tile.Hit == true){
        console.log("already hit, skipping");
        return false;
    }
    
    tile.setTint(0xFFFFFF); // Change tile color to blue
    tile.Hit = true;
    console.log("set color");
    return true;
  }


function toggleCellColor(ball, cell) {
    // Function to be called when the ball collides with a grid cell
    console.log("ball hit cell");
    
    if(cell.Hit === true){
        return true;
    }

    // Change the tint color of the cell
    if (cell.tintTopLeft === 0xFFFFFF) {
        cell.setTint(0xFF0000); // Change the cell color to red
    } else {
        cell.clearTint(); // Reset the cell color
    }
    cell.Hit = true;
}
function toggleCellColor2(ball, cell) {
    // Function to be called when the ball collides with a grid cell
    console.log("222 ball hit cell");
    // Change the tint color of the cell
    if (cell.tintTopLeft === 0xFFFFFF) {
        cell.setTint(0xFF0000); // Change the cell color to red
    } else {
        cell.clearTint(); // Reset the cell color
    }
}

console.log("game loaded");

If you want a tile to ignore collisions, you can do

tile.body.checkCollision.none = true;

in onCollision().

I don’t think you need to reverse the ball velocity, because Arcade Physics should do that after the collision.

Thank you for the response. You got me thinking about whether collision is even what I wanted, and instead you were right, overlap is a much better use for my physics.

I changed my code and it’s working like a champ now! The core fix was to discard collision checks and instead just look for overlap.

function preload() {
    this.load.image('ball', 'bullet.png');
    this.load.image('tile', 'turret.jpeg');
}

function addBall(physics, tilesGroup, x, y, color) {
    var ball1 = physics.add.sprite(x, y, 'ball');
    ball1
        .setScale(0.1)
        .setBounce(1)
        .setVelocity(400, 200)
        .setTint(color)
        .setCollideWorldBounds(true);
    ball1.targetColor = color;
    ball1.onCollide = true;
    physics.add.overlap(ball1, tilesGroup, changeTileColor);
}

function create() {
    const tileSize = 75; // Set the size of each tile
    const rows = 8; // Number of rows
    const cols = 10; // Number of columns

    // Create a group to hold the tiles
    const tilesGroup = this.add.group();

    for (let i = 0; i < rows; i++) {
        for (let j = 0; j < cols; j++) {
            const x = j * tileSize;
            const y = i * tileSize;
            const tile = this.physics.add.sprite(x, y, 'tile');
            tile.setScale(0.1);
            tile.onCollide = true;
            tile.color = 'white';
            tile.setImmovable(true); // Make the tiles immovable
            tile.setTint(0xFFFFFF)
            tilesGroup.add(tile);
        }
    }

    this.physics.world.setBounds(0, 0, 800, 600); // Set world bounds
    addBall(this.physics, tilesGroup, 50, 50, 0xFF2277);
    addBall(this.physics, tilesGroup, 400, 249, 0x99FF99);
}


function changeTileColor(ball, tile) {

    if (tile.color !== ball.targetColor) {
        tile.color = ball.targetColor;
        tile.setTint(ball.targetColor);
        tile.setAlpha(1);
        var rand = Math.floor(Math.random() * 70);
        ball.setVelocityX(-ball.body.velocity.x + rand); // Reverse the ball's X velocity
        ball.setVelocityY(-ball.body.velocity.y - rand); // Reverse the ball's Y velocity
        ball.rotation += 0.1;
    }

    return true;
}

var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: {
        preload: preload,
        create: create,
    },
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 0 }, // No gravity in this example
        },
    },
};

var game = new Phaser.Game(config);

console.log("game loaded");