Cocoa and Objective-C: Up and Running (by me) is now available from O'Reilly.

Core Animation Sample Code: NanoLife

NanoLife is a simple Core Animation project with a single layer-backed view and a collection of sublayers. Each sublayer has a glowing sphere and moves along a random path, giving the impression of a microscopic lifeforms (or maybe fireflies?).

NanoLife


You can switch to fullscreen mode by pressing any key, and switch back again by pressing a key again. The impressive bits about this is the very small amount of code used to achieve the effect, and the incredible scalability. The base layer count is 80 for artsy reasons, but I'm sure you could get away with a lot more.

The image size, opacity, and animation path are all random, so it's a new show each time. If you click hold the mouse button, the lifeforms will all be instinctively attracted to the mouse pointer. Once you've gathered them all up, you can drag them to a new location and release them for nice expansion effect.

For extra fun, try dragging them to different points outside of the window bounds and releasing them (for example, off the bottom edge of the window but horizontally centered).

This project is Leopard-only and has examples of:

- Core Animation
- Core Image filters
- Conversion between NSImage, CIImage, and CGImageRef
- Full screen mode for NSView

I did not use NS_BUILD_32_LIKE_64 for the project, because I wanted to avoid situations where somebody would copy-and-paste the code and see build errors in another project.

This project also has a simpler source usage terms than the BSD-ish license I've used in the past. The new license reads:

The purpose of this code is to provide an example of how to
write Mac software.

You may use this code for any purpose, though I ask you receive
permission before re-using any substantial portion of it in a
tutorial of your own. For info: theocacao at mac dot com.

An acknowledgement in release notes of your software is always
appreciated, but not required.


I hope that makes life easier for everyone. It also occurred to me that some people might want to run these little apps without dealing with Xcode, so I'm including a pre-built, double-clickable version too.

NanoLife Downloads: Xcode 3.0 Project / Pre-built App

Enjoy.
Design Element
Core Animation Sample Code: NanoLife
Posted Feb 21, 2008 — 36 comments below




 

Jonathan Grynspan — Feb 21, 08 5536

Nifty. Kind of reminds me of Snowplane. :)

Seth Willits — Feb 21, 08 5537

Slick.

Jason — Feb 21, 08 5538

I seem to get a weird visual bug in the app. If I click to attract the lifeforms to the cursor, let go, don't move the mouse and click again, they instantly jump to the mouse cursor without animating there. Either way, this is amazing that there is so much happening in so little code!

Joachim Bengtsson — Feb 21, 08 5539

I haven't seen much full-out use of Core Animation as the main UI component yet, so I thought I'd share my latest Core Animation creation, Aurora2D, which is a prototype I'm using for my candidate thesis. It's a bit crashy, but maybe there's some useful bits of Core Animation or NSOperationQueue in there. Binaries and source at http://nevyn.tumblr.com/post/26920477

Moitah — Feb 22, 08 5540

Please, please... Make a screensaver out of it !

ian — Feb 22, 08 5542

nice, thanks for sharing.

Chris Ryland — Feb 22, 08 5543

Nice! Thanks, Scott.

Nit-pick: these days, shouldn't the _cmd in NSLog() (-glowingSphereImageWithScaleFactor:) be wrapped in a sel_getName(_cmd)?

Bob Peterson — Feb 22, 08 5544

The pre-built app reliable freezes my Dual G5. I wonder if the G5's lack of advanced graphics has something to do with it.

Jason — Feb 22, 08 5545

// stop animating everything and move all the sphere layers so that // they're directly under the mouse pointer. NSArray* sublayers = self.containerLayerForSpheres.sublayers; for ( CALayer* layer in sublayers) { [layer removeAllAnimations]; layer.position = cgMousePointInView; }
This snippet shows that what you are seeing is on purpose

Phil — Feb 22, 08 5547

This really shows the power of CA.

I'm running it on a MacBook Pro 2.33Ghz with 2000 spheres whizzing around the place without any real noticeable slowdown.

Scott Stevenson — Feb 22, 08 5548 Scotty the Leopard

@Jason: If I click to attract the lifeforms to the cursor, let go, don't move the mouse and click again, they instantly jump to the mouse cursor without animating there

I noticed that too. Not sure offhand why it does that -- probably something simple. It was designed to not animate during -mouseDragged (as the comments in the code note), but it should always animate for normal -mouseDown.

@Moitah: Please, please... Make a screensaver out of it!

I thought about that, yeah. :)

@Chris Ryland: Nit-pick: these days, shouldn't the _cmd in NSLog() (-glowingSphereImageWithScaleFactor:) be wrapped in a sel_getName(_cmd)?

