我正在制作类似于“钢琴瓷砖”的游戏https://itunes.apple.com/us/app/piano-tiles-dont-tap-white/id848160327?mt=8

即使较早的动画尚未完成,您也可以点击图块。

这是我的实现

- (void)moveDown {


    [UIView animateWithDuration:DURATION_MOVE_DOWN delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{

        for (Tile *t in self.tiles) {
            if (t.y == NUM_TILES_Y - 1) {
                t.y = 0;
            }
            else {
                t.y++;
            }

            if (t.y == 0) {
                //move down
                //then place it to the top (in the completion handler)
                t.frame = [Tile frameWithX:t.x y:NUM_TILES_Y];
            }
            else {
                //move down
                t.frame = [Tile frameWithX:t.x y:t.y];
            }

        }

    } completion:^(BOOL finished) {

        for (Tile *t in self.tiles) {
            //if user tap while animating, just place the tile at its final position first, (then continue the new animation)
            t.frame = [Tile frameWithX:t.x y:t.y];
        }

        [self assignTouchDontTouchWithRowY:0];

    }];

}

AssignTouchDontTouchWithRowY方法是随机选择一行中的一个图块为TileTypeTouch(黑色图块),其余行作为TileTypeDontTouch(白色图块)
- (void)assignTouchDontTouchWithRowY:(int)y {
    int touchX = [Helper randomIntInclusiveBetweenLow:0 High:NUM_TILES_X -1];
    for (int x = 0; x < NUM_TILES_X; x++) {
        Tile *t = [self tileWithX:x y:y];
        if (x == touchX) {
            t.type = TileTypeTouch;
        }
        else {
            t.type = TileTypeDontTouch;
        }
    }

}

问题是,当我在完成较早的动画之前按一个图块时,某些代码未执行(例如,为新行着色,向下移动一行,有时底部的行会从上方翻译到顶部而不是滑动首先向下,然后放在顶部)

当我使用UIViewAnimationOptionBeginFromCurrentState选项时,当较早的一个动画时,用户交互将被取消。因此它也不起作用。

编辑:

在屏幕截图中,(0,1)磁贴是倒数第二个,它被平移到顶部(不向下滑动并更新其颜色)

还请注意,在(y = 1)行上方,屏幕外还有另一行(y = 0)。
即有5行,其中有4行在屏幕上,而第一行(y = 0)位于屏幕外部的顶部。向下滑动时,最后一行(y = 4)首先向下滑动,然后将其放在完成处理程序的顶部(y = 0)

编辑3:
以防万一我的逻辑不清楚:
  • 点击黑色图块时,所有图块都向下移动
  • 用于最后一行(y = 4),我先将其向下移动,然后将其放置在完成处理程序
  • 中的顶部(外部屏幕)
  • 如果用户在动画过程中点击一个图块,我首先会立即将图块放置在正确的位置(即旧动画的最终状态),然后开始新的动画。

  • 编辑4:
    视频中显示了错误

    https://drive.google.com/file/d/0B-iP0P7UfFj0Q01neEhaZmtBY2c/edit?usp=sharing

    最佳答案

    完成块是在新动画之后执行的(调用-moveDown时会立即发生

    完工块什么时候执行?我们不知道!它在排队/ future !

    因此,将前一个动画的清理代码移到moveDown的开头(动画之外),并且不要忘记检查(完成)是否省去了一些不必要的工作

    - (void)moveDown {
    
        Tile *t = self.tiles[0];
        if (t.layer.animationKeys.count) {
            for (Tile *t in self.tiles) {
                t.frame = [Tile frameWithX:t.x y:t.y];
            }
            [self assignTouchDontTouchWithRowY:0];
    
        }
    
    
        [UIView animateWithDuration:DURATION_MOVE_DOWN delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
    
            NSLog(@"anim");
            for (Tile *t in self.tiles) {
                if (t.y == NUM_TILES_Y - 1) {
                    t.y = 0;
                }
                else {
                    t.y++;
                }
    
                if (t.y == 0) {
                    //move down
                    //then place it to the top (in the completion handler)
                    t.frame = [Tile frameWithX:t.x y:NUM_TILES_Y];
                }
                else {
                    //move down
                    t.frame = [Tile frameWithX:t.x y:t.y];
                }
    
            }
    
        } completion:^(BOOL finished) {
    
            if (finished) {
    
                for (Tile *t in self.tiles) {
                    if (t.y == 0) {
                        t.frame = [Tile frameWithX:t.x y:t.y];
                    }
                }
                [self assignTouchDontTouchWithRowY:0];
    
    
            }
    
    
        }];
    
    }
    

    关于ios - iOS View 动画允许用户交互,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23728969/

    10-09 16:17
    查看更多