Spritekit 和 OpenGL:平滑的烟雾痕迹
Spritekit and OpenGL: smooth smoke trail
我想在我的 Spritekit 游戏中实现这种效果,其中角色后面有一条 平滑 轨迹。
在 Jetpack joyride 中查看硬币背后的踪迹:
木星跳跃英雄背后的这条线索:
或者 Ski Safari 英雄背后的这条超级平滑的小径:
这似乎是其他游戏引擎的标准功能?我认为 spritekit 粒子发射器只会提供 blocky/stamped 轨迹,而不是平滑轨迹。我应该使用某种精灵自定义着色器吗?还有其他创造性的想法吗?
您的问题没有包含要使用的运动类型这一关键问题。我的答案是基于触摸屏幕的目标点,但另一种选择是使用核心运动。无论使用哪种方法,基本代码原则都保持不变。只有实现会改变。
我在示例中使用了矩形尾部图像,因为我希望您能够复制和 运行 示例代码。您应该将矩形替换为圆形 image/texture 以使尾巴的侧面更光滑。
修改 fadeOutDuration 值将导致更长或更短的尾巴持续时间。
修改stepsDivider会导致尾部节点增加或减少
#import "GameScene.h"
@implementation GameScene {
SKSpriteNode *playerNode;
CGPoint destinationPoint;
NSMutableArray *myArray;
NSMutableArray *myDiscardArray;
BOOL working;
int numberOfSteps;
float xIncrement;
float yIncrement;
float fadeOutDuration;
int stepsDivider;
}
-(void)didMoveToView:(SKView *)view {
self.backgroundColor = [SKColor blackColor];
playerNode = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size:CGSizeMake(30, 30)];
playerNode.position = CGPointMake(200, 200);
[self addChild:playerNode];
myArray = [[NSMutableArray alloc] init];
myDiscardArray = [[NSMutableArray alloc] init];
working = false;
fadeOutDuration = 0.5;
stepsDivider = 10;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
if(working == false) {
destinationPoint = location;
if(fabsf(location.x - playerNode.position.x) > fabsf(location.y - playerNode.position.y)) {
numberOfSteps = fabsf(location.x - playerNode.position.x) / 10;
} else {
numberOfSteps = fabsf(location.y - playerNode.position.y) / 10;
}
xIncrement = (location.x - playerNode.position.x) / numberOfSteps;
yIncrement = (location.y - playerNode.position.y) / numberOfSteps;
working = true;
}
}
}
-(void)update:(CFTimeInterval)currentTime {
if (working == true) {
// create trail node at current player's position
SKSpriteNode *myNode = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size:CGSizeMake(30, 30)];
myNode.position = playerNode.position;
[self addChild:myNode];
[myArray addObject:myNode];
[myNode runAction:[SKAction fadeOutWithDuration:fadeOutDuration]];
// check array for any nodes with zero alpha
for(SKSpriteNode *object in myArray) {
if(object.alpha == 0) {
[myDiscardArray addObject:object];
}
}
// remove zero alpha nodes
if([myDiscardArray count] > 0) {
[myArray removeObjectsInArray:myDiscardArray];
[myDiscardArray removeAllObjects];
}
// update player's new position
playerNode.position = CGPointMake(playerNode.position.x+xIncrement, playerNode.position.y+yIncrement);
// check if player has arrived at destination
if(((int)playerNode.position.x == (int)destinationPoint.x) && ((int)playerNode.position.y == (int)destinationPoint.y)) {
working = false;
}
}
}
@end
我想在我的 Spritekit 游戏中实现这种效果,其中角色后面有一条 平滑 轨迹。
在 Jetpack joyride 中查看硬币背后的踪迹:
木星跳跃英雄背后的这条线索:
或者 Ski Safari 英雄背后的这条超级平滑的小径:
这似乎是其他游戏引擎的标准功能?我认为 spritekit 粒子发射器只会提供 blocky/stamped 轨迹,而不是平滑轨迹。我应该使用某种精灵自定义着色器吗?还有其他创造性的想法吗?
您的问题没有包含要使用的运动类型这一关键问题。我的答案是基于触摸屏幕的目标点,但另一种选择是使用核心运动。无论使用哪种方法,基本代码原则都保持不变。只有实现会改变。
我在示例中使用了矩形尾部图像,因为我希望您能够复制和 运行 示例代码。您应该将矩形替换为圆形 image/texture 以使尾巴的侧面更光滑。
修改 fadeOutDuration 值将导致更长或更短的尾巴持续时间。
修改stepsDivider会导致尾部节点增加或减少
#import "GameScene.h"
@implementation GameScene {
SKSpriteNode *playerNode;
CGPoint destinationPoint;
NSMutableArray *myArray;
NSMutableArray *myDiscardArray;
BOOL working;
int numberOfSteps;
float xIncrement;
float yIncrement;
float fadeOutDuration;
int stepsDivider;
}
-(void)didMoveToView:(SKView *)view {
self.backgroundColor = [SKColor blackColor];
playerNode = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size:CGSizeMake(30, 30)];
playerNode.position = CGPointMake(200, 200);
[self addChild:playerNode];
myArray = [[NSMutableArray alloc] init];
myDiscardArray = [[NSMutableArray alloc] init];
working = false;
fadeOutDuration = 0.5;
stepsDivider = 10;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
if(working == false) {
destinationPoint = location;
if(fabsf(location.x - playerNode.position.x) > fabsf(location.y - playerNode.position.y)) {
numberOfSteps = fabsf(location.x - playerNode.position.x) / 10;
} else {
numberOfSteps = fabsf(location.y - playerNode.position.y) / 10;
}
xIncrement = (location.x - playerNode.position.x) / numberOfSteps;
yIncrement = (location.y - playerNode.position.y) / numberOfSteps;
working = true;
}
}
}
-(void)update:(CFTimeInterval)currentTime {
if (working == true) {
// create trail node at current player's position
SKSpriteNode *myNode = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size:CGSizeMake(30, 30)];
myNode.position = playerNode.position;
[self addChild:myNode];
[myArray addObject:myNode];
[myNode runAction:[SKAction fadeOutWithDuration:fadeOutDuration]];
// check array for any nodes with zero alpha
for(SKSpriteNode *object in myArray) {
if(object.alpha == 0) {
[myDiscardArray addObject:object];
}
}
// remove zero alpha nodes
if([myDiscardArray count] > 0) {
[myArray removeObjectsInArray:myDiscardArray];
[myDiscardArray removeAllObjects];
}
// update player's new position
playerNode.position = CGPointMake(playerNode.position.x+xIncrement, playerNode.position.y+yIncrement);
// check if player has arrived at destination
if(((int)playerNode.position.x == (int)destinationPoint.x) && ((int)playerNode.position.y == (int)destinationPoint.y)) {
working = false;
}
}
}
@end