I need help creating the snake game in matlab for a personal project.

Hello, I am creating the snake game in which the user has to click the left, right, up and down arrow keys to move the direction of the snake, and when it moves over the food icon, it increases in size. I just started learning Matlab 2 months ago in school and I wanted to challenge myself by creating this game. Currently I think I have the code to create a 20x20 axis in which it randomly plots the snake and food, and I think I have the code for the key press functions to move the snake. I also have code to make it so that when the snake's x or y values touches the borders that it turns off the while loop by setting alive=false. However, it is giving me a couple errors, and honestly I feel like i did the keypress part incorrectly. I will paste the code below for anyone to give suggestions because I really need it. Most of what I used in this code was self taught so if I did something wrong I apologize in advance. Cheers!
%% Snake.m
% Creates the snake game
% By: Anonymous
clear;clc;
%% perameters
axis([0, 20, 0, 20]);
snakex = randi([1,19],1);
snakey = randi([1,19],1);
foodx = randi([1,19],1);
foody = randi([1,19],1);
alive = true;
while alive == true
figure(100);
Food = plot(foodx,foody,'db'); hold("on");
Snake = plot(snakex,snakey,'og'); pause(0.1); hold("on");
grid("on"); axis("tight"); axis([0, 20, 0, 20])
% Below is the keypress code and the main cause for confusion!
set(gcf, 'KeyPressFcn', @processKey)
function processKey(~,evnt)
Function definitions are not supported in this context. Functions can only be created as local or nested functions in code files.
if length(evnt.Key) >= 1
switch evnt.Key
case 'leftarrow'
snakex = snakex - 1;
LastInput = left;
case 'rightarrow'
snakex = snakex + 1;
LastInput = right;
case 'downarrow'
snakey = snakey - 1;
LastInput = down;
case 'uparrow'
snakey = snakey + 1;
LastInput = up;
otherwise
if LastInput == left
snakex = snakex - 1;
elseif LastInput == right
snakex = snakex + 1;
elseif LastInput == down
snakey = snakey - 1;
elseif LastInput == up
snakey = snakey + 1;
end
end
end
end
if snakex == 0
alive = false;
end
if snakex == 20
alive = false;
end
if snakey == 0
alive = false;
end
if snakey == 20
alive = false;
end
end

 Accepted Answer

"Function definitions are not supported in this context. Functions can only be created as local or nested functions in code files."
Like the error message says, function definitions are not supported inside control blocks (if, else, while, for, etc.). You'd have to define the function processKey outside any control block in your script.
Since your intent is for processKey to set variables that need to be accessed within the while loop of the script (snakex, snakey, LastInput), it is convenient to make processKey a nested function (which requires making your script into a function) since nested functions share variables with their parent function.
Some construction as follows might be close to what you had in mind:
function snake_game()
fig = figure();
% Only need to set the figure's KeyPressFcn once, before the while loop.
% (processKey() will be called whenever the user presses a key while the
% figure has focus.)
set(fig, 'KeyPressFcn', @processKey)
axis([0, 20, 0, 20]);
snakex = randi([1,19],1);
snakey = randi([1,19],1);
foodx = randi([1,19],1);
foody = randi([1,19],1);
alive = true;
% initialize LastInput here in the parent function so that
% processKey can modify it
LastInput = '';
while alive
figure(fig);
Food = plot(foodx,foody,'db'); hold("on");
Snake = plot(snakex,snakey,'og'); pause(0.1); hold("on");
grid("on"); axis("tight"); axis([0, 20, 0, 20])
if snakex == 0
alive = false;
end
if snakex == 20
alive = false;
end
if snakey == 0
alive = false;
end
if snakey == 20
alive = false;
end
end
function processKey(~,evnt)
if length(evnt.Key) >= 1
switch evnt.Key
case 'leftarrow'
snakex = snakex - 1;
LastInput = 'left';
case 'rightarrow'
snakex = snakex + 1;
LastInput = 'right';
case 'downarrow'
snakey = snakey - 1;
LastInput = 'down';
case 'uparrow'
snakey = snakey + 1;
LastInput = 'up';
otherwise
switch LastInput
case 'left'
snakex = snakex - 1;
case 'right'
snakex = snakex + 1;
case 'down'
snakey = snakey - 1;
case 'up'
snakey = snakey + 1;
end
end
end
end
end

8 Comments

