复刻《荒野乱斗》背景滚动效果的技术问题求助
复刻《荒野乱斗》背景效果的优化建议
我正尝试复刻《荒野乱斗》中的背景效果,实现图标铺满背景并按指定方向、速度移出屏幕。目前已实现视图加载时初始背景图标的显示,但在新图标的生成时机、速度匹配上存在问题,不确定当前方案是否最优,以下是我的尝试代码,欢迎提供建议:
func initializeBackgroundTiles() { let itemsPerRow = 4 let itemHeight = self.frame.width / 7 let widthBetween = (itemHeight * 2) / 5 let columnHeight = widthBetween * 4 for column in 0...10 { for row in 0...5 { let columnPosition = (columnHeight * CGFloat(column)) let xCalc = CGFloat( -(itemHeight + widthBetween) // 向左多偏移一行的位置 + (itemHeight * Double(row) + (widthBetween * Double(row)))) let yCalc = (((self.frame.height - itemHeight) - columnPosition * 2) + ((row % 2 == 1 ? columnHeight : 0))) let tileSubview = CustomImageView(frame: CGRect( x: xCalc, y: yCalc, width: itemHeight, height: itemHeight)) tileSubview.image = UIImage(named: "lightBand")!.withTintColor(.white) tileSubview.alpha = 0.04 ContentView.addSubview(tileSubview) UIView.animate(withDuration: 30, delay: 0, options: [.curveLinear]) { let newX = ((itemHeight * Double(row)) + (widthBetween * Double(row))) + widthBetween * 3 let newY = 0 - ((itemHeight + (row % 2 == 0 ? columnHeight : 0)) + columnPosition * 2) tileSubview.frame = CGRect( x: newX, y: newY, width: itemHeight, height: itemHeight ) } completion: { completed in tileSubview.removeFromSuperview() } } } } func addBackgroundTilesTimer() { Timer.scheduledTimer(timeInterval: 6, target: self, selector: #selector(continueBackgroundTiles), userInfo: nil, repeats: true) } @objc func continueBackgroundTiles() { // 每隔x秒生成一列垂直和水平的图标 let itemHeight = self.frame.width / 7 let widthBetween = (itemHeight * 2) / 5 let columnHeight = widthBetween * 4 for row in 0...7 { let columnPosition = (columnHeight * CGFloat(1)) let xCalc = CGFloat( -((itemHeight + widthBetween) * 2) // 向左多偏移两行的位置 + (itemHeight * Double(row) + (widthBetween * Double(row)))) let yCalc = (((self.frame.height - itemHeight) - columnPosition * 2) + ((row % 2 == 1 ? columnHeight : 0))) let tileSubview = CustomImageView(frame: CGRect( x: xCalc, y: yCalc, width: itemHeight, height: itemHeight)) tileSubview.image = UIImage(named: "lightBand")!.withTintColor(.white) tileSubview.alpha = 0.04 self.ContentView.addSubview(tileSubview) UIView.animate(withDuration: 30, delay: 0, options: [.curveLinear]) { let newX = ((itemHeight * Double(row)) + (widthBetween * Double(row))) + widthBetween * 3 let newY = 0 - ((itemHeight + (row % 2 == 0 ? columnHeight : 0)) + columnPosition * 2) tileSubview.frame = CGRect( x: newX, y: newY, width: itemHeight, height: itemHeight ) } completion: { completed in tileSubview.removeFromSuperview() } } }
核心问题与优化建议
现存问题
- 生成时机错位:Timer固定6秒触发,未与30秒的动画周期对齐,易出现背景空隙或图标重叠
- 速度不一致:初始生成图标与后续Timer生成图标的
columnPosition取值、布局计算逻辑存在差异,导致移动速度不统一 - 硬编码冗余:大量魔法数值(如循环范围、动画时长)散落在代码中,适配不同屏幕或调整效果时维护成本高
- 性能浪费:每次生成新图标都创建新视图并在动画结束后销毁,频繁的视图创建销毁会增加内存开销
优化方向
- 对齐生成时机与动画周期:
计算图标移动的实际速度(总移动距离 / 动画时长30秒),再根据图标列的间距,算出需要补充新图标的时间间隔,确保无缝衔接,避免空隙或重叠 - 统一布局与动画逻辑:
把布局计算(如xCalc、yCalc)、动画参数(时长、目标位置)抽成单独的工具方法或常量,让初始图标和后续生成的图标使用完全一致的逻辑,保证速度统一 - 改用AutoLayout实现动画:
放弃直接修改frame,用NSLayoutConstraint控制图标位置,动画时修改约束的constant值,更适配屏幕旋转、尺寸变化等场景 - 实现视图对象池:
维护一个可复用的CustomImageView池,动画结束后不销毁视图,而是将其隐藏并放回池中,需要时重新取出配置并显示,减少视图创建销毁的性能损耗 - 参数化配置:
将itemsPerRow、动画时长、图标透明度等参数定义为可配置的常量,便于快速调整效果,无需修改多处代码
内容的提问来源于stack exchange,提问作者Tyler Rutt
相关产品推荐
相关产品推荐

