IOS 贪吃蛇的简单实现

2025-11-02 05:22:57

1、创择侮恩建一个Single View Application,如下图,该应用将会包含一个应用程序委托类和一个视图控制器类,但程序还需要一个自定义UIView控件类,该控件类负责炼晃绘制贪吃蛇的游戏界面。

IOS 贪吃蛇的简单实现

IOS 贪吃蛇的简单实现

2、添加AudioToolbox.framework框架用于音频的播放,添加步骤如下图:

IOS 贪吃蛇的简单实现

3、下面是自定义的FKSnakeView类的接口代码:

FKSnakeView.h文件内容:

#import <UIKit/UIKit.h>

// 记录地图上的宽和高有多少个格子

#define WIDTH 15

#define HEIGHT 22

// 定义每个格子的大小

#define CELL_SIZE 20

typedef enum {

kDown = 0,

kLeft,

kRight,

kUp

} Orient;

@interface FKSnakeView : UIView <UIAlertViewDelegate>

// 定义蛇的移动方向排裁

@property (nonatomic , assign) Orient orient;

@end

FKSnakeView.m文件内容:

#import <AudioToolbox/AudioToolbox.h>

#import "FKSnakeView.h"

#import "FKPoint.h"

@implementation FKSnakeView

// 记录蛇的点, 最后一个点代表蛇头

NSMutableArray* snakeData;

// 定义食物所在的点

FKPoint* foodPos;

NSTimer* timer;

UIColor* bgColor;

UIImage* cherryImage;

UIAlertView * overAlert;

// 代表游戏音效变量

SystemSoundID gu;

SystemSoundID crash;

@synthesize orient;

- (id)initWithFrame:(CGRect)frame

{

self = [super initWithFrame:frame];

if (self) {

// 加载食物图片

cherryImage = [UIImage imageNamed:@"cherry.png"];

// 加载游戏背景图片,并将背景图片转换为平铺形式的颜色

bgColor = [UIColor colorWithPatternImage:

  [UIImage imageNamed:@"grass.png"]];

// 获取两个音效文件的的URL

NSURL* guUrl = [[NSBundle mainBundle]

URLForResource:@"gu" withExtension:@"mp3"];

NSURL* crashUrl = [[NSBundle mainBundle]

URLForResource:@"crash" withExtension:@"wav"];

// 加载两个音效文件

AudioServicesCreateSystemSoundID((__bridge CFURLRef)guUrl , &gu);

AudioServicesCreateSystemSoundID((__bridge CFURLRef)crashUrl , &crash);

  overAlert = [[UIAlertView alloc] initWithTitle:@"游戏结束"

message:@"您输了,是否重新再来?" delegate:self

cancelButtonTitle:@"不来了" otherButtonTitles:@"再来一盘!", nil];

[self startGame];

}

return self;

}

- (void) startGame

{

// FKPoint 第1个参数控制位于水平第几格,第2个参数控制位于垂直第几格

snakeData = [NSMutableArray arrayWithObjects:

[[FKPoint alloc] initWithX:1 y:0],

[[FKPoint alloc] initWithX:2 y:0],

[[FKPoint alloc] initWithX:3 y:0],

[[FKPoint alloc] initWithX:4 y:0],

[[FKPoint alloc] initWithX:5 y:0],nil];

// 定义蛇的初始移动方向

orient = kRight;

timer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self

selector:@selector(move) userInfo:nil repeats:YES];

}

- (void) move

