2019年1月2日水曜日

SKLabelNodeの文字を縁取りに

NSMutableAttributedStringクラスを使う。

以下のコードの内、strokeWidthが縁取りの太さになるのだが、正の数だと縁取りだけで中が塗られない袋文字になる。負の値だと縁取り+中の塗りつぶしになる。
strokeColorが縁取りの色、foregroundColorは中の塗りつぶし色。

let borderText = NSMutableAttributedString(string: "縁取る文字")
borderText.addAttributes([NSAttributedString.Key.strokeWidth : -2.0,
NSAttributedString.Key.strokeColor : UIColor.black,
NSAttributedString.Key.foregroundColor : fontColor,
NSAttributedString.Key.font : UIFont.systemFont(ofSize: 64.0)],
range: NSMakeRange(0, borderText.length))
labelNode.attributedText = borderText

注意点

同時にSKLabelNode.textに普通にcolorを設定すると、そちらが優先されたりされなかったり、挙動がおかしくなる場合がありよくわからない。
要するに両方同時に設定しないほうが無難。

また、SKLabelNodeの.textと、NSMutableAttributedStringのstringは別物になる。

SKLabelNodeの色を変える

UILabel同様にSKColor()のメソッドで色を指定する点は一緒。

その後、colorBlendFactor という色の濃さのプロパティを指定してやらないと思い通りの色で表示されない。(白で表示されてしまう)
alpha値同様、1.0が最も濃い。
labelNode.colorBlendFactor = 1.0

めんどくせえな。

2018年12月24日月曜日

2018/12/24 有料アプリの手続き変更されたらしい

有料アプリの申請、更新手続きが変更されたようなので、和訳を書いておく。
更新された有料アプリケーションスケジュールを確認してください。
既存のアプリを更新し、新しいアプリ内購入を作成し、新しいアプリをApp Storeに送信するには、Legalロール(チームエージェント)を持つユーザーが、有料アプリケーションスケジュール(Apple Developer Programのスケジュール2)を確認して同意する必要があります。 [契約]、[税、および銀行]モジュールの[使用許諾契約]の順にクリックします。
この契約に同意するには、開発者Webサイトのアカウントで、最新バージョンのApple Developer Program使用許諾契約に同意している必要があります。
更新されたアップルデベロッパプログラムライセンス契約を確認する必要があります。
既存のアプリを更新して新しいアプリをApp Storeに送信するには、法的役割を持つユーザー(チームエージェント)が開発者Webサイトのアカウントで更新された契約を確認して同意する必要があります。

2018/12/21 韓国での法律改正

お上(Apple)からのメール。
以下は機械翻訳。
大韓民国で配布されているゲームに関する韓国の法律が変更されました。 あなたは現在韓国のApp Storeで1つ以上のゲームを配布しているので、Appleはあなたのゲームの名前とあなたのApple開発者アカウントに関連付けられたEメールアドレスを2019年1月1日から韓国ゲーム評価・管理委員会に提供する必要があります。
開発者とユーザーのデータを保護することは、私たちが真剣に取り組むことです。 この情報を共有したくない場合は、韓国でゲームを配布しないことを選択できます。 App Store Connectの各ゲームの「価格および配信状況」セクションで設定を調整するだけです。
要するに、韓国の法律が変わったことにより、韓国向けにゲームを提供するならアカウントに登録したメールアドレスを韓国の管理委員会に教えなきゃいけなくなるよ。嫌なら設定変更で韓国に配布しないことを選択できるよ。
というわけだ。

価格および配信状況の、「配信可否/選択されたすべてのテリトリ」を編集して、韓国だけチェックを外せばいいのだ。
めんどくさいからそのままにするつもりだけど。

2018年12月3日月曜日

変なエラー/Unknown selected data source for Port スピーカー (type: Speaker)

[avas] AVAudioSessionPortImpl.mm:56:ValidateRequiredFields: Unknown selected data source for Port スピーカー (type: Speaker)

「スピーカーに対して、不明のデータソースが選ばれた」ってことか。

iOS12、Swift4.2、Xcode10になってから、上記のメッセージがずらずらと出るようになった。何も操作してないのに0.何秒かおきに次々と出る、もしくは数回出て止まったり。
ただWarningみたいなもので、実行上問題は出ていない。

音を鳴らすアプリではあるのだが、まだ音に関しての操作もコードもないViewControllerを実行中に出るので、コードの変更があったというよりはXcodeの設定を変更しなけりゃいけないのかもしれない。

ネットで調べると、Swift4.2でAVAudioSessionの関係で変更があり、try文を記述してどうのこうのと書いてあるが、音の操作関係のコードがないところでいっぱい出てるので、直しようがない。そもそもAVAudioSessionのコード書いてないし。

データソースが不明ということで音源ファイルが原因っぽいが、使ってるのはそれぞれmp3、m4r、m4aのフォーマットの音源なのだが、Xcodeの設定をどこかでいじらねばいけないのか?

原因はAdMob

広告にGoogleのAdMobを表示させてるんだけど、それが悪さしていたようで、AdMob表示させないようにしたらメッセージが出なくなった。

Google Mobile Ads SDK Developers掲示板でもその件が話されている。いつの投稿か日付がわかんないんだけど、最新の日付が2018/9/18頃らしいので、まあその少し前くらいだろう。
AdMob内でAVAudioSessionを使用してて、それの改修が遅れてるんだろう。
ちなみに現時点で最新のAdMobSDK 7.36.0(2018/9/10リリースらしい)にしてみたけどダメだった。
うざいメッセージだけど、実用上問題ないし、俺が悪いわけじゃないからいいや。さっさと直してほしいけどね。

