(1人でカウントダウン)
普通に差分書けばOK
(みんなでカウントダウン)
上記の方法では全員ずれが出る
ローカルの時計とNTPの時計を比較して差分を出し,その時間でカウントダウンする.カウントダウンは直前にしか見ないのでNTPの同期は1回でOK.
ただしコルーチンを頻繁に呼び出すのが怖かったので,1秒でコルーチンしている.つまり最大で0.99秒ずれる.
最近の端末はおもったより性能が良いので,0.1秒でコルーチンしてもいいかもしれません.(NTP呼び出しは1回だけにする)
(1人でカウントダウン)
普通に差分書けばOK
(みんなでカウントダウン)
上記の方法では全員ずれが出る
ローカルの時計とNTPの時計を比較して差分を出し,その時間でカウントダウンする.カウントダウンは直前にしか見ないのでNTPの同期は1回でOK.
ただしコルーチンを頻繁に呼び出すのが怖かったので,1秒でコルーチンしている.つまり最大で0.99秒ずれる.
最近の端末はおもったより性能が良いので,0.1秒でコルーチンしてもいいかもしれません.(NTP呼び出しは1回だけにする)
XBeeが混信した可能性があり,普段は30mでも平気なのにこの日は1mでも微妙な接続に.
謎です.
リンク先
http://nekosuko.jp/blog/?p=278
UnityAppController.mmのnotificationをコメントアウト系
カメラの背景色を変えるスクリプト
わりと簡単だったけど,おもしろみに欠ける
Camera.main.backgroundColor = Color.red;
CSVのテキストはテキスト内に\nとかいてても,改行と認識されない.そこで,強制的に@を改行コードに読み替える方法で回避する
テキストの改行カ所に半角の@を入れる.そこが改行される.
using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.IO;//use for file read using UnityEngine.UI;//use unity gui public class quiz : MonoBehaviour { //public string[] qq; // Use this for initialization public ArrayList qq =new ArrayList();//question store to this array private int no;//this means number public int maxQ = 3;//count of quiz public Text quizText, kaisetsu; //Text用変数 public Text bt1,bt2,bt3,bt4;//for assign btn tex public int answer;//answer number public int selected;//selected btn //public Toggle tog1, tog2, tog3, tog4; public ToggleGroup tgg1;//select btn group public GameObject kaisetsuPanelAlert; public GameObject seikaiPanelAlert; public GameObject ngPanelAlert; public GameObject selectAlert; void Start () { //Android is load from streming Assets floder // //jar:file://" + Application.dataPath + "!/assets" + "/"; //example // // TextAsset csv = Resources.Load("question") as TextAsset; // StringReader reader = new StringReader(csv.text); // while (reader.Peek () > -1) { // string line = reader.ReadLine (); // string[] values = line.Split (','); // Debug.Log (values[0]); // } kaisetsuPanelAlert.SetActive (false); seikaiPanelAlert.SetActive (false); ngPanelAlert.SetActive (false); selectAlert.SetActive (false); // no = 0;//initialize of quiz count //ArrayList qq =new ArrayList(); TextAsset csv = Resources.Load("question") as TextAsset; StringReader reader = new StringReader(csv.text); while (reader.Peek () > -1) { qq.Add (reader.ReadLine ()); } //Debug.Log ((string)qq[1]); qread ();//show first question } // Update is called once per frame void Update () { } public void tog1press(){ answer = 1; } public void tog2press(){ answer = 2; } public void tog3press(){ answer = 3; } public void tog4press(){ answer = 4; } public void qread(){//next mondai // for(no = 0; no < maxQ; no++){ tgg1.SetAllTogglesOff(); string qqq=(string)qq[no]; string[] values = qqq.Split(',');//values is string array //GameObject.Find ("SectionText").GetComponent<Text>().text=Section[ int.Parse(values[0]) ]; // string atxt = ""; // string atxt1 = ""; // string atxt2 = ""; // string atxt3 = ""; // int mode = Random.Range (0, 10); // if (mode == 0) // { // atxt=values[2];GoodNo=1; // atxt1=values[1]; // atxt2=values[4]; // atxt3=values[5]; // } string test1 = (string)values[0]; // quizText.text = (string)values[0]; quizText.text = test1.Replace("@", "\n"); selected = int.Parse((string)values [1]);//csv is text, so, covert to string bt1.text = (string)values[2]; bt2.text = (string)values[3]; bt3.text = (string)values[4]; bt4.text = (string)values[5]; string kaisetsuKaigyou = (string)values[6]; kaisetsu.text = kaisetsuKaigyou.Replace("@", "\n"); //kaisetsu.text = (string)values[6]; if (no < maxQ) { //quiz count limit no++; }else{ no = maxQ; //kokode resulthe,, } // Debug.Log(tgl); //} } public void answerCheck(){ //Boolean selectCheck = tgg1.AnyTogglesOn; if (!tgg1.AnyTogglesOn()) { selectAlert.SetActive (true); return; } if (selected == answer) { seikaiPanelAlert.SetActive (true); // Debug.Log ("seikai"); } else { ngPanelAlert.SetActive (true); // Debug.Log ("No!"); } } public void hideKaisetsuPanel(){ kaisetsuPanelAlert.SetActive (false); qread (); } public void showKaisetsunOK(){ seikaiPanelAlert.SetActive (false); kaisetsuPanelAlert.SetActive (true); } public void showKaisetsuNG(){ ngPanelAlert.SetActive (false); kaisetsuPanelAlert.SetActive (true); } public void hideSelecyAlert(){ selectAlert.SetActive (false); } }
そのユーザ名が存在するかチェックする
<?php // Send variables for the MySQL database class. $database = mysql_connect('myserver.jp', 'username', 'passwd') or die('Could not connect: ' . mysql_error()); mysql_select_db('dbname') or die('Could not select database'); //変数宣言 $keyword=''; //不正防止用キーワード $resultData=''; //返すデータ //データ受け取り if(isset($_POST['keyword'])){ $keyword=$_POST['keyword']; //キーワード } //print $_POST['keyword']; $name= $_POST['keyword']; //print $name; //if($keyword==null or !($keyword==$key['get_score_ranking'])){ // $redirectUrl = "http://filmm.info/404.html"; // header("HTTP/1.0 404 Not Found"); // print(file_get_contents($redirectUrl)); // exit; //} //search test $nameresult = mysql_query("SELECT * FROM `scores` WHERE `name` = $name");//文字列検索はシングルクォート if (!$nameresult) { die('クエリーが失敗しました。'.mysql_error()); } //echo mysql_num_rows($nameresult); print mysql_num_rows($nameresult); ?>
かなり不要部分多し
ちょっとセキュリティ的には良くない部分有り
Unityから呼び出したサーバ側に設置するPHPです
<?php $db = mysql_connect('severurl', 'sq_lusername', 'sql_password') or die('Could not connect: ' . mysql_error()); mysql_select_db('sql?database_name') or die('Could not select database'); // Strings must be escaped to prevent SQL injection attack. $name = mysql_real_escape_string($_GET['name'], $db); $score = mysql_real_escape_string($_GET['score'], $db); $cName = mysql_real_escape_string($_GET['cName'], $db); $hash = $_GET['hash']; $secretKey="****"; # Change this value to match the value stored in the client javascript below $real_hash = md5($name . $score . $cName . $secretKey); if($real_hash == $hash) { // Send variables for the MySQL database class. $query = "insert into scores values (NULL, '$name', '$score', '$cName');"; $result = mysql_query($query) or die('Query failed: ' . mysql_error()); } ?>
スコアを追加できます
ハイスコア記録用のCSスクリプト組んでます.
たぶんscoresというテーブルを作って,ID番号(自動インクリメント),名前,スコア,cName(独自に追加)を要素にするというものだと思う
CREATE TABLE `scores` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(128) NOT NULL DEFAULT 'anonymous', `score` INT(10) UNSIGNED NOT NULL DEFAULT '0', `cName` VARCHAR(128) NOT NULL DEFAULT 'anonymous' ) ENGINE=MyISAM;
最後のENGINE=MyISAMはmySQL5.5用
4.xだと
ENGINE=MyISAM;
だそうです
追加
CREATE TABLE `scores` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(128) NOT NULL DEFAULT 'anonymous', `cName` VARCHAR(128) NOT NULL DEFAULT 'anonymous', `area` VARCHAR(128) NOT NULL DEFAULT 'anonymous', `quize` BOOL NOT NULL DEFAULT '0', `score` INT(10) UNSIGNED NOT NULL DEFAULT '0' `time` INT(10) UNSIGNED NOT NULL DEFAULT '0' ) ENGINE=MyISAM;
Haloはライトオブジェクトにあてるとぼうっと光った雰囲気を出せます.(component>effectにはいっています)
トグルボタンを押した感を出すためにHaloをON/OFF表示させるためのスクリプトです
using UnityEngine; using System.Collections; using UnityEngine.UI; public class btnshowHalo : MonoBehaviour { public GameObject lightHalo;//assign activate object public Toggle toggleBtn;//for assign toggle btn // Use this for initialization void Start () { lightHalo.SetActive(false);//initialize } // Update is called once per frame void Update () { } public void showHalo(){ if (toggleBtn.isOn) { lightHalo.SetActive (true); //show halo } else { lightHalo.SetActive (false); //hide halo } } }
アサインすると,トグルボタンとアクティベートするゲームオブジェクトをエディタでアサインします.ボタン押された時のスクリプト設定をやって完了
カウントダウンアプリをつくっていますが,各自のスマホの時間がバラバラなので,ntpから差分とった時刻で正確な時間を出すようにしてみました.
修正中ですが,概ねこれで作動します.
元ネタはこれ→ http://ftvoid.com/blog/post/847
HTML5ならもう少し簡単だったのですが,,
using UnityEngine; using System; using System.Collections; using System.Net; using System.Net.Sockets; using System.Threading; using UnityEngine.UI;//use unity gui // NTP同期時刻を管理するクラス public class NtpDate : MonoBehaviour { private DateTime ntpDate; // NTP同期時刻 private float rcvAppDate; // NTP通信時のアプリ時刻 private IPEndPoint ipAny; private UdpClient sock; private Thread thread; private volatile bool threadRunning = false; private byte[] rcvData; public string myString; //for time display private DateTime endDate; //for end date public Transform myButton; //get button object public Text countText; //Text用変数 private TimeSpan zure; // 初期化 void Start() { // リクエスト実行 SyncDate(); // 時刻表示(デバッグ用) StartCoroutine(ShowSyncDate()); //Debug.Log (System.DateTime.Now); } // 同期時刻の表示 private IEnumerator ShowSyncDate() { while ( true ) { yield return new WaitForSeconds(0.1f);//0.5f timeCheck ();// do timeCheck() every 1 second //if ( Date == false ) { if ( Date == null ) { Debug.Log("Time is not received."); } else { //Debug.Log("Receive date : " + Date.ToString()); // Debug.Log (DateTime.Now);// DateTime.Now is confiured time } } } /// for GUI my add public void timeCheck(){ endDate = new DateTime(2016, 4, 2, 18,30,00); //本番用 // endDate = new DateTime(2016, 2, 4, 12,30,00);//for test TimeSpan sabun = endDate - DateTime.Now; //compare now time and end time // Debug.Log ("before" + sabun); // Debug.Log ("after" + (sabun - zure)); //int result = TimeSpan.Compare(endDate, DateTime.Now);// cant use sabun = sabun - zure;//zure naosu if (sabun.Days <= 0 && sabun.Hours <= 0 && sabun.Minutes <= 0 && sabun.Seconds <= 0) { //sabun is all zero and minus myString = "Light It Up Blue!"; //message of button countText.text = myString; //put text to GUItext myButton.GetComponent<Toggle>().interactable = true; //unlock the button } else { myString = string.Format ("{0:00}D{1:00}H{2:00}M{3:00}S", sabun.Days, sabun.Hours, sabun.Minutes, sabun.Seconds);//string format countText.text = myString; //time remaining myButton.GetComponent<Toggle>().interactable = false; //lock button before last time } } public void Update(){ // timeCheck (); } // アプリケーション終了時処理 void OnApplicationQuit() { if ( thread != null ) { thread.Abort(); } if ( sock != null ) { sock.Close(); } } // 時刻同期を行う public void SyncDate() { // リクエスト実行 threadRunning = true; thread = new Thread(new ThreadStart(Request)); thread.Start(); // リクエスト待機コルーチン実行 StartCoroutine(WaitForRequest()); Debug.Log("Thread is started."); } // NTPサーバに対してリクエストを実行する private void Request() { // ソケットを開く ipAny = new IPEndPoint(IPAddress.Any, 123); // sock = new UdpClient(ipAny); sock = new UdpClient(); // リクエスト送信 byte[] sndData = new byte[48]; sndData[0] = 0xB; sock.Send(sndData, sndData.Length, "ntp.jst.mfeed.ad.jp", 123); // データ受信 rcvData = sock.Receive(ref ipAny); // 実行中フラグクリア threadRunning = false; } // リクエスト待機コルーチン private IEnumerator WaitForRequest() { // リクエスト終了まで待機 while ( threadRunning ) { yield return 0; } // アプリ時刻保存 rcvAppDate = Time.realtimeSinceStartup; Debug.Log (rcvAppDate); // 受信したバイナリデータをDateTime型に変換 ntpDate = new DateTime(1900, 1, 1); var high = (double)BitConverter.ToUInt32(new byte[] { rcvData[43], rcvData[42], rcvData[41], rcvData[40] }, 0); var low = (double)BitConverter.ToUInt32(new byte[] { rcvData[47], rcvData[46], rcvData[45], rcvData[44] }, 0); ntpDate = ntpDate.AddSeconds(high + low / UInt32.MaxValue); // UTC→ローカル日時に変換 ntpDate = ntpDate.ToLocalTime(); zure = Date - DateTime.Now; Debug.Log ("zure" + zure); } // NTP同期時刻 public DateTime Date { get { return ntpDate.AddSeconds(Time.realtimeSinceStartup - rcvAppDate); } } }