アナログ時計

このエントリーをはてなブックマークに追加

 スマホアプリを実際に作ってみたいと思います。
 今回はアナログ時計を作成します。カチカチと言った動作ではなく連続的な動きのアナログ時計を作成します。

 

1. 仕様

 今回は単純なアナログ時計にします。

  • 時針、分針、秒針の表示
  • それぞれの針は連続的(滑らかに)に動作する
  • 画面の向きは固定

2. 画面設計

 今回、見た目はそれほど重要でないため省略します。

 

3. 本アプリで使うCorona SDK の機能

 アプリを作成するにあたり使用する機能です。

 

3.1 本サイトで説明した機能

3.2 Lua言語

  • 日時取得:os.date(“*t”)

   

 

4. アナログ時計の作成

 実際にアナログ時計を作っていきたいと思います。

 

4.1 見た目の作成

 まずは見た目の作成です。時針、分針および秒針の作成を行います。それぞれの針は四角形で表現することにします。秒針は同じ色だとわかりにくかったので、赤色にしています。
  続いて非常に重要なアンカーポイントの設定です。針を端を中心に回転させることになるので、アンカーポイントを変更します。アンカーポイントは通常中心位置になっています。なので、そのまま使用すると、四角形そのものがそのまま回転してしまいます。時計の針として動かしたいので、四角形の長い方の端を中心にして回転させるための設定を行います。そこで、アンカーポイントのyを端に設定します。
 いまいちイメージがわかない場合、アンカーポイントの設定を色々と変更して表示や動きの確認をしてください。

— 名前が長いので、変数に代入
local centerX = display.contentCenterX
local centerY = display.contentCenterY
local contentWidth = display.contentWidth
— 時
local rectHour = display.newRect(centerX, centerY, 6, contentWidth * 0.3)
rectHour.anchorX = 0.5
rectHour.anchorY = 1
— 分
local rectMin = display.newRect(centerX, centerY, 4, contentWidth * 0.5 – 30)
rectMin.anchorX = 0.5
rectMin.anchorY = 1
— 秒
local rectSec = display.newRect(centerX, centerY, 2, contentWidth * 0.5 – 30)
rectSec:setFillColor(1, 0, 0, 1)
rectSec.anchorX = 0.5
rectSec.anchorY = 1

 

4.2 タイマで作るアナログ時計

 まず簡単にアナログ時計を作る方法です。それはタイマを使用した方法です。
 プログラムは単純で、画面の更新関数をタイマで300ミリ秒間隔で呼び出しているだけです。プログラムの動きは以下の通りです。

1. 画面更新関数(Update)を作成
      1. 現在時刻を取得
      2. 現在時刻から時針の角度を計算し描画オブジェクトの角度を更新
            時間は24時間形式で取得となるため、2回転で720度としています。
            時針の角度は時刻の分も影響するので、分の角度を計算し加算しています。
      3. 現在時刻から分針の角度を計算し描画オブジェクトの角度を更新
            分針の角度は時刻の秒も影響するので、秒の角度を計算し加算しています。
      4. 現在時刻から秒針の角度を計算し描画オブジェクトの角度を更新

2. 画面更新関数(Update)を実行
      すぐに更新しないと起動直後に、描画オブジェクトを作成した初期位置で表示してしまうためです。

3. タイマ登録
      画面更新関数(Update)を300ミリ秒周期で繰り返すように設定

local function Update()
    — 現在時間を取得
    local now = os.date(“*t”)
    — 角度を計算
    rectHour.rotation = now.hour * 720 / 24 + now.min * (720
/ 24) / 60
    rectMin.rotation = now.min * 360 / 60 + now.sec * 360 / 60
/ 60
    rectSec.rotation = now.sec * 360 / 60
end

— 最初の描画を即更新
Update()
— 一定間隔で角度を更新
timer.performWithDelay(300, Update, -1)

 

4.3 連続動作のアナログ時計

 4.2で作成した時計はアナログ時計ではありますが、仕様通りのアナログ時計ではありません。そこで、連続して滑らかに動作する時計を作成します。
 タイマでミリ秒まで取得し、色々な計算を行えば滑らかに動作も可能だとは思うのですが、Corona SDKではオブジェクトの移動などが簡単に行えるので、「transition.to()」を使用したいと思います。
 ここでは秒を例にして処理の説明を行います。時分も計算が多少異なるだけで、方法は同様です。

1. 秒針の描画オブジェクトの作成

2. 秒針の描画オブジェクトの移動を制御するための変数を作成

3. 秒針の制御関数(UpdateSec)の作成
   1. 秒針が移動(回転)を行っている場合、停止させる
   2. 現在時刻の取得
   3. 秒針の角度を計算
   4. 秒針が1周するまでの残り時間の計算(単位はミリ秒)
   5. 移動(回転)を実行
         回転完了時に秒針の制御関数(UpdateSec)を呼び出すようにしているため、止めない限り動作します。

