1.创建游戏窗口
首先,我们需要创建一个窗口来显示游戏界面,可以使用figure
函数创建一个图形窗口:
figure('Name', 'Snake Game', 'Units', 'normalized', 'OuterPosition', [0.2 0.2 0.6 0.6], ... 'MenuBar', 'none', 'NumberTitle', 'off', 'Resize', 'off');
其中,Name
为窗口标题,Units
为窗口单位(normalized表示窗口大小与屏幕比例一致),OuterPosition
为窗口位置和大小(这里设为占屏幕60%宽和高,位于屏幕中间),MenuBar
为菜单栏(这里不需要,设为none),NumberTitle
为窗口标题是否显示数字(不需要,设为off),Resize
为窗口是否可缩放(不需要,设为off)。
2.初始化游戏数据
接下来,我们需要初始化一些游戏数据,如蛇的初始位置、长度、方向等。为了方便处理,我们可以用一个结构体来存储这些数据:
snake.head = [5,5]; % 蛇头位置
snake.body = [5,4]; % 蛇身位置
snake.tail = [5,3]; % 蛇尾位置
snake.length = 3; % 蛇的长度 s
nake.direction = 'right'; % 蛇的前进方向
这里我们将蛇头位置设为(5,5),蛇身位置设为(5,4),蛇尾位置设为(5,3),蛇的长度设为3,蛇的前进方向设为右侧。
另外,我们还需要初始化食物的位置,以及游戏结束的标志:
food.position = [randi(20), randi(20)]; % 食物位置随机生成
game_over = false; % 游戏结束标志
3.绘制游戏界面
接下来,我们要在窗口中绘制游戏界面,包括蛇和食物,可以使用rectangle
函数绘制矩形:
% 绘制蛇头
snake_head = rectangle('Position', [snake.head-0.5, 1, 1], 'Curvature', [1,1], 'FaceColor', 'r');
% 绘制蛇身
snake_body = rectangle('Position', [snake.body-0.5, 1, 1], 'Curvature', [1,1], 'FaceColor', 'g');
% 绘制蛇尾
snake_tail = rectangle('Position', [snake.tail-0.5, 1, 1], 'Curvature', [1,1], 'FaceColor', 'y');
% 绘制食物
food_item = rectangle('Position', [food.position-0.5, 1, 1], 'Curvature', [1,1], 'FaceColor', 'b');
这里蛇头、蛇身、蛇尾和食物都是一个正方形矩形,其位置和大小都可以通过Position
参数来控制。其中,Curvature
为矩形四个角的曲率,[1,1]表示圆形,即绘制圆形矩形。
4.监听键盘事件
然后,我们需要监听键盘事件,根据用户按键改变蛇的前进方向,可以使用KeyPressFcn
属性来实现:
set(gcf, 'KeyPressFcn', @change_direction);
其中,gcf
表示当前窗口,@change_direction
表示回调函数名(需要定义一个change_direction
函数来接收键盘事件并改变蛇的方向)。
具体实现如下:
function change_direction(~, event)
switch event.Key
case 'uparrow'
if ~strcmp(snake.direction, 'down') snake.direction = 'up';
end
case 'downarrow'
if ~strcmp(snake.direction, 'up') snake.direction = 'down';
end
case 'leftarrow'
if ~strcmp(snake.direction, 'right') snake.direction = 'left';
end
case 'rightarrow'
if ~strcmp(snake.direction, 'left') snake.direction = 'right';
end
end
end
这个函数接收两个参数,第一个参数是不用管的(因为我们不需要使用它),第二个参数是键盘事件,其中event.Key表示按下的键名(如'uparrow'表示上箭头键)。
根据不同的键名,我们可以改变蛇的前进方向。例如,如果按下了'uparrow'键,且当前蛇的方向不是向下,则将蛇的方向改为向上。
5.实现游戏循环
接下来,我们需要实现一个游戏循环,不断更新蛇和食物的位置,并检测游戏结束条件。可以使用while
循环来实现:
while ~game_over
% 移动蛇
move_snake();
% 检测游戏是否结束
game_over = is_game_over();
% 更新窗口显示
update_window();
% 等待一段时间,控制游戏速度
pause(0.1);
end
在循环内部,我们依次调用了三个函数:
move_snake
函数用于根据当前方向移动蛇的位置;is_game_over
函数用于检测游戏是否结束;update_window
函数用于更新窗口中蛇和食物的位置。
其中,pause(0.1)
语句用于等待一段时间,控制游戏速度。
6.实现移动蛇的函数
接下来,我们需要实现move_snake
函数来移动蛇的位置。具体实现如下:
function move_snake()
% 根据当前方向移动蛇头
switch snake.direction
case 'up'
snake.head = snake.head + [-1, 0];
case 'down'
snake.head = snake.head + [1, 0];
case 'left'
snake.head = snake.head + [0, -1];
case 'right'
snake.head = snake.head + [0, 1];
end
% 更新蛇身和蛇尾位置
snake.body = [snake.head; snake.body(1:end-1,:)];
snake.tail = snake.body(end,:);
end
这个函数首先根据当前方向移动蛇头的位置,然后更新蛇身和蛇尾的位置。具体来说,我们将蛇头位置加上一个向量,该向量表示当前方向的移动方向。例如,如果当前方向是向上,则将蛇头的行坐标减1,列坐标不变。
接着,我们将蛇身的第一段替换为新的蛇头位置,将蛇尾设置为蛇身的最后一段位置。
7.实现检测游戏是否结束的函数
接下来,我们需要实现is_game_over
函数来检测游戏是否结束。具体实现如下:
function game_over = is_game_over()
% 检测是否碰到边界
if any(snake.head < 1) || any(snake.head > 20) game_over = true; return;
end
% 检测是否碰到自己的身体
if any(all(bsxfun(@eq, snake.body, snake.head), 2)) game_over = true; return;
end
% 检测是否吃到食物
if all(snake.head == food.position) game_over = false;
% 更新蛇的长度和食物的位置
snake.length = snake.length + 1;
[food.position(1), food.position(2)] = find(flipud(~ismember(ones(20),[snake.head; snake.body]),1));
return;
end game_over = false;
end
这个函数首先检测蛇是否碰到了边界,如果是则游戏结束。如果蛇头的行坐标或列坐标小于1或大于20,则表示撞到了边界。
接着,我们检测蛇是否碰到了自己的身体。使用bsxfun
函数来比较蛇身的每一段是否与蛇头重合。如果有,则表示蛇头碰到了自己的身体,游戏结束。
最后,我们检测是否吃到了食物。如果蛇头的位置与食物位置重合,则表示吃到了食物,游戏继续进行。此时需要更新蛇的长度和食物的位置。蛇的长度加1,食物的位置随机生成(不能在蛇的身体部分)。
8.实现更新窗口显示的函数
接下来,我们需要实现update_window
函数来更新窗口中蛇和食物的位置。具体实现如下:
function update_window()
% 更新蛇头位置
set(snake_head, 'Position', [snake.head-0.5, 1, 1]);
% 更新蛇身位置
set(snake_body, 'Position', [snake.body-0.5, 1, 1]);
% 更新蛇尾位置
set(snake_tail, 'Position', [snake.tail-0.5, 1, 1]);
% 更新食物位置
set(food_item, 'Position', [food.position-0.5, 1, 1]);
% 重绘窗口
drawnow;
end
这个函数首先通过set
函数更新各个矩形的位置。注意,位置需要减去0.5才能正确显示,因为矩形的中心点坐标为整数(如(1,1)),而不是左上角坐标。然后利用drawnow
函数重绘窗口。