Hello! I am making a simple Snake game with p5.js. I drew a grid, and two rectangles (snake and apple). But, I want to keep my rectangles on the grid, so they align with it. How do I do that? Here is my code:
let snake;
let apple;
let size = 25;
function setup() {
let canvas = createCanvas(650, 650);
canvas.center("horizontal");
frameRate(15);
snake = new Snake();
DrawAppleRandomPos();
}
function draw() {
background(242);
for (let x = 0; x < width; x += width / 25) {
for (let y = 0; y < height; y += height / 25) {
stroke(100, 100, 100);
strokeWeight(0.5);
line(x, 0, x, height);
line(0, y, width, y);
}
}
snake.Move();
snake.Show();
if (snake.Eat(apple)) {
DrawAppleRandomPos();
}
fill(255, 100, 0);
rect(apple.x, apple.y, size, size);
}
const DrawAppleRandomPos = () => {
let cols = floor(width / size);
let rows = floor(height / size);
apple = createVector(floor(random(cols)), floor(random(rows)));
apple.mult(size);
}
function keyPressed() {
if (keyCode === UP_ARROW || key === "w") {
snake.Direction(0, -1);
} else if (keyCode === DOWN_ARROW || key === "s") {
snake.Direction(0, 1);
} else if (keyCode === LEFT_ARROW || key === "a") {
snake.Direction(-1, 0);
} else if (keyCode === RIGHT_ARROW || key === "d") {
snake.Direction(1, 0);
}
}
function Snake() {
this.vec = createVector(0, 0);
this.movex = 1;
this.movey = 0;
this.w = 25;
this.h = 25;
this.speed = 15;
this.Move = () => {
this.vec.x += this.movex * this.speed;
this.vec.y += this.movey * this.speed;
this.vec.x = constrain(this.vec.x, 0, width - this.w);
this.vec.y = constrain(this.vec.y, 0, height - this.h);
}
this.Show = () => {
fill(200, 20, 230);
rect(this.vec.x, this.vec.y, this.w, this.h);
}
this.Direction = (x, y) => {
this.movex = x;
this.movey = y;
}
this.Eat = (position) => {
let distance = dist(this.vec.x, this.vec.y, position.x, position.y);
if (distance < 10) {
console.log("ate");
return true;
} else {
return false;
}
}
}
I changed something in DrawAppleRandomPos. Now it works for the columns. The first columns x must be 0 so you have to calculate (column - 1) * size for the base x, and then add the stroke weights of the grid (for every column twice the stroke weight, because the stroke is on both sides).
let snake;
let apple;
let size = 25;
function setup() {
let canvas = createCanvas(650, 650);
canvas.center("horizontal");
frameRate(15);
snake = new Snake();
DrawAppleRandomPos();
}
function draw() {
background(242);
for (let x = 0; x < width; x += width / 25) {
for (let y = 0; y < height; y += height / 25) {
stroke(100, 100, 100);
strokeWeight(0.5);
line(x, 0, x, height);
line(0, y, width, y);
}
}
snake.Move();
snake.Show();
if (snake.Eat(apple)) {
DrawAppleRandomPos();
}
fill(255, 100, 0);
rect(apple.x, apple.y, size, size);
}
const DrawAppleRandomPos = () => {
let cols = floor(width / size);
let rows = floor(height / size);
const col = floor(random(cols));
const row = floor(random(rows));
const x = (col - 1) * size + (col) * 0.5 * 2
apple = createVector(x, floor(random(rows)) * 25);
}
function keyPressed() {
if (keyCode === UP_ARROW || key === "w") {
snake.Direction(0, -1);
} else if (keyCode === DOWN_ARROW || key === "s") {
snake.Direction(0, 1);
} else if (keyCode === LEFT_ARROW || key === "a") {
snake.Direction(-1, 0);
} else if (keyCode === RIGHT_ARROW || key === "d") {
snake.Direction(1, 0);
}
}
function Snake() {
this.vec = createVector(0, 0);
this.movex = 1;
this.movey = 0;
this.w = 25;
this.h = 25;
this.speed = 15;
this.Move = () => {
this.vec.x += this.movex * this.speed;
this.vec.y += this.movey * this.speed;
this.vec.x = constrain(this.vec.x, 0, width - this.w);
this.vec.y = constrain(this.vec.y, 0, height - this.h);
}
this.Show = () => {
fill(200, 20, 230);
rect(this.vec.x, this.vec.y, this.w, this.h);
}
this.Direction = (x, y) => {
this.movex = x;
this.movey = y;
}
this.Eat = (position) => {
let distance = dist(this.vec.x, this.vec.y, position.x, position.y);
if (distance < 10) {
console.log("ate");
return true;
} else {
return false;
}
}
}
The apple is now always aligned with the columns, not with the rows yet (same principle like columns). The snake is a little more complicated. Could be done like that: The snake now has a CheckMove function, because you need to store how much time has passed since the snake moved the last time. When this time reaches a threshhold, move the snake one complete field instead of a little bit each frame.
let snake;
let apple;
let size = 25;
function setup() {
let canvas = createCanvas(650, 650);
canvas.center("horizontal");
frameRate(15);
snake = new Snake();
DrawAppleRandomPos();
}
function draw() {
background(242);
for (let x = 0; x < width; x += width / 25) {
for (let y = 0; y < height; y += height / 25) {
stroke(100, 100, 100);
strokeWeight(0.5);
line(x, 0, x, height);
line(0, y, width, y);
}
}
snake.CheckMove();
snake.Show();
if (snake.Eat(apple)) {
DrawAppleRandomPos();
}
fill(255, 100, 0);
rect(apple.x, apple.y, size, size);
}
const DrawAppleRandomPos = () => {
let cols = floor(width / size);
let rows = floor(height / size);
const col = floor(random(cols));
const row = floor(random(rows));
const x = (col - 1) * size + (col) * 0.5 * 2
apple = createVector(x, floor(random(rows)) * 25);
}
function keyPressed() {
if (keyCode === UP_ARROW || key === "w") {
snake.Direction(0, -1);
} else if (keyCode === DOWN_ARROW || key === "s") {
snake.Direction(0, 1);
} else if (keyCode === LEFT_ARROW || key === "a") {
snake.Direction(-1, 0);
} else if (keyCode === RIGHT_ARROW || key === "d") {
snake.Direction(1, 0);
}
}
function Snake() {
this.vec = createVector(0, 0);
this.movex = size + 1;
this.movey = 0;
this.w = 25;
this.h = 25;
this.speed = 1000; // how many milliseconds for one box?
this.lastMoveTime = 0;
this.CheckMove = () => {
if (this.lastMoveTime === 0 || Date.now() - this.lastMoveTime > this.speed) {
this.Move()
}
}
this.Move = () => {
this.vec.x += this.movex;
this.vec.y += this.movey * this.speed;
this.vec.x = constrain(this.vec.x, 0, width - this.w);
this.vec.y = constrain(this.vec.y, 0, height - this.h);
this.lastMoveTime = Date.now()
}
this.Show = () => {
fill(200, 20, 230);
rect(this.vec.x, this.vec.y, this.w, this.h);
}
this.Direction = (x, y) => {
this.movex = x;
this.movey = y;
}
this.Eat = (position) => {
let distance = dist(this.vec.x, this.vec.y, position.x, position.y);
if (distance < 10) {
console.log("ate");
return true;
} else {
return false;
}
}
}
you want to move in grid increments, one way to do this is to make sure you are using the variable you’ve named size at every location that governs position and movement!
Another way to do it is to have position and movement operate on grid indexes and have a function that converts grid index to canvas pixel coordinates (scaling factor).
I can expand a bit more on this once I get home to a keyboard! (Right now I’ve only babbled in English without referring to any code!)
What I did here was to make sure that all increments, steps & movements happen in multiples of size, I think I initially understood your definition of size, it seems you wanted size to be the ‘count of columns and rows’ in the game, but I thought it was the actual grid size (25 pixels width & height). I’ve changed it so that it’s just the ‘size of a single cell’ aka. grid size.