Azzera filtri
Azzera filtri

Question regarding how to make a game similar to snake in MATLAB.

3 visualizzazioni (ultimi 30 giorni)
Currently, my snake game spawns two players as 1x1 rectangles. The script is functional in the sense that each player can move and eat apples which increases their collision count. The game stops when one player reaches a set collision count. I can't figure out how to implement a logic in my code that will allow each player to grow and move like a snake each time they collide with the apple. Can anyone help me fix this issue? Here is my code:
clc
clear
close all
% Create a new figure
figure('WindowState','maximized');
hold on
% Create a nested loop to plot lines for the grid
for i = 0:13
for j = 0:13
% Plot horizontal lines
plot([0 13], [i i], 'k', 'LineWidth', 1.25);
axis off
% Plot vertical lines
plot([j j], [0 13], 'k', 'LineWidth', 1.25);
axis off
end
end
% Set the axis limits
xlim([0 13]);
ylim([0 13]);
%Set aspect ratio to equal
axis square;
% Spawn a 1x1 black square in the top left corner of the grid
rect = rectangle('Position', [0, 12, 1, 1], 'FaceColor', 'black');
% Spawn a 1x1 red square randomly in the middle of the grid
red_rect = rectangle('Position', [6, 6, 1, 1], 'FaceColor', 'red');
% Spawn a 1x1 blue square in the bottom right corner of the grid
blue_rect = rectangle('Position', [12, 0, 1, 1], 'FaceColor', 'blue');
% Create a counter for collisions
global collision_count
global collision_count1
collision_count = 0;
collision_count1 = 0;
% Boolean value to determine if the game ends or not
global x
x = 1;
% Create a text object to display the collision count
text_obj = text(0, 13.5, ['Player 1 Score: ', num2str(collision_count)], 'Color', 'black');
text_obj1 = text(0, -0.5, ['Player 2 Score: ', num2str(collision_count)], 'Color', 'black');
% Set the callback function for the key presses of both players
set(gcf, 'KeyPressFcn', {@moveBothPlayer, rect, red_rect, blue_rect, text_obj, text_obj1});
% Define the callback function for the players
function moveBothPlayer(~, event, rect, red_rect, blue_rect, text_obj, text_obj1)
% Leave the function when the game ends
global collision_count
global collision_count1
global x
% Leave the function when the game is determined to be over
if (collision_count == 5 || collision_count1 == 5) && x == 0
return
end
if (collision_count || collision_count1 ~= 5) && x == 1
% Get the current/previous position of each square
pos = get(rect, 'Position');
blue_pos = get(blue_rect, 'Position');
prev_pos = pos;
prev_blue_pos = blue_pos;
% Check for 'w' key press
if strcmp(event.Key, 'w')
pos(2) = pos(2) + 1;
% Check for 'a' key press
elseif strcmp(event.Key, 'a')
pos(1) = pos(1) - 1;
% Check for 's' key press
elseif strcmp(event.Key, 's')
pos(2) = pos(2) - 1;
% Check for 'd' key press
elseif strcmp(event.Key, 'd')
pos(1) = pos(1) + 1;
end
% Check if the black square leaves the grid
if pos(1) > 12
pos(1) = 0;
elseif pos(1) < 0
pos(1) = 12;
end
if pos(2) > 12
pos(2) = 0;
elseif pos(2) < 0
pos(2) = 12;
end
% Check for 'uparrow' key press
if strcmp(event.Key, 'uparrow')
blue_pos(2) = blue_pos(2) + 1;
% Check for 'leftarrow' press
elseif strcmp(event.Key, 'leftarrow')
blue_pos(1) = blue_pos(1) - 1;
% Check for 'downarrow' press
elseif strcmp(event.Key, 'downarrow')
blue_pos(2) = blue_pos(2) - 1;
% Check for 'rightarrow' press
elseif strcmp(event.Key, 'rightarrow')
blue_pos(1) = blue_pos(1) + 1;
end
% Check if the blue square leaves the grid
if blue_pos(1) > 12
blue_pos(1) = 0;
elseif blue_pos(1) < 0
blue_pos(1) = 12;
end
if blue_pos(2) > 12
blue_pos(2) = 0;
elseif blue_pos(2) < 0
blue_pos(2) = 12;
end
% Check if a players position equals the position of the apple
red_pos = get(red_rect, 'Position');
if pos(1) == red_pos(1) && pos(2) == red_pos(2)
collision_count = collision_count + 1;
set(text_obj, 'String', ['Player 1 Score: ', num2str(collision_count)]);
set(red_rect, 'Position', [randi([0,12]), randi([0,12]), 1, 1]);
elseif blue_pos(1) == red_pos(1) && blue_pos(2) == red_pos(2)
collision_count1 = collision_count1 + 1;
set(text_obj1, 'String', ['Player 2 Score: ', num2str(collision_count1)]);
set(red_rect, 'Position', [randi([0,12]), randi([0,12]), 1, 1]);
end
% Update the position of Player 1
set(rect, 'Position', pos);
% Update the position of Player 2
set(blue_rect, 'Position', blue_pos);
end
% Prompting the users to play another game
if collision_count == 5
answer = questdlg( 'Player 1 Wins! Would you like to play again?', ...
'Choices', 'Yes','No','Yes');
% Handle response
switch answer
case 'Yes'
collision_count = 0;
collision_count1 = 0;
set(text_obj, 'String', ['Player 1 Score: ', num2str(collision_count)]);
set(red_rect, 'Position', [6, 6, 1, 1]);
set(rect, 'Position', [0, 12, 1, 1]);
set(blue_rect, 'Position', [12, 0, 1, 1]);
x = 1;
case 'No'
annotation('textbox', 'String', 'Thank you for playing!', 'BackgroundColor',...
'w', 'EdgeColor', 'black', 'Position', [0.468 0.5 0.1 0.1],...
'HorizontalAlignment', 'center', 'LineWidth', 1.5);
delete(red_rect);
delete(rect);
delete(blue_rect);
x = 0;
return
end
elseif collision_count1 == 5
answer = questdlg('Player 2 Wins! Would you like to play again?', ...
'Choices', 'Yes','No','Yes');
% Handle response
switch answer
case 'Yes'
collision_count = 0;
collision_count1 = 0;
set(text_obj1, 'String', ['Player 2 Score: ', num2str(collision_count1)]);
set(red_rect, 'Position', [6, 6, 1, 1]);
set(rect, 'Position', [0, 12, 1, 1]);
set(blue_rect, 'Position', [12, 0, 1, 1]);
x = 1;
case 'No'
annotation('textbox', 'String', 'Thank you for playing!', 'BackgroundColor',...
'w', 'EdgeColor', 'black', 'Position', [0.468 0.5 0.1 0.1],...
'HorizontalAlignment', 'center', 'LineWidth', 1.5);
delete(red_rect);
delete(rect);
delete(blue_rect);
x = 0;
return
end
end
end

