iOS MonsterBall(怪物舞会)~demo

//联系人:石虎  QQ: 1224614774昵称:嗡嘛呢叭咪哄

/**

注意点: 1.看 GIF 效果图.

       2.看连线视图的效果图.

       3.看实现代码(直接复制实现效果).

       4.需要真机设备 才有效果 ...

       5.关于  "gate" "ball1" "monster_move_1" "grass"  分别是加载的图片

*/

一、GIF 效果图:


二、连线视图的效果图:

图1:


图2:


图3:


图4:




三、实现代码:

=========================

===================================================

==========================

控制器1: SHBallView.h

//

//  SHBallView.h

//  MonsterBall(怪物舞会)~demo

//

//  Created by 石虎 on 2017/8/14.

//  Copyright © 2017 shihu. All rights reserved.

//


#import <UIKit/UIKit.h>

#import <CoreMotion/CoreMotion.h>


@interface SHBallView : UIView


// 定义属性来记录足球的当前位置

@property (nonatomic ,assign) CGPoint currentPoint;

@property (nonatomic ,assign) CMAcceleration acceleration;

// 定义属性来记录足球滚动的XY轴方向的速度

@property (nonatomic ,assign) CGFloat xVelocity;

@property (nonatomic ,assign) CGFloat yVelocity;

- (void)update;

@end




控制器1: SHBallView.m

//

//  SHBallView.m

//  MonsterBall(怪物舞会)~demo

//

//  Created by 石虎 on 2017/8/14.

//  Copyright © 2017 shihu. All rights reserved.

//


#import "SHBallView.h"



#define BALL_SIZE 24

// 定义怪物的数量

#define MONSTER_NUM 3

// 定义球门的起始位置

#define GATE_ORIGIN_X 85

// 定义球门的宽度

#define GATE_WIDTH 150


@interface SHBallView () <UIAlertViewDelegate>

{

    NSArray* ballImages;

    NSArray* monsterImages;

    UIImage* gateImage;

    // 定义变量记录足球动画帧的索引

    NSInteger ballIndex , count;

    // 定义变量记录每个怪物当前显示的动画帧的索引

    NSInteger monsterImageIndexs[MONSTER_NUM];

    // 定义数组来记录每个怪物的位置

    CGPoint monsterPoints[MONSTER_NUM];

    NSTimer* timer;

    BOOL isPlaying; // 定义变量记录游戏的状态

}

@end


@implementation SHBallView


- (id)initWithCoder:(NSCoder *)aDecoder

{

    self = [superinitWithCoder:aDecoder];

    if (self) {

        // 加载球门图片

        gateImage = [UIImageimageNamed:@"gate"];

        // 加载足球滚动的每一帧的图片

        ballImages = [NSArrayarrayWithObjects:

                      [UIImageimageNamed:@"ball1"],

                      [UIImageimageNamed:@"ball2"],

                      [UIImageimageNamed:@"ball3"],

                      [UIImageimageNamed:@"ball4"],

                      [UIImageimageNamed:@"ball5"],

                      [UIImageimageNamed:@"ball6"],

                      [UIImageimageNamed:@"ball7"],

                      [UIImageimageNamed:@"ball8"],nil];

        // 加载怪物走动的每一帧的图片

        monsterImages = [NSArrayarrayWithObjects:

                         [UIImageimageNamed:@"monster_move_1"],

                         [UIImageimageNamed:@"monster_move_2"],

                         [UIImageimageNamed:@"monster_move_3"],

                         [UIImageimageNamed:@"monster_move_4"],nil];

        monsterImageIndexs[1] =1;

        monsterImageIndexs[2] =2;

        [selfstartGame];   //开始游戏

    }

    returnself;

}

- (void) moveMonster

{

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

    {

        // 控制怪物动画显示下一帧的图片

        monsterImageIndexs[i] =monsterImageIndexs[i] + 1;

        // 改变第i个怪物的X坐标

        monsterPoints[i].x =monsterPoints[i].x +arc4random() % 9 -4;

    }

    [selfsetNeedsDisplay];

}

- (void)drawRect:(CGRect)rect