Sounds reasonable to me, although that _cmd stuff is just generated by TextMate's Objective-C bundle when I use the "log" tab trigger. I didn't write it out by hand.

@Bob Peterson: The pre-built app reliable freezes my Dual G5

Freezes the whole machine or just the app? If it freezes the machine, you should file a bug.

Jussi — Feb 22, 08 5549

The prebuilt app froze my old dear friend, 12" PowerBook, too..

I got a spinning cursor, for a few minutes nothing else seemed to respond but the mouse cursor -> reboot.

John C. Randolph — Feb 22, 08 5551

Thumbs up for using #pragma mark in your .m file.

-jcr

Chris L — Feb 23, 08 5552

Thanks! I've been adding some Core Animation to my app just in the past few days. You can never have too much sample code.

Works fine on a Mac mini with the G4 and Radeon 9200.

Adrian Bool — Feb 23, 08 5553

Scott, Could I ask you why you use extra local variables in your code, such as,

// create container layer for spheres
CALayer* sphereContainer = [CALayer layer];
sphereContainer.name = @"sphereContainer";
[mainLayer addSublayer:sphereContainer];
self.containerLayerForSpheres = sphereContainer;

As opposed to,

// create container layer for spheres
self.containerLayerForSpheres = [CALayer layer];
self.containerLayerForSpheres.name = @"sphereContainer";
[mainLayer addSublayer:self.containerLayerForSpheres];

You perform a similar action with sphereCount as well. I'm learning Cocoa and would love to know if the second form is significantly less efficient or if there is some other possible problem. Cheers!

Scott Stevenson — Feb 23, 08 5554 Scotty the Leopard

@Adrian Bool: Scott, Could I ask you why you use extra local variables in your code

Every time you do either one of these:
self.containerLayerForSpheres [self containerLayerForSpheres]

... there's a cost for the method call. It's very small in this case, but if you're making several hundreds or thousand calls like this, it's probably better to get a local reference to the object so you don't have to keep calling the method.

It's also much easier to read "sphereContainer" than the longer "self.containerLayerForSpheres". It's important that instance variables and methods have very descriptive names, but I think it's less important for local variables because their purpose is clear from the context (a variable name like "sc" is not clear enough, though).

A third reason is that it's typically better to "set up" an object locally before setting it as an instance variable with the setter method, because you might write a setter that does some post-processing, such as creating a cached version of the object. It's better to give the setter the complete, finished object.

Patrick — Feb 23, 08 5555

Thank you very much for the code!

kenneth — Feb 23, 08 5556

Hey,

I turned this into a screensaver because it's totally cool and someone here requested it... i hope this is OK with you Scott, otherwise I'll take it down.

http://www.seoxys.com/nanolifesaver/

Kenneth

Scott Stevenson — Feb 23, 08 5558 Scotty the Leopard

@kenneth: I turned this into a screensaver because it's totally cool and someone here requested it... i hope this is OK with you Scott, otherwise I'll take it down.

I just emailed you -- I think it's great. I made it my screensaver. My first request is a slider in the options sheet to control the number of spheres.

ACoolie — Feb 24, 08 5560

I thought this was quite cool. I haven't worked with CoreAnimation yet and it looks real easy.
To play around with it I added a window to change core/glow colors, change the background, and add/remove spheres.
I think I had to write more glue code for all the outlets than I did to actually do the CA stuff.
Changing sphere colors or adding a lot of them takes ~15 seconds each time on my PowerMac G5. Changing the gradient on the other hand is realtime.

Pic and Source. Someone might learn from it:
http://rapidshare.com/files/94640992/NanoLife-Colors.zip.html
http://img91.imageshack.us/img91/5425/picture1bh7.png

PS. I love it when you do things like this. Really encourages people to try it out for themselves.

Gav — Feb 24, 08 5561

Awesome work Scott.

I'm still at the beginner level of Cocoa/Objective-C, but it's stuff like this that gives me concrete milestones to work towards.

John Muir — Feb 24, 08 5562

No problems on my 12" PowerBook. Nice stuff. Though unlike my Intel peers I shan't be upping the count to the thousands!

Scott Stevenson — Feb 24, 08 5563 Scotty the Leopard

@ACoolie: Changing sphere colors or adding a lot of them takes ~15 seconds each time on my PowerMac G5

This is probably because a separate image is generated for each layer. You could change the code to only generate a single full-size image and resize the layer instead. If you do this, set kCAGravityResizeAspect for the contentsGravity property on the layer, so that the image scales with the layer.

The speed difference is nearly nonexistent for the original version of NanoLife, but it would be very noticeable for hundred/thousands of layers or if you're regenerating them frequently.

kenneth — Feb 24, 08 5564

