RSS

iPhone SDK Beta 5 Now Available

May 6th, 2008 Posted in iPhone | No Comments »

Apple has released Beta 5 of the iPhone SDK.

The readme doesn’t reveal much about what is in this release:

The ?fth beta ?xes bugs and adds support for the latest iPhone OS.

[del.icio.us] [Digg] [Reddit] [Technorati]

Exploring iPhone Graphics Part 3

May 5th, 2008 Posted in Software Development, iPhone | No Comments »

Graphics Icon

Last time we created a simple iPhone application that made a ball bounce around the screen. This time we are going to extend the last example to use the accelerometer to create a gravity influence on the ball. So as you tilt the device the ball will roll in the direction of the tilt.






The first thing we need to do is add a way to influence the ball’s motion. I’ve added an influence method to the Vector2D class. Also the GravityView class gets a gravity variable that is a Vector2D class instance.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- (void)influence:(Vector2D*)influenceVector Max:(CGFloat)max;
{
    [endPoint addVector:influenceVector];
    length = sqrt(endPoint.X * endPoint.X + endPoint.Y * endPoint.Y);
    CGFloat newAngle = atan2(-endPoint.Y, endPoint.X) * ONEEIGHTYOVERPI;
    if(newAngle < 0)
    {
        newAngle += 360;
    }
 
    if(abs(newAngle - influenceVector.angle) >= 90)
    {
        length *= 0.96;
    }
    else
    {
        length *= 1.03;
    }
 
    if(length > max)
    {
        length = max;
    }
    else if(length < 0.0)
    {
        length = 0.0;
    }
 
    [self setAngle:newAngle];
}

This method is passed another vector and a max value. The passed in influenceVector is added to the ball’s endPoint. If the ball is currently moving away from the influence vector then it is slowed down slightly by multiplying the vector length by 0.96. If the ball is currently moving toward the influence vector then it is sped up slightly by multiplying the vector length by 1.03. The maximum length of the vector is capped at the max value passed into the method. The vector is not allowed to have a negative length.

I’ve also added a method to the Vector2D class to scale the length of the vector.

1
2
3
4
5
6
7
8
9
10
11
12
- (void)scaleLength:(CGFloat)factor;
{
    length *= factor;
    if(length < 0.05)
    {
        length = 0.0;
    }
 
    double radians = angle * PIOVERONEEIGHTY;
    endPoint.X = length * cos(radians); // could speed these up with a lookup table
    endPoint.Y = -(length * sin(radians));
}

This method simply multiplies the vector length by the scale factor. When the length of the vector becomes very small it is set to zero.

In order to receive accelerometer events we make the GraphicsView class implement the UIAccelerometerDelegate prototype.

1
@interface GraphicsView : UIView <UIAccelerometerDelegate>

In the GraphicsView initWithFrame method we need to set up the accelerometer.

1
2
3
4
5
    accelX = 0.0;
    accelY = 0.0;
 
    [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / 60)];
    [[UIAccelerometer sharedAccelerometer] setDelegate:self];

We are initializing the accelerometer x and y values to zero, setting the update interval so that we receive updates 60 times per second and setting self as the delegate.

With the accelerometer set up the accelerometer method of our GraphicsView object instance will be called 60 times per second.

1
2
3
4
5
6
7
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
    accelX = (acceleration.x * kAccelFilt) + (accelX * (1.0 - kAccelFilt));
    accelY = (-acceleration.y * kAccelFilt) + (accelY * (1.0 - kAccelFilt));
 
    [gravity setEndPointX:accelX*2 Y:accelY*2];
}

We are using a filter to isolate the current device position. Each time the method is called we set the gravity vector’s end point to two times the accelerometer X and Y values. We don’t need the Z axis accelerometer for this example. Note that we are using negative Y to account for coordinate system differences.

The final piece of the puzzle is to call the influence method of our ball’s vector in the timer tick method.

1
2
3
4
5
6
7
8
9
10
11
- (void)tick
{
    // Apply gravity influence
    [ball.vector influence:gravity Max:8.0];
 
    // Update the balls position
    [ball move:self.bounds];
 
    // Tell the view that it needs to re-draw itself
    [self setNeedsDisplay];
}

That’s all there is to it. Prett simple eh?

