【问题标题】:Using sprite sheets in xcode在 xcode 中使用精灵表
【发布时间】:2015-03-16 11:35:54
【问题描述】:

我正在尝试使用精灵表为我的游戏制作动画。我将如何从精灵表中删除每个精灵并在 xcode 中使用精灵?我目前正在使用 obj -c。我在某处读到需要使用框架工作 cocoa2d 才能做到这一点?

【问题讨论】:

  • cocos-2d 是一个开源游戏引擎,有点像 sprite kit。剪切每个精灵从精灵表中创建一个 SKTexture 然后使用rect:InTexture: 剪切每个帧
  • 看看Texture Packer。这是一个免费的应用程序,可以创建纹理图集、处理动画并完成您需要的几乎所有其他工作。 codeandweb.com/texturepacker
  • @Okapi,我正在尝试为这个项目使用集成框架。我查看了一些raywenderlich tutorials,但这些示例似乎已经过时,例如他提到的示例使用 myscene 而不是具有不同属性的 gameviewcontroller。我也在努力寻找其他的例子,你知道吗?
  • 教程中提到的 MyScene 使用 GameScene 而不是 GameViewController。您可以在 SpriteKit 中剪切和动画精灵表,而无需使用其他框架,如果您需要,我可以为您提供代码
  • @Okapi,我应该把代码放在哪里(在项目的哪个文件中)来完成这个?

标签: objective-c sprite-kit


【解决方案1】:

在 sprite kit 中,您可以使用 SKTexture(rect: inTexture:) 初始化程序将纹理的一部分剪切掉。这是一个辅助类,它管理一个均匀分布的精灵表,并且可以在给定的行和列处剪切纹理。它像So一样使用

let sheet=SpriteSheet(texture: SKTexture(imageNamed: "spritesheet"), rows: 1, columns: 11, spacing: 1, margin: 1)
let sprite=SKSpriteNode(texture: sheet.textureForColumn(0, row: 0))

这是完整的代码

//
//  SpriteSheet.swift
//

import SpriteKit

class SpriteSheet {
    let texture: SKTexture
    let rows: Int
    let columns: Int
    var margin: CGFloat=0
    var spacing: CGFloat=0
    var frameSize: CGSize {
        return CGSize(width: (self.texture.size().width-(self.margin*2+self.spacing*CGFloat(self.columns-1)))/CGFloat(self.columns),
            height: (self.texture.size().height-(self.margin*2+self.spacing*CGFloat(self.rows-1)))/CGFloat(self.rows))
    }

    init(texture: SKTexture, rows: Int, columns: Int, spacing: CGFloat, margin: CGFloat) {
        self.texture=texture
        self.rows=rows
        self.columns=columns
        self.spacing=spacing
        self.margin=margin

    }

    convenience init(texture: SKTexture, rows: Int, columns: Int) {
        self.init(texture: texture, rows: rows, columns: columns, spacing: 0, margin: 0)
    }

    func textureForColumn(column: Int, row: Int)->SKTexture? {
        if !(0...self.rows ~= row && 0...self.columns ~= column) {
            //location is out of bounds
            return nil
        }

        var textureRect=CGRect(x: self.margin+CGFloat(column)*(self.frameSize.width+self.spacing)-self.spacing,
                               y: self.margin+CGFloat(row)*(self.frameSize.height+self.spacing)-self.spacing,
                               width: self.frameSize.width,
                               height: self.frameSize.height)

        textureRect=CGRect(x: textureRect.origin.x/self.texture.size().width, y: textureRect.origin.y/self.texture.size().height,
            width: textureRect.size.width/self.texture.size().width, height: textureRect.size.height/self.texture.size().height)
        return SKTexture(rect: textureRect, inTexture: self.texture)
    }

}

margin 属性是图像边缘和精灵之间的间隙。间距是每个精灵之间的间隙。成名大小是每个精灵的大小。这张图片解释了它:

