Hi currently my game is loading fl_gfood.png or fl_bfood.png from the fl_food.plist. That works fine but now I have 17 bad food items .png and 17 good food items .png. My question is how do I randomly display one of the 17 items from each group? Can I just do a wildcard for the sprite png file name? See code comment below. Also a suggestion was made that I could possibly load the .plist file names into an array and randomly pick a name, how would that be done.
#implementation Food
+ (void)loadAssets {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[FLSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:[AssetHelper getDeviceSpecificFileNameFor:#"fl_food.plist"]];
});
}
- (id)init {
self = [super init];
if (self) {
self.size = CGSizeMake(16 * __HIGHRES_SCALE, 16 * __HIGHRES_SCALE);
self.offset = CGPointMake(8 * __HIGHRES_SCALE, 8 * __HIGHRES_SCALE);
self.removeAfterCollision = YES;
self.collideable = NO;
self.score = 10;
}
return self;
}
- (FLSprite *)sprite {
if(_sprite == nil) {
if(self.score < 10) {
_sprite = [FLSprite spriteWithSpriteFrameName:#"fl_gfood.png"]; // fl_gfood_*.png ... Can I do something like this?
} else {
_sprite = [FLSprite spriteWithSpriteFrameName:#"fl_bfood.png"];
}
}
return _sprite;
}
I would use arc4random() and stringByAppendingString
- (FLSprite *)sprite {
if(_sprite == nil) {
NSString *disFood;
disFood = (self.score < 10) ? #"fl_gfood" : #"fl_bfood";
//random # between 1 - 10
int randNum = (arc4random() % 10)+1;
NSString *formattedName = [NSString stringWithFormat:#"_%i.png",randNum];
disFood = [disFood stringByAppendingString:formattedName];
_sprite = [FLSprite spriteWithSpriteFrameName:disFood];
NSLog(disFood);//Logging disFood String;
}
return _sprite;
}
Related
I am trying to capture the face area.
Here is what I do , in didOutputMetadataObjects: is get the AVMetadataFaceObject and process it in didOutputSampleBuffer
didOutputMetadataObjects shows marker correctly, where I consider the Yaw, roll axis
What could be the best possible way, where I get only the face area and at the same time I see a face marker?
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
for(AVMetadataObject *metaObject in metadataObjects){
if([metaObject isKindOfClass:[AVMetadataFaceObject class ]] && metaObject.type == AVMetadataObjectTypeFace){
AVMetadataFaceObject * adjustedMeta = (AVMetadataFaceObject*)[self.videoLayer transformedMetadataObjectForMetadataObject:metaObject];
self.metaFaceObject= adjustedMeta;
//Draw the face marker here
}
}
}
AVCaptureVideoDataOutputSampleBufferDelegate
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
if(pixelBuffer ){
CFDictionaryRef attachments = CMCopyDictionaryOfAttachments( kCFAllocatorDefault, sampleBuffer, kCMAttachmentMode_ShouldPropagate );
CIImage *ciImage = [[CIImage alloc] initWithCVPixelBuffer:pixelBuffer options:(__bridge NSDictionary<NSString *,id> * _Nullable)(attachments)];
ciImage = [ciImage imageByCroppingToRect:self.metaFaceObject.bounds];
//This Image is upside down. Second thing the it does not have the face.
UIImage *image=[UIImage imageWithCIImage:ciImage];
}
}
hello some suggests below:
1: add a stillImageOutPut
lazy var stillImageOutPut: AVCaptureStillImageOutput = {
let imageOutPut = AVCaptureStillImageOutput.init()
return imageOutPut
}()
2 add to session
if session.canAddOutput(stillImageOutPut){
session.addOutput(stillImageOutPut)
}
3 then implement this delegate function
// MARK: AVCaptureMetadataOutputObjectsDelegate
extension ZHFaceDetectorViewController: AVCaptureMetadataOutputObjectsDelegate {
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
printLog(Thread.current)
let metadataObject = metadataObjects.first
if let object = metadataObject {
while !hasDetectorFace {
if object.type == AVMetadataObject.ObjectType.face{
hasDetectorFace = true
DispatchQueue.global().async {
if let stillImageConnection = self.stillImageOutPut.connection(with: AVMediaType.video){
printLog(stillImageConnection)
printLog(connection)
stillImageConnection.videoOrientation = AVCaptureVideoOrientation(rawValue: UIDevice.current.orientation.rawValue)!
/// prepare settings 如果不设置 截取照片时屏幕会闪白
let settings = AVCaptureAutoExposureBracketedStillImageSettings.autoExposureSettings(exposureTargetBias: AVCaptureDevice.currentExposureTargetBias)
/// begin capture
self.stillImageOutPut.prepareToCaptureStillImageBracket(from: stillImageConnection, withSettingsArray: [settings], completionHandler: { (complete, error) in
if error == nil {
self.stillImageOutPut.captureStillImageAsynchronously(from: stillImageConnection, completionHandler: { (imageDataSampleBuffer, error) in
printLog(imageDataSampleBuffer)
printLog(error)
if error == nil {
if let sampleBuffer = imageDataSampleBuffer {
if let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer){
if let image = UIImage(data: imageData) {
/// operater your image
printLog(image)
}
}
}
}else{
printLog("something was wrong")
}
})
}
})
}
}
}
}
}
}
}
4 then i get my picture
log info
I'm wondering if it's possible to get any tab/window info from safari programmatically?
Is there a library to do it?
I'd prefer not applescript, as I've found that - I'd like to know if, and how it's possible in the Cocoa framework.
You can do this with Scripting Bridge, which is like AppleScript translated into Objective-C, or with accessibility objects, which you can inspect with Developer Tool Accessibility Inspector. Both technogies have their quirks and aren't documented very well.
Edit:
Scripting Bridge example:
SafariApplication *SafariApp = [SBApplication applicationWithBundleIdentifier:#"com.apple.Safari"];
for (SafariWindow *window in SafariApp.windows)
{
for (SafariTab *tab in window.tabs)
NSLog(#"%#", tab.name);
}
The hierarchy of accessibility objects in Safari is
AXApplication
AXWindow
AXTabGroup
AXRadioButton
Example (doesn't win a prize in a beauty contest):
static NSArray *getAXUIElements(AXUIElementRef theContainer, CFStringRef theRole)
{
// get children of theContainer
AXError error;
NSMutableArray *array = [NSMutableArray array];
CFTypeRef children;
error = AXUIElementCopyAttributeValue(theContainer, kAXChildrenAttribute, &children);
if (error != kAXErrorSuccess)
return nil;
// filter children whose role is theRole
for (CFIndex i = 0; i < CFArrayGetCount(children); i++)
{
AXUIElementRef child = CFArrayGetValueAtIndex(children, i);
CFTypeRef role;
error = AXUIElementCopyAttributeValue(child, kAXRoleAttribute, &role);
if (error == kAXErrorSuccess)
{
if (CFStringCompare(role, theRole, 0) == kCFCompareEqualTo)
[array addObject:(__bridge id)child];
CFRelease(role);
}
}
CFRelease(children);
return [NSArray arrayWithArray:array];
}
static void logTabs()
{
// get the title of every tab of every window of Safari
NSArray *appArray = [NSRunningApplication runningApplicationsWithBundleIdentifier:#"com.apple.Safari"];
AXUIElementRef SafariApp = AXUIElementCreateApplication([[appArray objectAtIndex:0] processIdentifier]);
if (SafariApp)
{
NSArray *windowArray = getAXUIElements(SafariApp, kAXWindowRole);
for (id window in windowArray)
{
NSArray *tabGroupArray = getAXUIElements((__bridge AXUIElementRef)(window), kAXTabGroupRole);
for (id tabGroup in tabGroupArray)
{
NSArray *radioButtonArray = getAXUIElements((__bridge AXUIElementRef)(tabGroup), kAXRadioButtonRole);
for (id radioButton in radioButtonArray)
{
CFTypeRef title = NULL;
AXError error = AXUIElementCopyAttributeValue((__bridge AXUIElementRef)radioButton, kAXTitleAttribute, &title);
if (error == kAXErrorSuccess)
{
NSLog(#"%#", title);
CFRelease(title);
}
}
}
}
CFRelease(SafariApp);
}
}
I've just implemented a share-button, that has a share menu:
[_shareButton sendActionOn:NSLeftMouseDownMask];
And has this action connected:
-(IBAction)share:(id)sender {
NSArray *shareArray = #[#"testShare"];
NSSharingServicePicker *sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:shareArray];
sharingServicePicker.delegate = self;
[sharingServicePicker showRelativeToRect:[sender bounds]
ofView:sender
preferredEdge:NSMinYEdge];
}
Now to my question, I don't want Facebook and Twitter to be an option in the menu. I only want E-Mail and Messages to be available. Also I would like to add "Print", but don't know if I can do that.
Is that possible?
Thanks
(Don't have enough rep points to add 'NSSharingService' as a tag)
Solved it by using proposedSharingServices.
- (NSArray *)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NSArray *)proposedServices{
// Find and the services you want
NSMutableArray *newProposedServices = [[NSMutableArray alloc] initWithCapacity:5];
for (NSSharingService *sharingService in proposedServices) {
if ([[sharingService title] isEqualToString:#"Email"] || [[sharingService title] isEqualToString:#"Message"]) {
[newProposedServices addObject:sharingService];
}
}
NSArray *services = newProposedServices;
NSSharingService *customService = [[NSSharingService alloc] initWithTitle:#"Print" image:[NSImage imageNamed:#"PrintImage"] alternateImage:nil handler:^{
// Do whatever
}];
services = [services arrayByAddingObject:customService];
return services;
}
Comparing a proposed service to a new named instance works. Here's a trivial Swift code from my project:
let excludedNames = [
NSSharingServiceNamePostOnFacebook,
NSSharingServiceNamePostOnTwitter,
]
var excludedServices = [NSSharingService]()
for name in excludedNames {
if let service = NSSharingService(named: name) {
excludedServices += [service]
}
}
return proposedServices.filter {
!excludedServices.contains($0)
}
No need to use a private name property.
Rather then trying to say what you don't want simply return a list of what you do want.
- (NSArray<NSSharingService *> *)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NSArray<NSSharingService *> *)proposedServices
{
NSArray *result = #[[NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail], [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeMessage]];
return result;
}
A slightly different approach via proposedSharingServices:
- (NSArray*)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NSArray *)proposedServices {
NSArray *excludedServices = #[NSSharingServiceNamePostOnFacebook,
NSSharingServiceNamePostOnTwitter];
NSArray *sharingServices = [proposedServices filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"NOT (name IN %#)", excludedServices]];
return sharingServices;
}
Here's a better way - no private API access required.
NSArray *excludedServices = #[NSSharingServiceNamePostOnFacebook,
NSSharingServiceNamePostOnTwitter];
NSMutableArray *includedServices = [[NSMutableArray alloc] init];
for (NSSharingService *service in proposedServices) {
if ([excludedServices indexOfObject:service] == NSNotFound) {
[includedServices addObject:service];
}
}
return includedServices;
How do I restrict a NSTextField to allow only numbers/integers? I've found questions like this one, but they didn't help!
Try to make your own NSNumberFormatter subclass and check the input value in -isPartialStringValid:newEditingString:errorDescription: method.
#interface OnlyIntegerValueFormatter : NSNumberFormatter
#end
#implementation OnlyIntegerValueFormatter
- (BOOL)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error
{
if([partialString length] == 0) {
return YES;
}
NSScanner* scanner = [NSScanner scannerWithString:partialString];
if(!([scanner scanInt:0] && [scanner isAtEnd])) {
NSBeep();
return NO;
}
return YES;
}
#end
And then set this formatter to your NSTextField:
OnlyIntegerValueFormatter *formatter = [[[OnlyIntegerValueFormatter alloc] init] autorelease];
[textField setFormatter:formatter];
Swift 3 Version
import Foundation
class OnlyIntegerValueFormatter: NumberFormatter {
override func isPartialStringValid(_ partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
// Ability to reset your field (otherwise you can't delete the content)
// You can check if the field is empty later
if partialString.isEmpty {
return true
}
// Optional: limit input length
/*
if partialString.characters.count>3 {
return false
}
*/
// Actual check
return Int(partialString) != nil
}
}
Use:
let onlyIntFormatter = OnlyIntegerValueFormatter()
myNsTextField.formatter = onlyIntFormatter
Here's a solution with filtering. Give a delegate and an outlet to textfield and set controlTextDidChange method.
- (void)controlTextDidChange:(NSNotification *)aNotification {
NSTextField *textfield = [notification object];
NSCharacterSet *charSet = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
char *stringResult = malloc([textfield.stringValue length]);
int cpt=0;
for (int i = 0; i < [textfield.stringValue length]; i++) {
unichar c = [textfield.stringValue characterAtIndex:i];
if ([charSet characterIsMember:c]) {
stringResult[cpt]=c;
cpt++;
}
}
stringResult[cpt]='\0';
textfield.stringValue = [NSString stringWithUTF8String:stringResult];
free(stringResult);
}
Try this -
NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[textField setFormatter:formatter];
Here is a Swift version:
override func isPartialStringValid(partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>) -> Bool {
if (count(partialString.utf16)) {
return true
}
if (partialString.rangeOfCharacterFromSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet) != nil) {
NSBeep()
return false
}
return true
}
In SWIFT, I do it this way
Convert the text value to Int with Int()
Check the converted value is not less than 0
If less than 0, display error message other accept the value
if ((Int(txtField.stringValue)) < 0){
// Display error message
}
[Works with Swift 3.0.1]
As others suggested, subclass NumberFormatter and override isPartialStringValid method. The easiest way is to drop a NumberFormatter object under your NSTextField in xib/storyboard and update it's Custom Class.
Next implementation allows only integers or blank value and plays a beep if string contains illegal characters.
class IntegerFormatter: NumberFormatter {
override func isPartialStringValid(_ partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
// Allow blank value
if partialString.numberOfCharacters() == 0 {
return true
}
// Validate string if it's an int
if partialString.isInt() {
return true
} else {
NSBeep()
return false
}
}
}
String's numberOfCharacters() and isInt() are methods added in an extension.
extension String {
func isInt() -> Bool {
if let intValue = Int(self) {
if intValue >= 0 {
return true
}
}
return false
}
func numberOfCharacters() -> Int {
return self.characters.count
}
}
Here is the steps to create the same....
Just create the ANYCLASS(called SAMPLE) with sub classing the NSNumberFormatter ...
in .m file write the following code...
- (BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **)error {
// Make sure we clear newString and error to ensure old values aren't being used
if (newString) { *newString = nil;}
if (error) {*error = nil;}
static NSCharacterSet *nonDecimalCharacters = nil;
if (nonDecimalCharacters == nil) {
nonDecimalCharacters = [[NSCharacterSet decimalDigitCharacterSet] invertedSet] ;
}
if ([partialString length] == 0) {
return YES; // The empty string is okay (the user might just be deleting everything and starting over)
} else if ([partialString rangeOfCharacterFromSet:nonDecimalCharacters].location != NSNotFound) {
return NO; // Non-decimal characters aren't cool!
}
return YES;
}
Now.. in your Actual Class set the formatter to your NSTextField object like below...
NSTextField *mySampleTxtFld;
for this set the Formatter...
SAMPLE* formatter=[[SAMPLE alloc]init];// create SAMPLE FORMATTER OBJECT
self.mySampleTxtFld.delegate=self;
[self.mySampleTxtFld setFormatter:formatter];
Your done!!!
Swift 2.0 custom formatter with 0 instead of empty space :
class OnlyIntegerValueFormatter: NSNumberFormatter {
override func isPartialStringValid(partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>) -> Bool {
if partialString.isEmpty {
newString.memory = "0"
return false
}
if Int(partialString) < 0 {
NSBeep()
return false
} else {
return true
}
}
}
// NSTextFieldNumberFormatter+Extension.swift
import Foundation
class TextFieldIntegerValueFormatter: NumberFormatter {
var maxLength: Int
init(maxLength: Int) {
self.maxLength = maxLength
super.init()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func isPartialStringValid(_ partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
// Ability to reset your field (otherwise you can't delete the content)
// You can check if the field is empty later
if partialString.isEmpty {
return true
}
// Optional: limit input length
if partialString.count > maxLength {
return false
}
// Actual check
return Int(partialString) != nil
}
}
//Need to call like:
myNsTextField.formatter = TextFieldIntegerValueFormatter(maxLength: 6)
Is it possible to see of a string ends with a number which length is not known?
"String 1" -> 1
"String 4356" -> 4356
"String" -> nil
If so, how can I determine that number?
To test that a string ends with numbers, you can use an NSPredicate, such as:
NSPredicate endsNumerically = [NSPredicate predicateWithFormat:#"SELF matches %#", #"\\d+$"];
[endsNumerically evaluateWithObject:string]; // returns TRUE if predicate succeeds
NSScanner is sometimes useful for extracting things from strings, but it doesn't scan backward. You could define a Gnirts (reverse string) class and use that with an NSScanner, but that's probably more hassle than it's worth.
NSString's rangeOfCharacterFromSet:options:, which I had hope to use, only looks for a single character (it's like strchr and strrchr, if you're familiar with C), but we can roll our own that returns a contiguous range of characters from a set (a little like strspn) as a category on NSString. While we're at it, let's include methods that return substrings rather than ranges.
RangeOfCharacters.h:
#interface NSString (RangeOfCharacters)
/* note "Characters" is plural in the methods. It has poor readability, hard to
* distinguish from the rangeOfCharacterFromSet: methods, but it's standard Apple
* convention.
*/
-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet;
-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask;
-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask range:(NSRange)range;
// like the above, but return a string rather than a range
-(NSString*)substringFromSet:(NSCharacterSet*)aSet;
-(NSString*)substringFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask;
-(NSString*)substringFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask range:(NSRange)range;
#end
RangeOfCharacters.m:
#implementation NSString (RangeOfCharacters)
-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet {
return [self rangeOfCharactersFromSet:aSet options:0];
}
-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask {
NSRange range = {0,[self length]};
return [self rangeOfCharactersFromSet:aSet options:mask range:range];
}
-(NSRange)rangeOfCharactersFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask range:(NSRange)range {
NSInteger start, curr, end, step=1;
if (mask & NSBackwardsSearch) {
step = -1;
start = range.location + range.length - 1;
end = range.location-1;
} else {
start = range.location;
end = start + range.length;
}
if (!(mask & NSAnchoredSearch)) {
// find first character in set
for (;start != end; start += step) {
if ([aSet characterIsMember:[self characterAtIndex:start]]) {
#ifdef NOGOTO
break;
#else
// Yeah, a goto. If you don't like them, define NOGOTO.
// Method will work the same, it will just make unneeded
// test whether character at start is in aSet
goto FoundMember;
#endif
}
}
#ifndef NOGOTO
goto NoSuchMember;
#endif
}
if (![aSet characterIsMember:[self characterAtIndex:start]]) {
NoSuchMember:
// no characters found within given range
range.location = NSNotFound;
range.length = 0;
return range;
}
FoundMember:
for (curr = start; curr != end; curr += step) {
if (![aSet characterIsMember:[self characterAtIndex:curr]]) {
break;
}
}
if (curr < start) {
// search was backwards
range.location = curr+1;
range.length = start - curr;
} else {
range.location = start;
range.length = curr - start;
}
return range;
}
-(NSString*)substringFromSet:(NSCharacterSet*)aSet {
return [self substringFromSet:aSet options:0];
}
-(NSString*)substringFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask {
NSRange range = {0,[self length]};
return [self substringFromSet:aSet options:mask range:range];
}
-(NSString*)substringFromSet:(NSCharacterSet*)aSet options:(NSStringCompareOptions)mask range:(NSRange)range {
NSRange range = [self rangeOfCharactersFromSet:aSet options:mask range:range];
if (NSNotFound == range.location) {
return nil;
}
return [self substringWithRange:range];
}
#end
To use the new category to check that a string ends with digits or to extract the number:
NSString* number = [string substringFromSet:[NSCharacterSet decimalDigitCharacterSet]
options:NSBackwardsSearch|NSAnchoredSearch];
if (number != nil) {
return [number intValue];
} else {
// string doesn't end with a number.
}
Lastly, you can use a third party regular expression library, such as RegexKit or RegexkitLite.
I couldn't get the NSPredicate code above to work correctly, though it looks like it should. Instead I accomplished the same thing with
if ([string rangeOfString:#"\\d+$" options:NSRegularExpressionSearch].location != NSNotFound) {
// string ends with a number
}
Hat-tip to this answer.