{

    // 绘制足球

    [ballImages[ballIndex++ %8] drawAtPoint:self.currentPoint];

    // 绘制球门

    [gateImagedrawAtPoint:CGPointMake(GATE_ORIGIN_X ,64)];

    // 采用循环绘制3个怪物

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

    {

        [monsterImages[monsterImageIndexs[i] %4] drawAtPoint:monsterPoints[i]];

    }

}

// 重写实现currentPoint属性的setter方法

- (void)setCurrentPoint:(CGPoint)newPoint

{

    // 如果正在游戏中,且足球新的位置点与原来的位置点不位于同一个点。

    if(isPlaying && (fabs(_currentPoint.x - newPoint.x) > 1

                     || fabs(_currentPoint.y - newPoint.y) > 1))

    {

        _currentPoint = newPoint;

        // 如果足球当前的X坐标小于0,就足球已经位于最左边

        if (_currentPoint.x <0)

        {

           // 将足球设置在最左边,并将水平速度设为0

            _currentPoint.x =0;

            self.xVelocity =0;

        }

        // 球已经到了底线,且没进球门

        if (_currentPoint.y <75 && (_currentPoint.x <GATE_ORIGIN_X + 2

                                     || _currentPoint.x >GATE_ORIGIN_X  + GATE_WIDTH - 4))

        {

           // 将足球设置在底线上,并将垂直速度设为0

            _currentPoint.y =75;

            self.yVelocity =0;

        }

        // 球进了球门

        if (_currentPoint.y <75 && (_currentPoint.x >=GATE_ORIGIN_X + 2

                                     || _currentPoint.x <=GATE_ORIGIN_X  + GATE_WIDTH - 4))

        {

            // 使用UIAlertView提示用户游戏结束,并询问用户是否要开始下一盘游戏

            [[[UIAlertViewalloc] initWithTitle:@"游戏结束"

                                        message:@"您进球了,再来一盘?"delegate:self

                              cancelButtonTitle:@""otherButtonTitles:nil]show];

            // 取消计时器

            [timerinvalidate];

            isPlaying =NO;

        }

        // 如果足球的X坐标大于该控件的高度,表明足球已经到了屏幕最下方

        if (_currentPoint.x >self.bounds.size.width -BALL_SIZE)

        {

           // 将足球设置到屏幕最下方,并将垂直速度设为0

            _currentPoint.x =self.bounds.size.width -BALL_SIZE;

            self.xVelocity =0;

        }

        // 如果足球的Y坐标大于该控件的宽度,表明足球已经到了屏幕最右边

        if (_currentPoint.y >self.bounds.size.height -BALL_SIZE)

        {

           // 将足球设置到屏幕最右边,并将水平速度设为0

            _currentPoint.y =self.bounds.size.height -BALL_SIZE;

            self.yVelocity =0;

        }

        // 遍历每个怪物,检测怪物与足球是否碰撞

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

        {

           // 如果怪物所在矩形和足球所在矩形有交集,表明二者相撞

            if(CGRectIntersectsRect([selfgetBallRect], [selfgetMonsterRect:i]))

            {

               // 怪物将足球快速向下踢出,也就是足球的Y方向上速度增加0.6

                self.yVelocity =self.yVelocity +0.6;

            }

        }

        [selfsetNeedsDisplay];

    }

}

- (void)update

{

    staticNSDate *lastUpdateTime;

    // 如果初始化过lastUpdateTime变量

    if (lastUpdateTime !=nil)

    {

        // 计算上次到现在的时间差

        NSTimeInterval secondsSinceLastDraw =

        -([lastUpdateTime timeIntervalSinceNow]);

        // 根据加速度数据计算足球在X方向、Y方向的速度

        self.yVelocity =self.yVelocity + -(self.acceleration.y *

                                            secondsSinceLastDraw);

        self.xVelocity =self.xVelocity +self.acceleration.x *

        secondsSinceLastDraw;

        // 根据足球的速度计算足球在单位时间内滚动的距离。

        // 由于实际算出来的滚动距离太小,因此都需要乘以500(实际上可用400600等)

        CGFloat xDelta = secondsSinceLastDraw *self.xVelocity *500;

        CGFloat yDelta = secondsSinceLastDraw *self.yVelocity *500;

        // 设置足球的位置为新计算出来的位置

        self.currentPoint =CGPointMake(self.currentPoint.x + xDelta,

                                        self.currentPoint.y + yDelta);

    }

    lastUpdateTime = [[NSDatealloc] init];

}

