简体   繁体   English

iOS多个弹跳球

[英]iOS Multiple Bouncing Balls

Below is the working view controller that allows multiple balls to be created based on tap location and then calculates the x and y velocity for the ball. 以下是工作视图控制器,该控制器允许根据拍子位置创建多个球,然后计算该球的x和y速度。 After a ball is created, it moves based on the calculated velocity and bounces off the screen perimeter. 创建一个球之后,它会根据计算出的速度运动并从屏幕周围反弹。 I use an NSTimer to animate the balls movement. 我使用NSTimer为球运动设置动画。 The issue is only the most recently created ball moves. 问题仅在于最近创建的球移动。 After a new ball is created, the previous ball stops moving. 创建新球后,上一个球将停止移动。 Methinks this is a concurrency type problem. 我认为这是一个并发类型问题。 I've done some research and tried a few things with threads, but couldn't get it to work. 我已经做了一些研究,并尝试了一些关于线程的事情,但是无法使其正常工作。 Maybe using an NSTimer is not the best approach? 也许使用NSTimer并不是最好的方法?

Anyways, the ultimate goal here is to have all the created balls moving simultaneously. 无论如何,这里的最终目标是使所有创建的球同时移动。

#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

In your doBallTick method, you only move currentBall . doBallTick方法中,仅移动currentBall You should schedule your selector only one time in the init method (instead of everytime your create a ball), and then loop over all the balls in the balls nsarray in your doBallTick method. 您应该安排你的选择在init方法只有一个时间(而不是每次你创建一个球),然后在循环中所有的球balls在你的NSArray doBallTick方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM