iOS 多个弹跳球

标签 ios objective-c

下面是工作 View Controller ,它允许根据点击位置创建多个球,然后计算球的 x 和 y 速度。创建球后,它会根据计算出的速度移动并弹离屏幕周边。我使用 NSTimer 来制作球运动的动画。问题只是最近创建的球移动。创建新球后,先前的球停止移动。 Methinks这是一个并发类型的问题。我做了一些研究并尝试了一些线程,但无法让它工作。也许使用 NSTimer 不是最好的方法?

无论如何,这里的最终目标是让所有创建的球同时移动。

#import "ViewController.h"
#import "Ball.h"
#import "Constants.h"

NSTimeInterval lastTouch;
NSTimeInterval eventTime;
Ball *currentBall;
CGPoint ballStartPosition;
NSMutableArray *balls;
// get iPhone display size & aspect ratio
CGSize screen_size;

@interface ViewController () {

}
@property (strong, nonatomic) EAGLContext *context;

- (void)setupGL;
- (void)tearDownGL;
- (void)setupOrthographicView;


@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];

    if (!self.context) {
        NSLog(@"Failed to create ES context");
    }

    GLKView *view = (GLKView *)self.view;
    view.context = self.context;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;


    balls = [[NSMutableArray alloc] initWithObjects: nil];

    [self setupGL];

    self.motionManager = [[CMMotionManager alloc] init];
    self.motionManager.accelerometerUpdateInterval = .2;
    [self.motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue    currentQueue]
            withHandler:^(CMAccelerometerData  *accelerometerData, NSError *error) {
                [self updateAcceleration:accelerometerData.acceleration];
                if(error){ NSLog(@"%@", error); }
            }];}

- (void)dealloc
{   
    [self tearDownGL];

    if ([EAGLContext currentContext] == self.context) {
        [EAGLContext setCurrentContext:nil];
    }
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

    if ([self isViewLoaded] && ([[self view] window] == nil)) {
    self.view = nil;

    [self tearDownGL];

    if ([EAGLContext currentContext] == self.context) {
        [EAGLContext setCurrentContext:nil];
    }
    self.context = nil;
}

// Dispose of any resources that can be recreated.
}

- (void)update
{
[self setupOrthographicView];
}

- (void)setupGL
{
[EAGLContext setCurrentContext:self.context];
}

- (void)tearDownGL
{
[EAGLContext setCurrentContext:self.context];
}

- (void)setupOrthographicView
{
screen_size= self.view.bounds.size;
// set viewport based on display size
glViewport(0, 0, screen_size.width, screen_size.height);


// set up orthographic projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, screen_size.width, 0, screen_size.height, -1.0f, 1.0f);

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
lastTouch = [NSDate timeIntervalSinceReferenceDate];

// get iPhone display size & aspect ratio
CGSize screen_size = self.view.bounds.size;

// get the touch point and fix coordinates
CGPoint touch_point = [[touches anyObject] locationInView:self.view];
touch_point.y = screen_size.height - touch_point.y;
touch_point = CGPointMake(touch_point.x, touch_point.y);

ballStartPosition = touch_point;

// generate random RGB values and store them in an array
float r = RANDOM_FLOAT_BETWEEN(0.0, 1.0);
float g = RANDOM_FLOAT_BETWEEN(0.0, 1.0);
float b = RANDOM_FLOAT_BETWEEN(0.0, 1.0);

NSMutableArray *random_color = [[NSMutableArray alloc] init];
[random_color addObject:[NSNumber numberWithFloat:r]];
[random_color addObject:[NSNumber numberWithFloat:g]];
[random_color addObject:[NSNumber numberWithFloat:b]];

currentBall = [[Ball alloc] init];
int initialBallRadius = 2;
[currentBall makeBallWithRadius: initialBallRadius position:touch_point color:random_color];
[currentBall setStart_position:ballStartPosition];

[balls addObject:currentBall];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
eventTime = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval touchBeginEndInterval = eventTime - lastTouch;
// NSLog(@"%f", touchBeginEndInterval );

// get the touch point and fix coordinates
CGPoint touch_point = [[touches anyObject] locationInView:self.view];
touch_point.y = screen_size.height - touch_point.y;
touch_point = CGPointMake(touch_point.x, touch_point.y);


int ball_scale = 15;
[currentBall setRadius:touchBeginEndInterval*ball_scale];

float x_distance = touch_point.x - ballStartPosition.x;
float y_distance = touch_point.y - ballStartPosition.y;
// NSLog(@"dx: %f dy: %f",x_distance, y_distance );

float x_velocity = x_distance / touchBeginEndInterval;
float y_velocity = y_distance / touchBeginEndInterval;
// NSLog(@"vx: %f vy: %f",x_velocity, y_velocity );

[currentBall setX_velocity:x_velocity];
[currentBall setY_velocity:y_velocity];

[NSTimer scheduledTimerWithTimeInterval:0.0001 target:self selector:@selector(doBallTick) userInfo:NULL repeats:YES];
}

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