@Scott: I did a new version of the screensaver based on this that has settings and works properly.

http://www.seoxys.com/nanolifesaver/

As soon as I have some free time I'll try to optimize the CA code so it only generates one image that gets resized... Tends to lag with 500+ layers (and it takes extremely long to load too).

Moitah — Feb 25, 08 5567

Thank you Kenneth ;-)

David — Mar 02, 08 5585

Froze my 12" Powerbook (running 10.5.2), the whole damned machine. 2x. Felt like System 7.

Your response to Bob Peterson was file a bug, but the link is to this article. Did you mean file a bug with Apple? I don't think I have enough information to file a useful bug report.

Scott Stevenson — Mar 02, 08 5586 Scotty the Leopard

@David: Froze my 12" Powerbook (running 10.5.2), the whole damned machine. 2x. Felt like System 7.

I wish I knew what to say about that, but I don't have the same hardware to test on.

Your response to Bob Peterson was file a bug, but the link is to this article. Did you mean file a bug with Apple?

Yes, typo on my part -- which is fixed now.

I don't think I have enough information to file a useful bug report

Actually you do. No application (especially something as simple as this) should hang the entire machine. You can file a bug with your system profile and attach the Xcode project for NanoLife (or just point to the url). That gives them plenty to work with.

This is all up to you, of course. It's just there's nothing I can personally do since I don't have the same hardware.

Peter — Mar 05, 08 5592

If I click to attract the lifeforms to the cursor, let go, don't move the mouse and click again, they instantly jump to the mouse cursor without animating there

Scott, I'm curios as to why they animate towards the cursor when you click. From reading the code I would expect the behavior stated above.

Interestingly if I replace this line
CGPoint cgMousePointInView = NSPointToCGPoint(mousePointInView);
with
CGPoint cgMousePointInView = CGPointMake(0., 0.);

It always jumps immediately to the origin. Now, if you change the coordinates of the point to something like (10, 50) the first time it will animate to the point but any subsequent clicks will cause it to jump directly there.

How come it animates when you remove all animations and just set it's position?

Scott Stevenson — Mar 05, 08 5594 Scotty the Leopard

@Peter: How come it animates when you remove all animations and just set it's position?

In this case, "remove animations" means "stop all animations which are currently in progress". When you set the "position" on the layer, you're changing the value of an animatable property which can trigger a new animation.

I haven't looked at the code to see why clicking in the same place twice only causes an animation the first time, but I suspect it's because the "random movement" animation is explicitly added -- it's not the result of animating a "position" property change. In other words, the layer may still consider itself to be at the location of the original mouse click, so it sees no reason to animate.

This is just a guess, though. I'd have to go back and look. Notably, Nano Spores does not have this issue.

Patrick Geiller — Mar 05, 08 5595

@Peter: I haven't looked at the code to see why clicking in the same place twice only causes an animation the first time

I've looked :) - on mouseup, Nanolife sets a path with mousedown's point as first point, where Nanospores sets the layer position to a new point, then sets a path from here.

Thanks for the code, btw !

Jeff — Mar 14, 08 5646

Wow... this is awesome. I've been away from Cocoa for a bit, and am now frantically trying to catch up on the new stuff. This is a great help - thanks!

Steve White — Jun 28, 08 6112

Being slightly bored today, I got this running on iPhoneOS-hardware. The generation of the spheres had to change due to the lack of CIFilters -- so I used a radial gradient instead. The devices will respond to a touch like the mouse on the desktop. No accelerometer support or such. Animates just fine on the hardware with the 80 spheres.

Screenshot, Xcode Project

Facepalm — Feb 28, 09 6614

Very useful files search engine. Indexoffiles.com is a search engine designed to search files in various file sharing and uploading sites.

Free Videos — Mar 11, 09 6622

http://sharesdigger.com is a great example of social site that really helps in getting useful things in Web. It helped me much, so I suggest it to everyone.

celik kapi — Jan 10, 10 7091

çelik kapı modeli ya da
çelik kapı aksesuarından, çelik kapı müşterisi de herhangi
bir tüketiciden daha fazlası olduğunun bilincindeyiz.
Çelik kapı, taşınmaz sınıfına giren demirbaş sayılan ayrıcalıklı bir üründür.

Business PowerPoint — Jan 15, 10 7109

Hi,
This article gives the light in which we can observe the reality. This is very nice one and gives in-depth information. Thanks for this nice article.

<a href="http://www.bizplancorner.com/resources/12/powerpoint_presentation.aspx">Business PowerPoint Presentation</a>




 

Comments Temporarily Disabled

I had to temporarily disable comments due to spam. I'll re-enable them soon.




Technorati Profile
Copyright © Scott Stevenson 2004-2008