Как создать индикатор выполнения в наборе спрайтов?
Я хочу создать свой собственный индикатор выполнения в Sprite Kit.
Я решил, что мне понадобится изображение - один полностью пустой индикатор выполнения и заполненный индикатор выполнения.
У меня есть эти образы, я накладываю заполненный поверх пустого, они регулярные SKSPriteNodes
, теперь я не могу понять, как я могу нарезать свое заполненное изображение там, где мне нужно?
Как отрезать изображение SKSpriteNode в определенный момент? Может быть, текстура?
Ответы
Ответ 1
Я бы рекомендовал посмотреть SKCropNode. Для наглядного пособия, как работает SKCropNode
, посмотрите его в Руководстве по программированию Apple. Я прочитал весь документ несколько раз, и он особенно хорошо читается.
SKCropNode
- это в основном SKNode, который вы добавляете к своей сцене, но его дети могут быть обрезаны маской. Эта маска устанавливается в свойстве maskNode
для SKCropNode. Таким образом, вам нужно только одно изображение текстуры. Я бы подклассифицировал SKCropNode для реализации функциональности для перемещения или изменения размера маски, поэтому вы можете легко обновить ее внешний вид.
@interface CustomProgressBar : SKCropNode
/// Set to a value between 0.0 and 1.0.
- (void) setProgress:(CGFloat) progress;
@end
@implementation CustomProgressBar
- (id)init {
if (self = [super init]) {
self.maskNode = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size:CGSizeMake(300,20)];
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"progressBarImage"];
[self addChild:sprite];
}
return self;
}
- (void) setProgress:(CGFloat) progress {
self.maskNode.xScale = progress;
}
@end
В вашей сцене:
#import "CustomProgressBar.h"
// ...
CustomProgressBar * progressBar = [CustomProgressBar new];
[self addChild:progressBar];
// ...
[progressBar setProgress:0.3];
// ...
[progressBar setProgress:0.7];
Примечание: этот код не перемещает маску (поэтому спрайт будет обрезаться с обеих сторон), но я уверен, что вы поняли эту идею.
Ответ 2
Довольно просто: вам нужно изображение кадра (необязательно) и изображение "бар". Изображение штриха должно быть единым, сплошным цветом и столь же высоким, насколько вам нужно, и шириной 1 или 2 пикселя. Также будет работать SKShapeNode в качестве панели.
Просто создание панели и анимация - это просто вопрос изменения свойства размера SKSpriteNode. Например, чтобы сделать панель показателем прогресса между 0 и 100, выполните:
sprite.size = CGSizeMake(progressValue, sprite.size.height);
Обновляйте размер при изменении значения progressValue.
Вы заметите, что изображение будет увеличиваться по ширине как влево, так и вправо, чтобы растянуть его только вправо, изменив привязку к левому выравниванию изображения:
sprite.anchorPoint = CGPointMake(0.0, 0.5);
Вот и все. Нарисуйте кадр спрайта вокруг него, чтобы он выглядел лучше.
Ответ 3
Предполагая, что HealthBarNode
является подклассом SKSpriteNode
с общедоступным свойством health
, который варьируется от 0.0 до 1.0 и родительское свойство texture
генерируется из всего изображения цветной полосы шириной _textureWidth
(частный свойство), вы можете сделать что-то вроде этого:
- (void)setHealth:(CGFloat)fraction
{
self.health = MIN(MAX(0.0, fraction), 1.0); // clamp health between 0.0 and 1.0
SKTexture *textureFrac = [SKTexture textureWithRect:CGRectMake(0, 0, fraction, 1.0) inTexture:self.texture];
// check docs to understand why you can pass in self.texture as the last parameter every time
self.size = CGSizeMake(fraction * _textureWidth, self.size.height);
self.texture = textureFrac;
}
Установка health
в новое значение приведет к тому, что панель работоспособности (добавляется как дочерний элемент в основную сцену, скажем) будет правильно отрегулирована.
Ответ 4
Я построил небольшую библиотеку, чтобы справиться с этим точным сценарием! Вот SpriteBar: https://github.com/henryeverett/SpriteBar
Ответ 5
Нет "разрезания" изображения/текстуры.
Альтернативой тому, что предлагает Cocos, является создание нескольких текстур и их замена в ваш node в зависимости от состояния здоровья. Я сделал игру, где панель здоровья меняла текстуру каждые 10 пунктов (диапазон был 0-100). Однако после некоторых проб и ошибок я только что сделал то, что предложил Cocos.
![enter image description here]()
Ответ 6
Я сделал это так, и он отлично работает.
Итак, сначала я объявил SKSpriteNode:
baseBar = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(CGRectGetMidX(self.frame)-40, self.frame.size.height/10)];
//The following will make the health bar to reduce from right to left
//Change it to (1,0.5) if you want to have it the other way
//But you'd have to play with the positioning as well
[baseBar setAnchorPoint:CGPointMake(0, 0.5)];
CGFloat goodWidth, goodHeight;
goodHeight =self.frame.size.height-(baseBar.frame.size.height*2/3);
goodWidth =self.frame.size.width-(10 +baseBar.frame.size.width);
[baseBar setPosition:CGPointMake(goodWidth, goodHeight)];
[self addChild:baseBar];
Затем я добавил "Frame" для панели с SKShapeNode без цвета заливки (clearcolour) и цвета штриха:
//The following was so useful
SKShapeNode *edges = [SKShapeNode shapeNodeWithRect:baseBar.frame];
edges.fillColor = [UIColor clearColor];
edges.strokeColor = [UIColor blackColor];
[self addChild:edges];
Когда я хотел уменьшить здоровье, я сделал следующее:
if (playerHealthRatio>0) {
playerHealthRatio -= 1;
CGFloat ratio = playerHealthRatio / OriginalPlayerHealth;
CGFloat newWidth =baseBar.frame.size.width*ratio;
NSLog(@"Ratio: %f newwidth: %f",ratio,newWidth);
[baseBar runAction:[SKAction resizeToWidth:newWidth duration:0.5]];
}else{
// NSLog(@"Game over");
}
Простая, чистая и не сложная.
Ответ 7
это мой ProgressBar
в быстрой:
import Foundation
import SpriteKit
class IMProgressBar : SKNode{
var emptySprite : SKSpriteNode? = nil
var progressBar : SKCropNode
init(emptyImageName: String!,filledImageName : String)
{
progressBar = SKCropNode()
super.init()
let filledImage = SKSpriteNode(imageNamed: filledImageName)
progressBar.addChild(filledImage)
progressBar.maskNode = SKSpriteNode(color: UIColor.whiteColor(),
size: CGSize(width: filledImage.size.width * 2, height: filledImage.size.height * 2))
progressBar.maskNode?.position = CGPoint(x: -filledImage.size.width / 2,y: -filledImage.size.height / 2)
progressBar.zPosition = 0.1
self.addChild(progressBar)
if emptyImageName != nil{
emptySprite = SKSpriteNode.init(imageNamed: emptyImageName)
self.addChild(emptySprite!)
}
}
func setXProgress(xProgress : CGFloat){
var value = xProgress
if xProgress < 0{
value = 0
}
if xProgress > 1 {
value = 1
}
progressBar.maskNode?.xScale = value
}
func setYProgress(yProgress : CGFloat){
var value = yProgress
if yProgress < 0{
value = 0
}
if yProgress > 1 {
value = 1
}
progressBar.maskNode?.yScale = value
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//Как использовать:
let progressBar = IMProgressBar(emptyImageName: "emptyImage",filledImageName: "filledImage")
или
let progressBar = IMProgressBar(emptyImageName: nil,filledImageName: "filledImage")
и добавьте этот progressBar в любой SKNode
:
self.addChild(progressBar)
//Это все.