4. 秒針の制御関数(UpdateSec)を実行

— 名前が長いので、変数に代入
local centerX = display.contentCenterX
local centerY = display.contentCenterY
local contentWidth = display.contentWidth
— 秒
local rectSec = display.newRect(centerX, centerY, 2, contentWidth * 0.5 – 30)
rectSec:setFillColor(1, 0, 0, 1)
rectSec.anchorX = 0.5
rectSec.anchorY = 1
— オブジェクトの移動管理用変数
local transitionSec = nil

— 秒針の制御
local function UpdateSec()
    if (transitionSec ~= nil) then
        transition.cancel(transitionSec)
        transitionSec = nil
    end
    — 現在日時を取得
    local now = os.date(“*t”)
    — 角度と時間の計算
    local angle = now.sec * 360 / 60
    local endTime = 60 * 1000 – (now.sec * 1000)
    rectSec.rotation = angle
    transitionSec = transition.to(rectSec, {rotation = 360, time
= endTime, onComplete = UpdateSec})
end

UpdateSec()

 

4.4 補正処理

 長時間の動作、複雑な計算や処理、サスペンドなどから戻った場合などに、間違った時間を表示してしまうことがあります。そこで補正処理を追加します。補正処理では、現在時刻で計算した時分秒それぞれの角度と、現在描画中の角度を比較し、その差が大きい場合、すべての更新を行うようにしています。Corona
SDK特有の処理はなく、単なる確認処理だけなので、最後に添付しているプログラムをみて確認してください。補正処理は「CorrectForVariations()」関数です。
 補正処理を実行する関数をタイマで繰り返し実行するようにしています。間隔の時間が変な数字になっているのは、他の処理とできる限り重ならないようにするためです。

 

4.5 プログラム内の計算について

 今回、プログラムでは全ての計算をできる限り意味が分かるように、そのまま記述しています。実行ファイルを作成する際の最適化処理によりますが、計算コストを考えると先に計算しておいた方が処理は早くなると思います。Corona
SDKがどこまで最適化を行っているかわからないため、先にしておける計算はしておくといいと思います。

例えば、
now.hour * 720 / 24
であれば、
now.hour * 30
としてしまうなどです。

   

 

5. 完成

 プログラムを実行すると以下のような画面が表示され、時間が更新されます。

 


 さて、完成とは言ったもののあまりにさみしいので、文字盤と多少の数字を追加したいと思います。以下の処理を表示順序を考えて追加します。文字盤は針の下にくる必要があるので、先に登録するようにしてください。

local clockBase = display.newCircle(centerX, centerY, contentWidth * 0.45)
clockBase:setFillColor(0.6, 0.6, 0.6, 0.6)
display.newText(“12”, centerX, centerY – contentWidth * 0.4, native.systemFont, 30)
display.newText(“3”, centerX + contentWidth * 0.4, centerY, native.systemFont, 30)
display.newText(“6”, centerX, centerY + contentWidth * 0.4, native.systemFont, 30)
display.newText(“9”, centerX – contentWidth * 0.4, centerY, native.systemFont, 30)

 追加して実行すると以下のような感じになります。

 


 少しは時計っぽくなりましたね。少し変更するだけでイメージは変わるので、色を変えてみたり、1時や2時などの位置に丸いぽっちを追加するなど色々なことに挑戦してみてください。

 

6. あとがき

 いかがでしたでしょうか、「また時計かよ」と思われた方もいたかもしれませんが、時計は基礎を勉強するにはとても便利な教材です。常に画面が更新されるため、動きの確認も行えます。
 今回作成したプログラムはおよそ180行、実行行数は5割くらいの90行程度でしょうか。それほど量は多くないと思うので、最初から動きとともに確認するのもいいと思います。
 また、完成したアナログ時計を少し変更するだけでイメージは変わるので、色を変えてみたり、1時や2時などの位置に丸いぽっちを追加するなど色々なことに挑戦してみてください。

私が作成したアプリです。

もし宜しければ見て行ってください。

 

7. ソースコード

 プログラムの全文を掲載します。

<注意>
設定ファイルはCorona SDKが自動で作成したままです。
文字コードUTF-8になっています。(Corona SDKではUTF-8が標準の為)
ファイル名は必要に応じて変更し利用してください。
本サイトの注意事項を確認してください。
ソースコードを使用する場合、上記注意とともに、自己責任でお願いします。

       

<更新履歴>

更新日 Corona SDKのバージョン
新規作成 2015年9月17日 v2015.2646

 

 

前へ          メニューへ          次へ

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)