【讨论】:

  • 感谢您提供包含所有代码的解决方案,但这是在 Swift 中:/,OP 被标记为 Objective-C
  • 抱歉,您应该可以将其桥接(或转换)为objective-c
  • @bagelboy 请看我的回复——Objective-C 中的SpriteSheet.m 类。
  • 所以这不需要 cocoa 2d 或任何东西,只需将其添加到任何普通的 swift 应用程序中,您就可以裁剪填充图像的精灵表?!
【解决方案2】:

由于最初的问题被标记为 Objective-C,这里是该语言的 SpriteSheet 类的粗略版本。希望这会有所帮助:

#import "SpriteSheet.h"

@interface SpriteSheet ()
@property (nonatomic, strong) SKTexture *texture;
@property (nonatomic)         NSInteger rows;
@property (nonatomic)         NSInteger cols;
@property (nonatomic)         CGFloat   margin;
@property (nonatomic)         CGFloat   spacing;
@property (nonatomic, getter=frameSize)         CGSize    frameSize;
@end


@implementation SpriteSheet

- (instancetype)initWithTextureName:(NSString *)name rows:(NSInteger)rows cols:(NSInteger)cols margin:(CGFloat)margin spacing:(CGFloat)spacing {
  SKTexture *texture = [SKTexture textureWithImageNamed:name];
  return [self initWithTexture:texture rows:rows cols:cols margin:margin spacing:spacing];
}

- (instancetype)initWithTexture:(SKTexture *)texture rows:(NSInteger)rows cols:(NSInteger)cols {
  return [self initWithTexture:texture rows:rows cols:cols margin:0 spacing:0];
}

- (instancetype)initWithTexture:(SKTexture *)texture rows:(NSInteger)rows cols:(NSInteger)cols margin:(CGFloat)margin spacing:(CGFloat)spacing {
  if (self == [super init]) {
    _texture = texture;
    _rows = rows;
    _cols = cols;
    _margin = margin;
    _spacing = spacing;
    _frameSize = [self frameSize];

  }
  return self;
}

- (CGSize)frameSize {

  CGSize newSize = CGSizeMake((self.texture.size.width - (self.margin * 2.0 + self.spacing * ((CGFloat)self.cols - 1.0))) / ((CGFloat)self.cols),
                    (self.texture.size.height - ((self.margin * 2.0) + (self.spacing * ((CGFloat)self.rows - 1.0))) / ((CGFloat)self.rows)));

  return newSize;
}

- (SKTexture *)textureForColumn:(NSInteger)column andRow:(NSInteger)row {

  if (column >= (self.cols) || row >= (self.rows)) {
    NSLog(@"Asking for row or col greater than spritesheet");
    return nil;
  }

  CGRect textureRect = CGRectMake(self.margin + (column * self.frameSize.width + self.spacing) - self.spacing,
                                  self.margin + (row * self.frameSize.width + self.spacing) - self.spacing, // note using width here
                                  self.frameSize.width,
                                  self.frameSize.height);

  textureRect = CGRectMake(textureRect.origin.x / self.texture.size.width, textureRect.origin.y / self.texture.size.height, textureRect.size.width / self.texture.size.width, textureRect.size.height/self.texture.size.height);

  return [SKTexture textureWithRect:textureRect inTexture:self.texture];
}