Here are the new source files:
Exploring iPhone Graphics Part 3 Source

[del.icio.us] [Digg] [Reddit] [Technorati]

WikipediaPick: Stanley Meyer’s Water Fuel Cell

May 1st, 2008 Posted in WikipediaPick | No Comments »

Stanley Meyer’s Water Fuel Cell is the WikipediaPick today. Back in ‘95 he claimed to have invented a way to run a car on nothing but water and a battery. His fuel cell would break the water molecules apart into hydrogen and oxygen using less energy then you would get back from burning them.

He died in ‘98 and some people think he was poisoned.

What do you think? Scammer or Genius?

Bonus link: WATERpoweredcar.com

[del.icio.us] [Digg] [Reddit] [Technorati]

Exploring iPhone Graphics Part 2

April 25th, 2008 Posted in Software Development, iPhone | No Comments »

Graphics Icon

In Part 1 of this series of articles we drew some simple graphic primitives on the iPhone display. In this article we are going to look at how to do some simple animation. The goal of this example is to create a 2D ball that bounces around the iPhone screen.

First of all we need an object to represent a point in our 2 dimensional coordinate system.





The Point2D object will take care of this and just keeps track of X and Y values.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@interface Point2D : NSObject
{
    CGFloat X;
    CGFloat Y;
}
 
@property (assign) CGFloat X;
@property (assign) CGFloat Y;
 
- (id)initWithX:(CGFloat)x Y:(CGFloat)y;
- (void)addVector:(Vector2D*)vector;
 
@end
 
@implementation Point2D
 
@synthesize X;
@synthesize Y;
 
- (id)init
{
    if (self = [super init])
    {
        X = 0.0;
        Y = 0.0;
    }
 
    return self;
}
 
- (id)initWithX:(CGFloat)x Y:(CGFloat)y;
{
    if (self = [super init])
    {
        X = x;
        Y = y;
    }
 
    return self;
}
 
- (void)addVector:(Vector2D*)vector
{
    X += vector.endPoint.X;
    Y += vector.endPoint.Y;
}
 
@end

It can be initialized with an X and Y value using the initWithX:Y method. The addVector method will be used to move our ball around the screen.

Next we need a class that represents a vector. The vector will be used to determine the direction that our ball is currently moving in and its speed. The Vector2D class will take of of this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
@interface Vector2D : NSObject
{
    CGFloat angle;
    CGFloat length;
    Point2D* endPoint;
}
 
@property (assign) CGFloat angle;
@property (assign) CGFloat length;
@property (assign) Point2D* endPoint;
 
- (id)initWithX:(CGFloat)x Y:(CGFloat)y;
- (void)setAngle:(CGFloat)degrees;
 
@end
 
// Geometry constants
#define PI 3.14159
#define ONEEIGHTYOVERPI 57.29582
#define PIOVERONEEIGHTY  0.01745
 
@implementation Vector2D
 
@synthesize angle;
@synthesize length;
@synthesize endPoint;
 
- (id)init
{
    if (self = [super init])
    {
        angle = 0.0;
        length = 0.0;
        endPoint = [[Point2D alloc] init];
    }
 
    return self;
}
 
- (id)initWithX:(CGFloat)x Y:(CGFloat)y;
{
    if (self = [super init])
    {
        endPoint = [[Point2D alloc] initWithX:x Y:y];
 
        // Calculate the angle based on the end point
        angle = atan2(-endPoint.Y, endPoint.X) * ONEEIGHTYOVERPI;
        if(angle < 0)
        {
            angle += 360;
        }
 
        // Calculate the length of the vector
        length = sqrt(endPoint.X * endPoint.X + endPoint.Y * endPoint.Y);
    }
 
    return self;
}
 
- (void)setAngle:(CGFloat)degrees
{
    angle = degrees;
    double radians = angle * PIOVERONEEIGHTY;
    endPoint.X = length * cos(radians); // could speed these up with a lookup table
    endPoint.Y = -(length * sin(radians));
}
 
@end

The Vector2D class manages the angle of the vector and the length of the vector. It also keeps track of the end point of the vector for convenience since we’ll be using the end point to move our ball. The vector can be initialize with an end point using the initWithX:Y method. The angle and length will automatically be calculated.

