无关对象之间的通信

时间:2017-06-27 18:40:51

标签: objective-c macos sprite-kit event-handling delegation

背景

我正在使用Mac OS上的SpriteKit为MIDI击鼓创建一个节奏应用程序。 Note个对象是下面的绿色和蓝色的对象。音符在屏幕上从右向左移动。随着音符越来越接近红色的“游戏栏”,我想在游戏栏旁边创建音符的轮廓,以向用户表明音符越来越接近游戏栏并且是时候玩了

Mock-up of rhythm app

问题

我需要每个Note对象在距离播放头一定距离时通知另一个名为Sequencer的类,以便它可以为最近的音符开始音符轮廓动画。这些音符知道它们距离游戏头有多远,所以这不是问题。 代表团是否会成为这种情况的候选人?我试图了解授权的目的,但我永远无法弄清楚如何将其实施到我与游戏相关的具体情况中。

编辑:已添加代码

GameScene.m

@implementation GameScene

- (void)didMoveToView:(SKView *)view {
    ...
    [self initSequence];
    [self initNoteProcessor];
    [self initPlayBar];
    ...
}

...

//keeps track of a collection of notes and vertical line measure markers and
//responsible for drawing them in scene and moving them left
-(void) initSequence {
    _sequence = [[Sequencer alloc] initWithWidth:1150];
    [_sequence setPosition:CGPointMake(130, 0)];
    [self addChild:_sequence];
}
...

//responsible for handling incoming MIDI input from a keyboard and checking to see
//if notes are played on time, early or late
-(void) initNoteProcessor {
    _noteProcessor = [[NoteProcessor alloc] initWithSequence:_sequence];
}
...
//creates a vertical line that indicates when notes need to be played
-(void) initPlayBar {
    _playBar = (SKSpriteNode*)[self childNodeWithName:@"playBar"];
    _playBar.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_playBar.frame.size];
    _playBar.physicsBody.affectedByGravity = NO;
    [_playBar.physicsBody setDynamic:YES];
    [_playBar.physicsBody setAllowsRotation:NO];
    [_playBar.physicsBody setCategoryBitMask:kPlayBarCategory];
    [_playBar.physicsBody setCollisionBitMask:kNoCategory];
    [_playBar.physicsBody setContactTestBitMask:kNoteCategory | kLineCategory];
    [[NSUserDefaults standardUserDefaults] setDouble:_playBar.position.x forKey:@"playBarXPosition"];
}



NoteProcessor.m

@implementation NoteProcessor

-(instancetype) initWithSequence:(Sequencer*)sequence {
    if (self = [super init]) {
        _sequence = sequence;
        _noteActiveIndex = 0;
        [self initActiveNoteIndices];
        [self initNoteIndicator];

        //when user plays key on keyboard, notify this class
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(midiPlayed:) name:@"MidiPlayedNotificationKey" object:nil];

    }
    return self;
}

//keeps track of the next note of each pitch that is incoming
-(void) initActiveNoteIndices {
    _activeNoteIndicesByPitch = [NSMutableArray array];
    for (int i = 0; i < kTotalKeys; i++) {
        [_activeNoteIndicesByPitch addObject:[NSNumber numberWithInteger:0]];
    }
}

//checks position of note and decides whether they are on time, early or late
-(void) updateCurrentNoteStatus {
    ...
}

//handles notifications from MIDI keyboard when user plays a key
-(void) midiPlayed:(NSNotification*)notification {
     //stuff happens here
}


@end



Sequencer.m

@implementation Sequencer

-(instancetype) initWithWidth:(double)width {
    if (self = [super init]) {
        ...

        [self drawNotes];
    }
    return self;
}

//draws all of the notes on screen
-(void) drawNotes {
    NSMutableArray *parsedNotes = [_midiParser getNoteData];
    float distancePerBeat = [self getGridArea] / [self getMeasuresDisplayed] / 4;
    float xPos = 0;

    for (int i = 0; i < [parsedNotes count]; i++) {
        NSArray *currNote = [parsedNotes objectAtIndex:i];
        double location = [[currNote objectAtIndex:0] doubleValue];
        double duration = [[currNote objectAtIndex:1] doubleValue];
        int midiValue = [[currNote objectAtIndex:2] intValue];

        Note *note = [[Note alloc] initWithLocation:location Duration:duration MidiValue:midiValue];
        xPos = distancePerBeat * (location - 1);
        float yPos = kNoteHeight[note.midiValue - 36];
        [note setPosition:CGPointMake(xPos, yPos)];
        [note setZPosition:kNoteZPosition];

        NSMutableArray *noteList = [_notes objectAtIndex:midiValue-36];
        [noteList addObject:note];
        [self addChild:note];
    }
}

//this method is called 60 times per second
//each call moves 1/60th of the distance it would move in 1/60th of a second
-(void) moveLeftAfterElapsedTime:(double)elapsedTime {
    double timePerBeat = 60 / [self getBpm];
    double timePerMeasure = timePerBeat * 4;

    double lengthPerMeasure = [self getGridArea] / [self getMeasuresDisplayed];
    double distancePerFrame = lengthPerMeasure / (timePerMeasure * 60);

    double x = elapsedTime * distancePerFrame * 60;

    [self moveAllNotesLeftByDistance:x];
}

//actually does all of the moving of the notes
-(void) moveAllNotesLeftByDistance:(double)distance {
    for (int i = 0; i < [_notes count]; i++) {
        NSMutableArray *noteList = [_notes objectAtIndex:i];
        for (int j = 0; j < [noteList count]; j++) {
            Note *note = [noteList objectAtIndex:j];
            double xPos = note.position.x - distance;
            double y = note.position.y;

            [note setPosition:CGPointMake(xPos, y)];
        }
    }
}

0 个答案:

没有答案