FireHD8plusが到着したので、作業を進めてインストールしてみる。スマートフォンだと小さすぎるし10インチだと重いしで、8インチくらいがちょうど良いのかな?とりあえず1ページ目で観察者名や実験名、生徒数、インターバルなどの基本情報を入力し、2ページ目で行動を記録する、というインターフェースにしてみた。
でもこれくらい画面が広いと、
1.いっそボタンに観察対象となる行動を文字で表示する
2.座席表や簡単な作業マニュアルなどを画面上で参照可能にする
などの改善案が可能という気もする。
以下にUnity側のc#スクリプトと、サーバー側のPHPスクリプトを記載する。
1行入力やスライダーの値をPlayerPrefsに保存し、「次へ」ボタンでページ遷移するプログラム。PlayerPrefsはUnity実行環境で利用できるディスク領域のようなもの。テキストや数値などの各種パラメータを保存できる。シーンをまたぐときに使うと便利。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine.Networking;
using TMPro;
public class procP1 : MonoBehaviour
{
public TMP_InputField input1;
public TMP_InputField input2;
public Slider slider1;
public TextMeshProUGUI mes1;
public Slider slider2;
public TextMeshProUGUI mes2;
// Start is called before the first frame update
void Start()
{
//Screen.SetResolution(1200, 540, true, 60); // RedmiNote11
Screen.SetResolution(1280, 800, true, 60); // Fire HD 8
//read PlayerPrefs
string username,expcode;
int studentnum = 0;
int interval = 0;
username = PlayerPrefs.GetString("username", "-");
if (username.Length > 1) {input1.text = username;}
expcode = PlayerPrefs.GetString("expcode", "-");
if (expcode.Length > 1) { input2.text = expcode; }
studentnum = PlayerPrefs.GetInt("studentnum", 0);
slider1.value = studentnum;
interval = PlayerPrefs.GetInt("interval", 0);
slider2.value = interval;
/*
username
expcode
studentnum
interval
*/
}
// Update is called once per frame
void Update()
{
mes1.text = slider1.value + "名";
mes2.text = slider2.value + "秒";
}
public void procNextBtn() {
// write playerPrefs
PlayerPrefs.SetString("username", input1.text);
PlayerPrefs.SetString("expcode", input2.text);
PlayerPrefs.SetInt("studentnum", (int)slider1.value);
PlayerPrefs.SetInt("interval", (int)slider2.value);
SceneManager.LoadScene("P2"); // load scene "P2"
}
}
ボタンのOn/Offを記憶し、定められた時間間隔でHTTP通信でサーバーへ値を送信するプログラム。ボタンのOn/Offは毎フレーム、文字などの更新処理は1秒間隔でおこなっている。HTTP通信はStartCoroutineで非同期処理。Post形式でサーバー側のPHPスクリプトに値を送っている。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using TMPro;
using UnityEngine.SceneManagement;
using UnityEngine.Networking;
public class procP2 : MonoBehaviour
{
public Button b1;
public Button b2;
public Button b3;
public Button b4;
public Button b5;
public TextMeshProUGUI mes1;
public TextMeshProUGUI mes2;
public TextMeshProUGUI mes3;
public AudioClip clip1;
bool sw1, sw2, sw3, sw4, sw5;
Color pink;
DateTime dt;
long t1, t0;
AudioSource audio;
int interval =10;
int currentst = 0;
// Start is called before the first frame update
void Start()
{
sw1 = sw2=sw3=sw4=sw5=false;
pink= new Color(255f / 255f, 100f / 255f, 100f / 255f, 1f);
// read PlayerPrefs
interval= PlayerPrefs.GetInt("interval", 0);
audio = gameObject.GetComponent<AudioSource>();
}
// Update is called once per frame
void Update()
{
dt = DateTime.Now; // get time info
// process SW color
if (sw1) { b1.image.color = pink; } else { b1.image.color = Color.white; }
if (sw2) { b2.image.color = pink; } else { b2.image.color = Color.white; }
if (sw3) { b3.image.color = pink; } else { b3.image.color = Color.white; }
if (sw4) { b4.image.color = pink; } else { b4.image.color = Color.white; }
if (sw5) { b5.image.color = pink; } else { b5.image.color = Color.white; }
////// 1S loop //////
t0 = t1;
t1=(long)Time.time;
if (t1 != t0) {
Debug.Log(t1);
mes2.text = "日時:" + dt;
mes1.text = "評価者:" + PlayerPrefs.GetString("username", "-");
mes1.text += " 研究区分:" + PlayerPrefs.GetString("expcode", "-");
mes1.text += " 観察生徒:" + currentst + "/" + PlayerPrefs.GetInt("studentnum", 0);
// exec HTTP communication
if (dt.Second % interval == 0) {
Debug.Log("HTTP_send");
audio.PlayOneShot(clip1);
StartCoroutine("HTTP_Post");
sw1 = sw2 = sw3 = sw4 = sw5= false; // reset SW
currentst++; // increment student cnt
}
}
}
public void ApplicationQuit()
{
Application.Quit();
}
public void procButton(int swnum)
{
if (swnum == 1) { sw1 = !sw1; }
if (swnum == 2) { sw2 = !sw2; }
if (swnum == 3) { sw3 = !sw3; }
if (swnum == 4) { sw4 = !sw4; }
if (swnum == 5) { sw5 = !sw5; }
}
IEnumerator HTTP_Post()
{
string URL = "http://kodamalab.sakura.ne.jp/WGL/SCRIPT/class/regist.php";
Debug.Log("URL:" + URL);
WWWForm form = new WWWForm();
form.AddField("sampletime", dt.ToString());
form.AddField("username", PlayerPrefs.GetString("username", "---"));
form.AddField("expcode", PlayerPrefs.GetString("expcode", "---"));
form.AddField("studentnum", PlayerPrefs.GetInt("studentnum", 99));
form.AddField("interval", PlayerPrefs.GetInt("interval", 99));
form.AddField("currentst", currentst);
form.AddField("sw1", Convert.ToInt32(sw1));
form.AddField("sw2", Convert.ToInt32(sw2));
form.AddField("sw3", Convert.ToInt32(sw3));
form.AddField("sw4", Convert.ToInt32(sw4));
form.AddField("sw5", Convert.ToInt32(sw5));
UnityWebRequest www = UnityWebRequest.Post(URL, form);
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
string log;
log = www.downloadHandler.text;
Debug.Log("POST process complete!:" + log);
mes3.text = "LOG:" + log;
}
}
}
PHP側のスクリプト。postで受け取った値をディスクに追加方式で書き込むだけ。
<?
$stamp=strftime("%Y%m%d_%H%M%S");
$fn=strftime("./data/classdat%Y%m%d.csv");
echo"posted ";
if($_POST['username']!=""){
$fp=fopen($fn,"a");
fprintf($fp,"%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
$_POST['sampletime'],
$_POST['username'],
$_POST['expcode'],
$_POST['studentnum'],
$_POST['interval'],
$_POST['currentst'],
$_POST['sw1'],
$_POST['sw2'],
$_POST['sw3'],
$_POST['sw4'],
$_POST['sw5'],
);
fclose($fp);
echo"->saved $fn/$stamp";
}
//echo"{$_POST['IF1']}/{$_POST['IF2']}/{$_POST['IF3']}/";
?>