{

// 除了蛇头受方向控制之外,其他点都是占它的前一个

// 获取最后一个点,作为蛇头

FKPoint* first = [snakeData objectAtIndex: snakeData.count - 1];

FKPoint* head = [[FKPoint alloc] initWithX:first.x y:first.y];

switch(orient)

{

case kDown: // 代表向下

// 新蛇头的位置

head.y = head.y + 1;

break;

case kLeft: // 代表向左

// 新蛇头的位置

head.x = head.x - 1;

break;

case kRight: // 代表向右

// 新蛇头的位置

head.x = head.x + 1;

break;

case kUp: // 3代表上

// 新蛇头的位置

head.y = head.y - 1;

break;

}

// 如果移动后蛇头超出界面或与蛇身碰撞,游戏结束

if(head.x < 0 || head.x > WIDTH - 1

  || head.y < 0 || head.y > HEIGHT - 1

  || [snakeData containsObject:head])

{

// 播放碰撞的音效

AudioServicesPlaySystemSound(crash);

[overAlert show];

[timer invalidate];

};

// 表明蛇头与食物点重合

if([head isEqual:foodPos])

{

// 播放吃食物的音效

AudioServicesPlaySystemSound(gu);

// 将食物点添加成新的蛇头

[snakeData addObject:foodPos];

// 食物清空

foodPos = nil;

}

else

{

// 从第一个点开始,控制蛇身向前

for (int i = 0 ; i < snakeData.count - 1; i++)

{

// 将第i个点的坐标设置为第i+1个点的的坐标

FKPoint* curPt = [snakeData objectAtIndex:i];

FKPoint* nextPt = [snakeData objectAtIndex:i + 1];

curPt.x = nextPt.x;

curPt.y = nextPt.y;

}

// 重新设置蛇头坐标

[snakeData setObject:head atIndexedSubscript:(snakeData.count - 1)];

}

if(foodPos == nil)

{

while(true)

{

FKPoint* newFoodPos = [[FKPoint alloc]

initWithX:arc4random() % WIDTH

y:arc4random() % HEIGHT];

// 如果新产生的食物点,没有位于蛇身体上

if(![snakeData containsObject:newFoodPos])

{

foodPos = newFoodPos;

break; // 成功生成了食物的位置,跳出循环

}

}

}

[self setNeedsDisplay];

}

// 定义绘制蛇头的方法

- (void) drawHeadInRect:(CGRect)rect context:(CGContextRef)ctx

{

CGContextBeginPath(ctx);

// 根据蛇头的方向,决定开口的角度

CGFloat startAngle;

switch (orient) {

case kUp:

startAngle = M_PI * 7 / 4;

break;

case kDown:

startAngle = M_PI * 3 / 4;

break;

case kLeft:

startAngle = M_PI * 5 / 4;

break;

case kRight:

startAngle = M_PI * 1 / 4;

break;

default:

break;

}

// 添加一段弧作为路径

CGContextAddArc(ctx, CGRectGetMidX(rect), CGRectGetMidY(rect)

, CELL_SIZE / 2, startAngle, M_PI * 1.5 + startAngle, 0);

// 将绘制点移动到中心

CGContextAddLineToPoint(ctx, CGRectGetMidX(rect), CGRectGetMidY(rect));

// 关闭路径

CGContextClosePath(ctx);

CGContextFillPath(ctx);

}

- (void)drawRect:(CGRect)rect

{

// 获取绘图API

CGContextRef ctx = UIGraphicsGetCurrentContext();

CGContextClearRect(ctx, CGRectMake(0 , 0

, WIDTH * CELL_SIZE , HEIGHT * CELL_SIZE));

CGContextSetFillColorWithColor(ctx, [bgColor CGColor]);

// 绘制背景,

CGContextFillRect(ctx, CGRectMake(0 , 0

, WIDTH * CELL_SIZE , HEIGHT * CELL_SIZE));

// 绘制文字

[@"疯狂贪食蛇" drawAtPoint:CGPointMake(50 ,20)

withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:

[UIFont fontWithName:@"Heiti SC" size: 40] , NSFontAttributeName,

[UIColor colorWithRed:1 green:0 blue:1 alpha:.4],

NSForegroundColorAttributeName,  nil]];

[@"www.fkjava.org" drawAtPoint:CGPointMake(50 ,60)

withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:

[UIFont fontWithName:@"Heiti SC" size: 26] , NSFontAttributeName,

[UIColor colorWithRed:1 green:0 blue:1 alpha:.4],

NSForegroundColorAttributeName, nil]];

// 设置绘制蛇的填充颜色

CGContextSetRGBFillColor(ctx, 1, 1, 0, 1);

// 遍历蛇的数据,绘制蛇的数据

for (int i = 0 ; i < snakeData.count ; i++ )

{

// 为每个蛇的点(记录的是在数组的位置),在屏幕上绘制一个圆点

FKPoint* cp = [snakeData objectAtIndex:i];

// 定义将要绘制蛇身点的矩形

CGRect rect = CGRectMake(cp.x * CELL_SIZE , cp.y * CELL_SIZE

, CELL_SIZE , CELL_SIZE);

// 绘制蛇尾巴,让蛇的尾巴小一些

if(i < 4)

{

CGFloat inset =  (4 - i);

CGContextFillEllipseInRect(ctx,CGRectInset(rect, inset, inset));

}

// 如果是最后一个元素,代表蛇头,绘制蛇头

else if (i == snakeData.count - 1)

{

[self drawHeadInRect:rect context:ctx];

}

else

{

CGContextFillEllipseInRect(ctx, rect);

}

}

