0

我对这一切都很陌生,所以如果这是一个非常无知的问题,我深表歉意。我正在尝试制作一个炮塔,该炮塔将旋转以面对水龙头并朝该方向开火。在 Ray Wenderlich 的旋转炮塔教程中找到了一些代码,我将炮塔移动到屏幕的底部中心,并将弹丸的起点重新定位到同一点。这个位置更类似于旧的导弹指挥风格的游戏。

不幸的是,现在当我点击屏幕右侧时,武器会正确开火,但是当我点击左侧时,它会向下并向右开火,就像它以某种方式翻转命令一样。谁能帮我解决这个问题?是否有另一种编码方式,这样我就不会出现左击问题,或者我是否需要输入额外的内容来翻译坐标以便水龙头正确注册?

// Import the interfaces
#import "HelloWorldLayer.h"
#import "SimpleAudioEngine.h"
#import "GameOverLayer.h"
#import "Monster.h"
#import "LevelManager.h"

// Needed to obtain the Navigation Controller
#import "AppDelegate.h"

#pragma mark - HelloWorldLayer

// HelloWorldLayer implementation
@implementation HelloWorldLayer

// Helper class method that creates a Scene with the HelloWorldLayer as the only child.
+(CCScene *) scene
{
    // 'scene' is an autorelease object.
    CCScene *scene = [CCScene node];

    // 'layer' is an autorelease object.
    HelloWorldLayer *layer = [HelloWorldLayer node];

    // add layer as a child to scene
    [scene addChild: layer];

// return the scene
return scene;
}

- (void) addMonster {

    //CCSprite * monster = [CCSprite spriteWithFile:@"monster.png"];
    Monster * monster = nil;
    if (arc4random() % 2 == 0) {
        monster = [[[WeakAndFastMonster alloc] init] autorelease];
    } else {
        monster = [[[StrongAndSlowMonster alloc] init] autorelease];
    }

    // Determine where to spawn the monster along the Y axis
    CGSize winSize = [CCDirector sharedDirector].winSize;
    int minY = monster.contentSize.height / 2;
    int maxY = winSize.height - monster.contentSize.height/2;
    int rangeY = maxY - minY;
    int actualY = (arc4random() % rangeY) + minY;

    // Create the monster slightly off-screen along the right edge,
    // and along a random position along the Y axis as calculated above
    monster.position = ccp(winSize.width + monster.contentSize.width/2, actualY);
    [self addChild:monster];

    // Determine speed of the monster
    int minDuration = monster.minMoveDuration; //2.0;
    int maxDuration = monster.maxMoveDuration; //4.0;
    int rangeDuration = maxDuration - minDuration;
    int actualDuration = (arc4random() % rangeDuration) + minDuration;

    // Create the actions
    CCMoveTo * actionMove = [CCMoveTo actionWithDuration:actualDuration position:ccp(-monster.contentSize.width/2, actualY)];
    CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
        [_monsters removeObject:node];
        [node removeFromParentAndCleanup:YES];

        CCScene *gameOverScene = [GameOverLayer sceneWithWon:NO];
        [[CCDirector sharedDirector] replaceScene:gameOverScene];
    }];
    [monster runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];

    monster.tag = 1;
    [_monsters addObject:monster];

}

-(void)gameLogic:(ccTime)dt {
    [self addMonster];
}

- (id) init
{
    if ((self = [super initWithColor:[LevelManager sharedInstance].curLevel.backgroundColor])) {

        CGSize winSize = [CCDirector sharedDirector].winSize;
        _player = [CCSprite spriteWithFile:@"player2.png"];
        _player.position = ccp(winSize.width/2, 20);
        [self addChild:_player];

        [self schedule:@selector(gameLogic:) interval:[LevelManager sharedInstance].curLevel.secsPerSpawn];

        [self setTouchEnabled:YES];

        _monsters = [[NSMutableArray alloc] init];
        _projectiles = [[NSMutableArray alloc] init];

        [self schedule:@selector(update:)];

        [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"background-music-aac.caf"];

    }
    return self;
}

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

    if (_nextProjectile != nil) return;

    // Choose one of the touches to work with
    UITouch *touch = [touches anyObject];
    CGPoint location = [self convertTouchToNodeSpace:touch];

    // Set up initial location of projectile
    CGSize winSize = [[CCDirector sharedDirector] winSize];
    _nextProjectile = [[CCSprite spriteWithFile:@"projectile2.png"] retain];
    _nextProjectile.position = ccp(winSize.width/2, 20);

    // Determine offset of location to projectile
    CGPoint offset = ccpSub(location, _nextProjectile.position);

    // Bail out if you are shooting down or backwards
    //if (offset.x <= 0) return;

    // Determine where you wish to shoot the projectile to
    int realX = winSize.width + (_nextProjectile.contentSize.width/2);
    float ratio = (float) offset.y / (float) offset.x;
    int realY = (realX * ratio) + _nextProjectile.position.y;
    CGPoint realDest = ccp(realX, realY);

    // Determine the length of how far you're shooting
    int offRealX = realX - _nextProjectile.position.x;
    int offRealY = realY - _nextProjectile.position.y;
    float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
    float velocity = 480/1; // 480pixels/1sec
    float realMoveDuration = length/velocity;

    // Determine angle to face
    float angleRadians = atanf((float)offRealY / (float)offRealX);
    float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
    float cocosAngle = -1 * angleDegrees;
    float rotateDegreesPerSecond = 180 / 0.5; // Would take 0.5 seconds to rotate 180 degrees, or half a circle
    float degreesDiff = _player.rotation - cocosAngle;
    float rotateDuration = fabs(degreesDiff / rotateDegreesPerSecond);
    [_player runAction:
     [CCSequence actions:
      [CCRotateTo actionWithDuration:rotateDuration angle:cocosAngle],
      [CCCallBlock actionWithBlock:^{
         // OK to add now - rotation is finished!
         [self addChild:_nextProjectile];
         [_projectiles addObject:_nextProjectile];

         // Release
         [_nextProjectile release];
         _nextProjectile = nil;
     }],
      nil]];

    // Move projectile to actual endpoint
    [_nextProjectile runAction:
     [CCSequence actions:
      [CCMoveTo actionWithDuration:realMoveDuration position:realDest],
      [CCCallBlockN actionWithBlock:^(CCNode *node) {
         [_projectiles removeObject:node];
         [node removeFromParentAndCleanup:YES];
    }],
      nil]];

    _nextProjectile.tag = 2;

    [[SimpleAudioEngine sharedEngine] playEffect:@"pew-pew-lei.caf"];
}

