I have created a SpriteKit game for shape recognition where there are two same shapes one is at lower part of the scene while other one which is to be matched is at upper side of the scene. I am creating these shapes by calling method from other class which contain code to create the shape.
I am able to do all the things in the proper way and works fine. But I am unable to find that how to make upper side shapes static. Mean user must be able to drag only lower side shapes to upper side shapes for matching but the should not be able to drag upper side shapes to match with lower side shapes. I have so far searched in SpriteKit Programming Guide by Apple but there is no such clue in that that helps me perform the above mentioned task.
Please help me if anyone can.
Easy way to do is set their name when you create them. Use a constant is any easy way so you ensure you are adding / checking the right name.
static NSString * const kCanMoveMe = #"movable";
static NSString * const kCanNotMoveMe = #"not-movable";
// for example
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:imageName];
sprite.name = kCanMoveMe
SKSpriteNode *sprite2 = [SKSpriteNode spriteNodeWithImageNamed:imageName];
sprite.name = kCanNotMoveMe
Then when you touch check the name and then you know if you can move it or not.
You can also leverage the SKNode .userData property to store custom node data for the actual sprite, in your situation if it is movable or not or any other game specific data.
More info here: Apple documentation about the userData property
I suggest subclassing the SKSpriteNode and adding a isMoveable BOOL property to designate if it is able to be moved.
The other answers will definitely work, but both lack advantages of your property being named appropriately and accessible via the Xcode code completion capabilities.
For example in Xcode you would type mySprite.i and the isMoveable BOOL property would be available to choose for code completion.
Related
I can take answers in either Swift or Objective-C.
I'm using SceneKit, and I have a 2D OverlayScene that's displaying on top of the 3D GameScene. I'd like GameScene to be able to reference back and forth between OverlayScene so that I can detect taps, run functions, etc. But whenever I try to create an instance of Overlay, I get various crashes. I have tried a few things, including but not limited to:
/* THIS IS IS MY 3D GAME-SCENE */
// Some crash about not using "init(size:CGSize)".
let overlayScene = SK_OverlayScene()
// There is no such thing as "self.size" in SceneKit.
let overlayScene = SK_OverlayScene(size: self.size)
// Some crazy crash I can't figure out at all.
let overlayScene = SK_OverlayScene(size: myGameViewController.sceneView.bounds.size)
In other words, I have tried many different solutions. If you don't believe that I did one of those solutions correctly, then ask me for the exact code and I'll give it to you.
My question is this: am I even going about this the correct way? Should I be using instances of the overlay scene, or should I be trying to contact the scene directly? I'm not really sure what's wrong here, that's why I'm asking for help.
EDIT: I have already tried to move the code inside OverlayScene's init(size:CGSize) into a simple init(), but that is also giving me problems.
I'm making a tool that will pull data from a .csv and create a grid of images with captions [like "This"] in Cocoa, then export that to a PDF. I do not need to actually display the view, just save a file. As a complete beginner to drawing programmatically, I have some questions about the process:
What class should I use? I'm assuming NSView, but like I said I've never done this before so I'm not sure.
Do I need to specify the pixel coordinates for every single object, or can I make each object relative to another in some way?
How do I create separate pages for the view?
Keep in mind that I read the Apple guides, and while it had some helpful tidbits, overall it was unusually hard for me to comprehend. If someone could explain in layman's terms what I need to know it would be very appreciated! Thank you in advance.
Have a look at NSCollectionView
Overview
NSCollectionView class displays an array of content as a grid of
views. The views are specified using the NSCollectionViewItem class
which makes loadings nibs containing the view easy, and supports
bindings
There are lots of tutorials.
Including:
Cocoa Programming L42 - NSCollectionView
And
Apples own quick guide to Collection Views
And maybe also look at NSDocuments
Overview
The NSDocument abstract class defines the interface for OS X
documents. A document is an object that can internally represent data
displayed in a window and that can read data from and write data to a
file or file package. Documents create and manage one or more window
controllers and are in turn managed by a document controller.
Documents respond to first-responder action messages to save, revert,
and print their data.
Conceptually, a document is a container for a body of information
identified by a name under which it is stored in a disk file. In this
sense, however, the document is not the same as the file but is an
object in memory that owns and manages the document data. In the
context of AppKit, a document is an instance of a custom NSDocument
subclass that knows how to represent internally, in one or more
formats, persistent data that is displayed in windows.
A document can read that data from a file and write it to a file. It
is also the first-responder target for many menu commands related to
documents, such as Save, Revert, and Print. A document manages its
window’s edited status and is set up to perform undo and redo
operations. When a window is closing, the document is asked before the
window delegate to approve the closing.
NSDocument is one of the triad of AppKit classes that establish an
architectural basis for document-based apps (the others being
NSDocumentController and NSWindowController).
Figured it out a few days ago, thought I'd come back to answer for anyone else with the same question.
What class should I use? I'm assuming NSView, but like I said I've never done this before so I'm not sure.
NSView is in fact the class I used to draw each page.
Do I need to specify the pixel coordinates for every single object, or can I make each object relative to another in some way?
I did end up specifying the pixel coordinates for each image on the grid (plus its caption), but it was easy to calculate where they should be placed once I learned the size of a 8.50 x 11 inch page in points. The next challenge was drawing them in a for loop rather than having to explicitly declare each possible NSRect. Here's my code in drawRect:
// Declared elsewhere: constants for horizontal/vertical spacing,
// the width/height for an image, and a value for what row the image
// should be drawn on
for (int i = 0; i < [_people count]; i++) {
float horizontalPoint = 0.0; // What column should the image be in?
if (i % 2 != 0) { // Is i odd? (i.e. Should the image be in the right column?)
horizontalPoint += (imageWidth + horizontalSpace); // Push it to the right
}
NSRect imageRect = NSMakeRect(horizontalSpace + horizontalPoint, verticalSpace + verticalPoint,
imageWidth, imageHeight);
// Draw the image with imageRect
if (i % 2 != 0) { // Is i odd? (i.e. Is the current row drawn?)
verticalPoint = (imageRect.origin.y + imageRect.size.height); // Push the row down
}
}
I do realize that I could've coded that more efficiently (e.g. making a BOOL for i % 2 != 0), but I was rushing the whole project because my friend who needed it was on a deadline.
How do I create separate pages for the view?
With some googling, I came up with this SO answer. However, this wasn't going to work unless I had one big view with all the pages concatenated together. I came up with a way to do just that:
// Get an array of arrays containing 1-6 JANPerson objects each using data from a parsed in .csv
NSArray *paginatedPeople = [JANGridView paginatedPeople:people];
int pages = [JANGridView numberOfPages:people];
// Create a custom JANFlippedView (just an NSView subclass overriding isFlipped to YES)
// This will hold all of our pages, so the height should be the # of pages * the size of one page
JANFlippedView *view = [[JANFlippedView alloc] initWithFrame:NSMakeRect(0, 0, 612, 792 * pages)];
for (int i = 0; i < [paginatedPeople count]; i++) { // Iterate through each page
// Create a custom JANGridView with an array of people to draw on a grid
JANGridView *gridView = [[JANGridView alloc] initWithFrame:NSMakeRect(0, 0, 612, 792) people:paginatedPeople[i]];
// Push the view's frame down by 792 points for each page drawn already
// and add it to the main view
gridView.frame = NSMakeRect(0, 792 * i, gridView.frame.size.width, gridView.frame.size.height);
[view addSubview:gridView];
}
I apologize if this is hard to understand for anybody; I'm better at talking through my process than writing! I welcome anyone to ask for help if there's something unclear, or edit if they can make it better.
NsView; so tis a mac app?
CGPointMake Returns a point with the specified coordinates. i.e. placing an image in a specific spot on the screen using matrices i.e.
layer.position = CGPointMake ([self view].bounds.size.width /2, [self view].bounds.size.height /3 );
(this example is oriented around core animation (moving objects on screen so please don't take it too literally) hence the layer attribute)
Also this line
layer.bounds= CGRectMake (100,100,1000,1000);
specifies a rectangles boundaries (rectangles can be filled with images and custom data using a bridge i believe; like this):
UIImage *image2 = [[UIImage alloc]initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"flogo#2x"ofType:#"png"]];
layer.contents = (__bridge id)image2.CGImage;
Also i believe the cgdrawrect class when combined with matrices i.e. (x,x,x,x) can draw custom rectangles as in your image.
But hopefully you catch my drift with drawing and substituting images . The Core graphics framework will probably be used here. ( my whole answer used core animation as a reference)
I have an NSBrowser and try to use setRowHeight, but I get the error:
"setRowHeight: is not supported for browsers with matrix delegates."
I really don't understand what this means, and if someone could help me out by either telling me how to fix it or even just what a matrix delegate is, it would be much appreciated.
A delegate is a helper object that you tell the NSBrowser instance about either by using -setDelegate: in code or hooking the delegate outlet up in IB (the NIB editor). It is commonly used to fill the browser's data, determine programmatically the layout options, etc.
If you have a delegate assigned in your NSBrowser instance, you are expected (required) to give the row height using the delegate method:
- (CGFloat)browser:(NSBrowser *)browser heightOfRow:(NSInteger)row inColumn:(NSInteger)columnIndex
Which will allow you to optionally set the row height on a per-row basis, but in your case, you can safely return a constant.
A NSBrowser creates one instance of NSMatrix per column. The browser itself only manages the columns and leaves row management entirely to the matrices. The matrices display cell objects (NSCell or subclasses of it). A cell is a simple displayable object that knows nothing but how to draw itself. Unlike a view (NSView and subclasses), it never manages an own drawing context, it also doesn't belong to a window (and thus won't ever directly access the window's drawing context) and it knows nothing about the "view hierarchy" (superviews, subviews, view order, constraints, etc.), it just manages some properties, some state and knows how to draw itself to a drawing context provided.
If your delegate works with items (the docs speak about "the item delegate methods"), the developers of NSBrowser thought it's unlikely that you ever want to deal with matrices directly, thus the browser will control all the display aspects for you. You are only supposed to hand out items (basically arbitrary objects) in your delegate and answer questions about them by implementing various delegate methods. E.g.: What is the root item? Is item x a leaf item or has children? How many children does it have? What's child number n of item x? What display object (string, image, etc.) shall I use to display that item?
If you don't work with items, you have to work directly with the cells (NSBrowserCell, a subclass of NSCell) that the matrix owns and is going to display. In that case you are said to be a "browser matrix delegate". That means the browser will only ask you how many rows a column has, setup a matrix with cells for you for that column and finally pass every cell once to your delegate, so you can do something meaningful with it, e.g. fill it with displayable content, otherwise the cell would just be empty, and teach it all the stuff the browser has to know (e.g. setting the leaf property).
As a matrix based delegate has to deal with cells directly, it can as well also deal with the matrices directly and in fact that his exactly what you have to do here. E.g. if you want that all rows of your browser have a height of 50 points, implement the following NSBrowser delegate method:
- (void)browser:(NSBrowser *)browser
didChangeLastColumn:(NSInteger)oldLastColumn
toColumn:(NSInteger)column
{
NSMatrix * matrix = [browser matrixInColumn:column];
CGSize cellSize = [matrix cellSize];
if (cellSize.height != 50) {
cellSize.height = 50;
matrix.cellSize = cellSize;
[matrix sizeToCells];
}
}
Every matrix created by the browser is passed to that method at least once before it gets displayed on screen. In case that matrix is not using a cell height of 50 already, we change that and finally tell the matrix to re-layout; that is important as otherwise it won't recalculate its total height. The if is only to avoid that we call sizeToCells more often than necessary as this call may be rather expensive. In this example all columns get equal row height but of course you can set a different row heights per column.
I add my sprite frames to CCSpriteFrameCache. Then I create a CCSpriteBatchNode with my desired image file.
This is what I don't quite understand:
When I make a CCSprite, if I want to take advantage of the CCSpriteBatchNode, I need to initialize the CCSprite with [CCSprite spriteWithBatchNode: rect:]? But if that's the case, I don't see how am I taking advantage of CCSpriteFrameCache to get the frames, since now I would be manually making the rect.
So I guess I use [CCSprite spriteWithSpriteFrameName:] and then I add this sprite to the batch node. But I am still unsure.
You should use:
CCSprite *sp = [CCSprite spriteWithSpriteFrameName:#"monster.png"];
The .plist that you specified in the SpriteFrameCache will take care of the frames for you.
Then you create the sprite and add to the batch.
If you create the batchnode with a file called "myArt.png", you CAN ONLY add a sprite to it that is contained inside "myArt.png".
Hope it helps!
According to what I've learned of cocos2d. SpriteFrameCache and SpriteBatchNode have the same result but are used differently and can notice a slight performance difference if your game is very big...
CCSpriteFrameCache loads your frames according to when they are called by their named according to the plist file it was given. The atlas associated with the plist has to be added to the project as well or else the frames will be called but nothing will be found to be drawn. The Plist is like the address of where the image is located inside the image atlas.
The good part of CCSpriteFrameCache is that the code is neater, and smaller than CCSpriteBatchNode method, at the cost that for every call of that frame, it goes to that specific atlas and draws it.
CCSpriteBatchNode, on the other hand, loads the atlas and loads it in one draw call. This is efficient because it reduces the amount of times the draw has to be done per need in the game. The only difficulty here is that you need to do math for the rectangles of each sprite in the atlas. This is because lets say your atlas is of 2 actions of a character, the atlas image file has a size of 1024x1024, and each sprite has a size of 128x128. so you would do the math to get each rectangle for the whole jump action for example.(This is where .plist come in handy to avoid doing such math)
The code gets complicated as you can see but it will only do one call, making it performance-wise your best call.
Another way to use CCSpriteBatchNode is to have different static sprites and you would just do one draw call for those multiple static images or sprites.
If you need example code just ask, I would be more than happy to provide it.
Update: Adding Link for SpriteBatchNode and an Example of my own.
SpriteBatchNode:
Example using SpriteBatchNode with Ray Wenderlich
I believe in this guy, and I have learned alot of Cocos2d from his tutorials. I would suggest you to read other of his tutorials.
In a nutshell, CCSpriteBatchNode is the exact same process we did below with the CCSpriteFrameCache the ONLY difference and its that you add the Sprite Child Node to the CCSpriteBatchNode and not the Layer, BUT you do Add the CCSpriteBatchNode to the Layer.
This is the hard concept that new comers to Cocos2d get entangled at.
SpriteFrameCache:
The SpriteFrameCache I couldn't find a good example so here is one simple one.
//By doing this your sprites are now in the cache ready to be used
//by their names declared in the .plist file.
-(void) loadingSprites:(NSString*) plistName {
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:plistName];
}
-(id)initGameLayer {
//CCSprite accepts CCSpriteFrame and your img is now ready to be displayed.
//However is still not drawn yet.
CCSprite * mySprite = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:framename];
//set a position if desired
//20 pixels to the right and 0 pixels to the top.
mySprite.position = CGPointMake(20,0);
//Now the Image has been drawn, making 1 draw call.
[self addChild:mySprite];
}
It is noteworthy to point out that CCSpriteBatchNode makes just 1 drawcall, HOWEVER all the sprites being added to the batchnode have to be part of the same SpriteAtlas.
And using SpriteFrameCache only its easier and simpler, but for every child added to the layer it means +1 draw call is being done.(This is the downside, performance)
So if you add 10 Sprites to the layer with SpriteFrameCache you will have 10 drawcalls.
However if you implement the SpriteBatchNode and add those 10 Sprites in the CCSpriteBatchNode instead and just add that CCSpriteBatchNode to the layer, you will have the same 10 sprites added but only ONE draw call will be done. Hence the Performance difference(for the best) will be significant in larger games.
Hope it helps, Cheers!
I want a UIButton to pulse, and I plan to do this by fading slowly between two color arrays on a CAGradientLayer. Is there a way to repeat an animation back and forth?
Yes. In Core Animation you create an explicit animation to do the fade and then you must also set two other properties for the animation object: autoReverses and repeatCount (number of repetitions to perform, each 2 repetitions will take you through your animation and back again). In your case you’d add the following lines to your code that sets up the animation object (I’ll call the object anim):
anim.repeatCount = HUGE_VALF;
anim.autoReverses = YES;
HUGE_VALF causes the animation to repeat forever though you could specify a number larger than any amount of repetitions that might occur.
These properties aren’t shown in the documentation of the CAAnimation object or it’s subclasses since it is defined in the CAMediaTiming Protocol which is adopted by CAAnimation and it's subclasses. But you can see examples and discussion of the CAMediaTiming protocol as it applies to CAAnimation objects in the Timing, Timespaces, and CAAnimation section of the Animation Types and Timing Programming Guide either on Apple’s Developer site or in the documentation provided through XCode.
(Many people seem to find Apple's Core Animation documentation to be particularly hard to understand until you get a good overall grasp of the disparate parts. I basically knew what you had to do but still found it hard to remember exactly where to find the actual information as to the properties involved.)