SpriteKit: отправлено касание / наведение курсора мыши на освобожденный объект

#objective-c #sprite-kit #scenekit

#objective-c #sprite-kit #scenekit

Вопрос:

У меня проблема в том, что touchesEnded (на iOS) или mouseUp (на macOS) по-прежнему вызываются для выпущенных объектов, когда касание / щелчок был запущен до выпуска. Такое поведение вызывает сбои в моем проекте. Я создал урезанную программу с SceneKit и наложением SpriteKit, но я не уверен, что я делаю неправильно.

Я начал с игрового шаблона SceneKit (iOS или macOS) и добавил два класса:


В GameViewController.m в конце -(void)awakeFromNib я добавил это:

 OverlayScene *overlay=[OverlayScene sceneWithSize:self.gameView.frame.size];// init the overlay
[overlay setupButtons];// create a small GUI menu
[self.gameView setOverlaySKScene:overlay];// add the overlay to the SceneKit view
  

Затем два класса
OverlayScene.m:

 #import <SpriteKit/SpriteKit.h>
#import "Button.h"

@interface OverlayScene : SKScene
-(void)setupButtons;
@end
  

OverlayScene.m:

 #import "OverlayScene.h"
@implementation OverlayScene

-(void)setupButtons{//showing a menu mockup 
    NSLog(@"setupButtons");
    srand((unsigned)time(NULL));// seed the RNG
    [self removeAllChildren];//remove all GUI element (only one button or nothing (in the first call)
    Button *b=[[Button alloc] initWithSelector:@selector(setupButtons) onObject:self];// a new button
    b.position=CGPointMake(rand()%300, rand()%300);// just a random position so we can see the change
    [self addChild:b];// finally attach the button to the scene
}

@end
  

Button.h:

 #import <SpriteKit/SpriteKit.h>
@interface Button : SKSpriteNode{
    SEL selector;//the method which is supposed to be called by the button
    __weak id selectorObj;//the object on which the selector is called
}
-(id)initWithSelector:(SEL)s onObject:(__weak id)o;
@end
  

Button.m:

 #import "Button.h"
@implementation Button
-(id)initWithSelector:(SEL)s onObject:(__weak id)o{
    //self=[super initWithColor:[UIColor purpleColor] size:CGSizeMake(200, 60)];//this is the code for iOS
    self=[super initWithColor:[NSColor purpleColor] size:CGSizeMake(200, 60)];// this is for macOS
    selector=s;//keep the selector with the button
    selectorObj=o;
    [self setUserInteractionEnabled:YES];//enable touch handling
    return self;
}
//-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{//called on iOS
-(void)mouseDown:(NSEvent *)event{//called on macOS
    [selectorObj performSelector:selector];//we are calling the method which was given during the button initialization
}
@end
  

Когда вы нажимаете на кнопку, она удаляется (и освобождается по дуге), как и ожидалось, и создается новая. Все в порядке, пока вы продолжаете удерживать нажатой кнопку мыши. Когда вы отпускаете его, приложение вылетает, потому что это событие наведения мыши отправляется на удаленную кнопку:
введите описание изображения здесь

Комментарии:

1. похоже, ваши имена переменных очень трудно читать, но почему вы вызываете кнопки настройки внутри вашего селектора? Вы удаляете свои кнопки с помощью remove all, тем самым получая свои ошибки

2. Если вы могли бы предоставить проект, я посмотрю на него сегодня вечером

3. Хорошо, вот что происходит, mouseUp ищет кнопку, но кнопка не существует, похоже, в коде mouseUp есть дефект, который не проверяет, существует ли кнопка, прежде чем запускать событие для нее. Вам придется как-то сохранить его и удалить в конечном обновлении

4. Предполагается, что mouseDragged не будет запущен, как и mouseUp, если объект равен нулю, но есть ошибка с набором сцен с наложением набора спрайтов. По-видимому, я видел еще одну проблему с этим, но код был неясен, и я предположил, что это только набор спрайтов, поэтому я найду его завтраи также сообщите об этом пользователю.

5. ну, технически, это и то, и другое, вы не должны удалять вещи из своей сцены с набором спрайтов до конца обновления по причинам, которые вы наблюдаете. Конечно, это в основном мое мнение, но с точки зрения дизайна имеет смысл убивать только в конце обновления, потому что мне нравится рассматривать каждое обновление как замороженный момент времени, оценивать этот момент, а затем, когда вы будете готовы разморозить время, вносить изменения.