zoukankan      html  css  js  c++  java
  • 【Swift 2.0】实现简单弹幕功能

    前言

      简单实现弹幕功能,表跟我谈效率,但也有用队列控制同时弹的数量。

    声明
      欢迎转载,但请保留文章原始出处:)
      博客园:http://www.cnblogs.com
      农民伯伯: http://over140.cnblogs.com

    正文

        let DANMAKU_SPEED: CGFloat = 150    // 弹幕每秒移动速度
        let DANMAKU_SPACE_TIME: NSTimeInterval = 1    // 弹幕之间的时间间隔
        let DANMAKU_MAX_ROW = 3    // 最多同时弹幕行数
        let danmakuFont = UIFont.systemFontOfSize(18)    // 弹幕字体大小
        var rowArray = Array<Array<Danmaku>>(count: 3, repeatedValue: Array<Danmaku>())    
        var danmakuQueue = NSOperationQueue()    // 队列
    
        class Danmaku : NSObject{
            var msg: Msg
            var view: UILabel?
            var size = CGSize( 0, height: 0)
            var row = 0
            var startTime: NSDate?
            var duration: NSTimeInterval = 0
            var delay: NSTimeInterval = 0
            
            init(_ msg: Msg, _ row: Int, _ delay: NSTimeInterval = 0) {
                self.msg = msg
                self.row = row
                self.delay = delay
            }
        }
     
        func queueDanmaku(msg: Msg) {
            danmakuQueue.addOperation(NSBlockOperation(block: { [weak self] in
    
                if let weakself = self {
                    repeat {
                        //检测放第几行
                        for var row = 0; row < weakself.DANMAKU_MAX_ROW; ++row {
                            let rowDanmaku = weakself.rowArray[row]
                            if rowDanmaku.count == 0 {
                                let danmaku = Danmaku(msg, weakself.danmakuFont, row)
                                weakself.rowArray[row].append(danmaku)
                                self?.performSelectorOnMainThread("sendDanmaku:", withObject: danmaku, waitUntilDone: true)
                                return
                            } else {
                                if let lastDanmaku = rowDanmaku.last {
                                    if let startTime = lastDanmaku.startTime {
                                        let now = NSDate()
                                        let seconds = now.timeIntervalSinceDate(startTime)
                                        let widthDuration = Double(lastDanmaku.size.width / weakself.DANMAKU_SPEED)
                                        
                                        var delay = seconds - weakself.DANMAKU_SPACE_TIME - widthDuration
                                        if delay >= 0 {
                                            delay = 0
                                        } else {
                                            if lastDanmaku.delay > lastDanmaku.duration {
                                                continue
                                            }
                                        }
                    
                                        let danmaku = Danmaku(msg, weakself.danmakuFont, row, abs(delay) + lastDanmaku.delay)
                                        weakself.rowArray[row].append(danmaku)
                                        
                                        self?.performSelectorOnMainThread("sendDanmaku:", withObject: danmaku, waitUntilDone: true)
                                        return
                                    }
                                }
                            }
                        }
                        
                        sleep(1000)
                    } while self != nil
                }
                
                }))
        }
        
        func sendDanmaku(danmaku: Danmaku) {
            let text = "(danmaku.msg.user_name) : (danmaku.msg.text)"
            let size = NSString(string: text).sizeWithAttributes([NSFontAttributeName : danmakuFont])
            let width = UIScreen.mainScreen().bounds.size.width
            let top = 54 + danmaku.row * (Int(size.height) + 10)
            let label = UILabel(frame: CGRectMake(width, CGFloat(top), size.width, size.height))
            let duration = (width + size.width) / DANMAKU_SPEED
    
            danmaku.view = label
            danmaku.size = size
            danmaku.startTime = NSDate()
            danmaku.duration = NSTimeInterval(duration)
            
            label.text = text
            label.font = danmakuFont
            label.textColor = UIColor.whiteColor()
            label.shadowColor = UIColor.blackColor()
            label.shadowOffset = CGSizeMake(0, -1.0)
            
            self.view.addSubview(label)
            UIView.animateWithDuration(Double(duration), delay: danmaku.delay, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
                    label.left = -label.width
                }) { [weak self] (Bool) -> Void in
                    if !(self?.rowArray[danmaku.row].isEmpty ?? true) {
                        self?.rowArray[danmaku.row].removeFirst()
                    }
                    label.removeFromSuperview()
            }
        }

        代码说明:

          代码控制了最多同时只能弹三行,每行最后一条如果延迟大于跑弹幕的时间(已经有一条处于完全等待状态)就自动切到下一行,超过最大限制就等待。

          *  rowArray 主要用于查询前一个弹幕的位置和时间

          *  别忘了在 deinit 里面加上 danmakuQueue.cancelAllOperations()

          *  注意 NSBlockOperation 的 block 并不在主线程上

  • 相关阅读:
    前端与算法 leetcode 344. 反转字符串
    JavaScript闭包使用姿势指南
    前端与算法 leetcode 48. 旋转图像
    前端与算法 leetcode 36. 有效的数独
    前端与算法 leetcode 1. 两数之和
    前端与算法 leetcode 283. 移动零
    前端与编译原理 用js去运行js代码 js2run
    前端与算法 leetcode 66. 加一
    前端与算法 leetcode 350. 两个数组的交集 II
    前端与算法 leetcode 26. 删除排序数组中的重复项
  • 原文地址:https://www.cnblogs.com/over140/p/4861347.html
Copyright © 2011-2022 走看看