Source/Bit.m
author snej@snej.local
Sun Jan 11 00:02:27 2009 -0800 (2009-01-11)
changeset 26 e7a464fb6d39
parent 16 28392c9a969f
permissions -rw-r--r--
Added ball graphics to Xcode project, which fixes the Go game. Fixed Tic-Tac-Toe. Fixed an exception in the demo app when changing games.
jens@0
     1
/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
jens@0
     2
    http://developer.apple.com/samplecode/GeekGameBoard/
jens@0
     3
    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
jens@0
     4
jens@0
     5
    Redistribution and use in source and binary forms, with or without modification, are permitted
jens@0
     6
    provided that the following conditions are met:
jens@0
     7
jens@0
     8
    * Redistributions of source code must retain the above copyright notice, this list of conditions
jens@0
     9
      and the following disclaimer.
jens@0
    10
    * Redistributions in binary form must reproduce the above copyright notice, this list of
jens@0
    11
      conditions and the following disclaimer in the documentation and/or other materials provided
jens@0
    12
      with the distribution.
jens@0
    13
jens@0
    14
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
jens@0
    15
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
jens@0
    16
    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
jens@0
    17
    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
jens@0
    18
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
jens@0
    19
    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
jens@0
    20
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
jens@0
    21
    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jens@0
    22
*/
jens@0
    23
#import "Bit.h"
jens@0
    24
#import "Game.h"
jens@10
    25
#import "Player.h"
jens@0
    26
#import "QuartzUtils.h"
jens@0
    27
jens@0
    28
jens@9
    29
#ifdef TARGET_OS_IPHONE
jens@9
    30
#define kPickedUpScale   2.0      // more magnification, so piece shows up underneath fingertip
jens@9
    31
#define kPickedUpOpacity 0.6
jens@9
    32
#else
jens@9
    33
#define kPickedUpScale   1.2
jens@9
    34
#define kPickedUpOpacity 0.9
jens@9
    35
#endif
jens@9
    36
jens@9
    37
jens@0
    38
@implementation Bit
jens@0
    39
jens@0
    40
jens@0
    41
- (id) copyWithZone: (NSZone*)zone
jens@0
    42
{
jens@1
    43
    Bit *clone = [super copyWithZone: zone];
jens@1
    44
    clone->_owner = _owner;
jens@12
    45
    clone->_tag   = _tag;
jens@1
    46
    return clone;
jens@0
    47
}
jens@0
    48
jens@7
    49
- (void) dealloc
jens@7
    50
{
jens@7
    51
    [super dealloc];
jens@7
    52
}
jens@7
    53
jens@7
    54
jens@12
    55
@synthesize owner=_owner, tag=_tag;
jens@0
    56
jens@0
    57
- (BOOL) isFriendly         {return _owner.friendly;}
jens@0
    58
- (BOOL) isUnfriendly       {return _owner.unfriendly;}
jens@0
    59
jens@7
    60
/*
jens@7
    61
- (NSString*) identifier
jens@7
    62
{
jens@7
    63
    if( _identifier )
jens@7
    64
        return _identifier;
jens@7
    65
    // Defaults to just identifying the owner:
jens@7
    66
    return [NSString stringWithFormat: @"p%i", _owner.index+1];
jens@7
    67
}
jens@7
    68
*/
jens@0
    69
jens@0
    70
- (CGFloat) scale
jens@0
    71
{
jens@0
    72
    NSNumber *scale = [self valueForKeyPath: @"transform.scale"];
jens@0
    73
    return scale.floatValue;
jens@0
    74
}
jens@0
    75
jens@0
    76
- (void) setScale: (CGFloat)scale
jens@0
    77
{
jens@0
    78
    [self setValue: [NSNumber numberWithFloat: scale]
jens@0
    79
        forKeyPath: @"transform.scale"];
jens@0
    80
}
jens@0
    81
jens@22
    82
- (void) scaleBy: (CGFloat)scale
jens@22
    83
{
jens@22
    84
    self.transform = CATransform3DConcat(self.transform,
jens@22
    85
                                         CATransform3DMakeScale(scale, scale, scale));
jens@22
    86
}
jens@22
    87
jens@0
    88
jens@0
    89
- (int) rotation
jens@0
    90
{
jens@0
    91
    NSNumber *rot = [self valueForKeyPath: @"transform.rotation"];
jens@0
    92
    return round( rot.doubleValue * 180.0 / M_PI );
jens@0
    93
}
jens@0
    94
jens@0
    95
