我用两种移动方法制作游戏。当点击屏幕时,玩家向上移动。游戏世界也朝向玩家看起来像鸟儿飞向前方。当用户按住屏幕上的时候,玩家将开始向前飞行。当玩家根本没有触摸屏幕时,玩家会摔倒(几乎像飞鸟一样)。
游戏工作得非常顺利,直到我添加了长按方法。因为一秒太短,它会被检测为水龙头。因此,当我快速点击屏幕2次时,长按方法也会被调用。所以我认为必须有另一种方式,而不是使用长按手势?
有没有办法以编程方式检测内部触摸并触摸并保持spritekit?我知道你可以在按钮上的UIKit单视图应用程序中执行此操作。
但我需要让它在屏幕上的任何地方都能正常工作,而不仅仅是点击按钮。
我使用Spritekit作为游戏技术,Xcode作为平台。
有什么想法吗?
答案 0 :(得分:2)
这是一个完整的解决方案。点击跳转块,按住屏幕向前移动。当你触摸墙壁时,你将重置位置。
Swift3:
class Bird: SKSpriteNode {
private let flyUpImpulse = CGVector(dx: 0, dy: 20)
private let flyForwardForce = CGVector(dx: 100, dy: 0)
// var pb: SKPhysicsBody { return self.physicsBody! }
func initialize() {
color = .blue
size = CGSize(width: 50, height: 50)
physicsBody = SKPhysicsBody(rectangleOf: size)
physicsBody!.categoryBitMask = UInt32(1)
}
func flyUp() {
physicsBody!.applyImpulse(flyUpImpulse)
}
func flyForward() {
physicsBody!.applyForce(flyForwardForce)
}
func resetPosition() {
guard let scene = self.scene else {
print("reset position failed: bird has not been added to scene yet!")
return
}
run(.move(to: CGPoint(x: scene.frame.minX + 50, y: scene.frame.midY), duration: 0))
physicsBody!.velocity = CGVector.zero
}
}
class GameScene: SKScene, SKPhysicsContactDelegate {
enum ControlToDo { case tap, longPress, none }
var controlToDo = ControlToDo.none
// How many frames we have to release screen in order to recognize a "tap".
// Less frames will give a faster response time, but may also give incorrect input:
let tapThreshold = 10
var isTouchingScreen = false
var frameCountSinceFirstTouch = 0
let bird = Bird()
// Scene setup:
override func didMove(to view: SKView) {
removeAllChildren() // Remove this from your actual project.
anchorPoint = CGPoint(x: 0.5, y: 0.5)
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
physicsBody!.categoryBitMask = UInt32(2)
physicsBody!.contactTestBitMask = UInt32(1)
physicsWorld.gravity = CGVector(dx: 0, dy: -2)
physicsWorld.contactDelegate = self
bird.initialize()
addChild(bird)
}
// Touch handling stuff:
func tap() {
bird.flyUp()
controlToDo = .none
}
func longPress() {
bird.flyForward()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
isTouchingScreen = true
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
isTouchingScreen = false
if frameCountSinceFirstTouch > tapThreshold {
controlToDo = .none
frameCountSinceFirstTouch = 0
}
else if frameCountSinceFirstTouch < tapThreshold {
controlToDo = .tap
frameCountSinceFirstTouch = 0
}
}
override func update(_ currentTime: TimeInterval) {
// Increase counter if touching the screen:
if isTouchingScreen {
frameCountSinceFirstTouch += 1
}
// If we have held the screen for long enough, do a longPress:
if frameCountSinceFirstTouch > tapThreshold {
controlToDo = .longPress
}
switch controlToDo {
case .tap: tap()
case .longPress: longPress()
case .none: break
}
}
// Reset positon on touch of wall:
func didBegin(_ contact: SKPhysicsContact) {
bird.resetPosition()
}
}
目标C:
// MAKE SURE YOU HAVE <SKPhysicsContactDelegate> in your .h file!
#import "GameScene.h"
@implementation GameScene {
SKSpriteNode *_bird;
/// 1 is tap, 2 is longpress (i couldn't figure out how to compare strings, or do an enum)
int _controlToDo;
CGFloat _tapThreshold;
CGFloat _frameCountSinceFirstTouch;
Boolean _isTouchingScreen;
}
- (void) setupProperties {
_controlToDo = 0;
_tapThreshold = 10;
_isTouchingScreen = false;
_frameCountSinceFirstTouch = 0;
}
- (void) setupScene {
self.anchorPoint = CGPointMake(0.5, 0.5);
[self removeAllChildren];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody.categoryBitMask = 2;
self.physicsBody.contactTestBitMask = 1;
self.physicsWorld.gravity = CGVectorMake(0, -2);
self.physicsWorld.contactDelegate = self;
_bird = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(50, 50)];
_bird.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_bird.size];
_bird.physicsBody.categoryBitMask = 1;
[self addChild:_bird];
}
- (void) birdResetPosition {
CGFloat min = 0 - (self.size.width / 2) + (_bird.size.width / 2) + 5;
CGPoint center = CGPointMake(min, 0);
SKAction *movement = [SKAction moveTo:center duration:0];
[_bird runAction:movement];
}
- (void)didMoveToView:(SKView *)view {
[self setupProperties];
[self setupScene];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
_isTouchingScreen = true;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
_isTouchingScreen = false;
if (_frameCountSinceFirstTouch > _tapThreshold) {
_controlToDo = 0;
}
else if (_frameCountSinceFirstTouch < _tapThreshold) {
_controlToDo = 1;
}
_frameCountSinceFirstTouch = 0;
}
-(void)update:(CFTimeInterval)currentTime {
// Increase counter if touching the screen:
if (_isTouchingScreen == true) {
_frameCountSinceFirstTouch += 1;
}
// If we have held the screen for long enough, do a longPress:
if (_frameCountSinceFirstTouch > _tapThreshold) {
_controlToDo = 2;
}
// Bird fly up:
if (_controlToDo == 1) {
[_bird.physicsBody applyImpulse:CGVectorMake(0, 20)];
_controlToDo = 0;
}
// Bird fly forward:
else if (_controlToDo == 2) {
[_bird.physicsBody applyForce:CGVectorMake(100, 0)];
}
}
- (void) didBeginContact:(SKPhysicsContact *)contact {
[self birdResetPosition];
_bird.physicsBody.velocity = CGVectorMake(0, 0);
}
@end
答案 1 :(得分:1)
所有SKNode都可以访问触摸事件,您只需启用userInteractionEnabled
默认设置为false
,但如果您使用的是SKS文件,则SKS默认设置为true
只要您没有启用任何其他节点,当您触摸场景时,它将为场景触发。
要举行暂停活动,我建议您在场景中使用SKAction
。
基本上,我们希望等待特定时间段,然后触发事件
如果在任何时候手指被移除,那么我们会移除动作,而不会触发你的事件。
夫特:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let wait = SKAction.wait(forDuration:1)
let beginHoldEvent = SKAction(run:{//function to start hold event})
run(SKAction.sequence([wait,beginHoldEvent],withKey:"holding")
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
guard let _ = action(forKey:"holding") else {return}
removeAction(forKey:"holding")
//do single click event
}
目标C:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
void (^holdBlock)(void) = ^{
//do holding code here
};
SKAction* wait = [SKAction waitForDuration:1];
SKAction* beginHoldEvent = [SKAction runBlock:holdBlock];
SKAction* seq = [SKAction sequence:@[wait,beghinHoldEvent]];
[self runAction:seq withKey:@"holding"];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if([self actionForKey:@"holding"] == nil){
//we are on a long touch do nothing
return;
}
[self removeActionForKey:@"holding")];
//do tap event
}
现在这段代码不能处理多个触摸,你需要处理它。