簡體   English   中英

iOS多個彈跳球

[英]iOS Multiple Bouncing Balls

以下是工作視圖控制器,該控制器允許根據拍子位置創建多個球,然后計算該球的x和y速度。 創建一個球之后,它會根據計算出的速度運動並從屏幕周圍反彈。 我使用NSTimer為球運動設置動畫。 問題僅在於最近創建的球移動。 創建新球后,上一個球將停止移動。 我認為這是一個並發類型問題。 我已經做了一些研究,並嘗試了一些關於線程的事情,但是無法使其正常工作。 也許使用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方法只有一個時間(而不是每次你創建一個球),然后在循環中所有的球balls在你的NSArray doBallTick方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM