📄 crashlandingappdelegate.m
字号:
else [self resetGame]; }}// Saves the user's score in the application preferences- (void)saveScore { NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; NSString* name = [defaults stringForKey:kUserNameDefaultKey]; NSDate* date = [NSDate date]; NSMutableArray* scores; NSMutableString* string; unsigned i; NSDictionary* dictionary; //Dismiss text field [_textField endEditing:YES]; [_textField removeFromSuperview]; //Make sure a player name exists, if only the default if(![name length]) name = @"Player"; //Update the high-scores in the preferences scores = [NSMutableArray arrayWithArray:[defaults objectForKey:kHighScoresDefaultKey]]; [scores addObject:[NSDictionary dictionaryWithObjectsAndKeys:name, @"name", [NSNumber numberWithUnsignedInt:_score], @"score", date, @"date", nil]]; [scores sortUsingDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"score" ascending:NO] autorelease]]]; [defaults setObject:scores forKey:kHighScoresDefaultKey]; //Display high-scores in status texture string = [NSMutableString stringWithString:@" HIGH-SCORES\n"]; for(i = 0; i < MIN([scores count], 10); ++i) { dictionary = [scores objectAtIndex:i]; [string appendFormat:@"\n%s%i. %@ (%@ Pts)", ([[dictionary objectForKey:@"date"] isEqualToDate:date] ? "> " : " "), i + 1, [dictionary objectForKey:@"name"], [dictionary objectForKey:@"score"]/*, [[dictionary objectForKey:@"date"] descriptionWithCalendarFormat:@"%m/%d %I:%M %p" timeZone:nil locale:nil]*/]; } [_statusTexture release]; _statusTexture = [[Texture2D alloc] initWithString:string dimensions:CGSizeMake(256, 256) alignment:UITextAlignmentLeft fontName:kFontName fontSize:kScoreFontSize]; _state = kState_StandBy; //Render a frame [self renderScene];}// Release the status texture and initialized values in preparation for starting a new game- (void)resetGame { CGRect bounds = [glView bounds]; //Destroy the status texture [_statusTexture release]; _statusTexture = nil; //Reset the state to running mode _state = kState_Running; _lastTime = CFAbsoluteTimeGetCurrent(); _lastThrust = NO; //Randomize the landing base position _basePosition = RANDOM_FLOAT() * (bounds.size.width - kBaseSize) + kBaseSize / 2; //Set the initial state or the rocket _fuel = kInitialFuel; _rotation = 0.0; _rotationVelocity = 0.0; _position.x = RANDOM_FLOAT() * (bounds.size.width - _landerBounds.size.width) + _landerBounds.size.width / 2; _position.y = bounds.size.height + _landerBounds.size.height; _velocity.x = 0.0; _velocity.y = -kInitialVelocity; //Render a frame immediately [self renderScene]; //Start rendering timer _timer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / kRenderingFPS) target:self selector:@selector(renderScene) userInfo:nil repeats:YES]; //Play start sound SoundEngine_StartEffect( _sounds[kSound_Start]);}// Renders one scene of the game- (void)renderScene { CGRect bounds = [glView bounds]; float maxDistance = (kBaseSize - _landerBounds.size.width) / 2.0; BOOL thrust = NO; CFTimeInterval time; float dTime; Vector2D force, orientation; CGRect rect; float lateralAcceleration; CGSize size; //Update game state if(_state == kState_Running) { time = CFAbsoluteTimeGetCurrent(); dTime = time - _lastTime; //Update lander position _position.x += _velocity.x * dTime; _position.y += _velocity.y * dTime; //Wrap the lander horizontal position if(_position.x < 0.0) _position.x = bounds.size.width + _position.x; else if(_position.x > bounds.size.width) _position.x = bounds.size.width - _position.x; //Clamp the lander top vertical position if(_position.y > bounds.size.height - _landerBounds.size.height / 2) { _position.y = bounds.size.height - _landerBounds.size.height / 2; _velocity.y = 0.0; } //Update the rocket orientation _rotation += _rotationVelocity * dTime; //Check to see if the rocket touched the ground orientation.x = sinf(DEGREES_TO_RADIANS(_rotation)); orientation.y = cosf(DEGREES_TO_RADIANS(_rotation)); rect = CGRectApplyAffineTransform(_landerBounds, CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(_rotation))); if(_position.y + CGRectGetMinY(rect) <= kBaseOffset + (GLfloat)[_textures[kTexture_Base] pixelsHigh] / 2) { //Check whether the landing is successful or not if((_velocity.y >= -kMaxVelocity) && (fabsf(_rotation) <= kMaxRotation) && (fabsf(_position.x - _basePosition) < maxDistance)) { SoundEngine_StartEffect(_sounds[kSound_Success]); _state = kState_Success; _score = kScoreVelocity * (1.0 - _velocity.y / -kMaxVelocity) + kScoreFuel * (_fuel / kInitialFuel) + kScoreRotation * (1.0 - _rotation / kMaxRotation) + kScoreDistance * (1.0 - fabsf(_position.x - _basePosition) / maxDistance); _statusTexture = [[Texture2D alloc] initWithString:[NSString stringWithFormat:@"SUCCESS!\nYou scored %i Points\n\nEnter your name:", _score] dimensions:CGSizeMake(256, 128) alignment:UITextAlignmentCenter fontName:kFontName fontSize:kStatusFontSize]; //Show text field that allows the user to enter a name for the score [_textField setText:[[NSUserDefaults standardUserDefaults] stringForKey:kUserNameDefaultKey]]; [window addSubview:_textField]; } else { // The landing is not successful; the rocket crashed! SoundEngine_Vibrate(); SoundEngine_SetEffectPosition(_sounds[kSound_Failure], 2.0 * (_position.x / bounds.size.width) - 1.0, 0.0, 0.0); SoundEngine_StartEffect(_sounds[kSound_Failure]); _state = kState_Failure; _statusTexture = [[Texture2D alloc] initWithString:@"YOU CRASHED!" dimensions:CGSizeMake(256, 32) alignment:UITextAlignmentCenter fontName:kFontName fontSize:kStatusFontSize]; } //Stop rendering timer [_timer invalidate]; _timer = nil; } //Update lander velocity, rotation speed and fuel else { thrust = (_accelerometer[1] <= kMainThrustThreshold ? YES : NO); force.x = 0.0; force.y = -kMass * kGravity; if(thrust && (_fuel > 0.0)) { force.x = -orientation.x * kMainThrust; force.y = orientation.y * kMainThrust; } else thrust = NO; _velocity.x += force.x / kMass * dTime; _velocity.y += force.y / kMass * dTime; lateralAcceleration = _accelerometer[0]; if(fabsf(lateralAcceleration) >= kLateralThrustThreshold) { _velocity.x += (lateralAcceleration > 0.0 ? lateralAcceleration - kLateralThrustThreshold : lateralAcceleration + kLateralThrustThreshold) * kLateralSpeed; _rotationVelocity = -(lateralAcceleration > 0.0 ? lateralAcceleration - kLateralThrustThreshold : lateralAcceleration + kLateralThrustThreshold) * kRotationSpeed; } if(thrust) { // Update the fuel level _fuel -= dTime; if(_fuel < 0.0) _fuel = 0.0; } _lastTime = time; } //Start or stop thurst sound & update its position if(thrust && !_lastThrust) SoundEngine_StartEffect( _sounds[kSound_Thrust]); else if(!thrust && _lastThrust) SoundEngine_StopEffect(_sounds[kSound_Thrust], false); if(thrust) SoundEngine_SetEffectPosition(_sounds[kSound_Thrust], 2.0 * (_position.x / bounds.size.width) - 1.0, 0.0, 0.0); _lastThrust = thrust; } //Draw background glDisable(GL_BLEND); [_textures[kTexture_Background] drawInRect:bounds]; glEnable(GL_BLEND); //Draw the game elements if(_state != kState_StandBy) { //Draw the landing base [_textures[kTexture_Base] drawAtPoint:CGPointMake(_basePosition, kBaseOffset)]; //Draw the lander glPushMatrix(); glTranslatef(_position.x, _position.y, 0); if(_rotation) glRotatef(_rotation, 0, 0, 1); [_textures[kTexture_Lander] drawAtPoint:CGPointZero]; if(_state == kState_Running) { if(thrust) [_textures[kTexture_MainThrust] drawAtPoint:CGPointMake(0, -56)]; if(lateralAcceleration > kLateralThrustThreshold) [_textures[kTexture_LeftThrust] drawAtPoint:CGPointMake(-35.5, -48)]; if(lateralAcceleration < -kLateralThrustThreshold) [_textures[kTexture_RightThrust] drawAtPoint:CGPointMake(35.5, -48)]; } glPopMatrix(); //Draw the status lights [_textures[(_velocity.y >= -kMaxVelocity ? kTexture_LightGreen : kTexture_LightRed)] drawAtPoint:CGPointMake(kSpeedX, kLightY)]; [_textures[(fabsf(_rotation) <= kMaxRotation ? kTexture_LightGreen : kTexture_LightRed)] drawAtPoint:CGPointMake(kAngleX, kLightY)]; [_textures[(fabsf(_position.x - _basePosition) < maxDistance ? kTexture_LightGreen : kTexture_LightRed)] drawAtPoint:CGPointMake(kPositionX, kLightY)]; glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); [_textures[kTexture_LabelSpeed] drawAtPoint:CGPointMake(kSpeedX + kLabelOffset, kLabelY)]; [_textures[kTexture_LabelAngle] drawAtPoint:CGPointMake(kAngleX + kLabelOffset, kLabelY)]; [_textures[kTexture_LabelPosition] drawAtPoint:CGPointMake(kPositionX + kLabelOffset, kLabelY)]; glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); //Draw the explosion if the lander is crashed if(_state == kState_Failure) [_textures[kTexture_Explosion] drawAtPoint:CGPointMake(_position.x, _position.y)]; //Draw the fuel bar if(_state == kState_Running) { size = [_textures[kTexture_FuelBar] contentSize]; [_textures[kTexture_FuelBar] drawAtPoint:CGPointMake(kFuelBarX, kFuelBarY)]; if(_fuel > 0) [_textures[kTexture_FuelLevel] drawInRect:CGRectMake(kFuelBarX - size.width / 2 + 1, kFuelBarY - size.height / 2 + 1, size.width - 2, _fuel / kInitialFuel * (size.height - 2))]; } } //Draw the overlay status texture if(_statusTexture) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); [_statusTexture drawAtPoint:CGPointMake(bounds.size.width / 2, bounds.size.height * 2 / 3)]; glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } //Swap the framebuffer [glView swapBuffers];}@end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -