IOS 实现植物大战僵尸



一。实现界面上的图像;

1.这是界面的布局成为这个熊样。

2.将4个相同类型的植物槽中的植物关联到同一个事件中。

@property (strong, nonatomic) IBOutletCollection(UIImageView) NSArray *plantIVs;

3.将下面的45个草坪中的坑 添加uiview,然后关联到一个相同功能的数组中。

@property (strong, nonatomic) IBOutletCollection(UIView) NSArray *boxes;

4.背景出现什么就拖出什么 ,拖出阳光的图片  阳光图片的下面托出一个lable用于显示数据。

 

二。拖拽植物槽里点植物:

1。以下代码是用来实现 植物槽里点植物多,从一张图片中截取出你要的图片显示在植物槽里;

-(void)initUI{

   

    UIImage *plantsImage = [UIImageimageNamed:@"seedpackets.png"];

    float w = plantsImage.size.width/18;

    float h = plantsImage.size.height;

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

        UIImageView *plantIV =self.plantIVs[i];

        float x = 0;

        switch (i) {

            case1://豌豆射手

                x= 2*w;

                break;

               

            case2://寒冰射手

                x= 3*w;

                break;

            case3://坚果

                x= 5*w;

                break;

       }

       

        CGImageRef subImage = CGImageCreateWithImageInRect(plantsImage.CGImage, CGRectMake(x, 0, w, h));

       

        plantIV.image = [UIImageimageWithCGImage:subImage];

        CGImageRelease(subImage);

 

 

三。 创建一个植物类,用来显示植物了, 植物类应该继承uiimageview;

 

1.因为所有以后要用到多植物都是属于要有动态效果的, 所以在创建好  植物父类的时候就要对其进行一个timer方法: 然后在调用这个方法的时候要创建一个改变图片的方法

- (id)initWithFrame:(CGRect)frame

{

    self = [superinitWithFrame:frame];

    if (self) {

        

        [NSTimerscheduledTimerWithTimeInterval:.1target:selfselector:@selector(changeImage) userInfo:nilrepeats:YES];

        

    }

    returnself;

}

然后在初始化此方法后要对这个方法进行实现。   , 此段代码就是实现图片的所有植物类图片的动态效果。  此方法需要在 viewdidload里面实现。

而且注意对是: 这里面用到了一个count的变量,  所以需要在.h里面进行声明

@property (nonatomic)int count;

@property (nonatomic, strong)UIImage *plantImage;

.h里面的声明代码。  而plantImage 是表示植物槽里点植物 声明的全局属性,其它子类可以继承。

 

-(void)changeImage{

    

 

    float w = self.plantImage.size.width/8;

//    x  0w   1w  2w  3w

    CGImageRef subImage = CGImageCreateWithImageInRect(self.plantImage.CGImage, CGRectMake(self.count++%8*w, 0, w, self.plantImage.size.height));

    

    self.image = [UIImageimageWithCGImage:subImage];

    

    CGImageRelease(subImage);

    

}做完这些后,也无法实现显示动态植物的原因是, 没有在viewcontroller中进行初始化的声明及使用。

 

 

 

四。接下来  需要创建其它的子类用来继承plant植物类,  因为现在声明了一个全局变量叫plantImage

1.声明一个子类叫做sunflower就是向日葵:  继承父类plant,然后在其自己的类当中实现自己要显示的图片。

- (id)initWithFrame:(CGRect)frame

{

    self = [superinitWithFrame:frame];

    if (self) {

        self.plantImage = [UIImageimageNamed:@"plant_0.png"];   此段代码是这个阶段要用的!  此时需要在页面中创建一个花 需要代码进行初始化,

就是self.dragPlant =[[SunFloweralloc]initWithFrame:plantIV.frame];类似于这样的

        //打开用户交互不然自身及内部子控件的事件响应不了

        self.userInteractionEnabled= YES;

        //让超出自身范围的子控件不显示

        self.clipsToBounds = YES;

    }

    returnself;

}

 

接下来此阶段的工作酒时重复以上的工作,创建一个豌豆射手,寒冰射手,坚果类  然后继承父类 的方法:然后在其具体的方法中进行自身图片的显示。

 

五。第五步,接下来这部分应该实现的是具体的每个草坪的坑中, 需要托45个view   然后45个view需要将其设置成透明,alpha里面设置,用控件全选。

此阶段就需要实现鼠标的点击事件了。

-(void)touchesBegan:(NSSet *)toucheswithEvent:(UIEvent *)event{

UITouch *t = [touches anyObject];

    

    CGPoint p = [t locationInView:self.view];

    

    for (UIImageView *plantIV inself.plantIVs) {

        if (CGRectContainsPoint(plantIV.frame, p)) {    //植物槽上的植物和p点(鼠标的点)点位置相同的话,用一个switch来创建点击不同植物槽,在当前的植物槽上创建植物。

            switch (plantIV.tag) {

                case0:

                {

                   self.dragPlant = [[SunFloweralloc]initWithFrame:plantIV.frame];

                 

                }

                   break;

                case1:

                {

                   self.dragPlant = [[Peaalloc]initWithFrame:plantIV.frame];

           

                }

                   break;

                case2:

                {

                   self.dragPlant = [[IcePeaalloc]initWithFrame:plantIV.frame];

                

                }

                   break;

                case3:

                {

                   self.dragPlant = [[Nutalloc]initWithFrame:plantIV.frame];

                }

                   break;

            }

            self.dragPlant.delegate = self;

            [self.viewaddSubview:self.dragPlant];

        }

    }

    

}     此段代码的意思就是  当你点击植物槽里点植物时  在当前点击的植物上复制一个新的植物   每个植物槽的tag不同。

 

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{  鼠标移动的事件情况

    UITouch *t = [touches anyObject];

    CGPoint p = [t locationInView:self.view];

    

    self.dragPlant.center = p;

 

-(void)touchesEnded:(NSSet *)toucheswithEvent:(UIEvent *)event{

    //判断是否拖拽着植物

    if (self.dragPlant) {如果拖动的是植物的话:下面的判断是遍历每个草坪上的槽;

        

        for (UIView *box inself.boxes) {

           if (CGRectContainsPoint(box.frame, self.dragPlant.center)&&box.subviews.count==0) {如果草坪上的frame拖动植物的中心点中心点重叠多话:将植物显示到当前你拖动到的草坪槽的中心点上,    而后面加的box的count的判断是为了避免:   一个草坪槽里出现多个植物。

         

               [box addSubview:self.dragPlant];

                self.dragPlant.center = CGPointMake(box.frame.size.width/2, box.frame.size.height/2);

               //开火儿

                [self.dragPlantbeginFire];

            }

        }

        //判断如果没有扔到任何一个坑里面的话就把植物删除

        if ([self.dragPlant.superviewisEqual:self.view]) {

            [self.dragPlantremoveFromSuperview];

        }

        

        

        self.dragPlant = nil;   //如果没有次方法:会出现  如果拖动一个植物后拖动到草坪槽里,  但是点击松手后,但是你鼠标移动的话也会出现植物跟着移动;

    }

    

}

此时实现以上的方法后    会有一个小bug 因为如果遇到了意外中断的情况  是可以讲图片添加等任意位置的:  所以此时就需要实现一个意外中断的方法:

-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{

    

    if (self.dragPlant) {

        [self.dragPlantremoveFromSuperview];

    }

 

第五步完成了以后, 现在所有植物槽的植物能拖动了,,植物也能正确懂种植在草坪上,  但是现在当情况是,没有阳光,  每一个植物所对应的:如产阳光,发射子弹,等功能没有实现。所以,下一步的功能就是  实现��产出阳光。

 

 

第六步:

解决方案与需求: 因为��产出阳光 是其自身的状态属性, 但是这个 状态属性,基本上大部分的植物都存在,  所以需要声明一个父类的方法, 然后在父类的.h中声明.m中实现, 但是父类的实现的代码里不做任何代码的操作,  而是要通过子类继承重写的方式进行各自的  子类的植物的具体功能的实现,  所以需要重写。

 

在子类的重写方法中  因为是要动态的有规律的添加太阳, 需要调用计时器的方法:      然后selector中加入一个 添加阳光的方法:

 

需要注意的一点是。当你这个��扔到坑里的时候就需要调用开火这个方法,  所以还需要在view didload里面实现:

 

注意:  一般控件都有一个属性是用户交互, 因为当你拖动到草坪上时交互不开的花可能点不了:  原因是因为图片imageview的交互是默认关闭的,而他如果关闭了,所有在他内部的所有子控件也就变成了关闭的:  所以在这里需要写入一个方法;  这个方法是在向日葵自己的.m方法里面写的;自定义的时候。

//打开用户交互 不然自身及内部子控件的事件响应不了

        self.userInteractionEnabled= YES;

        //让超出自身范围的子控件不显示

        self.clipsToBounds = YES;

 

 

-(void)beginFire{

    [NSTimerscheduledTimerWithTimeInterval:8target:selfselector:@selector(addSun) userInfo:nilrepeats:YES];

    

}

-(void)addSun{

    

    UIButton *sunBtn = [[UIButtonalloc]initWithFrame:CGRectMake(10, 25, 25, 25)];//因为阳光是按钮,需要收集,所以是按钮,

    [sunBtn setImage:[UIImageimageNamed:@"sun.png"] forState:UIControlStateNormal];

    [sunBtn addTarget:selfaction:@selector(clicked:) forControlEvents:UIControlEventTouchUpInside];

    

    [selfaddSubview:sunBtn];

    

    //阳光自己消失

    [NSTimerscheduledTimerWithTimeInterval:3target:selfselector:@selector(removeSunAction:) userInfo:sunBtn repeats:NO];

    

    

}

-(void)removeSunAction:(NSTimer *)timer{

    UIButton *sunBtn = timer.userInfo;

    

    [sunBtn removeFromSuperview];

}

-(void)clicked:(UIButton *)sunBtn{阳光按钮自己的点击事件。

    [sunBtn removeFromSuperview];

    

    [self.delegateaddSunCount:25];

 

现在剩余一个小功能就是:没有阳光的计数。  所以要涉及到反向调用

 

 

第七步: 反向调用 给阳光的label添加修改功能。

反向传值流程:1.在B类的.h中声明一个A类型的weak属性delegate

2.在A类中创建完B类的时候给B类型对象的delegate属性赋值 

3.在A类的.h中声明方法供B类调用 如果需要传递回来参数那该方法声明时需要带参数

 

  viewcontroller是A类  ,太阳花是B类

 

1.现在是在sunflower中声明的, 因为方向调用要改Label的值得话 不仅仅是在这个子类当中,其他地方也要用,  所以需要声明在父类当中

2.在A类中 创建完B类的时候 也就是创建太阳花初始化方法的时候   给B类型的对象的delegate赋值。 self.dragPlant.delegate = self;

3.A类的.h中声明方法供B调用,-(void)addSunCount:(int)count;

  然后再.m里面实现以下

-(void)addSunCount:(int)count{

    int oldCount = self.sunCountLabel.text.intValue;

    self.sunCountLabel.text = [NSStringstringWithFormat:@"%d",oldCount+count];

 

剩下的工作就是只需要在点击按钮事件的时候  调用此方法就可以了  ;就是太阳花自己的点击消失的时候要计数;

-(void)clicked:(UIButton *)sunBtn{

    [sunBtn removeFromSuperview];

    

    [self.delegateaddSunCount:25];

 

 

 

做完这些 ,植物的大部分工作都已经做完了,剩下的工作就是添加子弹。

 

第八步.添加子弹 

 

 

发射子弹是每隔一段事件发射, 所以在开火的方法中应该开一个timer pea的.m方法里


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值