昨天写了一个js版贪吃蛇,今天突然想写一个OC版的,来对比一下两种语言的区别

oc版功能,适配所有尺寸iphone,可暂停,可设置地图和蛇的比例,可加速

对比一下会发现js版的相对OC版的会简单一些,有想看js版的可以看我上一篇随笔

程序中没用到任何素材,效果图如下:

github源码地址:https://github.com/masterChunlinHan/snake_OC

下面开始,跟js版一样,为了方便学习,所有代码都写在一个controller中,所以头文件中什么也不用写

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end

1,首先看需要定义的宏,和需要的全局变量,各个变量的含义都已经写在注释中

#import "ViewController.h"
#define SCREENWIDTH [UIScreen mainScreen].bounds.size.width//屏幕的高度
#define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height//屏幕宽度
#define LINECOUNT 30 //地图上可显示的行数,这里规定地图是正方形,所以只需要一个数
#define BOXWIDTH SCREENHEIGHT/LINECOUNT //每格的宽度,既是食物的宽度也是每节蛇身的宽度 @interface ViewController ()
@property(nonatomic,strong)UIView *map;//地图只有一个,定义成全局的
@property(nonatomic,strong)UIView *food;//食物也只有一个
@property(nonatomic,assign)NSInteger foodx;//食物的x坐标,以格子的宽度为单位
@property(nonatomic,assign)NSInteger foody;//食物的y坐标
@property(nonatomic,strong)NSMutableArray *body;//蛇的身体是变化的,所以用一个可变数组来存
@property(nonatomic,strong)NSTimer *timer;//定时器
@property(nonatomic,assign)NSInteger directionCode;//定义一个数字来代表方向0,1,2,3分别代表上下左右
@property(nonatomic,assign)float time;//定时器的时间间隔,默认为0.5秒走一步
@end

2,一些初始化工作

@implementation ViewController
//初始化定时器的间隔
-(float)time{
if(!_time){
_time=0.5;
}
return _time;
}
//viewDidLoad中创建一些不会变的控件,这些控件始终只有一份,不需要创建第二次
- (void)viewDidLoad {
[super viewDidLoad];
//创建地图
[self createMap];
//添加重置按钮,默认进入程序不会立刻开始游戏,需要点击这个按钮才开始
[self createReloadButton];
//添加开始暂停按钮
[self createControlButtons];
//添加方向键
[self createDirectionButtons]; }

3,创建地图

-(void)createMap{
//先判断地图是否已经存在,如果存在就不再创建
if(!self.map){
self.map = [[UIView alloc]initWithFrame:CGRectMake(,, SCREENHEIGHT, SCREENHEIGHT)];
[self.view addSubview:self.map];
UIColor *lightColor = [UIColor colorWithRed:/255.0 green:/255.0 blue:/255.0 alpha:];
self.map.backgroundColor =lightColor;
self.map.center = self.view.center;
} }

4,创建食物

//创建食物,每次刷新时都会调用这个方法
-(void)createFood{
//先判断食物是否已经存在,如果存在就不再创建
if(!self.food){
self.food = [[UIView alloc]initWithFrame:CGRectMake(,, BOXWIDTH, BOXWIDTH)];
UIColor *foodColor = [UIColor redColor];
self.food.backgroundColor = foodColor;
[self.map addSubview:self.food];
}
//每次刷新食物的坐标都是一个随机值
self.foodx = arc4random()%LINECOUNT;
self.foody = arc4random()%LINECOUNT;
self.food.frame = CGRectMake(self.foodx*BOXWIDTH, self.foody*BOXWIDTH, BOXWIDTH, BOXWIDTH); }

5,创建蛇