- (void)update:(ccTime)dt {

    NSMutableArray *projectilesToDelete = [[NSMutableArray alloc] init];
    for (CCSprite *projectile in _projectiles) {

        BOOL monsterHit = FALSE;
        NSMutableArray *monstersToDelete = [[NSMutableArray alloc] init];
        for (Monster *monster in _monsters) {

            if (CGRectIntersectsRect(projectile.boundingBox, monster.boundingBox)) {
                monsterHit = TRUE;
                monster.hp --;
                if (monster.hp <= 0) {
                    [monstersToDelete addObject:monster];
                }
                break;
            }
        }

        for (CCSprite *monster in monstersToDelete) {

            [_monsters removeObject:monster];
            [self removeChild:monster cleanup:YES];

            _monstersDestroyed++;
            if (_monstersDestroyed > 30) {
                CCScene *gameOverScene = [GameOverLayer sceneWithWon:YES];
                [[CCDirector sharedDirector] replaceScene:gameOverScene];
            }
        }

        if (monsterHit) {
            [projectilesToDelete addObject:projectile];
            [[SimpleAudioEngine sharedEngine] playEffect:@"explosion.caf"];
        }
        [monstersToDelete release];
    }

    for (CCSprite *projectile in projectilesToDelete) {
        [_projectiles removeObject:projectile];
        [self removeChild:projectile cleanup:YES];
    }
    [projectilesToDelete release];
}


// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
    [_monsters release];
    _monsters = nil;
    [_projectiles release];
    _projectiles = nil;
    [super dealloc];
}
@end
4

2 回答 2

0

我再次查看了您的代码,并发现了其他问题。我更改了以下部分:

  • 下面拍摄时的“救助”条件(注意顺序更改,否则在第一次满足救助条件后您将无法获得镜头!)
  • 计算realYrealX- 您离开了 Ray 教程中的代码,并将目标位置设置为始终位于右侧,而在下面的代码中,它始终位于顶部
  • 删除atan/atan2功能并ccpToAngle(ccp(offRealX, offRealY))改为使用

以下是已更改的代码部分。如果您需要,我可以分享整个修改后的项目,但它应该足以替换您ccTouchesEnded方法的开头。

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (_nextProjectile != nil) return;

    CGSize winSize = [[CCDirector sharedDirector] winSize];

    // Choose one of the touches to work with
    UITouch *touch = [touches anyObject];
    CGPoint location = [self convertTouchToNodeSpace:touch];

    CGPoint targetPosition = ccp(winSize.width / 2, 20);

    // Determine offset of location to projectile
    CGPoint offset = ccpSub(location, targetPosition);

    // Bail out if you are shooting down or backwards
    if (offset.y <= 0)
    {
    return;
    }

    // Set up initial location of projectile
    _nextProjectile = [[CCSprite spriteWithFile:@"projectile2.png"] retain];
    _nextProjectile.position = targetPosition;

    // Determine where you wish to shoot the projectile to
    int realY = winSize.height + (_nextProjectile.contentSize.height/2);
    float ratio = (float) offset.x / (float) offset.y;
    int realX = (realY * ratio) + _nextProjectile.position.x;
    CGPoint realDest = ccp(realX, realY);

    // Determine the length of how far you're shooting
    int offRealX = realX - _nextProjectile.position.x;
    int offRealY = realY - _nextProjectile.position.y;
    float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
    float velocity = 480/1; // 480pixels/1sec
    float realMoveDuration = length/velocity;

    // Determine angle to face
    float angleRadians = ccpToAngle(ccp(offRealX, offRealY));
于 2013-04-16T03:51:23.390 回答
0

我会说你应该用 替换你atanfatan2f,即替换

float angleRadians = atanf((float)offRealY / (float)offRealX);

with (注意分别atan2f接受YX!)

float angleRadians = atan2f((float)offRealY, (float)offRealX);

查看有关 atan2 的 Wikipedia 文章。您将从 0-PI/2 看到这一点,atanf并将atan2f给您相同的结果。然而,一旦你从 PI/2 转向 PI,你会得到负角,而使用atanfwhileatan2f会产生正确的角。

于 2013-04-15T19:41:57.823 回答