mirror of https://github.com/LIJI32/SameBoy.git
Swipe controls option, improve dpad angle thresholds
This commit is contained in:
parent
413212f993
commit
defd8d4f69
|
@ -5,4 +5,5 @@
|
|||
@interface GBBackgroundView : UIImageView
|
||||
@property (readonly) GBView *gbView;
|
||||
@property (nonatomic) GBLayout *layout;
|
||||
@property (nonatomic) bool usesSwipePad;
|
||||
@end
|
||||
|
|
|
@ -29,9 +29,59 @@ static void positionView(UIImageView *view, CGPoint position)
|
|||
};
|
||||
}
|
||||
|
||||
static GB_key_mask_t angleToKeyMask(double angle)
|
||||
{
|
||||
signed quantizedAngle = round(angle / M_PI * 16);
|
||||
if (quantizedAngle < 0) {
|
||||
quantizedAngle += 32;
|
||||
}
|
||||
switch (quantizedAngle) {
|
||||
case 32:
|
||||
case 0: return GB_KEY_RIGHT_MASK;
|
||||
case 1: return GB_KEY_RIGHT_MASK;
|
||||
case 2: return GB_KEY_RIGHT_MASK;
|
||||
case 3: return GB_KEY_RIGHT_MASK | GB_KEY_DOWN_MASK;
|
||||
case 4: return GB_KEY_RIGHT_MASK | GB_KEY_DOWN_MASK;
|
||||
case 5: return GB_KEY_DOWN_MASK;
|
||||
case 6: return GB_KEY_DOWN_MASK;
|
||||
case 7: return GB_KEY_DOWN_MASK;
|
||||
|
||||
case 8: return GB_KEY_DOWN_MASK;
|
||||
case 9: return GB_KEY_DOWN_MASK;
|
||||
case 10: return GB_KEY_DOWN_MASK;
|
||||
case 11: return GB_KEY_LEFT_MASK | GB_KEY_DOWN_MASK;
|
||||
case 12: return GB_KEY_LEFT_MASK | GB_KEY_DOWN_MASK;
|
||||
case 13: return GB_KEY_LEFT_MASK;
|
||||
case 14: return GB_KEY_LEFT_MASK;
|
||||
case 15: return GB_KEY_LEFT_MASK;
|
||||
|
||||
case 16: return GB_KEY_LEFT_MASK;
|
||||
case 17: return GB_KEY_LEFT_MASK;
|
||||
case 18: return GB_KEY_LEFT_MASK;
|
||||
case 19: return GB_KEY_LEFT_MASK | GB_KEY_UP_MASK;
|
||||
case 20: return GB_KEY_LEFT_MASK | GB_KEY_UP_MASK;
|
||||
case 21: return GB_KEY_UP_MASK;
|
||||
case 22: return GB_KEY_UP_MASK;
|
||||
case 23: return GB_KEY_UP_MASK;
|
||||
|
||||
case 24: return GB_KEY_UP_MASK;
|
||||
case 25: return GB_KEY_UP_MASK;
|
||||
case 26: return GB_KEY_UP_MASK;
|
||||
case 27: return GB_KEY_RIGHT_MASK | GB_KEY_UP_MASK;
|
||||
case 28: return GB_KEY_RIGHT_MASK | GB_KEY_UP_MASK;
|
||||
case 29: return GB_KEY_RIGHT_MASK;
|
||||
case 30: return GB_KEY_RIGHT_MASK;
|
||||
case 31: return GB_KEY_RIGHT_MASK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@implementation GBBackgroundView
|
||||
{
|
||||
NSMutableSet<UITouch *> *_touches;
|
||||
UITouch *_swipePadTouch;
|
||||
CGPoint _swipeOrigin;
|
||||
UIImageView *_dpadView;
|
||||
UIImageView *_dpadShadowView;
|
||||
UIImageView *_aButtonView;
|
||||
|
@ -79,10 +129,24 @@ static void positionView(UIImageView *view, CGPoint position)
|
|||
|
||||
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
static const double dpadRadius = 75;
|
||||
CGPoint dpadLocation = _layout.dpadLocation;
|
||||
double factor = [UIScreen mainScreen].scale;
|
||||
dpadLocation.x /= factor;
|
||||
dpadLocation.y /= factor;
|
||||
for (UITouch *touch in touches) {
|
||||
if (CGRectContainsPoint(self.gbView.frame, [touch locationInView:self])) {
|
||||
CGPoint point = [touch locationInView:self];
|
||||
if (CGRectContainsPoint(self.gbView.frame, point)) {
|
||||
[self.window.rootViewController presentViewController:[GBMenuViewController menu] animated:true completion:nil];
|
||||
}
|
||||
|
||||
if (_usesSwipePad && !_swipePadTouch) {
|
||||
if (fabs(point.x - dpadLocation.x) <= dpadRadius &&
|
||||
fabs(point.y - dpadLocation.y) <= dpadRadius) {
|
||||
_swipePadTouch = touch;
|
||||
_swipeOrigin = point;
|
||||
}
|
||||
}
|
||||
}
|
||||
[_touches unionSet:touches];
|
||||
[self touchesChanged];
|
||||
|
@ -90,6 +154,9 @@ static void positionView(UIImageView *view, CGPoint position)
|
|||
|
||||
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
if ([touches containsObject:_swipePadTouch]) {
|
||||
_swipePadTouch = nil;
|
||||
}
|
||||
[_touches minusSet:touches];
|
||||
[self touchesChanged];
|
||||
}
|
||||
|
@ -111,9 +178,28 @@ static void positionView(UIImageView *view, CGPoint position)
|
|||
GB_key_mask_t mask = 0;
|
||||
double factor = [UIScreen mainScreen].scale;
|
||||
double buttonRadiusSquared = 36 * 36 * factor * factor;
|
||||
double dpadRadiusSquared = 75 * 75 * factor * factor;
|
||||
double dpadRadius = 75 * factor;
|
||||
bool dpadHandled = false;
|
||||
if (_usesSwipePad) {
|
||||
dpadHandled = true;
|
||||
if (_swipePadTouch) {
|
||||
CGPoint point = [_swipePadTouch locationInView:self];
|
||||
double squaredDistance = CGPointSquaredDistance(point, _swipeOrigin);
|
||||
if (squaredDistance > 16 * 16) {
|
||||
double angle = CGPointAngle(point, _swipeOrigin);
|
||||
mask |= angleToKeyMask(angle);
|
||||
if (squaredDistance > 24 * 24) {
|
||||
double deltaX = point.x - _swipeOrigin.x;
|
||||
double deltaY = point.y - _swipeOrigin.y;
|
||||
double distance = sqrt(squaredDistance);
|
||||
_swipeOrigin.x = point.x - deltaX / distance * 24;
|
||||
_swipeOrigin.y = point.y - deltaY / distance * 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (UITouch *touch in _touches) {
|
||||
if (touch == _swipePadTouch) continue;
|
||||
CGPoint point = [touch locationInView:self];
|
||||
point.x *= factor;
|
||||
point.y *= factor;
|
||||
|
@ -129,31 +215,12 @@ static void positionView(UIImageView *view, CGPoint position)
|
|||
else if (CGPointSquaredDistance(point, _layout.selectLocation) <= buttonRadiusSquared) {
|
||||
mask |= GB_KEY_SELECT_MASK;
|
||||
}
|
||||
else if (!dpadHandled && CGPointSquaredDistance(point, _layout.dpadLocation) <= dpadRadiusSquared) {
|
||||
else if (!dpadHandled &&
|
||||
fabs(point.x - _layout.dpadLocation.x) <= dpadRadius &&
|
||||
fabs(point.y - _layout.dpadLocation.y) <= dpadRadius) {
|
||||
dpadHandled = true; // Don't handle the dpad twice
|
||||
double angle = CGPointAngle(point, _layout.dpadLocation);
|
||||
signed quantizedAngle = round(angle / M_PI * 6);
|
||||
if (quantizedAngle < 0) {
|
||||
quantizedAngle += 12;
|
||||
}
|
||||
switch (quantizedAngle) {
|
||||
case 12:
|
||||
case 0 : mask |= GB_KEY_RIGHT_MASK; break;
|
||||
case 1 : mask |= GB_KEY_RIGHT_MASK | GB_KEY_DOWN_MASK; break;
|
||||
case 2 : mask |= GB_KEY_DOWN_MASK; break;
|
||||
|
||||
case 3 : mask |= GB_KEY_DOWN_MASK; break;
|
||||
case 4 : mask |= GB_KEY_LEFT_MASK | GB_KEY_DOWN_MASK; break;
|
||||
case 5 : mask |= GB_KEY_LEFT_MASK; break;
|
||||
|
||||
case 6 : mask |= GB_KEY_LEFT_MASK; break;
|
||||
case 7 : mask |= GB_KEY_LEFT_MASK | GB_KEY_UP_MASK; break;
|
||||
case 8 : mask |= GB_KEY_UP_MASK; break;
|
||||
|
||||
case 9: mask |= GB_KEY_UP_MASK; break;
|
||||
case 10: mask |= GB_KEY_RIGHT_MASK | GB_KEY_UP_MASK; break;
|
||||
case 11: mask |= GB_KEY_RIGHT_MASK; break;
|
||||
}
|
||||
mask |= angleToKeyMask(angle);
|
||||
}
|
||||
}
|
||||
if (mask != _lastMask) {
|
||||
|
@ -180,7 +247,13 @@ static void positionView(UIImageView *view, CGPoint position)
|
|||
|
||||
_dpadShadowView.hidden = hidden;
|
||||
if (!hidden) {
|
||||
_dpadShadowView.image = [UIImage imageNamed:diagonal? @"dpadShadowDiagonal" : @"dpadShadow"];
|
||||
if (_usesSwipePad) {
|
||||
_dpadShadowView.image = [UIImage imageNamed:diagonal? @"swipepadShadowDiagonal" : @"swipepadShadow"];
|
||||
|
||||
}
|
||||
else {
|
||||
_dpadShadowView.image = [UIImage imageNamed:diagonal? @"dpadShadowDiagonal" : @"dpadShadow"];
|
||||
}
|
||||
_dpadShadowView.transform = CGAffineTransformMakeRotation(rotation);
|
||||
}
|
||||
|
||||
|
@ -228,4 +301,10 @@ static void positionView(UIImageView *view, CGPoint position)
|
|||
_screenLabel.frame = screenFrame;
|
||||
}
|
||||
|
||||
- (void)setUsesSwipePad:(bool)usesSwipePad
|
||||
{
|
||||
_usesSwipePad = usesSwipePad;
|
||||
_dpadView.image = [UIImage imageNamed:usesSwipePad? @"swipepad" : @"dpad"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -160,7 +160,7 @@ contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
|
|||
[self renameRow:indexPath];
|
||||
}],
|
||||
[UIAction actionWithTitle:@"Duplicate"
|
||||
image:[UIImage systemImageNamed:@"plus.rectangle.on.rectangle"]
|
||||
image:[UIImage systemImageNamed:@"plus.square.on.square"]
|
||||
identifier:nil
|
||||
handler:^(__kindof UIAction *action) {
|
||||
[[GBROMManager sharedManager] duplicateROM:[GBROMManager sharedManager].allROMs[[indexPath indexAtPosition:1]]];
|
||||
|
|
|
@ -283,14 +283,14 @@ static NSString const *typeLightTemp = @"typeLightTemp";
|
|||
@"header": @"D-pad Style",
|
||||
@"items": @[
|
||||
// TODO: Convert to enum when implemented
|
||||
@{@"type": typeRadio, @"pref": @"GBDpadMode", @"title": @"Standard", @"value": @(0),},
|
||||
@{@"type": typeRadio, @"pref": @"GBDpadMode", @"title": @"Swipe", @"value": @(1),},
|
||||
@{@"type": typeRadio, @"pref": @"GBSwipeDpad", @"title": @"Standard", @"value": @NO,},
|
||||
@{@"type": typeRadio, @"pref": @"GBSwipeDpad", @"title": @"Swipe", @"value": @YES,},
|
||||
],
|
||||
@"footer": ^NSString *(){
|
||||
return (NSString * const[]){
|
||||
[0] = @"Directional input is determined by the touch position.",
|
||||
[1] = @"Directional input is determined by the swipe direction.",
|
||||
}[MIN(1, [[NSUserDefaults standardUserDefaults] integerForKey:@"GBDpadMode"])];
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBSwipeDpad"]) {
|
||||
return @"Directional input is determined by the swipe direction.";
|
||||
}
|
||||
return @"Directional input is determined by the touch position.";
|
||||
},
|
||||
},
|
||||
@{
|
||||
|
|
|
@ -156,10 +156,15 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBFilterChanged" object:nil];
|
||||
} forKey:@"GBFilter"];
|
||||
|
||||
__weak GBView *weakGBView = _gbView;
|
||||
__weak GBView *gbview = _gbView;
|
||||
[self addDefaultObserver:^(id newValue) {
|
||||
weakGBView.frameBlendingMode = [newValue integerValue];
|
||||
gbview.frameBlendingMode = [newValue integerValue];
|
||||
} forKey:@"GBFrameBlendingMode"];
|
||||
|
||||
__weak GBBackgroundView *backgroundView = _backgroundView;
|
||||
[self addDefaultObserver:^(id newValue) {
|
||||
backgroundView.usesSwipePad = [newValue boolValue];
|
||||
} forKey:@"GBSwipeDpad"];
|
||||
|
||||
|
||||
[self willRotateToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
Loading…
Reference in New Issue