//创建蛇,每次刷新时先让蛇的身体坐标发生改变,再调用这个方法,让蛇重新显示
-(void)createSnake{
//先判断食物是否已经存在,如果存在就不再创建
if(!self.body){
//初始化蛇前进的方向为向右
self.directionCode = ;
//初始化蛇的身体,开始时只有一个头,两节身体,头为红色,身体为蓝色
self.body = [NSMutableArray arrayWithArray:@[
@{@"bodyx":@"",@"bodyy":@"",@"color":[UIColor redColor]},
@{@"bodyx":@"",@"bodyy":@"",@"color":[UIColor blueColor]},
@{@"bodyx":@"",@"bodyy":@"",@"color":[UIColor blueColor]}
]];
}
for (int i=; i<self.body.count; i++) {
NSMutableDictionary *mDic = [NSMutableDictionary dictionaryWithDictionary:self.body[i]];
UIView *body = mDic[@"body"];
if(!body){
body = [[UIView alloc]initWithFrame:CGRectMake(, , BOXWIDTH, BOXWIDTH)];
[self.map addSubview:body];
[mDic setObject:body forKey:@"body"];
} float bodyx =BOXWIDTH*[mDic[@"bodyx"] intValue];
float bodyy =BOXWIDTH*[mDic[@"bodyy"] intValue];
body.frame = CGRectMake(bodyx, bodyy, BOXWIDTH, BOXWIDTH);
body.backgroundColor = mDic[@"color"];
self.body[i] = mDic;
}
}

6,蛇移动的方法

//蛇移动,每次刷新时会在这个方法里改变蛇的坐标,并计算与食物的碰撞和自身的碰撞
-(void)snakeMove{ //设置蛇身
for(NSInteger i=self.body.count-;i>;i--){
NSMutableDictionary *mDic = [NSMutableDictionary dictionaryWithDictionary:self.body[i]];
NSString *bodyx = self.body[i-][@"bodyx"];
NSString *bodyy = self.body[i-][@"bodyy"];
[mDic setObject:bodyx forKey:@"bodyx"];
[mDic setObject:bodyy forKey:@"bodyy"];
self.body[i] = mDic;
}
//设置蛇头
NSMutableDictionary *mDic = [NSMutableDictionary dictionaryWithDictionary:self.body[]];
NSString *headx=mDic[@"bodyx"] ;
NSString *heady=mDic[@"bodyy"];
if(self.directionCode==){//上
heady = [NSString stringWithFormat:@"%d",[heady intValue]-];
}else if (self.directionCode==){//下
heady = [NSString stringWithFormat:@"%d",[heady intValue]+];
}else if (self.directionCode==){//左
headx = [NSString stringWithFormat:@"%d",[headx intValue]-];
}else if (self.directionCode==){//右
headx = [NSString stringWithFormat:@"%d",[headx intValue]+];
}
[mDic setObject:headx forKey:@"bodyx"];
[mDic setObject:heady forKey:@"bodyy"];
self.body[] = mDic;
//判断是否吃到食物
if([headx integerValue]==self.foodx&&[heady integerValue]==self.foody){
[self.body addObject:@{@"bodyx":@"-1",@"bodyy":@"",@"color":[UIColor blueColor]}];
if(self.time>0.25){
self.time-=0.05;
[self start];
// [self createTimer];
} [self createFood];
}
//判断是否撞到边界
if([headx integerValue]<||[headx integerValue]>LINECOUNT-||[heady intValue]<||[heady intValue]>LINECOUNT-){
// [self reload];
[self stop];
[self gameOver]; return; }
//判断是否撞到自己 [self createSnake];
}

7,创建计时器,因为创建计时器的工作和暂停之后继续游戏的方法功能一样,所以直接调用继续游戏的方法

//创建定时器
-(void)createTimer{
[self start];
}

继续游戏

//继续,这里创建定时器之前先销毁旧的计时器可以保证始终只有一个计时器在工作
-(void)start{
//如果不先销毁定时器,不断点击继续按钮会创建很多个定时器,会出现蛇跑很快的bug,
[self.timer invalidate];
self.timer = [NSTimer timerWithTimeInterval:self.time repeats:YES block:^(NSTimer * _Nonnull timer) {
[self snakeMove];
}];
[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSDefaultRunLoopMode];
}

8,暂停游戏,只要将计时器销毁就行了

//暂停
-(void)stop{
[self.timer invalidate]; }

9,设置重置按钮方法,每一次执行(包括第一次)都会清空地图再创建蛇、食物、并重置计时器,所以第一次点击相当于开始游戏