Risposta accettata

Chris
Chris il 30 Gen 2023
Modificato: Chris il 30 Gen 2023
You could introduce a "grow" bit for each snake. Set it to false initially.
grow = false;
If a snake collides with an apple, set it to true.
Whenever a move occurs, check that bit. If it's true, add a new rectangle element to the snake and reset the bit before moving:
rect(end+1) = rect(end);
grow = false;
Finally, increment the position of the other rectangles. The tail segment stays put for this move, but gets updated in subsequent moves.
Next, you'll need to remember where the snake turns and increment the positions differently after they reach that square.
This program is getting large enough that it might be helpful to break it out into numerous small functions that could exist in their own file (or after the end of the program) and are easy to comprehend--like, as an extreme example, a "move_rect(rect,x,y)" to change the position of a single rectangle. Then you could call that function repeatedly to update each rectangle in a snake. Small functions tend to make things easier to debug as you continue building out your code.
function rect = move_rect(rect,x,y)
rect.Position(1:2) = rect.Position(1:2) + [x, y];
end
If you have lots of time, this could also be a perfect opportunity to learn some object-oriented programming. You could create a "snake" class, with properties like an Mx2 "Position" array, with an x and y value for each of the M segments, and a "Turns" array containing each of the snake's current turning positions. Then you would need a move() method, a grow() method, checkCollision(), etc. blue_snake and black_snake would each be objects, or instances, of the snake class.
  1 Commento
Kyle Hendrix
Kyle Hendrix il 30 Gen 2023
Thank you for the helpful advice, I was able to get the snake moving around the map now. When I have a chance I will research some object-oriented programming to improve my game. Thank you again for the help!

Accedi per commentare.

Più risposte (0)

Categorie

Scopri di più su Strategy & Logic in Help Center e File Exchange

Tag

Prodotti


Release

R2021a

Community Treasure Hunt

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

Start Hunting!

Translated by