OMG! Thank you so much. This solves a LOT of my confusion. I am going to start working on figuring out how to have the snake interact with the food now and actually making the game fully functional. If I have any other questions I'll probably post it here. Thanks again!
Hello, I need some help again! I havent progressed too much because I took a break on this project for a while, however I am working on it again. Currently I am trying to find a way to keep the snake at its Snakelength (starts at 3) and have it grow in size when it eats a food. In my code right now, I have it so that it resets the plot everytime the snake goes over the snake size, but thats not what I really want. I also have it so that it increases its Snakelength each time it touches the food and now it resets the location of the food after consumption. I'll paste the code below so feel free to try to find a solution. If you are confused about the purpose of any section of code, let me know in the comments and thanks again!
%% SnakeGame.m
% Creates the Snake game
% By: Anonymous
function SnakeGame()
clc;
fig = figure();
set(fig, 'KeyPressFcn', @processKey)
axis([0, 20, 0, 20]);
snakex = randi([1,19],1);
snakey = randi([1,19],1);
foodx = randi([1,19],1);
foody = randi([1,19],1);
snakelength = 3;
counter = 0;
alive = true;
LastInput = '';
while alive == true
figure(fig);
plot(foodx,foody,'db'); hold("on"); % Plots the Food
plot(snakex,snakey,'og'); pause(0); % Plots the Snake
hold("on"); grid("on"); axis("tight"); axis([0, 20, 0, 20]);
if snakex == foodx
if snakey == foody
snakelength = snakelength + 1;
foodx = randi([1,19],1);
foody = randi([1,19],1);
plot(foodx,foody, 'db'); hold("off");
end
end
if counter == snakelength
plot(snakex,snakey,'og'); hold("off");
counter = counter*0;
end
if snakex <= 0
alive = false;
disp("You Lose!!!!! MWAHAHAHAHAHHAHAHAHAHA");
end
if snakex >= 20
alive = false;
disp("You Lose!!!!! MWAHAHAHAHAHHAHAHAHAHA");
end
if snakey <= 0
alive = false;
disp("You Lose!!!!! MWAHAHAHAHAHHAHAHAHAHA");
end
if snakey >= 20
alive = false;
disp("You Lose!!!!! MWAHAHAHAHAHHAHAHAHAHA");
end
end
function processKey(~,evnt)
if length(evnt.Key) >= 1
if alive == true
switch evnt.Key
case 'leftarrow'
snakex = snakex - 1;
LastInput = 'left';
counter = counter + 1;
disp(LastInput);
case 'rightarrow'
snakex = snakex + 1;
LastInput = 'right';
counter = counter + 1;
disp(LastInput);
case 'downarrow'
snakey = snakey - 1;
LastInput = 'down';
counter = counter + 1;
disp(LastInput);
case 'uparrow'
snakey = snakey + 1;
LastInput = 'up';
counter = counter + 1;
disp(LastInput);
end
end
end
end
end
Maybe something like this:
function snake_game()
figure('KeyPressFcn',@processKey);
axis([0, 20, 0, 20]);
N = 3; % initial snake length
snakex = randi([N,19],1)-(N-1:-1:0);
snakey = randi([1,19],1)-zeros(1,N);
foodx = randi([1,19],1);
foody = randi([1,19],1);
alive = true;
hold on
Food = plot(foodx,foody,'db'); % Plots the Food
Snake = plot(snakex,snakey,'og'); % Plots the Snake
grid("on"); axis("tight"); axis([0, 20, 0, 20]);
function processKey(~,evnt)
if ~alive
return
end
[ism,idx] = ismember(evnt.Key,["left","right","down","up"]+"arrow");
if ~ism
return
end
switch idx
case 1
newx = snakex(1) - 1;
newy = snakey(1);
case 2
newx = snakex(1) + 1;
newy = snakey(1);
case 3
newx = snakex(1);
newy = snakey(1) - 1;
case 4
newx = snakex(1);
newy = snakey(1) + 1;
end
if newx == foodx && newy == foody
snakex = [newx snakex];
snakey = [newy snakey];
foodx = randi([1,19],1);
foody = randi([1,19],1);
set(Food,'XData',foodx,'YData',foody);
else
snakex = [newx snakex(1:end-1)];
snakey = [newy snakey(1:end-1)];
end
set(Snake,'XData',snakex,'YData',snakey);
drawnow();
if snakex(1) <= 0 || snakex(1) >= 20 || snakey(1) <= 0 || snakey(1) >= 20
alive = false;
disp("You Lose!!!!! MWAHAHAHAHAHHAHAHAHAHA");
end
end
end
What the heck. This code is amazing! Although, I am pretty confused on how some of this works, so I will go part by part and ask questions about the parts I'm confused about.
For example what does this part of the code mean and what is its purpose?
snakex = randi([N,19],1)-(N-1:-1:0); snakey = randi([1,19],1)-zeros(1,N);
And then I am really confused about this code, as I have never seen it before:
[ism,idx] = ismember(evnt.Key,["left","right","down","up"]+"arrow");
if ~ism
return
end
What is [ism,idx]? Also what does ismember do?
Then, I understand the switch case part with the newx and newy, but I don't understand some of this part:
if newx == foodx && newy == foody
snakex = [newx snakex];
snakey = [newy snakey];
foodx = randi([1,19],1);
foody = randi([1,19],1);
set(Food,'XData',foodx,'YData',foody);
else
snakex = [newx snakex(1:end-1)];
snakey = [newy snakey(1:end-1)];
end
set(Snake,'XData',snakex,'YData',snakey);
drawnow();
What does snakex = [newx snakex] mean?
What does set(Food,'XData',foodx,'YData',foody); mean?
What does snakex = [newx snakex(1:end-1)]; mean?
And lastly what does set(Snake,'XData',snakex,'YData',snakey); drawnow(); mean?
I'm sorry for asking so many questions, but I am just geniunely confused about a lot of components of this code. Thank you so much!
Cheers!
1.
snakex = randi([N,19],1)-(N-1:-1:0);
snakey = randi([1,19],1)-zeros(1,N);
That stores the initial x- and y-coordinates of the snake. Inititally the snake is horizontal (so the y-coordinates are all the same random integer between 1 and 19) and of length N (so the x-coordinates are N consecutive integers, with the largest being a random integer between N and 19, so that the smallest is not less than 1, i.e., the snake is entirely on the board initially).
Example:
N = 3;
snakex = randi([N,19],1)-(N-1:-1:0);
snakey = randi([1,19],1)-zeros(1,N);
snakex,snakey
snakex = 1×3
10 11 12
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
snakey = 1×3
17 17 17
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Note that the snake is initally facing left, i.e., a leftarrow key press causes the snake to move one unit left, while a rightarrow key press causes the snake to turn around and double up on itself as it moves one unit right.
2.
[ism,idx] = ismember(evnt.Key,["left","right","down","up"]+"arrow");
if ~ism
return
end
This determines whether evnt.Key is an element of the string array ["leftarrow","rightarrow","downarrow","uparrow"], and if so, which one. ism is a logical which tells us whether evnt.Key is among those four strings, and idx stores its index in the string array or 0 if it's not a member. If evnt.Key is not among the string array, return early (i.e., nothing to do if the user hits a key other than one of the arrow keys).
Example:
evnt.Key = "downarrow";
[ism,idx] = ismember(evnt.Key,["left","right","down","up"]+"arrow");
evnt.Key
ans = "downarrow"
ism
ism = logical
1
idx
idx = 3
More info:
3. See my comments below about the final questions.
% check if the snake has just encountered a piece of food
if newx == foodx && newy == foody
% on food:
% grow the snake by prepending the food coordinates
% to the snake coordinate vectors:
snakex = [newx snakex];
snakey = [newy snakey];
% generate a new random food location
foodx = randi([1,19],1);
foody = randi([1,19],1);
% update the food line object in the axes
set(Food,'XData',foodx,'YData',foody);
else
% not on food:
% move the snake forward by prepending the new location to the snake
% coordinate vectors, and at the same time drop off the last coordinate
% of the snake. thus the snake's length doesn't change; it merely moves
% forward one unit along its path.
snakex = [newx snakex(1:end-1)];
snakey = [newy snakey(1:end-1)];
end
% update the snake line object in the axes
set(Snake,'XData',snakex,'YData',snakey);
drawnow();
More info:
Okay that makes a lot more sense. I am very thankful for your help yet again and I really appreciate you explaining my questions for me. Like I said, im still relatively new to matlab so I really appreciate your help. I am pretty satisfied with the code as it stands, the only thing I may try to add on is having the snake automatically move so you don't need to hold down an arrow key or keep pressing it and also a score system as well as having highscores. I will try to experiment with that on my own. Thanks for all your help throughout the project!
Cheers!

Sign in to comment.

More Answers (0)

Categories

Find more on Strategy & Logic in Help Center and File Exchange

Asked:

on 13 Nov 2024

Commented:

on 10 Dec 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!