// 获取怪物所在的矩形框

- (CGRect) getMonsterRect:(NSInteger) monsterIndex

{

    CGRect rect;

    // 获取索引为monsterIndex的怪物的左上角坐标

    rect.origin =monsterPoints[monsterIndex];

    // 获取图片的大小

    rect.size = ((UIImage*)monsterImages[0]).size;

    return rect;

}

// 获取足球所在的矩形框

- (CGRect) getBallRect

{

    CGRect rect;

    rect.origin =self.currentPoint;

    rect.size = ((UIImage*)ballImages[0]).size;

    return rect;

}

- (void) resetGame

{

    // 依次设置每个怪物的位置

    monsterPoints[0] =CGPointMake(20 ,150);

    monsterPoints[1] =CGPointMake(190 ,150);

    monsterPoints[2] =CGPointMake(80 ,280);

    // 设置足球开始的位置,位于该UIView的中心

    self.currentPoint =CGPointMake((self.bounds.size.width - BALL_SIZE ) / 2.0f,

                                    (self.bounds.size.height - BALL_SIZE) / 2.0f);

    // 设置足球的开始速度

    self.xVelocity =0.0f;

    self.yVelocity =0.0f;

}

// 当用户单击UIAlertView警告框上按钮时激发该方法

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:

(NSInteger)buttonIndex

{

    // 如果用户单击第一个按钮

    if(buttonIndex ==0)

    {

        [selfstartGame];  //重新开始游戏

    }

}

- (void) startGame

{

    // 设置游戏状态:正在游戏

    isPlaying =YES;

    // 重设足球和怪物的位置

    [selfresetGame];

    // 使用定时器控制怪物的动作

    timer = [NSTimerscheduledTimerWithTimeInterval:0.2target:self

                                           selector:@selector(moveMonster)userInfo:nilrepeats:YES];

}

@end



=========================

===================================================

控制器2: ViewController.m


//

//  ViewController.m

//  MonsterBall(怪物舞会)~demo

//

//  Created by 石虎 on 2017/8/14.

//  Copyright © 2017 shihu. All rights reserved.

//


#import "ViewController.h"

#import <CoreMotion/CoreMotion.h>

#import "SHBallView.h"


@interface ViewController ()


//运动管理器

@property (strong,nonatomic) CMMotionManager *motionManager;

@property (weak,nonatomic) SHBallView *ballView;


@end


@implementation ViewController


- (void)viewDidLoad {

    [superviewDidLoad];

    

    // 创建以grass.png图片平铺的颜色

    UIColor* bgColor = [UIColorcolorWithPatternImage:

                        [UIImageimageNamed:@"grass"]];

    

    // 将该视图控制器管理的View控件转换为SHBallView

    self.ballView = (SHBallView *)self.view;

    

    // 将背景设为以grass.png图片平铺的颜色

    self.ballView.backgroundColor = bgColor;

    

    // 创建CMMotionManager对象

    self.motionManager = [[CMMotionManageralloc] init];

    

    NSOperationQueue* queue = [[NSOperationQueuealloc] init];

    

    // 设置CMMotionManager获取加速度数据的频率

    self.motionManager.accelerometerUpdateInterval = 0.05;

    

    // 使用代码块获取加速度数据

    [self.motionManagerstartAccelerometerUpdatesToQueue:queuewithHandler:

     ^(CMAccelerometerData *accelerometerData,NSError *error)

     {

         // 将获取得到的加速度数据传给FKBallView对象

         self.ballView.acceleration = accelerometerData.acceleration;

         // 在主线程中调用FKBallView对象的update方法

         [self.ballViewperformSelectorOnMainThread:@selector(update)

                                         withObject:nilwaitUntilDone:NO];

     }];

}

@end

=========================

===================================================




谢谢!!!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值