در این آموزش، به کمک آبجکتهای سادهای که در یونیتی وجود دارند، یک ساعت عقربهای سهبعدی (3D) میسازیم که زمان فعلی سیستم را نشان دهد. همچنین سورس نهایی در انتهای مطلب قرار داده شده است.
برای شروع کار، یونیتی را اجرا کرده و یک پروژه 3D جدید ایجاد کنید.
1. گیم آبجکت پایه
برای آنکه صفحهی ساعت و اجزای آن را ایجاد کنیم، ابتدا یک گیم آبجکت خالی (Empty Game Object) ایجاد میکنیم تا بقیه موارد را درون آن قرار دهیم. بنابراین از منوی GameObject، برروی Create Empty کلیک کرده و سپپس نام آبجکت ظاهر شده در هایراکی را به Clock تغییر دهید.
در نهایت نیز توجه داشته باشید که مقادیر Transform آن را در Inspector بهصورت زیر باشد. البته بدیهی است که این مورد الزامی نبوده و تنها برای این میباشد که همراه آموزش جلو بروید.
2. ساخت صفحه ساعت
ضفحه ساعت آنالوگ معمولا دایرهای شکل است. در یونیتی میتوان آن را با استفاده از یک سیلندر ایجاد کرد. بنابراین از منوی GameObject برروی Cylinder کلیک کرده و پس از آنکه مقادیر Transform آن را همانند آبجکت Clock تنظیم کردید، بایستی مقادیر Scale را تغییر دهید تا به یک دایره برای صفحهی ساعت تبدیل شود. بنابراین ارتفاع آن را 0.1 و x و z آن را به 10 تغییر دهید.
حالا که دایرهی ساعت خود را در اختیار داریم؛ نام آن را به Face تغییر داده و آن را زیرمجموعهی Clock قرار دهید.
3. قرار دادن نشانگرها
مقادیر ساعت از 1 تا 12 تقسیمبندی میشوند. بنابراین در این قسمت، محیط دایره را به 12 قسمت تقسیم کرده و نشانگر ساعتها را برروی آن میچینیم. برای اینکار اجازه دهید از یک Cube استفاده کنیم! ابتدا از منوی GameObject، یک Cube ایجاد کنید. نام آن را به Hour Indicator تغییر داده و مقادیر Transform آن را به ترتیب برای Position مقدار 0,0.2,4 و برای Scale مقدار 0,0.5,1 تنظیم کنید.
حالا یکی از تقسیمبندیهای ساعت را انجام دادیم که آن را مثلا ساعت 12 در نظر میگیریم. اما بیایید قبل از ادامهی بقیه کار، رنگ این نشانگر را به سیاه تغییر دهیم. لذا در بخش Assets راست کلیک کرده و از منوی Create برروی Material کلیک کنید. سپس نام آن را Clock Dark قرار داده و آن را انتخاب کنید. حال از بخش Inspector، مقدار Albedo را به یک رنگ سیاه تغییر دهید.
متریال را برروی آبجکت Hour Indicator درگ کنید. (کشیده و رها کنید)
نشانگر که در حال نمایش ساعت 12 است؛ حالا چگونه نشانگری را برای ساعت 1 و … تنظیم کنیم؟! میدانیم که 12 ساعت در اختیار داریم یعنی 12 بخش و دایره نیز 360 درجه است. با تقسیم 360 بر 12، به 30 میرسیم. بنابراین انتظار میرود که با چرخش کیوب ایجاد شده حول محور y و به اندازه 30 درجه، بتوان آن را برای ساعت بعدی تنظیم کرد. بیایید انجام دهیم:
چه اتفاقی افتاد؟! نشانگر برروی دایره و بهطور 30 درجه نچرخید! بلکه سر جای خودش 30 درجه چرخش پیدا کرد! چرا که چرخش آن به مرکز لوکال (local) خود بستگی دارد. برای حل مشکل، ابتدا y نشانگر را به 0 تغییر دهید. سپس یک گیمآبجکت خالی (Empty) ایجاد کنید. پوزیشن و روتیشن آن را 0 و Scale آن را 1 قرار دهید (که در نتیجه، در مرکز دایره قرار خواهد گرفت). حالا نشانگر را فرزند آن قرار دهید.
گیمآبجکت خالی را که پدر نشانگر است، 30 درجه حول محور y بچرخانید! خواهید دید که Hour Indicator برروی محیط دایره 30 درجه جابهجا میشود!
این کار را با دوپلیکیت کردن تکرار کنید تا زمانی که 12 نشناگر ساعت ساخته شود. (هربار 30 درجه به قبلی اضافه خواهید کرد، 30، 60، 90 و …)
حالا دیگر نیازی به گیمآبجکتهای خالی نداریم و میتوان نشانگرها را از آنها خارج کرد. بنابراین اینکار را انجام داده و کل نشانگرها را به زیرمجموعهی آبحکت Clock انتقال دهید.
4. ایجاد عقربهها
ساعت سه عقربه دارد؛ که شامل ثانیه، دقیقه و خود ساعت است. برای ایجاد عقربهها نیز از کیوب استفاده میکنیم. بنابراین در ابتدا یک Cube ایجاد کرده و نام آن را Arm قرار دهید. اسکیل آن را به 0.3,0.2,2.5 و پوزیشن آن را به 0,0.2,0.75 تغییر دهید. متریال Clock Dark را نیز برروی آن اعمال کنید. این عقربهی کوچک ساعت است که خود ساعت را نشان میدهد.
یک گیمآبجکت خالی ساخته و نام آن را Hour Arms قرار دهید. مقادیر پوزیشن و روتیشن آن را 0 و اسکیل را 1 قرار داده و آن را زیر مجموعهی Clock قرر دهید. سپس عقربهی ایجاد شده را نیز زیرمجموعهی Hour Arms انتقال دهید.
از Hour Arms یک دوپلیکیت گرفته و نام آن را به Minutes Arm تغییر دهید. برای آبجکت Arm درون آن، مقدار Scale را برابر 0.2,0.15,4 و پوزیشن را برابر 0,0.375,1 قرار دهید. یک کپی دیگر از Hour Arms گرفته و نام آن را Seconds Arm انتخاب کنید. سپس مقدار Scale آن را برابر 0.1,0.1,5 و پوزیشن را نیز برابر 0,0.5,1.25 قرار دهید. برای تغییر رنگ ثانیهشمار که معمولا به رنگ قرمز است نیز یک متریال به نام Clock Red ایجاد و پس از انتخاب رنگ قرمزی برای آن، متریال را برروی آبجکت عقربهی ثانیهشمار درگ کنید.
حالا ساعت ما آماده است؛ اما روحی نداشته و نیاز به کدنویسی دارد. 🙂
5. اسکریپتنویسی ساعت
اسکریپیتی به نام Clock ایجاد کنید. برای اینکار، در Assets راست کلیک کرده و از منوی Create برروی C# Script کلیک کنید. نام آن را Clock قرار داده و سپس برروی آن دبل کلیک کنید.
قرار است عقربهها را جابهجا کنیم. بنابراین به Transform عقربهها نیاز خواهیم داشت! لذا در ابتدا، سه فیلد زیر را در اسکریپت خود تعریف کنید:
1 2 3 |
public Transform hoursTransform; public Transform minutesTransform; public Transform secondsTransform; |
در دنیای واقعی، عقربهی ساعتها معمولا بهدو صورت نرم (پیوسته) و گسسته حرکت میکنند. این مورد را در ثانیه شمار ساعتها احتمالا دیدهاید. بنابراین ابتدا یک فیلد بولی بهنام continuous ایجاد کنید که اگر true بود، حرکت عقربهها نرم و اگر false بود، حرکت گسسته باشد.
1 |
public bool continuous; |
حالا دو متد بهنامهای UpdateContinuous (برای حالت نرم) و UpdateDiscrete (برای حالت گسسته) ایجاد کنید. سپس با بررسی فیلد continuous در متد Update، یکی از آنها را فراخوانی کنید. کدهای اسکریپت بهصورت زیر خواهد بود:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Clock : MonoBehaviour { public Transform hoursTransform; public Transform minutesTransform; public Transform secondsTransform; public bool continuous; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { if (continuous) { UpdateContinuous(); } else { UpdateDiscrete(); } } void UpdateContinuous() { } void UpdateDiscrete() { } } |
اما اکنون نوبت پیادهسازی بدنهی متدها است. ابتدا متد گسسته را پیادهسازی میکنیم. برای بدست آوردن ساعت فعلی سیستم، از DateTime.Now استفاده و روتیشن عقربهها را تنها حول محور Y و بهصورت زیر تغییر میدهیم:
1 2 3 4 5 6 7 |
void UpdateDiscrete() { DateTime now = DateTime.Now; hoursTransform.localRotation = Quaternion.Euler(0f, now.Hour * 30f, 0f); minutesTransform.localRotation = Quaternion.Euler(0f, now.Minute * 6f, 0f); secondsTransform.localRotation = Quaternion.Euler(0f, now.Second * 6f, 0f); } |
همانطور که مشاهده میکنید، برای هر عقربهای روتیشن جدید آن را به کمک متد Euler کواترنیون مقداردهی کردهایم.
- ساعت که بین 1 تا 12 خواهد بود. با ضرب در 30 درجه، میتوان مقدار روتیشن آن را بین 12 نشانگر موجود برروی 360 درجه بدست آورد.
در واقع 360 تقسیم بر 12 برابر 30 درجه است. - دقیقه که بین 1 تا 60 خواهد بود، با ضرب آن در 6 درجه، میتوان مقدار روتیشن آن را بین 60 نشانگر موجود در 360 درجه بدست آورد.
در واقع 360 تقسیم بر 60 برابر 6 درجه است. - ثانیه نیز همانند دقیقه 60 نشانگر دارد که مثل آن تنظیم میشود.
این متد از آنجهت حرکت نرمی ندارد، چراکه خروجی now.Hour و now.Minute و now.Second همواره عدد صحیح بوده و دقیق نیست! بنابراین برای پیادهسازی متد UpdateContinuous بایستی از روش دیگری برای بدست آوردن زمان دقیق استفاده کرد تا حرکت نرمی بدست آورد! بدین منظور از DateTime آبجکت TimeSpan را دریافت میکنیم که از طریق آن میتوان زمان دقیق را بهصورت double بدست آورد؛ لذا متد UpdateContinuous بصورت زیر خواهد بود:
1 2 3 4 5 6 7 |
void UpdateContinuous() { TimeSpan now = DateTime.Now.TimeOfDay; hoursTransform.localRotation = Quaternion.Euler(0f, (float)now.TotalHours * 30f, 0f); minutesTransform.localRotation = Quaternion.Euler(0f, (float)now.TotalMinutes * 6f, 0f); secondsTransform.localRotation = Quaternion.Euler(0f, (float)now.TotalSeconds * 6f, 0f); } |
بههمان روش قبل، Now را بدست آوردیم که مقدار DateTime فعلی را بهما میدهد. اما از طریق یک DateTime نیز میتوان TimeSpan را بدست آورد که اینکار از طریق متد TimeOfDay آن صورت میگیرد که زمان یک روز را برحسب TimeSpan شامل میشود.
سپس از طریق متدهای TotalHours و TotalMinutes و TotalSeconds، ساعت و دقیقه و ثانیه را بدست آورده و طبق روش قبل عمل میکنیم. اما از آنجا که ورودیها باید از نوع float باشند، مقادیر double را نیز به float تبدیل میکنیم و بقیهی روند کار نیز بههمان صورت است.
در نهایت اسکریپت ما بهصورت زیر خواهد شد:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class Clock : MonoBehaviour { public Transform hoursTransform; public Transform minutesTransform; public Transform secondsTransform; public bool continuous; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { if (continuous) { UpdateContinuous(); } else { UpdateDiscrete(); } } void UpdateContinuous() { TimeSpan now = DateTime.Now.TimeOfDay; hoursTransform.localRotation = Quaternion.Euler(0f, (float)now.TotalHours * 30f, 0f); minutesTransform.localRotation = Quaternion.Euler(0f, (float)now.TotalMinutes * 6f, 0f); secondsTransform.localRotation = Quaternion.Euler(0f, (float)now.TotalSeconds * 6f, 0f); } void UpdateDiscrete() { DateTime now = DateTime.Now; hoursTransform.localRotation = Quaternion.Euler(0f, now.Hour * 30f, 0f); minutesTransform.localRotation = Quaternion.Euler(0f, now.Minute * 6f, 0f); secondsTransform.localRotation = Quaternion.Euler(0f, now.Second * 6f, 0f); } } |
6. نهایی سازی
اسکریپت Clock را برروی آبجکت Clock اعمال کرده و از طریق Inspector، حالت continuous آن را نیز تعیین کنید؛ سپس مقادیر hoursTransform و minutesTransform و secondsTransform را نیز برای آن تنظیم کنید. که بایستی Hours Arm و Minutes Arm و Seconds Arm را به آنها نصبت دهید. پس از اتمام این فرآیند ساده، پروژه را اجرا کنید.
نظرات ثبت شده بدون دیدگاه