CocoaDev

Edit AllPages

I want to make a SIMPLE screen saver with a SIMPLE NSBezierPath. I got the path, I got a color, but I can’t get variables that will make my shape move. Here is my code so far :

// Balle.h

#import <Foundation/Foundation.h> #import <AppKit/AppKit.h> #import <ScreenSaver/ScreenSaver.h>

@interface BalleView : ScreenSaverView { NSBezierPath *balle; NSRect rect; NSColor *couleur;

int x1; int y1;
int x2; int y2; }

@end

And my implementation :

#import “BalleView.h”

@implementation BalleView

@end


MacEdition has a screensaver article at http://macedition.com/bolts/bolts_20020514.php

The basic thing you are overlooking is you are not regenerating the bezier curve after you change the control points. This doesn’t happen automatically. Try this instead:

// Balle.h

#import <Foundation/Foundation.h> #import <AppKit/AppKit.h> #import <ScreenSaver/ScreenSaver.h>

@interface BalleView : ScreenSaverView { /* NSBezierPath *balle; No need for this ivar */ NSRect rect; NSColor *couleur;

int x1; int y1;
int x2; int y2; }

@end

// Balle.m #import “BalleView.h”

@implementation BalleView

@end

Remember that method dispatches are just function calls. You wouldn’t expect:

int x = 7; printf(“x = %d\n”, x); x = 10;

to print “x = 10” would you? That’s what you were expecting in your example above.

– MikeTrent


There’s still something I need to know. When I try the code, the ball doesn’t really move, it actually copies itself in the direction I give to it with x and y. That’s why I intended to make the NSBezierPath a more global variable. I want the ball to move and not leave a trail of the same color behind it…


When you draw to a view, you have complete control of the bits on screen. That means you are responsible for all of the animation. if you want the ball to move, you must move the ball. The most simple way to do this is to re-draw your entire window every time:

But you are actually touching all the bits in your view every time, and that can get expensive (unless you’re using OpenGL …). It’s better to limit the area you are updating. For example, you could paint the old ball in black, move x and y, and paint the new ball in couleur; next time through the animation cycle you’ll end up drawing black over the new ball, moving x and y again, and so on. But drawing circles is expensive too, more so than drawing a square of the same size. The following is a good compromise:

This is probably the most basic computer animation technique, and there are other techniques for doing reasonable 2D animation. You might try poking around game programming web sites for a good overview or tutorial on 2D animation techniques. A book I found fairly helpful (although is pre-Carbon, and may be out of print) was Tricks of the Mac Game Programming Gurus. Or maybe someone here will kindly write a 2D animation primer.

– MikeTrent


If the original poster wants some screensaver code that stores state between frames, and does some simple animation, they’re welcome to steal from my Borkware Drip screensaver at http://borkware.com/products/borkware-drip/ . Source code is available.

– MarkDalrymple

One thought: does it really work anymore to erase the old circle by simply painting over the background colour? Doesn’t quartz’ antialiasing leave traces behind? – EnglaBenny

If you’re seeing artifacts, make the rectangle you’re erasing to be a little larger, so it will erase any antialiasing left behind. – someone

Yes, and yes. So maybe do this:

Drawing a rect is definitely faster than drawing a circle, anti-aliasing or no. – MikeTrent


Actually, I’ve found that things move along quite nicely if you render the object (ball, in this case) into an NSImage, and then just tell the image to draw itself on the screen. For example:

If you do it this way, you don’t have the expense of recalculating the bezier path at all… you just copy the pixels onto the screen! You’ll still have to clear the screen as previously stated, however. – AndrewMiner