CAAnimation completion callback block

CAAnimation completion callback block

onedayitwillmake No Comments

It’s really useful to fire a function when an animation is complete.
There’s no built in way to do that in CoreAnimation, it does have the concept of delegate’s, which get you half way there.

However if you have multiple animations firing, and your delegate is catching everything, you’re gonna be in for a world of hurt.

Here is a simple Swift class I wrote to extend CAAnimation to accept onStart/onCompletion blocks:


import Foundation import Cocoa public typealias CAAnimationCallback = (CAAnimation, Bool) -> (); public class CAAnimationDelegate:NSObject { var onStartCallback:CAAnimationCallback? var onCompleteCallback:CAAnimationCallback? override public func animationDidStart(anim: CAAnimation) { if let startHandler = onStartCallback { startHandler(anim, true); } } override public func animationDidStop(anim: CAAnimation, finished flag: Bool) { if let completionHandler = onCompleteCallback { completionHandler(anim, flag); } } } public extension CAAnimation { // See if there is already a CAAnimationDelegate handling this animation // If there is, add onStart to it, if not create one func setonStartCallbackBlock(callback:CAAnimationCallback) { if let myDelegate = delegate { if(myDelegate.isKindOfClass(CAAnimationDelegate)) { let myThing = myDelegate as! CAAnimationDelegate; myThing.onStartCallback = callback; } } else { let callbackDelegate = CAAnimationDelegate(); callbackDelegate.onStartCallback = callback; self.delegate = callbackDelegate; } } // See if there is already a CAAnimationDelegate handling this animation // If there is, add onCompletion to it, if not create one func setCompletionBlock(callback:CAAnimationCallback) { if let myDelegate = delegate { if(myDelegate.isKindOfClass(CAAnimationDelegate)) { let myThing = myDelegate as! CAAnimationDelegate; myThing.onCompleteCallback = callback; } } else { let callbackDelegate = CAAnimationDelegate(); callbackDelegate.onCompleteCallback = callback; self.delegate = callbackDelegate; } } }

Usage

var animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 0.0
animation.toValue = 1.0
animation.setCompletionBlock({ (anim:CAAnimation) in
  Swift.print("On Complete!")
})

CAAnimation delegate not working (Swift)

onedayitwillmake No Comments

CAAnimation provides a way of receiving a callback upon start or completion of an animation.
If you have a ‘pure’ class, that is a class that does not inherit from anything, doing this will have no effect:


class Petal { func startAnimation(duration: Double = 2.0) { let pathAnimation = CABasicAnimation(keyPath: "strokeEnd"); pathAnimation!.delegate = self; pathAnimation!.duration = duration; pathAnimation!.fromValue = 0.0; pathAnimation!.toValue = 1.0; self.shapeLayer.addAnimation(pathAnimation!, forKey: "strokeEnd"); } func animationDidStart(anim: CAAnimation) { Swift.print("ANIMATION DID START!"); } func animationDidStop(anim: CAAnimation, finished flag: Bool) { Swift.print("ANIMATION DID END!"); } }

The reason is because:
You must subclass NSObject, as the delegate methods exist as an informal protocol extension on NSObject

So simply changing it to this is enough:


class Petal:NSObject { // Subclass NSObject func startAnimation(duration: Double = 2.0) { .... } // These are now overrides override func animationDidStart(anim: CAAnimation) { Swift.print("ANIMATION DID START!"); } override func animationDidStop(anim: CAAnimation, finished flag: Bool) { Swift.print("ANIMATION DID END!"); } }

Numeric operator overloading in Swift

onedayitwillmake No Comments

Sometimes when developing in Swift if you’re trying to do seemingly simple things like divide 2 numbers:

let interval:Double = 1.0/fps;

You’ll get errors like these:

binary operator '*' cannot be applied to operands of type 'CGFloat' and 'Double'
binary operator '*' cannot be applied to operands of type 'Int' and 'CGFloat'
cannot convert value of type 'Float' to expected argument type 'Double'
binary operator '*' cannot be applied to operands of type 'CGFloat' and 'Int8'

This is because Swift is more strict about how it treats numeric types, and you have to manually cast them to the same type in order for those operations to work.

However cause we can write our own operator in Swift, we can make it so that when it encounters 2 types, it will check to see if we have a matching operator and use that instead.

So as I’ve encountered them, I’ve been appending to a my little NumericOperatorOverloadingExtensions.swift file:

import Foundation

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////// ADDITION ////////////////////////////////////////////////////////////////
public func +(a: Float, scalar: Int)  -> Float  { return a + Float(scalar); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////// MULTIPLICATION  //////////////////////////////////////////////////////////////
// Int *
public func *(a: Int, scalar: CGFloat)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(a: Int, scalar: Float)    -> Float    { return Float(a) * scalar; }
public func *(a: Int, scalar: Double)   -> Double   { return Double(a) * scalar; }
public func *(scalar: CGFloat, a: Int)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(scalar: Float, a: Int)    -> Float    { return Float(a) * scalar; }
public func *(scalar: Double, a: Int)   -> Double   { return Double(a) * scalar; }

// Int8 *
public func *(a: Int8, scalar: CGFloat)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(a: Int8, scalar: Float)    -> Float    { return Float(a) * scalar; }
public func *(a: Int8, scalar: Double)   -> Double   { return Double(a) * scalar; }
public func *(scalar: CGFloat, a: Int8)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(scalar: Float, a: Int8)    -> Float    { return Float(a) * scalar; }
public func *(scalar: Double, a: Int8)   -> Double   { return Double(a) * scalar; }

// Int32 *
public func *(a: Int32, scalar: CGFloat)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(a: Int32, scalar: Float)    -> Float    { return Float(a) * scalar; }
public func *(a: Int32, scalar: Double)   -> Double   { return Double(a) * scalar; }
public func *(scalar: CGFloat, a: Int32)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(scalar: Float, a: Int32)    -> Float    { return Float(a) * scalar; }
public func *(scalar: Double, a: Int32)   -> Double   { return Double(a) * scalar; }

// Float *
public func *(a: Float, scalar: Double)  -> Float  { return a * Float(scalar); }
public func *(a: Float, scalar: Double)  -> CGFloat  { return CGFloat(a * Float(scalar)); }
public func *(a: Float, scalar: Double)  -> Double  { return Double(a) * scalar; }

// CGFLOAT  *
public func *(a: CGFloat, scalar: Double)  -> CGFloat  { return a * CGFloat(scalar); }
public func *(a: CGFloat, scalar: Double)  -> Float  { return Float(a) * Float(scalar); }
public func *(a: CGFloat, scalar: Double)  -> Double  { return Double(a) * scalar; }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////// DIVISION ////////////////////////////////////////////////////////////////
// Double /
public func /(a: Double, b: Int)  -> Double  { return a / Double(b); }
public func /(a: Double, b: Float)  -> Double  { return a / Double(b); }
public func /(a: Double, b: Int)  -> Int  { return Int(a) / b; }
public func /(a: Int, b: Double)  -> Double  { return Double(a) / b; }
public func /(a: Int, b: Double)  -> Int  { return Int(Double(a) / b); }

// Float /
public func /(a: Float, b: Int)  -> Float  { return a / Float(b); }
public func /(a: Float, b: Int)  -> Int  { return Int(a) / b; }
public func /(a: Int, b: Float)  -> Float  { return Float(a) / b; }
public func /(a: Int, b: Float)  -> Int  { return Int(Float(a) / b); }
public func /(a: Float, scalar: Double)  -> Float  { return a / Float(scalar); }

NPM install from branch on private repo

onedayitwillmake No Comments

Something you need a specific branch of a repository that has not been published yet.

git+http://git@SUBDOMAIN.DOMAIN.COM/USER/REPO-URL.git#4d331600

For example:

// this URL
https://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs/tree/39333c6227ea537e3f5d4ec9e893d7f9c670c867
 
// becomes in your package.json
git+https://git@github.com/onedayitwillmake/RealtimeMultiplayerNodeJs.git#39333c6227ea537e3f5d4ec9e893d7f9c670c867

Swap HTTP for HTTPS, depending on your repo location

Running a python/shell script from the UnityEditor

onedayitwillmake No Comments

While working on your game, sometimes you develop little python or shell scripts that help along the process, and it’d be nice to run them from the editor.
Or better yet, during your automated build process, have it call out to this from within Unity.

It’s actually quite simple, and you can even capture the output into the editor.

[MenuItem("MyGame/Downscale Reference Textures")]
public static void DownscaleRefTextures() {
        // using System.Diagnostics;
    Process p = new Process();
    p.StartInfo.FileName = "python";
    p.StartInfo.Arguments = "resize_reference_sprites.py";    
        // Pipe the output to itself - we will catch this later
    p.StartInfo.RedirectStandardError=true;
    p.StartInfo.RedirectStandardOutput=true;
    p.StartInfo.CreateNoWindow = true;
 
       // Where the script lives
    p.StartInfo.WorkingDirectory = Application.dataPath+"/SpriteCollections/"; 
    p.StartInfo.UseShellExecute = false;
 
    p.Start();
        // Read the output - this will show is a single entry in the console - you could get  fancy and make it log for each line - but thats not why we're here
    UnityEngine.Debug.Log( p.StandardOutput.ReadToEnd() );
    p.WaitForExit();
    p.Close();
}

ios-creating-reusable-uiviews-with-storyboard – Part 2

onedayitwillmake No Comments

This has is an updated version of ios-creating-reusable-uiviews-with-storyboard for Xcode 6.

TL:DR version:

  1. Create a new UIView subclass name it MyView.h/MyView.h
  2. Create a new XIB name it MyView.xib
  3. In MyView.xib select the File's Owner and set the class (using the right pane, third tab) to MyView
  4. Create an IBOutlet in MyView.h is of the type UIView*, call it contentView
  5. In InterfaceBuilder (with MyView.xib open) right-click drag the File's Owner the root view, and link it to contentView
  6. In MyView.m, override -awakeFromNib with the following:
    -(void)awakeFromNib {
        [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
     
        // The following is to make sure content view, extends out all the way to fill whatever our view size is even as our view's size is changed by autolayout
        [self.contentView setTranslatesAutoresizingMaskIntoConstraints:NO];
        [self addSubview: self.contentView];
     
        [[self class] addEdgeConstraint:NSLayoutAttributeLeft superview:self subview:self.contentView];
        [[self class] addEdgeConstraint:NSLayoutAttributeRight superview:self subview:self.contentView];
        [[self class] addEdgeConstraint:NSLayoutAttributeTop superview:self subview:self.contentView];
        [[self class] addEdgeConstraint:NSLayoutAttributeBottom superview:self subview:self.contentView];
     
    }
     
    +(void)addEdgeConstraint:(NSLayoutAttribute)edge superview:(UIView *)superview subview:(UIView *)subview {
        [superview addConstraint:[NSLayoutConstraint constraintWithItem:subview
                                                              attribute:edge
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:superview
                                                              attribute:edge
                                                             multiplier:1
                                                               constant:0]];
    }

So that’s the first part, the second part is to create a UIView in some other XIB or storyboard, do whatever autolayout stuff you want with it and set it’s UIView class to “MyView”. When the XIB is loaded and displayed -it will show your view in there allowing you to customize views and reuse them.

Open two instances of Unity at once

onedayitwillmake No Comments

Sometimes you have a project that you’re using as reference, maybe you added some functionality in a previous project or you downloaded a sample project and you are trying to recreate that thing in your new project. It would be great if you could have them both open side by side so you can compare them right?

Unfortunately if you try to open Unity by clicking the icon, it will just bring your current instance into focus, so what can be done?

Here’s a simple trick that allows you to have two instances of Unity open at once, open the second instance from the command line and point it to a project.

$ /Applications/Unity/Unity.app/Contents/MacOS/Unity -projectPath ~/projects/coolgame

Note: You cannot open the same project twice, so if you have to do that create a temporary copy of the project.

Create iOS / Android icons from master icon

onedayitwillmake No Comments

This is just a simple script that will create your iOS icons from a masterfile.
I’m using it on a Unity project (Even though Unity will make the icons for you, the way it resizes the images leaves them appearing jaggy).

It works best with a 1024×768 icon as the source

#!/bin/bash
# Author: Mario Gonzalez
# Modified for iOS7 from: https://gist.github.com/jessedc/837916
f=$(pwd)
 
# App Icon - iPhone iOS7+
sips --resampleWidth 60 "${f}/${1}" --out "${f}/icon60.png"
sips --resampleWidth 120 "${f}/${1}" --out "${f}/icon120.png"
# App Icon - iPhone <= iOS6
sips --resampleWidth 57 "${f}/${1}" --out "${f}/icon57.png"
sips --resampleWidth 114 "${f}/${1}" --out "${f}/icon114.png"
# App Icon - iPad iOS7+
sips --resampleWidth 76 "${f}/${1}" --out "${f}/icon76.png"
sips --resampleWidth 152 "${f}/${1}" --out "${f}/icon152.png"
# App Icon - iPad <= iOS6
sips --resampleWidth 72 "${f}/${1}" --out "${f}/icon72.png"
sips --resampleWidth 144 "${f}/${1}" --out "${f}/icon144.png"
# Spotlight iOS7+
sips --resampleWidth 40 "${f}/${1}" --out "${f}/icon40.png"
sips --resampleWidth 80 "${f}/${1}" --out "${f}/icon80.png"
# Spotlight - Ipad <= iOS6
sips --resampleWidth 50 "${f}/${1}" --out "${f}/icon50.png"
sips --resampleWidth 100 "${f}/${1}" --out "${f}/icon100.png"
# Spotlight - iPhone <= iOS6
sips --resampleWidth 29 "${f}/${1}" --out "${f}/icon29.png"
sips --resampleWidth 58 "${f}/${1}" --out "${f}/icon58.png"
# iTunesArtwork
sips --resampleWidth 512 "${f}/${1}" --out "${f}/iTunesArtwork"
sips --resampleWidth 1024 "${f}/${1}" --out "${f}/iTunesArtwork@2x"
 
###### ANDROID ICONS
sips --resampleWidth 96 "${f}/${1}" --out "${f}/icon96.png"
sips --resampleWidth 48 "${f}/${1}" --out "${f}/icon48.png"
sips --resampleWidth 36 "${f}/${1}" --out "${f}/icon36.png"

Use it as such:

$ ./updateicon.sh  iconmaster.png

Note you made need to run chmod +x updateicon.sh on it before it will be recognized as executable

Using Greensock JS / TweenMax in a Dart application

onedayitwillmake No Comments

Once you use Greensock / TweenMax / TweenLite, you don’t really want to use anything else.
It’s fast, it’s feature rich, and it works on more browsers than dart itself.
This is a quick post on how to use the animation library, it’s surprisingly easy.

  • First import the dart:js library
    import 'dart:js';

  • Next, add dart.interop.js to your HTML after your own apps script tags.
    Mine looks like this:

    <script type="application/dart" src="dart/mandala.dart"></script>
    <script src="packages/browser/dart.js"></script>
    <script src="packages/browser/interop.js"></script>

Now to call JS from dart you must follow the js-interop syntax, which I agree is a bit annoying – but one approach is to create a wrapper class / function for it.

  • With that out of the way, here is an example of a Tweenmax call to modify the Y / Alpha values of a div:
      // You can also just pass the element's ID instead to greensock
      // but assuming we already retrieved it or may not have an id we would use this method
      HTMLElement divToAnimate = querySelectorAll("#myDiv");
 
      // Context refers to the JSContext, and retrieves global window objects
      context['TweenMax'].callMethod("to", [divToAnimate 
            0.15,
            new JsObject.jsify({
                  "delay" : 0.5,
                  "y": "40"
                  "autoAlpha": 0
            })]);
 
      // A simpler one for reference
      context['TweenMax'].callMethod("to",["#myDiv", 0.15, new JsObject.jsify({x:100})]);

We can think of Context as referring to the Window object in the javascript context. So we retrieve it, and then call a method on it. Passing the method name to and then an array of parameters. For the last parameters, we create a new javascript object using the JsObject.jsify method which takes a map of primitive types with strings as keys.

In the next post / or an update to this one, I will show you how to create a simple wrapper class to make using Greensock more like calling it from JS

Placing an AppKit controls over a NSOpenGLView / CinderView

onedayitwillmake No Comments

Currently working on an OSX application that requires UI controls to live above a CinderView (Which is a type of NSOpenGLView).

Obviously first I tried to simply place the objects above one another in InterfaceBuilder, but that had no effect. The NSOpenGLView always draws above all other content.

Next I tried some information someone suggested, with switching to layer-backed views.
That crashed my application on startup.

Instead what I found that worked, was to create a separate NSWindow, and style it to be transparent and place it inside of your NSWindow that contains the CinderView / NSOpenGLView.

Create a window to house your AppKit UI controls, and place your NSView inside

    // Transparent UI window
    CGRect wRect = self.window.frame;
    NSView *contentView = self.window.contentView;
    CGRect cRect = contentView.frame;
    CGRect rect = CGRectMake(wRect.origin.x, wRect.origin.y, cRect.size.width, cRect.size.height);
    self.overlayWindow = [[NSWindow alloc]initWithContentRect:rect
                                                         styleMask:NSBorderlessWindowMask
                                                           backing:NSBackingStoreBuffered
                                                             defer:NO];
    self.overlayWindow.backgroundColor = [NSColor clearColor];
    [self.overlayWindow setOpaque:NO];
  // Add it to the window which contains our NSOpenGLView
    [self.window addChildWindow:self.overlayWindow ordered:NSWindowAbove];
 
    // Place UI in overlay window
    self.settingsController = [[SettingsViewController alloc] init];
    [self.overlayWindow.contentView addSubview:self.settingsController.view];