- (void) setRotation: (int)rotation
jens@0
    96
{
jens@0
    97
    [self setValue: [NSNumber numberWithDouble: rotation*M_PI/180.0]
jens@0
    98
        forKeyPath: @"transform.rotation"];
jens@0
    99
}
jens@0
   100
jens@0
   101
jens@0
   102
- (BOOL) pickedUp
jens@0
   103
{
jens@9
   104
    return _pickedUp;
jens@0
   105
}
jens@0
   106
jens@0
   107
- (void) setPickedUp: (BOOL)up
jens@0
   108
{
jens@9
   109
    if( up != _pickedUp ) {
jens@22
   110
        CGFloat shadow, radius, opacity, z;
jens@11
   111
        CGSize offset;
jens@22
   112
        CATransform3D transform;
jens@22
   113
        
jens@0
   114
        if( up ) {
jens@0
   115
            shadow = 0.8;
jens@11
   116
            offset = CGSizeMake(2,2);
jens@0
   117
            radius = 8;
jens@9
   118
            opacity = kPickedUpOpacity;
jens@0
   119
            z = kPickedUpZ;
jens@0
   120
            _restingZ = self.zPosition;
jens@22
   121
            _restingTransform = self.transform;
jens@22
   122
            transform = CATransform3DScale(_restingTransform, kPickedUpScale, kPickedUpScale, kPickedUpScale);
jens@16
   123
#if !TARGET_OS_IPHONE
jens@11
   124
            _restingShadowOpacity = self.shadowOpacity;
jens@11
   125
            _restingShadowOffset  = self.shadowOffset;
jens@11
   126
            _restingShadowRadius  = self.shadowRadius;
jens@16
   127
#endif
jens@0
   128
        } else {
jens@16
   129
#if !TARGET_OS_IPHONE
jens@11
   130
            shadow = _restingShadowOpacity;
jens@11
   131
            offset = _restingShadowOffset;
jens@11
   132
            radius = _restingShadowRadius;
jens@16
   133
#endif
jens@11
   134
            opacity = 1;
jens@22
   135
            transform = _restingTransform;
jens@0
   136
            z = _restingZ;
jens@0
   137
        }
jens@9
   138
jens@8
   139
#if !TARGET_OS_IPHONE
jens@13
   140
        self.zPosition = z;
jens@0
   141
        self.shadowOpacity = shadow;
jens@11
   142
        self.shadowOffset = offset;
jens@0
   143
        self.shadowRadius = radius;
jens@1
   144
#endif
jens@0
   145
        self.opacity = opacity;
jens@22
   146
        self.transform = transform;
jens@9
   147
        _pickedUp = up;
jens@0
   148
    }
jens@0
   149
}
jens@0
   150
jens@0
   151
jens@0
   152
- (BOOL)containsPoint:(CGPoint)p
jens@0
   153
{
jens@0
   154
    // Make picked-up pieces invisible to hit-testing.
jens@0
   155
    // Otherwise, while dragging a Bit, hit-testing the cursor position would always return
jens@0
   156
    // that Bit, since it's directly under the cursor...
jens@0
   157
    if( self.pickedUp )
jens@0
   158
        return NO;
jens@0
   159
    else
jens@0
   160
        return [super containsPoint: p];
jens@0
   161
}
jens@0
   162
jens@0
   163
jens@0
   164
-(id<BitHolder>) holder
jens@0
   165
{
jens@0
   166
    // Look for my nearest ancestor that's a BitHolder:
jens@0
   167
    for( CALayer *layer=self.superlayer; layer; layer=layer.superlayer ) {
jens@0
   168
        if( [layer conformsToProtocol: @protocol(BitHolder)] )
jens@0
   169
            return (id<BitHolder>)layer;
jens@0
   170
        else if( [layer isKindOfClass: [Bit class]] )
jens@0
   171
            return nil;
jens@0
   172
    }
jens@0
   173
    return nil;
jens@0
   174
}
jens@0
   175
jens@0
   176
jens@0
   177
- (void) destroy
jens@0
   178
{
jens@0
   179
    // "Pop" the Bit by expanding it 5x as it fades away:
jens@0
   180
    self.scale = 5;
jens@0
   181
    self.opacity = 0.0;
jens@0
   182
    // Removing the view from its superlayer right now would cancel the animations.
jens@0
   183
    // Instead, defer the removal until sometime shortly after the animations finish:
jens@0
   184
    [self performSelector: @selector(removeFromSuperlayer) withObject: nil afterDelay: 1.0];
jens@0
   185
}
jens@0
   186
jens@0
   187
jens@0
   188
@end