The angle is calculated from the end point by using the atan2 function. This function returns the angle in radians so we multiply the result by 180/PI to get the angle in degrees. You’ll also notice that we pass a negative Y coordinate to the atan2 function. This is because in our screen coordinate system the Y axis starts at zero at the top of the screen and has positive values as your go down the screen. The geometry functions we are using expect the opposite so we need to reverse the Y coordinates.

If the atan2 function returns a negative number we add 360 to make it positive.

To get the length of the vector we take the square root of x squared + y squared.

Calling the setAngle method will change the angle of the vector and update it’s end point to match the angle. First we convert the angle in degrees to radians by multiplying the angle by PI/180. We get the x end point by multiplying the length of the vector by the cosine of the angle. We get the y end point by multiplying the length of the vector by the sine of the angle. Notice we used a negative on the y value of the endpoint to fix the coordinate system problem.

Now we need a class to represent the ball we are going to move around the screen. I’m calling it Object2D because later this will most likely become a base class for other types of objects. It’ll just be a ball for now though.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
@interface Object2D : NSObject
{
    Point2D* position;
    Vector2D* vector;
    CGSize size;
}
 
@property (assign) Point2D* position;
@property (assign) Vector2D* vector;
@property (assign) CGSize size;
 
- (id)initWithPosition:(Point2D*)pos vector:(Vector2D*)vec;
- (void)move:(CGRect)bounds;
- (void)bounce:(CGFloat)boundryNormalAngle;
- (void)draw:(CGContextRef)context;
 
@end
 
// Screen edge normals
#define kLeftNorm 0.0
#define kLeftTopNorm 315.0
#define kTopNorm 270.0
#define kRightTopNorm 225.0
#define kRightNorm 180.0
#define kRightBottomNorm 135.0
#define kBottomNorm 90.0
#define kLeftBottomNorm 45.0
 
#define kDefaultSize 25.0
 
@implementation Object2D
 
@synthesize position;
@synthesize vector;
@synthesize size;
 
- (id)init
{
    if (self = [super init])
    {
        position = [[Point2D alloc] init];
        vector = [[Vector2D alloc] init];
        size.width = kDefaultSize;
        size.height = kDefaultSize;
    }
 
    return self;
}
 
- (id)initWithPosition:(Point2D*)pos vector:(Vector2D*)vec 
{
    if (self = [super init])
    {
        position = [pos retain];
        vector = [vec retain];
        size.width = kDefaultSize;
        size.height = kDefaultSize;
    }
 
    return self;
}
 
- (void)move:(CGRect)bounds
{
    // Move the ball by adding the vector to the position
    [position addVector:vector];
 
    // If the ball has hit the edge of the screen bounce it
    if (position.X <= bounds.origin.x && position.Y <= bounds.origin.y)
    {
        position.X = bounds.origin.x;
        position.Y = bounds.origin.y;
        [self bounce:kLeftTopNorm];
    }
    else if (position.X <= bounds.origin.x && position.Y+size.height >= bounds.size.height)
    {
        position.X = bounds.origin.x;
        position.Y = bounds.size.height - size.height;
        [self bounce:kLeftBottomNorm];
    }
    else if (position.X+size.width >= bounds.size.width && position.Y <= bounds.origin.y)
    {
        position.X = bounds.size.width - size.width;
        position.Y = bounds.origin.y;
        [self bounce:kRightTopNorm];
    }
    else if (position.X+size.width >= bounds.size.width && position.Y+size.height >= bounds.size.height)
    {
        position.X = bounds.size.width - size.width;
        position.Y = bounds.size.height - size.height;
        [self bounce:kRightBottomNorm];
    }
    else if (position.X <= bounds.origin.x)
    {
        position.X = bounds.origin.x;
        [self bounce:kLeftNorm];
    }
    else if (position.X+size.width >= bounds.size.width)
    {
        position.X = bounds.size.width - size.width;
        [self bounce:kRightNorm];
    }
    else if (position.Y <= bounds.origin.y)
    {
        position.Y = bounds.origin.y;
        [self bounce:kTopNorm];
    }
    else if (position.Y+size.height >= bounds.size.height)
    {
        position.Y = bounds.size.height - size.height;
        [self bounce:kBottomNorm];
    }
}
 