//reload方法,执行之后一切重置,移除地图上的所有东西,并重新创建
-(void)reload{
self.body = nil;
for(UIView *subview in self.map.subviews){
if(subview!=self.food){
[subview removeFromSuperview];
}
}
[self createFood];
[self createSnake];
[self createTimer];
}
//创建重置按钮
-(void)createReloadButton{
UIButton *reloadBtn = [[UIButton alloc]initWithFrame:CGRectMake(, , (SCREENWIDTH-SCREENHEIGHT)/, SCREENHEIGHT/)];
[self.view addSubview:reloadBtn];
[reloadBtn setTitle:@"重置/开始" forState:UIControlStateNormal];
reloadBtn.backgroundColor = [UIColor orangeColor];
[reloadBtn addTarget:self action:@selector(reload) forControlEvents:UIControlEventTouchUpInside];
}

10,创建各种按键,在地图创建好之后就可以调用,因为有些按钮要相对于地图的位置来放置

//下面是创建各种按钮,就不多说了
//上下左右按键
-(void)createDirectionButtons{
// float btnW = (SCREENWIDTH-SCREENHEIGHT)/2;
//左边的方向键view
UIView *leftDirectionView = [[UIView alloc]initWithFrame:CGRectMake(, SCREENHEIGHT/, (SCREENWIDTH-SCREENHEIGHT)/, *SCREENHEIGHT/)];
[self.view addSubview:leftDirectionView];
//右边的方向键view
UIView *rightDirectionView = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMaxX(self.map.frame), SCREENHEIGHT/, (SCREENWIDTH-SCREENHEIGHT)/, *SCREENHEIGHT/)];
[self.view addSubview:rightDirectionView]; float btnH = *SCREENHEIGHT/;
for (int i=; i<; i++) {
NSString *title;
float x;
float y;
float w;
UIColor *backColor;
switch (i) {
case :
x = ;
y = ;
w = (SCREENWIDTH-SCREENHEIGHT)/;
title = @"上";
backColor = [UIColor redColor];
break;
case :
x = ;
y = *btnH;
w = (SCREENWIDTH-SCREENHEIGHT)/;
title = @"下";
backColor = [UIColor greenColor];
break;
case :
x = ;
y = btnH;
w = (SCREENWIDTH-SCREENHEIGHT)/;
title = @"左";
backColor = [UIColor grayColor];
break;
default:
x= (SCREENWIDTH-SCREENHEIGHT)/;
y=btnH;
w = (SCREENWIDTH-SCREENHEIGHT)/;
title=@"右";
backColor = [UIColor orangeColor];
break;
}
//左边的按钮
UIButton*btnLeft = [[UIButton alloc]initWithFrame:CGRectMake(x, y, w, btnH)];
btnLeft.tag = i;
[btnLeft setBackgroundColor:backColor];
[btnLeft setTitle:title forState:UIControlStateNormal];
[btnLeft addTarget:self action:@selector(directionChanged:) forControlEvents:UIControlEventTouchUpInside];
//右边的按钮
UIButton*btnRight = [[UIButton alloc]initWithFrame:CGRectMake(x, y, w, btnH)];
btnRight.tag = i;
[btnRight setBackgroundColor:backColor];
[btnRight setTitle:title forState:UIControlStateNormal];
[btnRight addTarget:self action:@selector(directionChanged:) forControlEvents:UIControlEventTouchUpInside]; [leftDirectionView addSubview:btnLeft];
[rightDirectionView addSubview:btnRight];
// [self.view addSubview:btn];
}
}
//点击方向按钮后让代表方向的全局变量改变,这样在蛇移动的方法中才能获取到
-(void)directionChanged:(UIButton*)btn{
self.directionCode = btn.tag;
// NSLog(@"%zd",btn.tag);
}
@end

