OC版贪吃蛇
昨天写了一个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版贪吃蛇的更多相关文章
- TOJ 3973 Maze Again && TOJ 3128 简单版贪吃蛇
TOJ3973传送门:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3973 时间限制(普通 ...
- 如何用python制作贪吃蛇以及AI版贪吃蛇
用python制作普通贪吃蛇 哈喽,大家不知道是上午好还是中午好还是下午好还是晚上好! 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很 ...
- js版贪吃蛇
之前没有写博客的习惯,这是我的第一个博客,有些的不好的地方,希望大家多多提意见 js版的贪吃蛇相对比较简单,废话不多说直接上代码,有需要注意的地方我会标红,github源码地址https://gith ...
- JavaScript 实现简易版贪吃蛇(Day_13)
时光永远在变迁,你始终要丢下过去. 使用语言 JavaScript 概述 运用JavaScript 实现简易版<贪吃蛇>. Html 页面 1 <!DOCTYPE htm ...
- Javascript基础示例:用JS写简易版贪吃蛇(面向对象)
废话不多说,代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> & ...
- JavaScript版—贪吃蛇小组件
最近在学习JavaScript,利用2周的时间看完了<JavaScript高级编程>,了解了Js是一门面向原型编程的语言,没有像C#语言中的class,也没有私有.公有.保护等访问限制的级 ...
- Winfrom 极简版贪吃蛇源码
该源码是我在百度知识库借助前辈的的经验,加上自己的一点小改动写的一个非常简陋的贪吃蛇小程序.如果你们有更好的改动方案,欢迎评论. 进入主题吧! 1.创建一个桌面应运程序,拖一个定时器控件.这样,程序界 ...
- 用GUI实现java版贪吃蛇小游戏
项目结构 新建一个JFrame窗口,作为程序入口 public class GameStart{ public static void main(String[] args) { JFrame jFr ...
- c语言版贪吃蛇小游戏
编译环境:windows 7 64位 编译工具:codeblocks 13.12 备注:未使用graphics.h 声明:个人原创,未经允许,禁止转载!!! 数据结构:双向链表 1.程序未使用grap ...
随机推荐
- 构建混合应用方式之 - Azure混合连接
前面介绍了通过WCF中继构建混合应用的方式,由于对WCF的依赖,使得其使用有一定的局限性,基本上只适用于本地服务是WCF的.NET应用.而混合连接则弥补了这一块的缺陷,除了支持原有WCF中继的功能之外 ...
- voa 2015 / 4 / 14
Even with falling oil prices and strong U.S. growth, the head of the International Monetary Fund sai ...
- 30分钟学会使用Spring Web Services基础开发
时隔一年终于又推出了一篇30分钟系列,上一篇<30分钟学会反向Ajax>是2016年7月的事情了.时光荏苒,岁月穿梭.虽然一直还在从事Java方面的开发工作,但是私下其实更喜欢使用C++. ...
- shell统计文本中单词的出现次数
Ubuntu14.04 给定一个文本,统计其中单词出现的次数 方法1 # solution 1 grep与awk配合使用,写成一个sh脚本 fre.sh sh fre.sh wordfretest.t ...
- for循环问题
印象中的for语句是这样的,语法: for (语句 1; 语句 2; 语句 3) { 被执行的代码块 } 语句 1 (代码块)开始前执行 starts. 语句 2 定义运行循环(代码块)的条件 语 ...
- Spring NamedParameterJdbcTemplate命名参数查询条件封装, NamedParameterJdbcTemplate查询封装
Spring NamedParameterJdbcTemplate命名参数查询条件封装, NamedParameterJdbcTemplate查询封装 >>>>>> ...
- Spring-Framework 源码阅读之AnnotationBeanUtils
Java程序员,就是要学会一个名字叫做"春"的东西,这玩意运用的非常的广泛,现在如果你的业务系统或者软件没有在这个东西上开发,都不要意思拿出来.因为你更不上时代了.在平时的工作的中 ...
- Hadoop常用命令集合
查看安全模式 bin/hadoop dfsadmin -safemode enter | leave | get | wait
- C#导入导出Excele数据
注:对于实体类对象最好新建一个并且继承原有实体类,这样可以将类型进行修改: 方法一:此种方法是用EPPLUS中的FileInfo流进行读取的(是不是流我还真不太了解,若有懂得请留言,非常感谢了) us ...
- Linux 下安装jetty服务器
jetty和我们通常使用的tomcat一样,是一个开源的servlet容器,特点是轻量易部署,一方面jetty可以作为web容器使用,另一方面也是最一般的方式是jetty以一组jar包的形式发布,所以 ...