Googleって高い給料もらってるすごいエンジニアばかりだと思うんだけど、こういうのを直すのがすごい遅い。直されないことも多いし。変な入社試験で人を選んでるせいでエンジニアが足りないの?

2018年11月15日木曜日

タッチ座標の色情報を得る

やりたいこと

UIImageViewをタッチしたピクセルの色情報とアルファ値を得る。
たとえば赤いピクセルをタッチしたら
r:255.0 g:0.0 b:0.0 a:255.0
などと出るように。

やり方

タッチ位置に相当するImageViewに貼られたImageのアドレスを参照し、色情報を得る。
ImageViewに表示したImageはたいてい縮小か拡大されてるので、画面のタッチ位置からImage上の位置を計算する。

Image上の位置から画像データのメモリ上のアドレスを計算する。
アドレス計算時は1ピクセルを何バイトで扱っているのかの考慮が必要。(4バイトだった)
Retinaディスプレイの場合、縦横ともデータが2.0倍とかなるので(最近は3.0倍もあるんだっけ?)それも考慮に入れてアドレス計算要。
(注:Retinaで2.0のscaleを得て計算したらかえってうまくいかなかったので、以下のコードでは1.0を代入してある。おそらく画面比率の計算とかを二重にやっちゃってるんじゃないかと思うんだけど、よくわからねぇ…(^^;)ゞ
画面のタッチ位置とオリジナルImage上の位置の変換をしなければ、Retina解像度を考慮に入れたやり方でうまくいくんじゃないかと思う…)

サイトを参考にUIImageを拡張して機能を付けた。

画像の本当の大きさとImageView上に貼られた画像の比率を計算する過程でAVFoundationをimport要。

注意点

CGImageは必ずしもRGBAの順番で並んでいるわけじゃないそうな。
CGImageのCGImageAlphaInfo.rawValueでどういう並びなのか調べられる
以下のコードではRGBAの並びとして書いている。

コード

Swift4.1
import UIKit
import AVFoundation

let pixelDataBytesSize = 4; //1ピクセルのバイト数

extension UIImage {
func getColor(pos: CGPoint) -> (color:UIColor, r:CGFloat, g:CGFloat, b:CGFloat, a:CGFloat) {
let imageData = self.cgImage?.dataProvider?.data //画像データ
let data:UnsafePointer = CFDataGetBytePtr(imageData) //画像データのポインタ(配列扱い)を得るらしい
let scale:CGFloat = 1.0 //UIScreen.main.scale //画面のスケール(Retinaなら多分2.0〜3.0)を得る(コメントアウト中)
//任意のピクセルアドレスを計算
let address:Int = ((Int(self.size.width) * Int(pos.y * scale)) + Int(pos.x * scale)) * pixelDataBytesSize
//RGBαの各値を得る
let r = CGFloat(data[address])
let g = CGFloat(data[address + 1])
let b = CGFloat(data[address + 2])
let a = CGFloat(data[address + 3])
return (UIColor(red: r / 255, green: g / 255, blue: b / 255, alpha: a / 255), r, g, b, a)
}
}

class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel!
@IBOutlet weak var myImageView: UIImageView!

override func viewDidLoad() {
super.viewDidLoad()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//imageView上の実表示フレーム
let presentedFrame = AVMakeRect(aspectRatio: (myImageView.image?.size)!, insideRect: myImageView.bounds)
let marginX = presentedFrame.origin.x //上部のマージン
let marginY = presentedFrame.origin.y //左のマージン
if let touch = touches.first as UITouch? {
let loc = touch.location(in: myImageView) //タッチ座標
let image = myImageView.image
//画面上のタップ位置とimage上のタップ位置の変換
let tapX = (image?.size.width)! / presentedFrame.size.width * (loc.x - marginX)
let tapY = (image?.size.height)! / presentedFrame.size.height * (loc.y - marginY)
let color = image?.getColor(pos: CGPoint(x: tapX, y: tapY))
myLabel.textColor = color?.color
myLabel.text = "r:\(color!.r.description) g:\(color!.g.description) b:\(color!.b.description) a:\(color!.a.description)"
}
}
}

参考サイト

ImageViewに表示されたImageの、表示部分だけのframeを求める

ただし、AspectFitで表示された場合のみ有効。

ImageViewにImageを表示する際、contentModeの設定次第でImageを拡大/縮小して収めてくれるわけだが、Imageが実際に表示されている部分のframeサイズを得たいことがある。
そんな時に使うのが以下の関数。
ただしImageの縦横比を保ったまま拡大/縮小する .scaleAspectFit に設定された場合のみ。(他の設定にしても同じ結果しか得られなかった)
以下はすでにImageViewに表示中のImageについてframeサイズを得たが、表示前のImageでも大丈夫だろう。

Swift4.1
let presentedFrame = AVMakeRect(aspectRatio: (myImageView.image?.size)!, insideRect: myImageView.bounds)
print("表示サイズ \(presentedFrame)")

あらかじめAVFoundationをimportして使う。

ずっとわからず、比率を自前で計算してやってたんだけど、誤差が出たりとってもめんどうだった。
他のcontentModeでも使える関数ないかしら?

参考サイト:AS blind side/UIImagwViewにAspect Fitで配置されたUIImageの位置・サイズを求める