下面是工作视图控制器,它允许根据拍子位置创建多个球,然后计算球的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
答案 0 :(得分:1)
在doBallTick
方法中,您只需移动currentBall
。你应该在init方法中只安排你的选择器一次(而不是每次你创建一个球),然后在balls
方法的doBallTick
nsarray中遍历所有球。