【讨论】:

    【解决方案3】:

    我将此添加到单独的答案中,因为它包含我发现的两个重要内容:

    第一:

    var textureRect=CGRect(x: self.margin+CGFloat(column)*(self.frameSize.width+self.spacing)-self.spacing,
                           y: self.margin+CGFloat(row)*(self.frameSize.width+self.spacing)-self.spacing,
                           width: self.frameSize.width,
                           height: self.frameSize.height)
    

    Swift 中的这段代码及其对应的 Objective-C 代码都有一个错误。 self.frameSize.width 用于行和列计算。高度需要用于列。

    第二: SKTexture 的坐标系将其 (0,0) 原点放置在图像的左下角,在制作精灵时必须考虑这一点,或者需要更改代码。

    例如,您可以像这样获取精灵从左上角到右下角的所有帧:

    var anim = [SKTexture]()
    for row in (0..<self.rows).reversed() {
      for column in 0..<self.columns {
        if let frame = textureForColumn(column: column, row: row) {
            anim.append(frame)
        }
      }
    }
    

    PS。我对SpriteKit没有太多经验,所以如果我的回答有任何错误,请纠正我。

    【讨论】:

      【解决方案4】:

      我修复了从上到下、从左到右获取精灵的问题。

      还添加了一个totalFrames,因此如果您没有包含所有帧的精灵,您可以设置总帧数,以便数组只包含精灵,没有空白精灵。

      //
      //  SpriteSheet.swift
      //
      
      import SpriteKit
      
      class SpriteSheet {
          let texture: SKTexture
          let rows: Int
          let columns: Int
          var margin: CGFloat=0
          var spacing: CGFloat=0
          var frameSize: CGSize {
              return CGSize(width: (self.texture.size().width-(self.margin*2+self.spacing*CGFloat(self.columns-1)))/CGFloat(self.columns),
                        height: (self.texture.size().height-(self.margin*2+self.spacing*CGFloat(self.rows-1)))/CGFloat(self.rows))
          }
      
          init(texture: SKTexture, rows: Int, columns: Int, spacing: CGFloat, margin: CGFloat) {
              self.texture=texture
              self.rows=rows
              self.columns=columns
              self.spacing=spacing
              self.margin=margin
      
          }
      
          convenience init(texture: SKTexture, rows: Int, columns: Int) {
              self.init(texture: texture, rows: rows, columns: columns, spacing: 0, margin: 0)
          }
      
          func textureForColumn(column: Int, row: Int)->SKTexture? {
              if !(0...self.rows ~= row && 0...self.columns ~= column) {
                  return nil
              }
              var textureRect = CGRect(x: self.margin + CGFloat(column) * (self.frameSize.width+self.spacing)-self.spacing, y: self.margin + CGFloat(self.rows - row - 1) * (self.frameSize.height+self.spacing)-self.spacing,
                                 width: self.frameSize.width,
                                 height: self.frameSize.height)
      
              textureRect = CGRect(x: textureRect.origin.x/self.texture.size().width, y: textureRect.origin.y/self.texture.size().height,
                             width: textureRect.size.width/self.texture.size().width, height: textureRect.size.height/self.texture.size().height)
              return SKTexture(rect: textureRect, in: self.texture)
          }
      }
      

      要调用,只需像这样添加动画:

      fileprivate let framesOpening: [SKTexture] = {
          let totalFrames = 28
          let rows = 6
          let columns = 5
          let sheet = SpriteSheet(texture: SKTexture(imageNamed: "GETREADY"), rows: rows, columns: columns, spacing: 0, margin: 0)
          var frames = [SKTexture]()
          var count = 0
      
          for row in (0..<rows) {
              for column in (0..<columns){
                  if count < totalFrames {
                      if let texture = sheet.textureForColumn(column: column, row: row) {
                          frames.append(texture)
                      }
                  }
                  count+=1
              }
          }
          return frames
      }()
      

      然后调用它

          let sprite1 = SKSpriteNode(texture: framesOpening.first)
          let openingAnimation: SKAction = SKAction.animate(with: framesOpening, timePerFrame: 0.2, resize: false, restore: true)
          sprite1.position = CGPoint(x: frame.midX, y: frame.midY)
          sprite1.zPosition = 2000
          self.addChild(sprite1)
          sprite1.run(SKAction.repeatForever(openingAnimation))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-14
        • 1970-01-01
        • 1970-01-01
        • 2017-01-07
        • 2012-03-14
        • 2023-03-21
        • 2012-02-10
        • 2023-04-06
        相关资源
        最近更新 更多