- (void)bounce:(CGFloat)boundryNormalAngle
{
    double angle = vector.angle;
    double oppAngle = (int)(angle + 180) % 360;
    double normalDiffAngle;
 
    if (boundryNormalAngle >= oppAngle)
    {
        normalDiffAngle = boundryNormalAngle - oppAngle;
        angle = (int)(boundryNormalAngle + normalDiffAngle) % 360;        
    }
 
    if (boundryNormalAngle < oppAngle)
    {
        normalDiffAngle = oppAngle - boundryNormalAngle;
        angle = boundryNormalAngle - normalDiffAngle;
        if (angle < 0)
        {
            angle += 360;
        }
    }
 
    // Set the new vector angle
    [vector setAngle:angle];
}
 
- (void)draw:(CGContextRef)ctx
{
    CGContextSetRGBFillColor(ctx, 255, 0, 0, 1);
    CGContextFillEllipseInRect(ctx, CGRectMake(position.X, position.Y, size.width, size.height));
}

The data stored for our ball is just its current position and its current vector. We also have a size that determines the width and height of the ball. If you just call init on the object you get a ball at 0,0 with a zero vector so it won’t move. If you call initWithPostion:vector you can pass in the initial position and vector.

The move method is called to actually move the ball. It adds the vector to the position then it checks to see if the ball has hit any of the screen edges including landing exactly in the corners of the screen. If it has hit a screen edge the bounce method is called and passed the normal angle for the screen edge that was hit.

The bounce method uses the normal angle passed to it to calculate the correct bounce angle for the ball. Then it calls setAngle on the vector to update it.

The draw method is passed a graphics context and draws the ball on it.

Now all we need is a view to make this work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@interface GraphicsView : UIView
{
    Object2D* ball;
    NSTimer* timer;
}
 
- (void)tick;
 
@end
 
@implementation GraphicsView
 
- (id)initWithFrame:(CGRect)frameRect
{
    self = [super initWithFrame:frameRect];
 
    // Create a ball 2D object in the upper left corner of the screen
    // heading down and right
    ball = [[Object2D alloc] init];
    ball.position = [[Point2D alloc] initWithX:0.0 Y:0.0];
    ball.vector = [[Vector2D alloc] initWithX:5.0 Y:4.0];
 
    // Start a timer that will call the tick method of this class
    // 30 times per second
    timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/30.0)
        target:self selector:@selector(tick) userInfo:nil repeats:YES];
 
    return self;
}
 
- (void)tick
{
    // Update the balls position
    [ball move:self.bounds];
 
    // Tell the view that it needs to re-draw itself
    [self setNeedsDisplay];
}
 
- (void)drawRect:(CGRect)rect
{
    // Clear the display and draw the ball
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextClearRect(ctx, rect);
    [ball draw:ctx];
}

The view class derives from UIView and will be created by the application delegate class. It just creates a single Object2D to represent our ball and starts an NSTimer to move the ball around. We initialize the ball at 0,0 on the screen and give it a vector with an X,Y of 5,4. We then start a timer that will be called every 1/30th of a second. The timer will call the tick method of the GraphicsView class.

The tick method calls the ball’s move method and passes in the bounds of the view to use for our bounce testing. It then calls setNeedsDisplay to notify the view that it needs to redraw itself.

The drawRect method gets the graphics context, clears it and then calls the ball’s draw method to tell it to draw itself.

That’s all there is to it. Pretty simple, eh? Next time we’ll tie in the accelerometer and maybe add some physics to simulate gravity.

Here are all of the source files:
main.m - ExploringGraphics2AppDelegate.h - ExploringGraphics2AppDelegate.m - GraphicsView.h - GraphicsView.m - Object2D.h - Object2D.m - Point2D.h - Point2D.m - Vector2D.h - Vector2D.m

[del.icio.us] [Digg] [Reddit] [Technorati]

WikipediaPick: Whiz Kids TV Series

April 24th, 2008 Posted in WikipediaPick | No Comments »

Whiz Kids

I’m not done with these goofy ’80s TV shows just yet! Whiz Kids was inspired by the movie WarGames and is about a group of teenage computer hackers that use their skillz to solve crimes. Of course I watched it back in the day. It starred Matthew Laborteaux. He played Albert on Little House on the Prarie.

