Rubyでどう書く?:RubyCocoa+Core Animationでお手軽アニメーション

佐藤伸吾(KBMJ)
2008/08/14 08:00

今回はRubyCocoaとMac OS XのフレームワークであるCore Animationを使って、お手軽にアニメーションを作成してみましょう。

問題

 RubyCocoaは、Mac OS XCocoaオブジェクトをRubyスクリプトからRubyオブジェクトとして扱うための、Rubyライブラリフレームワークです。RubyCocoaを用いれば、RubyCocoaアプリケーションを記述することができるのです。

 Core AnimationはMax OS Xのフレームワークで、その利点は手軽さにあります。普通にアニメーションプログラミングを行おうとすると、時間軸管理、非同期な描画スレッド、パフォーマンスの向上など、考慮すべき点があまりにも多すぎます。

 しかし、Core Animationを用いれば、面倒な部分はOSに任せて、自分の実現したいことに集中できるのです。

 今回はRubyCocoaMac OS XフレームワークであるCore Animationを使って、お手軽にアニメーションを作成してみましょう。

回答例

 AppController.rbを作成し、以下のように記述します。

require 'osx/cocoa'
OSX.require_framework 'QuartzCore'

class AppController < OSX::NSObject
	ib_outlet :window
	ib_outlet :view
	ib_action :pressPosition
	ib_action :pressRotation
	ib_action :pressSepia
	ib_action :pressBloom
	ib_action :pressHole
	ib_action :pressZoom
	ib_action :pressHalftone
	
	def awakeFromNib
		bitmapImage = OSX::NSBitmapImageRep.imageRepWithContentsOfFile_('/Users/ssato/Pictures/ruby.png')
		image = bitmapImage.CGImage()

		layer = OSX::CALayer.layer()
		layer.contents = image
		layer.frame = OSX::CGRectMake(0,0,995/4,996/4)

		black=OSX::CGColorCreateGenericRGB(0,0, 0,1.0)
		backgroundLayer=OSX::CALayer.layer()
		backgroundLayer.backgroundColor=black

		backgroundLayer.addSublayer_(layer)

		@view.setLayer_(backgroundLayer)
		@view.setWantsLayer_(true)
	end
	def pressPosition(sender)
		animation = OSX::CABasicAnimation.animationWithKeyPath_('position')
		animation.duration = 1.0
		
		layer = @view.layer.sublayers.objectAtIndex_(0)
		position = layer.position
		animation.fromValue = OSX::NSValue.valueWithPoint_(OSX::NSPointFromCGPoint(position))
		position.x += 256;
		position.y += 160;
		animation.toValue = OSX::NSValue.valueWithPoint_(OSX::NSPointFromCGPoint(position))
		animation.autoreverses = true
		animation.repeatCount = 4
		layer.addAnimation_forKey_(animation, 'positionAnimation')
	end
	def pressRotation(sender)
		animation = OSX::CABasicAnimation.animationWithKeyPath_('transform')
		animation.duration = 0.5
		animation.autoreverses = true
		animation.repeatCount = 4
		transform = OSX::CATransform3DIdentity
		animation.fromValue = OSX::NSValue.valueWithCATransform3D(transform)
		transform = OSX::CATransform3DMakeRotation(Math::PI, 0, 1.0, 0)
		transform.m34 = 1.0 / -420.0
		animation.toValue = OSX::NSValue.valueWithCATransform3D(transform)
		layer = @view.layer.sublayers.objectAtIndex_(0)
		layer.addAnimation_forKey_(animation, 'transformAnimation')
	end
	def pressSepia(sender)
		filter = OSX::CIFilter.filterWithName_('CISepiaTone')
		filter.setDefaults()
		layer = @view.layer.sublayers.objectAtIndex_(0)
		layer.name = 'sepiaFilter'
		layer.setFilters_(OSX::NSArray.arrayWithObject_(filter))
	end
	def pressBloom(sender)
		filter2 = OSX::CIFilter.filterWithName_('CIBloom')
		filter2.setDefaults
		filter2.setValue_forKey_(OSX::NSNumber.numberWithFloat_(0.0), 'inputIntensity')
		filter2.setValue_forKey_(OSX::NSNumber.numberWithFloat_(5.0), 'inputRadius')
		filter2.setName_('bloomFilter')
		
		layer = @view.layer.sublayers.objectAtIndex_(0)
		layer.setFilters_(OSX::NSArray.arrayWithObject_(filter2))

		pluseAnimation = OSX::CABasicAnimation.animation
		pluseAnimation.keyPath = 'filters.bloomFilter.inputIntensity'
		pluseAnimation.fromValue = OSX::NSNumber.numberWithFloat_(0.0)
		pluseAnimation.toValue = OSX::NSNumber.numberWithFloat_(1.5*2)
		pluseAnimation.duration = 1.0
		pluseAnimation.repeatCount = 4
		pluseAnimation.autoreverses = true
		layer.addAnimation_forKey_(pluseAnimation, 'bloom')
	end
	def pressHole(sender)
		filter = OSX::CIFilter.filterWithName_('CIHoleDistortion')
		filter.setDefaults()
		layer = @view.layer.sublayers.objectAtIndex_(0)
		layer.setFilters_(OSX::NSArray.arrayWithObject_(filter))
	end
	def pressZoom(sender)
		filter = OSX::CIFilter.filterWithName_('CIZoomBlur')
		filter.setDefaults()
		layer = @view.layer.sublayers.objectAtIndex_(0)
		layer.setFilters_(OSX::NSArray.arrayWithObject_(filter))
	end
	def pressHalftone(sender)
		filter = OSX::CIFilter.filterWithName_('CICMYKHalftone')
		filter.setDefaults()
		layer = @view.layer.sublayers.objectAtIndex_(0)
		layer.setFilters_(OSX::NSArray.arrayWithObject_(filter))
	end
end

 Interface Builderで画像1のようにコンポーネントを配置します。

画像1 画像1

 NSObjectを追加して、ClassにAppcontrollerを指定します(画像2)。

画像2 画像2

 OutletsとActionsのConnectionを画像3のように設定します。

画像3 画像3

実行結果

 Positionボタンを押すと、画像が斜めに移動します(画像4)。

画像4

 Rotationボタンを押すと画像が回転し、Sepiaをクリックすると画像がセピア色になります(画像5)。

画像5 画像5

 同様に、Bloomは画像が光り輝き(画像6)、Holeは画像に穴が空きます(画像7)。Zoomボタンはズームエフェクト(画像8)で、Halftoneはハーフトーンフィルタです(画像9)。

画像6 画像6
画像7 画像7
画像8 画像8
画像9 画像9

解説

記事に関係する情報をコメントでお寄せください

ニックネーム : CNET_IDにログインしてコメントする

コメント本文(必須) :
  • 新着記事
  • 人気記事
  • 特集
  • ブログ