Source/Bit.m
author Jens Alfke <jens@mooseyard.com>
Mon Jul 21 17:32:21 2008 -0700 (2008-07-21)
changeset 21 2eb229411d73
parent 13 db7bb080c3d5
child 22 4cb50131788f
permissions -rw-r--r--
* Added API to Stack for removing bits.
* GoGame correctly saves/restores number of captured pieces.
* Improved positioning of captured-piece Stacks in GoGame.
* New Go piece icons.
* Added "Warn" function to GGBUtils.
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@0
    82
jens@0
    83
- (int) rotation
jens@0
    84
{
jens@0
    85
    NSNumber *rot = [self valueForKeyPath: @"transform.rotation"];
jens@0
    86
    return round( rot.doubleValue * 180.0 / M_PI );
jens@0
    87
}
jens@0
    88
jens@0
    89
- (void) setRotation: (int)rotation
jens@0
    90
{
jens@0
    91
    [self setValue: [NSNumber numberWithDouble: rotation*M_PI/180.0]
jens@0
    92
        forKeyPath: @"transform.rotation"];
jens@0
    93
}
jens@0
    94
jens@0
    95
jens@0
    96
- (BOOL) pickedUp
jens@0
    97
{
jens@9
    98
    return _pickedUp;
jens@0
    99
}
jens@0
   100
jens@0
   101
- (void) setPickedUp: (BOOL)up
jens@0
   102
{
jens@9
   103
    if( up != _pickedUp ) {
jens@11
   104
        CGFloat shadow, radius, opacity, z, scale;
jens@11
   105
        CGSize offset;
jens@0
   106
        if( up ) {
jens@0
   107
            shadow = 0.8;
jens@11
   108
            offset = CGSizeMake(2,2);
jens@0
   109
            radius = 8;
jens@9
   110
            opacity = kPickedUpOpacity;
jens@9
   111
            scale = kPickedUpScale;
jens@0
   112
            z = kPickedUpZ;
jens@0
   113
            _restingZ = self.zPosition;
jens@16
   114
#if !TARGET_OS_IPHONE
jens@11
   115
            _restingShadowOpacity = self.shadowOpacity;
jens@11
   116
            _restingShadowOffset  = self.shadowOffset;
jens@11
   117
            _restingShadowRadius  = self.shadowRadius;
jens@16
   118
#endif
jens@0
   119
        } else {
jens@16
   120
#if !TARGET_OS_IPHONE
jens@11
   121
            shadow = _restingShadowOpacity;
jens@11
   122
            offset = _restingShadowOffset;
jens@11
   123
            radius = _restingShadowRadius;
jens@16
   124
#endif
jens@11
   125
            opacity = 1;
jens@9
   126
            scale = 1.0/kPickedUpScale;
jens@0
   127
            z = _restingZ;
jens@0
   128
        }
jens@9
   129
jens@8
   130
#if !TARGET_OS_IPHONE
jens@13
   131
        self.zPosition = z;
jens@0
   132
        self.shadowOpacity = shadow;
jens@11
   133
        self.shadowOffset = offset;
jens@0
   134
        self.shadowRadius = radius;
jens@1
   135
#endif
jens@0
   136
        self.opacity = opacity;
jens@0
   137
        self.scale *= scale;
jens@9
   138
        _pickedUp = up;
jens@0
   139
    }
jens@0
   140
}
jens@0
   141
jens@0
   142
jens@0
   143
- (BOOL)containsPoint:(CGPoint)p
jens@0
   144
{
jens@0
   145
    // Make picked-up pieces invisible to hit-testing.
jens@0
   146
    // Otherwise, while dragging a Bit, hit-testing the cursor position would always return
jens@0
   147
    // that Bit, since it's directly under the cursor...
jens@0
   148
    if( self.pickedUp )
jens@0
   149
        return NO;
jens@0
   150
    else
jens@0
   151
        return [super containsPoint: p];
jens@0
   152
}
jens@0
   153
jens@0
   154
jens@0
   155
-(id<BitHolder>) holder
jens@0
   156
{
jens@0
   157
    // Look for my nearest ancestor that's a BitHolder:
jens@0
   158
    for( CALayer *layer=self.superlayer; layer; layer=layer.superlayer ) {
jens@0
   159
        if( [layer conformsToProtocol: @protocol(BitHolder)] )
jens@0
   160
            return (id<BitHolder>)layer;
jens@0
   161
        else if( [layer isKindOfClass: [Bit class]] )
jens@0
   162
            return nil;
jens@0
   163
    }
jens@0
   164
    return nil;
jens@0
   165
}
jens@0
   166
jens@0
   167
jens@0
   168
- (void) destroy
jens@0
   169
{
jens@0
   170
    // "Pop" the Bit by expanding it 5x as it fades away:
jens@0
   171
    self.scale = 5;
jens@0
   172
    self.opacity = 0.0;
jens@0
   173
    // Removing the view from its superlayer right now would cancel the animations.
jens@0
   174
    // Instead, defer the removal until sometime shortly after the animations finish:
jens@0
   175
    [self performSelector: @selector(removeFromSuperlayer) withObject: nil afterDelay: 1.0];
jens@0
   176
}
jens@0
   177
jens@0
   178
jens@0
   179
@end