// get the touch point and fix coordinates
CGPoint touch_point = [[touches anyObject] locationInView:self.view];
touch_point.y = screen_size.height - touch_point.y;
touch_point = CGPointMake(touch_point.x, touch_point.y);
// NSLog(@"x: %f y: %f", touch_point.x, touch_point.y);

[currentBall setPosition:touch_point];
}

- (void) doBallTick {
NSTimeInterval current_time = [NSDate timeIntervalSinceReferenceDate];
[currentBall setCurrent_time:(current_time - eventTime)];
[currentBall update];
//NSLog(@"%f", (eventTime));

 //Checks if the ball is outside bounds
 if ((currentBall.position.x - currentBall.radius) <= 0) {
     eventTime = current_time;
     [currentBall hitLeft];
 }else if ((currentBall.position.x + currentBall.radius) >= screen_size.width){
     eventTime = current_time;
    [currentBall hitRight];
 }else if ((currentBall.position.y - currentBall.radius) <= 0) {
     eventTime = current_time;
     [currentBall hitBottom];
 }else if ((currentBall.position.y + currentBall.radius) >= screen_size.height){
     eventTime = current_time;
     [currentBall hitTop];
 }


}

- (void)updateAcceleration:(CMAcceleration)acceleration
{
// add acceleration code here
}

void GLDrawEllipse (int segments, CGFloat width, CGFloat height, CGPoint center, bool filled)
{
glPushMatrix();
glTranslatef(center.x, center.y, 0.0);
GLfloat vertices[segments*2];
int count=0;
for (GLfloat i = 0; i < 360.0f; i+=(360.0f/segments))
{
    vertices[count++] = (cos(DEGREES_TO_RADIANS(i))*width);
    vertices[count++] = (sin(DEGREES_TO_RADIANS(i))*height);
}
glVertexPointer (2, GL_FLOAT , 0, vertices);
glDrawArrays ((filled) ? GL_TRIANGLE_FAN : GL_LINE_LOOP, 0, segments);
glPopMatrix();
}

void GLDrawCircle (int circleSegments, CGFloat circleSize, CGPoint center, bool filled)
{
GLDrawEllipse(circleSegments, circleSize, circleSize, center, filled);
}

#pragma mark - GLKView and GLKViewController delegate methods

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
// clear the rendering buffer
glClear(GL_COLOR_BUFFER_BIT);
// enable the vertex array rendering
glEnableClientState(GL_VERTEX_ARRAY);

// draw and dispaly the balls
for(int i = 0; i < [balls count]; i++) {
    Ball *current_ball = (Ball *) [balls objectAtIndex: i];
    NSMutableArray *random_color = [current_ball color];
    glColor4f([[random_color objectAtIndex:0] floatValue], [[random_color objectAtIndex:1] floatValue], [[random_color objectAtIndex:2] floatValue], 1);
    GLDrawCircle(30, [current_ball radius], [current_ball position], true);
}
}

@end

最佳答案

在您的doBallTick 方法中,您只移动currentBall。你应该只在 init 方法中安排你的选择器一次(而不是每次你创建一个球),然后在你的 doBallTick 中遍历 balls nsarray 中的所有球方法。

关于iOS 多个弹跳球,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22413163/

相关文章:

iOS 9+ Testflight 蜂窝数据无法正常工作

ios - Swift:如何将不同的 UITableViewCell 执行 Segue 到不同的 ViewController?

ios - 向 UITableView 插入行时的行为

iphone - 以编程方式获取来电号码

objective-c - 如何使用Reachability类来检测网络状态?

iphone - 键/值更新字符串值

ios - 此 iOS SDK 安装不支持 “mydevice_name” 上的 iOS 版本

iphone - 有没有办法在 iOS 中的应用程序安装和卸载之间保留应用程序数据

objective-c - 具有多个客户端的 Ruby UDP 服务器?

objective-c - 区分对同一委托(delegate)方法的调用