// 绘制“食物”图片

[cherryImage drawAtPoint:CGPointMake(foodPos.x * CELL_SIZE

, foodPos.y * CELL_SIZE)];

}

-(void)alertView:(UIAlertView *)alertView

clickedButtonAtIndex:(NSInteger)buttonIndex

{

// 如果用户点击了第二个按钮,重新开始游戏

if(buttonIndex == 1)

[self startGame];

}

@end

4、FKPoint类,该类用于封装X、Y两个属性,并重写了isEqual:方法,用于提供自定义判断两个点相等的标准。

FKPoint.h文件内容:

#import <Foundation/Foundation.h>

@interface FKPoint : NSObject

@property (nonatomic, assign) NSInteger x;

@property (nonatomic, assign) NSInteger y;

- (id)initWithX:(NSInteger)x y:(NSInteger)y;

- (BOOL) isEqual:(FKPoint*)other;

@end

FKPoint.m文件内容:

#import "FKPoint.h"

@implementation FKPoint

- (id)initWithX:(NSInteger)x y:(NSInteger)y

{

    self = [super init];

    if (self) {

        _x = x;

_y = y;

    }

    return self;

}

- (BOOL) isEqual:(FKPoint*)other

{

if(self == other)

{

return YES;

}

if (FKPoint.class == [other class])

{

return self.x == other.x

&& self.y == other.y;

}

return NO;

}

- (NSString*)description

{

return [NSString stringWithFormat:@"{%d,%d}" , self.x,self.y];

}

@end

5、FKViewController.m文件内容:

#import <QuartzCore/QuartzCore.h>

#import "FKViewController.h"

#import "FKSnakeView.h"

@implementation FKViewController

FKSnakeView* snakeView;

- (void)viewDidLoad

{

    [super viewDidLoad];

// 创建FKSnakeView控件

snakeView = [[FKSnakeView alloc] initWithFrame:

CGRectMake(10, 30, WIDTH*CELL_SIZE , HEIGHT * CELL_SIZE)];

// 为snakeView控件设置边框和圆角。

snakeView.layer.borderWidth = 3;

snakeView.layer.borderColor = [[UIColor redColor] CGColor];

snakeView.layer.cornerRadius = 6;

snakeView.layer.masksToBounds = YES;

// 设置self.view控件支持用户交互

self.view.userInteractionEnabled = YES;

// 设置self.view控件支持多点触碰

self.view.multipleTouchEnabled = YES;

for (int i = 0 ; i < 4 ; i++)

{

// 创建手势处理器,指定使用该控制器的handleSwipe:方法处理轻扫手势

UISwipeGestureRecognizer* gesture = [[UISwipeGestureRecognizer alloc]

initWithTarget:self action:@selector(handleSwipe:)];

// 设置该点击手势处理器只处理i个手指的轻扫手势

gesture.numberOfTouchesRequired = 1;

// 指定该手势处理器只处理1 << i方向的轻扫手势

gesture.direction = 1 << i;

// 为self.view控件添加手势处理器。

[self.view addGestureRecognizer:gesture];

}

[self.view addSubview:snakeView];

}

// 实现手势处理器的方法,该方法应该声明一个形参。

// 当该方法被激发时,手势处理器会作为参数传给该方法的参数。

- (void) handleSwipe:(UISwipeGestureRecognizer*)gesture

{

// 获取轻扫手势的方向

NSUInteger direction = gesture.direction;

switch (direction)

{

case UISwipeGestureRecognizerDirectionLeft:

if(snakeView.orient != kRight) // 只要不是向右,即可改变方向

snakeView.orient = kLeft;

break;

case UISwipeGestureRecognizerDirectionUp:

if(snakeView.orient != kDown) // 只要不是向下,即可改变方向

snakeView.orient = kUp;

break;

case UISwipeGestureRecognizerDirectionDown:

if(snakeView.orient != kUp) // 只要不是向上,即可改变方向

snakeView.orient = kDown;

break;

case UISwipeGestureRecognizerDirectionRight:

if(snakeView.orient != kLeft) // 只要不是向左,即可改变方向

snakeView.orient = kRight;

break;

}

}

@end

6、将上面的文件内容修改之后,点击run运行就可以看到如下界面:进行游戏,游戏结束后可以选择退出或再来一局

IOS 贪吃蛇的简单实现

IOS 贪吃蛇的简单实现

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