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 ...
随机推荐
- Markdown速查手册
之前一直使用简书做笔记,沉浸式的写作环境很棒.然而不知什么时候起,氛围愈发浮躁,软文鸡汤泛滥,离"简"字越来越远. 相比更加喜欢沉稳低调.内涵取胜的博客园.于是乎搬家! 搬家就要丢 ...
- es6的一些个人总结
es6的一些知识点 前言:es6(ECMAscript2015)标准 let.const.var的一些区别 let.const 块级作用域.全局作用域.函数作用域 var 全局作用域.函数作用域 变量 ...
- 将 MacOS 默认的 PHP 版本升级到 7.*
上接:在macOS Sierra 10.12搭建PHP开发环境 设置 brew brew tap homebrew/dupes brew tap homebrew/versions brew tap ...
- mysql数据库左联的使用(一张数据库表关联到另外一张数据库表)
左联的数据库表,然后显示的在页面显示的jsp里面改一下代理种类ID的name,这样在页面上显示的不是id了,而是变成你修改了以后相对于的name了
- PHP面向对象 ——多态
接口 接口(interface)是抽象方法和静态常量定义的集合. 接口是一种特殊的抽象类,这种抽象类中只包含抽象方法和静态常量. 接口中没有其它类型的内容 接口的定义 /** * 接口可以认为是特殊的 ...
- 分享网上搜到的Oracle中对判定条件where 1=1的正解
今天在网上找到了Oracle中对判定条件where 1=1的正解,粘贴出来和大家分享下 1=1 是永恒成立的,意思无条件的,也就是说在SQL语句里有没有这个1=1都可以. 这个1=1常用于应用程序根据 ...
- TCP服务通讯
一.TCP 1.TCP又叫做套接字,传输安全,速度慢. TCP和UTP是网络的传输协议,跟java没什么关系,没有说用java做的客户端必须连接java做的服务器,我们可以用c和c++做客户端,直接连 ...
- 基于Spring4的定时任务管理
在项目中,有时会遇到定时任务的处理,下面介绍一下我的做法. 此做法基于Spring4,Spring框架搭建成功,另需引入quartz.jar,pom.xml文件中加入 <dependency&g ...
- MSDTC启用——分布式事务
一.前言 最近在做一个项目的时候使用了.NET中的System.Transactions(分布式事务),当项目开发完成以后,调用的时候遇到了MSDTC的问题,在查阅了相关资料后将这个问题解决了,大致的 ...
- (转)@ContextConfiguration注解说明
场景:学习spring实战中相关的单元测试 1 正常使用 @ContextConfiguration Spring整合JUnit4测试时,使用注解引入多个配置文件 1.1 单个文件 @ContextC ...