I haven’t found this one on BitTorrent yet.

[del.icio.us] [Digg] [Reddit] [Technorati]

iPhone OS Beta 4 Install Problems

April 24th, 2008 Posted in iPhone | No Comments »

iPhone Program Icon
Getting the Beta 4 OS (build 5A258f) for iPhone or iPod Touch onto your device has a glitch and the install will not work. Restoring the OS from the Xcode Organizer will get stuck before the OS in even installed. When the device is rebooted it will appear as a second device with no information in the Organizer. The original device will still be there and will be at a status of “waiting for device” forever. The Organizer apparently doesn’t recognize the device after it is prepared and rebooted.

The good news is that there is a simple workaround for the problem. After the device reboots and you have two devices in the Organizer right click the original device and remove it. Now perform the OS restore for the new version on the remaining device. The restore will work this time.

[del.icio.us] [Digg] [Reddit] [Technorati]

iPhone Beta 4 Released

April 23rd, 2008 Posted in iPhone | No Comments »

Apple has released Beta 4 of the iPhone SDK and the iPhone/iPod Touch OS. The SDK build number is 9M2165 and the OS build number is 5A258f.

New in the release is OpenGL ES support to the iPhone Simulator!

[del.icio.us] [Digg] [Reddit] [Technorati]

WikipediaPick: Automan TV Series

April 21st, 2008 Posted in WikipediaPick | No Comments »

One of my co-workers and I got into a discussion about sci-fi TV shows from the ’80s. Having been a computer nerd growing up in the ’80s I didn’t miss too many sci-fi shows back then. I remember watching the series Automan as a kid. I don’t recall it being the best of shows but hey, I also watched the A-Team and the Dukes of Hazzard!

Automan

Automan is an American, science fiction, superhero, television series produced by Glen A. Larson. It aired for only 12 episodes (although 13 were made) on ABC between 1983 and 1984. The series was loosely, and unofficially, based on the ground-breaking 1982 film Tron.

You should be able to find the complete series available for download via BitTorrent.

[del.icio.us] [Digg] [Reddit] [Technorati]

WikipediaPick: Grok

April 18th, 2008 Posted in WikipediaPick | 1 Comment »

Grok

As first used in the Heinlein novel Stranger in a Strange Land:

“Grok means to understand so thoroughly that the observer becomes a part of the observed—to merge, blend, intermarry, lose identity in group experience. It means almost everything that we mean by religion, philosophy, and science—and it means as little to us (because of our Earthly assumptions) as color means to a blind man.

I heard this term used in a podcast I listened to a while back and had to look it up. I had never heard it used before but I like the word! I’ve read a lot of Heinlein books but either I haven’t read Stranger in a Strange Land or I glossed over this word without giving it a second thought.

Anyway, it’s a cool word. Do you grok it?

[del.icio.us] [Digg] [Reddit] [Technorati]

Plotting a Sine Wave with the iPhone SDK

April 17th, 2008 Posted in Software Development, iPhone | 2 Comments »

Graphics Icon
Got the following request from Leo on the Exploring iPhone Graphics Part 1 article:

Could you give me a quick primer on how to draw a sinus curve (or similar curve) with the data coming from an array?







Here it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#define PI 3.14159
 
CGContextBeginPath(ctx);
 
int x;
for(int y=rect.origin.y; y < rect.size.height; y++)
{
    x = ((rect.size.width/4) * sin(((y*4) % 360) * PI/180)) + rect.size.width/2;
 
    if(y == 0)
    {
        CGContextMoveToPoint(ctx, x, y);
    }
    else
    {
        CGContextAddLineToPoint(ctx, x, y);
    }
}
 
CGContextStrokePath(ctx);

The CGContextBeginPath function starts a graphics path. Next we loop the y screen coordinate from the top of the screen to the bottom of the screen. For each y position we calculate the x position based on the sin function. The wave will be half the width of the screen and centered. On the first iteration of the loop (y = 0) we use the CGContextMoveToPoint to set the first drawing position. On each subsequent iteration we draw a line from the last point to the current point.

Here’s a screen shot with this code added to the original application:
Sine wave screenshots

[del.icio.us] [Digg] [Reddit] [Technorati]