user3614030
user3614030

Reputation: 511

How can I simulate a beating heart?

I am making a game and I want the heart to look like it is beating. My approach is to have two images of a heart. One is bigger then the other. I have one as a UIButton (because to start the game I want to click the heart to do so), and the other bigger version of the heart is as UIImageView. So far I have it so the heart changes size every second, but I want it to be more realistic. For example, every second, it will change to the big heart and back (but not instantly so it is clearly visible). How can I do this? Here is my code:

PlayViewController.h

#import <UIKit/UIKit.h>

@interface PlayViewController : UIViewController
{    
    IBOutlet UIButton *heartButton;
    IBOutlet UIImageView *heartBig;
    NSTimer *heartBeat;
}

@end

PlayViewController.m

#import "PlayViewController.h"

@interface PlayViewController ()

@end

@implementation PlayViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    heartBig.hidden = YES;

    heartBeat = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(beatHeart) userInfo:nil repeats:YES];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)beatHeart
{
    if(heartBig.hidden == true)
        heartBig.hidden = false;

    else
        heartBig.hidden = true;
}

@end

Upvotes: 7

Views: 7300

Answers (6)

S.S.D
S.S.D

Reputation: 1686

Swift 5 code:

    let pulse = CASpringAnimation(keyPath: "transform.scale")
    pulse.duration = 0.4
    pulse.fromValue = 1.0
    pulse.toValue = 1.12
    pulse.autoreverses = true
    pulse.repeatCount = .infinity
    pulse.initialVelocity = 0.5
    pulse.damping = 0.8
    button.layer.add(pulse, forKey: nil)

Upvotes: 1

palla89
palla89

Reputation: 41

Here's another example with Facebook's POP, with a more "natural" pulse.

POPBasicAnimation *pulseAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewScaleXY];
pulseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pulseAnimation.fromValue = [NSValue valueWithCGSize:CGSizeMake(1, 1)];
pulseAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(1.1, 1.1)];

pulseAnimation.autoreverses = YES;
pulseAnimation.duration = 1.0;
pulseAnimation.repeatForever = YES;
[self pop_addAnimation:pulseAnimation forKey:@"pulseAnimation"];

Upvotes: 0

andykkt
andykkt

Reputation: 1706

Animation

/**
 Heart beating animation
 */
func addHeartBeatAnimation () {
    let beatLong: CABasicAnimation = CABasicAnimation(keyPath: "transform.scale")
    beatLong.fromValue = NSValue(CGSize: CGSizeMake(1, 1))
    beatLong.toValue = NSValue(CGSize: CGSizeMake(0.7, 0.7))
    beatLong.autoreverses = true
    beatLong.duration = 0.5
    beatLong.beginTime = 0.0

    let beatShort: CABasicAnimation = CABasicAnimation(keyPath: "transform.scale")
    beatShort.fromValue = NSValue(CGSize: CGSizeMake(1, 1))
    beatShort.toValue = NSValue(CGSize: CGSizeMake(0.5, 0.5))
    beatShort.autoreverses = true
    beatShort.duration = 0.7
    beatShort.beginTime = beatLong.duration
    beatLong.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn )

    let heartBeatAnim: CAAnimationGroup = CAAnimationGroup()
    heartBeatAnim.animations = [beatLong, beatShort]
    heartBeatAnim.duration = beatShort.beginTime + beatShort.duration
    heartBeatAnim.fillMode = kCAFillModeForwards
    heartBeatAnim.removedOnCompletion = false
    heartBeatAnim.repeatCount = FLT_MAX
    self.layer.addAnimation(heartBeatAnim, forKey: nil)
}

Based on BCBlanka's answer, little more realistic animation

Upvotes: 8

Sean Dev
Sean Dev

Reputation: 1309

BCBlanka used Core Animation, if anyone wants to use Facebooks POPAnimation library this would be the implementation:

POPBasicAnimation *beatingHeartAnim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewScaleXY];
beatingHeartAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
beatingHeartAnim.fromValue = [NSValue valueWithCGSize:CGSizeMake(1, 1)];
beatingHeartAnim.toValue = [NSValue valueWithCGSize:CGSizeMake(0.7, 0.7)];
beatingHeartAnim.autoreverses = YES;
beatingHeartAnim.duration = 1.0;
beatingHeartAnim.repeatCount = 120;
[heart  pop_addAnimation:beatingHeartAnim forKey:@"beatingHeartAnim"];

Upvotes: 0

BCBlanka
BCBlanka

Reputation: 485

Try this pulse animation:

enter image description here

CABasicAnimation *theAnimation;
theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale"];
theAnimation.duration=0.7;
theAnimation.repeatCount=HUGE_VALF;
theAnimation.autoreverses=YES;
theAnimation.fromValue=[NSNumber numberWithFloat:1.0];
theAnimation.toValue=[NSNumber numberWithFloat:0.7];
theAnimation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[self.heart.layer addAnimation:theAnimation forKey:@"animateOpacity"];

Upvotes: 25

Stephen C
Stephen C

Reputation: 719229

So far I have it so the heart changes size every second, but I want it to be more realistic.

The obvious suggestion is to use a sequence of images, to give you a "smooth" animation.

Upvotes: 2

Related Questions