OC版贪吃蛇的更多相关文章

  1. TOJ 3973 Maze Again && TOJ 3128 简单版贪吃蛇

    TOJ3973传送门:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3973 时间限制(普通 ...

  2. 如何用python制作贪吃蛇以及AI版贪吃蛇

    用python制作普通贪吃蛇 哈喽,大家不知道是上午好还是中午好还是下午好还是晚上好! 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很 ...

  3. js版贪吃蛇

    之前没有写博客的习惯,这是我的第一个博客,有些的不好的地方,希望大家多多提意见 js版的贪吃蛇相对比较简单,废话不多说直接上代码,有需要注意的地方我会标红,github源码地址https://gith ...

  4. JavaScript 实现简易版贪吃蛇(Day_13)

    时光永远在变迁,你始终要丢下过去. 使用语言 JavaScript  概述 运用JavaScript  实现简易版<贪吃蛇>.     Html 页面 1 <!DOCTYPE htm ...

  5. Javascript基础示例:用JS写简易版贪吃蛇(面向对象)

    废话不多说,代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> & ...

  6. JavaScript版—贪吃蛇小组件

    最近在学习JavaScript,利用2周的时间看完了<JavaScript高级编程>,了解了Js是一门面向原型编程的语言,没有像C#语言中的class,也没有私有.公有.保护等访问限制的级 ...

  7. Winfrom 极简版贪吃蛇源码

    该源码是我在百度知识库借助前辈的的经验,加上自己的一点小改动写的一个非常简陋的贪吃蛇小程序.如果你们有更好的改动方案,欢迎评论. 进入主题吧! 1.创建一个桌面应运程序,拖一个定时器控件.这样,程序界 ...

  8. 用GUI实现java版贪吃蛇小游戏

    项目结构 新建一个JFrame窗口,作为程序入口 public class GameStart{ public static void main(String[] args) { JFrame jFr ...

  9. c语言版贪吃蛇小游戏

    编译环境:windows 7 64位 编译工具:codeblocks 13.12 备注:未使用graphics.h 声明:个人原创,未经允许,禁止转载!!! 数据结构:双向链表 1.程序未使用grap ...

随机推荐

  1. SharePoint 2013 安装

    步骤 1:打开提升的 SharePoint 2013 命令行管理程序 选择与您的服务器操作系统对应的过程. 在 Windows Server 2008 R2 中 单击“开始”>“所有程序”> ...

  2. jsp登陆页面验证码在火狐浏览器不能刷新问题处理方案

    jsp登陆页面在火狐浏览器验证码不能刷新问题处理方案: <img src="YzmServlet" onClick="this.src='YzmServlet?ti ...

  3. python编程快速上手之第8章实践项目参考答案

    第8章实践项目之疯狂填词 创建一个一个疯狂填词(Mad Libs),程序,它将读入文本文件,并让用户在该文本文件中出现 ADJECTIVE,NOUN,VERB等单词的地方,加上他们自己的文本. 首先准 ...

  4. 阿里云服务器 Windows连接不成功 提示“你的凭证不工作” 解决方法

    HKEY_LOCAL_MACHINE -> SYSTEM -> CurrentControlSet -> Control ->Terminal Server -> Wds ...

  5. C# Using的用法

    C#里面Using有两种用法: 1.作为指令. using+命名空间,导入其他命名空间中定义的类型,这样可以在程序中直接用命名空间中的类型,不必指定命名空间: 命名空间是.NET程序在逻辑上的组织结构 ...

  6. poj 1161 Walls

    https://vjudge.net/problem/POJ-1161 题意:有m个区域,n个小镇,有c个人在这些小镇中,他们要去某一个区域中聚会,从一个区域到另一个区域需要穿墙,问这些人聚到一起最少 ...

  7. .net ElasticSearch-Sql 扩展类

    官方提供的是java sdk,并支持jdbc方式的查询结果输出;但是却没有.net sdk的支持. 开发 ElasticSearch-Sql 第三方开源项目的.net sdk,未来集成入bsf框架.( ...

  8. 使用Nginx+CppCMS构建高效Web应用服务器(之三)

    使用Nginx+CppCMS构建高效Web应用服务器(之三) --充分利用服务器和客户端计算能力 欢迎测试,攻击:http://www.litelottery.com     网页右上角,选择博彩,演 ...

  9. Python项目实战:福布斯系列之数据采集

    1 数据采集概述 开始一个数据分析项目,首先需要做的就是get到原始数据,获得原始数据的方法有多种途径.比如: 获取数据集(dataset)文件 使用爬虫采集数据 直接获得excel.csv及其他数据 ...

  10. InnoDB关键特性之change buffer

    一.关于IOT:索引组织表 表在存储的时候按照主键排序进行存储,同时在主键上建立一棵树,这样就形成了一个索引组织表,一个表的存储方式以索引的方式来组织存储的. 所以,MySQL表一定要加上主键,通过主 ...