天天看点

iPhone Graphics 入门(三)

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

继续阅读