使用 Visual Studio Code 編譯C# 方法:
- 下載 Visual Studio Code 後進行安裝
- 並安裝C# 相關套件
- 再來 Visual Studio Code 新增資料夾到工作區
- 終端機 打上: dotnet new console
目前使用Unity2019 LTS版本,估計今年6月會使用Unity 2020 LTS版本
使用 Visual Studio Code 編譯C# 方法:
Unity 練習UI 腳本,因此做了一個小型居家照顧小工具,主要家人工作關係,都要計算,就拿來當練習玩玩。
專案會持續更新.....會弄到導航計算公里數功能。
顯示結果:
本文 只提供場景的UI 功能程式。
主頁
MainInterface 腳本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MainInterface
{
private Image buttonArea;
private RectTransform area;
ImageSetting buttonAreaSetting;
AreaSetting areaSetting;
public MainInterface(Image buttonArea, RectTransform area)
{
this.buttonArea = buttonArea;
this.area = area;
}
public void buttonArea_Layout()
{
buttonAreaSetting = new ImageSetting(buttonArea, 1f, 1f, 1.6f, 1.6f);
buttonAreaSetting.function(null, false, true, area);
// buttonArea 物件底下子物件
area.transform.parent = buttonArea.transform;
areaSetting = new AreaSetting(area, new Vector2(0, 0), new Vector2(1, 1), new Vector2(0.5f, 0.5f));
areaSetting.function(TextAnchor.MiddleCenter, false, false, false, false, true, true);
}
}
------------------------
服務時間計算
ServiceInterface 腳本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
public class ServiceInterface
{
private RectTransform manage;
private Text hour, minute, titleMessage, serviceMessage;
private InputField hourInput, minuteInput, serviceInputField;
AreaSetting manageSetting;
TextSetting titleMessageSetting;
InterfaceSetting hourSetting, minuteSetting, servicesSetting;
private Image breakGroud;
private Image breaGroudArea;
ImageSetting breakGroudSetting;
ImageSetting breakGraoudAreaSetting;
public ServiceInterface(RectTransform manage, Text titleMessage,
Text hour, InputField hourInput, Text minute, InputField minuteInput)
{
this.manage = manage;
this.titleMessage = titleMessage;
this.hour = hour;
this.hourInput = hourInput;
this.minute = minute;
this.minuteInput = minuteInput;
}
public ServiceInterface(Image breakGroud, Image breaGroudArea, RectTransform manage)
{
this.breakGroud = breakGroud;
this.breaGroudArea = breaGroudArea;
this.manage = manage;
}
public ServiceInterface(RectTransform manage, Text serviceMessage, InputField serviceInputField)
{
this.manage = manage;
this.serviceMessage = serviceMessage;
this.serviceInputField = serviceInputField;
}
public void breakGroud_Layout()
{
breakGroudSetting = new ImageSetting(breakGroud, 1f, 1f, 1.6f, 1.6f);
breakGroudSetting.function(null);
// breakGroudArea 物件底下子物件
breaGroudArea.transform.parent = breakGroud.transform;
breakGraoudAreaSetting = new ImageSetting(breaGroudArea, 1f, 1.4f, 1.6f, 0.8f);
breakGraoudAreaSetting.function(null, false, true, manage);
// breaGroudArea 物件底下子物件
manage.transform.parent = breaGroudArea.transform;
manageSetting = new AreaSetting(manage, Vector2.zero, new Vector2(1, 1), new Vector2(0.5f, 1));
manageSetting.defaultFunction(new Vector2(0, Screen.height / 2 * 0.8f));
}
// 服務次數
public void serviceTime_Layout(Font font, float pointY)
{
manageSetting = new AreaSetting(manage, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f));
manageSetting.defaultFunction(Vector2.zero);
servicesSetting = new InterfaceSetting(serviceMessage, serviceInputField, font);
servicesSetting.funtcionHoliday("服務次數", pointY, Color.green);
serviceMessage.transform.parent = manage.transform;
serviceInputField.transform.parent = manage.transform;
}
public void serverTime_Layout(Font font, float pointY, string title)
{
manageSetting = new AreaSetting(manage, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f));
manageSetting.defaultFunction(Vector2.zero);
titleMessageSetting = new TextSetting(titleMessage, 0.6f, pointY, 0.58f, 0.1f);
titleMessageSetting.function(font, FontStyle.Normal, title, TextAnchor.MiddleLeft, Color.green, 7);
hourSetting = new InterfaceSetting(hour, hourInput, font);
hourSetting.dateWeekfunction("小時", pointY - 0.16f, Color.red);
minuteSetting = new InterfaceSetting(minute, minuteInput, font);
minuteSetting.dateWeekfunction("分鐘", pointY - 0.36f, Color.red);
// manage 物件底下子物件
titleMessage.transform.parent = manage.transform;
hour.transform.parent = manage.transform;
hourInput.transform.parent = manage.transform;
minute.transform.parent = manage.transform;
minuteInput.transform.parent = manage.transform;
titleMessage.transform.parent = manage.transform;
}
public int getServiceValue()
{
if (serviceInputField.text == "")
return 1;
return Int32.Parse(serviceInputField.text);
}
public int getMinuteValue()
{
if (minuteInput.text == "")
return 0;
return Int32.Parse(minuteInput.text);
}
public int getHourValue()
{
if (hourInput.text == "")
return 0;
return Int32.Parse(hourInput.text);
}
}
------------------------
單位換算
TimeConversionInterface 腳本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using UnityEngine.Events;
public class TimeConversionInterface
{
private Text hour, minute, calculatorProcess, calculatorResult;
private InputField hourInput, minuteInput;
private RectTransform hourManage, minuteMange, calculatorArea;
AreaSetting hourMangeSetting, minuteMangeSetting, calculatorAreaSetting;
InterfaceSetting hourSetting, minuteSetting;
public TimeConversionInterface(RectTransform hourManage, Text hour, InputField hourInput,
RectTransform minuteMange, Text minute, InputField minuteInput)
{
this.hourManage = hourManage;
this.hour = hour;
this.hourInput = hourInput;
this.minuteMange = minuteMange;
this.minute = minute;
this.minuteInput = minuteInput;
}
private Image breakGroud, instructionBreakGroud;
private Text instruction;
ImageSetting breakGroudSetting, instructionBreakGroudSetting;
TextSetting instructionSetting;
public TimeConversionInterface(Image breakGroud, Image instructionBreakGroud, Text instruction)
{
this.breakGroud = breakGroud;
this.instructionBreakGroud = instructionBreakGroud;
this.instruction = instruction;
}
TextSetting calculatorProcessSetting, calculatorResultSetting;
public TimeConversionInterface(Image breakGroud, RectTransform calculatorArea, Text calculatorProcess, Text calculatorResult)
{
this.breakGroud = breakGroud;
this.calculatorArea = calculatorArea;
this.calculatorProcess = calculatorProcess;
this.calculatorResult = calculatorResult;
}
private Button button1, button2, button3, button4;
ButtonSetting button1Setting, button2Setting, button3Setting, button4Setting;
public TimeConversionInterface(Button button1, Button button2, Button button3, Button button4)
{
this.button1 = button1;
this.button2 = button2;
this.button3 = button3;
this.button4 = button4;
}
public void calculatorHorizontalBtns(float pointY, Font font, string btnStr1, string btnStr2, string btnStr3, string btnStr4,
UnityAction unityAction1, UnityAction unityAction2, UnityAction unityAction3, UnityAction unityAction4)
{
button1Setting = new ButtonSetting(button1, 0.4f, 0.7f + pointY, 0.3f, 0.15f, unityAction1);
button1Setting.function(font, FontStyle.Normal, btnStr1, TextAnchor.MiddleCenter, Color.black, 7);
button2Setting = new ButtonSetting(button2, 0.8f, 0.7f + pointY, 0.3f, 0.15f, unityAction2);
button2Setting.function(font, FontStyle.Normal, btnStr2, TextAnchor.MiddleCenter, Color.black, 7);
button3Setting = new ButtonSetting(button3, 1.2f, 0.7f + pointY, 0.3f, 0.15f, unityAction3);
button3Setting.function(font, FontStyle.Normal, btnStr3, TextAnchor.MiddleCenter, Color.black, 7);
button4Setting = new ButtonSetting(button4, 1.6f, 0.7f + pointY, 0.3f, 0.15f, unityAction4);
button4Setting.function(font, FontStyle.Normal, btnStr4, TextAnchor.MiddleCenter, Color.black, 7);
}
// 計算機介面
public void calculayoutSetting(Font font, float povitY, int textSize)
{
breakGroudSetting = new ImageSetting(breakGroud, 1f, 0.6f, 1.6f, 0.66f);
breakGroudSetting.function(null, false, true, calculatorArea);
calculatorAreaSetting = new AreaSetting(calculatorArea, Vector2.zero, new Vector2(1, 1), new Vector2(0.5f, 1f));
calculatorAreaSetting.defaultFunction(new Vector2(1, Screen.height / 2 * povitY));
// 顯示過程
calculatorProcessSetting = new TextSetting(calculatorProcess, 1f, 0.86f, 1.5f, 0.1f);
calculatorProcessSetting.function(font, FontStyle.Normal, "", TextAnchor.MiddleLeft, Color.black, 7);
// 顯示計算後結果
calculatorResultSetting = new TextSetting(calculatorResult, 1f, 0.76f, 1.5f, 0.1f);
calculatorResultSetting.function(font, FontStyle.Normal, "", TextAnchor.MiddleLeft, Color.black, 7);
}
// 背景
public void breakGroud_Layout(string instructionMessage)
{
breakGroudSetting = new ImageSetting(breakGroud, 1f, 1f, 1.6f, 1.6f);
breakGroudSetting.function(null);
instructionBreakGroudSetting = new ImageSetting(instructionBreakGroud, 1f, 1.59f, 1.6f, 0.42f);
instructionBreakGroudSetting.function(null, false, true, instruction.rectTransform);
// instructionBreakGroud 物件底下子物件
instruction.transform.parent = instructionBreakGroud.transform;
instructionSetting = new TextSetting(instruction, 0, 0, 0, 0.74f);
instructionSetting.function(7, instructionMessage, new Vector2(0, 0f), new Vector2(1, 1), new Vector2(0.5f, 1f));
}
// 小時與分鐘
public void hourAndminute(Font font, float pointY)
{
hourMangeSetting = new AreaSetting(hourManage, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f));
hourMangeSetting.defaultFunction(Vector2.zero);
// hourManage 物件底下子物件
hour.transform.parent = hourManage.transform;
hourInput.transform.parent = hourManage.transform;
hourSetting = new InterfaceSetting(hour, hourInput, font);
hourSetting.dateWeekfunction("小時", pointY, Color.red);
minuteMangeSetting = new AreaSetting(minuteMange, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f));
minuteMangeSetting.defaultFunction(Vector2.zero);
// minuteMange 物件底下子物件
minuteMange.transform.parent = minuteMange.transform;
minuteInput.transform.parent = minuteMange.transform;
minuteSetting = new InterfaceSetting(minute, minuteInput, font);
minuteSetting.dateWeekfunction("分鐘", pointY - 0.15f, Color.red);
}
public int getHourValue()
{
if (hourInput.text == "")
return 0;
return Int32.Parse(hourInput.text);
}
public int getMinuteValue()
{
if (minuteInput.text == "")
return 0;
return Int32.Parse(minuteInput.text);
}
}
------------------------
週次計算
InterfaceObj 腳本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public abstract class InterfaceObj
{
protected Text message;
protected InputField inputFiled;
protected Font font;
public InterfaceObj(Text message, InputField inputFiled, Font font)
{
this.message = message;
this.inputFiled = inputFiled;
this.font = font;
}
public abstract void dateWeekfunction(string textMessage, float pointY);
public abstract void funtcionHoliday(string textMessage, float pointY);
public abstract void systemAndYear(string textMessage, float pointX);
}
InterfaceSetting 腳本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
public class InterfaceSetting : InterfaceObj
{
public InterfaceSetting(Text messge, InputField inputFiled, Font font) : base(messge, inputFiled, font) { }
TextSetting textSetting;
InputFieldSetting inputFieldSetting;
// 週次
public override void dateWeekfunction(string textMessage, float pointY)
{
textSetting = new TextSetting(message, 0.5f, pointY, 0.3f, 0.1f);
textSetting.function(font, FontStyle.Normal, textMessage, TextAnchor.MiddleLeft, Color.red, 7);
inputFieldSetting = new InputFieldSetting(inputFiled, 1.15f, pointY + 0.01f, 0.9f, 0.1f);
inputFieldSetting.function(font, FontStyle.Normal, TextAnchor.MiddleLeft, Color.black, 11,
InputField.ContentType.IntegerNumber);
}
// 假期
public override void funtcionHoliday(string textMessage, float pointY)
{
textSetting = new TextSetting(message, 0.65f, pointY, 0.6f, 0.1f);
textSetting.function(font, FontStyle.Normal, textMessage, TextAnchor.MiddleLeft, Color.red, 7);
inputFieldSetting = new InputFieldSetting(inputFiled, 1.28f, pointY + 0.01f, 0.64f, 0.1f);
inputFieldSetting.function(font, FontStyle.Normal, TextAnchor.MiddleLeft, Color.black, 11,
InputField.ContentType.IntegerNumber);
}
// 年與月
public override void systemAndYear(string textMessage, float pointX)
{
textSetting = new TextSetting(message, pointX, 1.89f, 1f, 0.13f);
textSetting.function(font, FontStyle.Normal, textMessage, TextAnchor.MiddleLeft, Color.red, 7);
inputFieldSetting = new InputFieldSetting(inputFiled, pointX - 0.65f, 1.89f, 0.3f, 0.12f);
inputFieldSetting.function(font, FontStyle.Normal, TextAnchor.MiddleLeft, Color.black, 11,
InputField.ContentType.IntegerNumber);
}
}
外部 Dll 都屬於非Unity的套件,加上Unity API 依賴 .net 架構,所以每一個版本Unity 支援的 .NET 版本 會有些不同。
因此 我們要對於專案的設定如下:
※ 匯入Dll 檔案,非Unity內部功能,會導致錯誤,因此要更改。
Unity 2019 LTS - 2020 做法:
Unity 環境下執行可正常,發佈不正常的情況下,大多數都是缺少:
那些dll檔案在Unity 安裝路徑下都能找的到,以下路徑 2019 LTS 路徑
路徑: C:\Program Files\Unity 2019.4.34f1\Editor\Data\MonoBleedingEdge\lib\mono\unityjit
就能尋找的到了。
本篇使用自然語言處理其中最基礎的一環,就是斷詞。斷詞方法有很多,這裡只舉長詞優先。長詞優先,主要中文特性的規範存在「字→詞→句」構成。需要由詞的部分開始下手。
所先需要資料庫存放詞語數據,再由演算法比對的方式來呈現。得到結果後就可以做出各式各樣的功能 (如: 關鍵字搜尋)。
Hyphenation 腳本(斷詞類別)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public abstract class Hyphenation
{
protected List<string> ward;
protected string dataBaseTitlle;
public Hyphenation(List<string>ward, string dataBaseTitlle)
{
this.ward = ward;
this.dataBaseTitlle = dataBaseTitlle;
}
public abstract List<string> reverse(MySQLFunction mySQLFunction);
public abstract List<string> forward(MySQLFunction mySQLFunction);
public abstract List<string> speech(MySQLFunction mySQLFunction);
}
HyphenationSetting 腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HyphenationSetting : Hyphenation
{
private int forwardWardNumber = 0;
private int reverceWardNumber = 0;
public HyphenationSetting(List<string> ward, string dataBaseTitlle) : base(ward, dataBaseTitlle) { }
// 正向
public override List<string> forward(MySQLFunction mySQLFunction)
{
List<string> list = new List<string>();
list.Clear();
forwardWardNumber = 0;
while (ward.Count >= 1)
{
if (forwardWardNumber < ward.Count)
{
if (ward[forwardWardNumber] != "")
{
for (int y = 0; y <= ward[forwardWardNumber].Length; y++)
{
string ForwardMessage = ward[forwardWardNumber].Substring(0, ward[forwardWardNumber].Length - y);
if (ForwardMessage == mySQLFunction.inquire(dataBaseTitlle, 0, ForwardMessage))
{
list.Add(ForwardMessage);
ward[forwardWardNumber] = ward[forwardWardNumber].Remove(0, ForwardMessage.Length);
}
else if (ForwardMessage.Length == 1 && ward[forwardWardNumber] != mySQLFunction.inquire(dataBaseTitlle, 0, ForwardMessage))
{
list.Add(ForwardMessage);
ward[forwardWardNumber] = ward[forwardWardNumber].Remove(0, ForwardMessage.Length);
}
}
}
else
forwardWardNumber += 1;
}
else ward.Clear();
}
return list;
}
// 反向
public override List<string> reverse(MySQLFunction mySQLFunction)
{
List<string> list = new List<string>();
list.Clear();
reverceWardNumber = 0;
while (ward.Count >= 1)
{
if (reverceWardNumber < ward.Count)
{
if (ward[reverceWardNumber] != "")
{
for (int y = 0; y <= ward[reverceWardNumber].Length; y++)
{
string ReverseMessage = ward[reverceWardNumber].Substring(y);
if (ReverseMessage == mySQLFunction.inquire(dataBaseTitlle, 0, ReverseMessage))
{
list.Add(ReverseMessage);
ward[reverceWardNumber] = ward[reverceWardNumber].Substring(0, ward[reverceWardNumber].Length - ReverseMessage.Length);
}
else if (ReverseMessage.Length <= 1 && ReverseMessage != mySQLFunction.inquire(dataBaseTitlle, 0, ReverseMessage))
{
list.Add(ReverseMessage);
ward[reverceWardNumber] = ward[reverceWardNumber].Substring(0, ward[reverceWardNumber].Length - ReverseMessage.Length);
}
}
}
else
reverceWardNumber += 1;
}
else ward.Clear();
}
return list;
}
// 詞性
public override List<string> speech(MySQLFunction mySQLFunction)
{
List<string> list = new List<string>();
foreach (string str in ward)
{
if (mySQLFunction.inquire(dataBaseTitlle, 1, str) != "")
list.Add(mySQLFunction.inquire(dataBaseTitlle, 1, str));
else list.Add("?");
}
return list;
}
}
設計介面:
以下3張圖片:
常常看到手機遊戲都有Joystick 圖示來控制角色移動,按鈕控制角色: 跳躍,攻擊.....等等的功能,大概花時間研究了一下,可以用UnityUI的屬性方式來進行。
操作之前,我們可以理解成介面都是由圖片方式來進行與操作者互動。
例如:
以上圖示Joystick 圖示按鈕
結果:
以下藉由Unity.EventSystems interface 方式來進行撰寫功能。
Joystick -- C# 腳本
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class Joystick : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler
{
// Init
protected Image container;
protected Image joystick;
protected Vector3 InputDirection = Vector3.zero;
public void OnDrag(PointerEventData ped)
{
Vector2 position = Vector2.zero;
// Get InputDirection
RectTransformUtility.ScreenPointToLocalPointInRectangle(
container.rectTransform,
ped.position,
ped.pressEventCamera,
out position
);
float x = (position.x / container.rectTransform.sizeDelta.x);
float y = (position.y / container.rectTransform.sizeDelta.y);
InputDirection = new Vector3(x, y, 0);
InputDirection = (InputDirection.magnitude > 1) ? InputDirection.normalized : InputDirection;
// Define the area in which joystick can move around
joystick.rectTransform.anchoredPosition = new Vector3(
InputDirection.x * container.rectTransform.sizeDelta.x / 3,
InputDirection.y * container.rectTransform.sizeDelta.y / 3
);
}
public void OnPointerDown(PointerEventData ped)
{
OnDrag(ped);
}
public void OnPointerUp(PointerEventData ped)
{
InputDirection = Vector3.zero;
joystick.rectTransform.anchoredPosition = Vector3.zero;
}
}
InterfaceOBJ -- C# 腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
public class InterfaceOBJ
{
private Image imageObj;
private Button buttonObj;
private interfaceObj interfaceObj;
public InterfaceOBJ(Image imag, interfaceObj interfaceObj)
{
this.imageObj = imag;
this.interfaceObj = interfaceObj;
}
public InterfaceOBJ(Button button, interfaceObj interfaceObj)
{
this.buttonObj = button;
this.interfaceObj = interfaceObj;
}
// image
public void image(float pointX, float pointY, float sizeX, float sizeY)
{
interfaceObj.image(imageObj, pointX, pointY, sizeX, sizeY);
}
// button
public void button(float pointX, float pointY, float sizeX, float sizeY, UnityAction onClick)
{
interfaceObj.button(buttonObj, pointX, pointY, sizeX, sizeY, onClick);
}
}
public interface interfaceObj
{
void image(Image image, float pointX, float pointY, float sizeX, float sizeY);
void button(Button button, float pointX, float pointY, float sizeX, float sizeY, UnityAction onClick);
}
InterfaceObj -- C# 腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class InterfaceObj : interfaceObj
{
public void button(Button button, float pointX, float pointY, float sizeX, float sizeY, UnityAction onClick)
{
try
{
button.transform.position = new Vector2(Screen.width / 2 * pointX, Screen.height / 2 * pointY);
button.image.rectTransform.sizeDelta = new Vector2(Screen.width / 2 * sizeX, sizeY);
button.onClick.AddListener(onClick);
}
catch { }
}
public void image(Image image, float pointX, float pointY, float sizeX, float sizeY)
{
try
{
image.rectTransform.position = new Vector2(Screen.width / 2 * pointX, Screen.height / 2 * pointY);
image.rectTransform.sizeDelta = new Vector2(Screen.width / 2 * sizeX, Screen.height / 2 * sizeY);
}
catch { }
}
}
Layout_Main -- C# 腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Layout_Main : Joystick
{
public Image fixedJoystick_image, handle_image;
public Button jump_btn;
InterfaceOBJ fixedJoystick, jump;
public static Vector3 DIRCTION;
public static bool JUMP_SW;
// 計時器
private float timeCount;
private float timeCD = 1f;
public static bool JUMP_ACTIVE;
private void Start()
{
base.container = fixedJoystick_image;
base.joystick = handle_image;
fixedJoystick = new InterfaceOBJ(fixedJoystick_image, new InterfaceObj());
fixedJoystick.image(0.23f, 0.4f, 0.2f, 0.35f);
jump = new InterfaceOBJ(jump_btn, new InterfaceObj());
jump.button(1.68f, 0.42f, 0.2f, 80, jump_onClkck);
}
private void Update()
{
DIRCTION = base.InputDirection;
JUMP_ACTIVE = jumpCd();
}
void jump_onClkck()
{
if (JUMP_ACTIVE == true)
{
JUMP_SW = true;
timeCount = timeCD;
}
}
// 跳躍冷卻時間
public bool jumpCd()
{
return ((timeCount -= Time.deltaTime) <= 0) ? true : false;
}
}
Player -- C# 腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
Rigidbody rigidbody;
private float gravity = 10.0f, maxVelocityChange = 50f, jumpHeight = 1f;
public float speed;
void Start()
{
rigidbody = GetComponent();
rigidbody.freezeRotation = true;
rigidbody.useGravity = false;
}
private void FixedUpdate()
{
if(Layout_Main.DIRCTION.magnitude != 1)
{
Vector3 position = new Vector3(Layout_Main.DIRCTION.x * speed, 0,
Layout_Main.DIRCTION.y * speed);
position = transform.TransformDirection(position);
Vector3 velocity = rigidbody.velocity;
Vector3 velocityChange = (position - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0;
rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
if (Layout_Main.JUMP_SW)
rigidbody.velocity = new Vector3(velocity.x, CalculateJumpVerticalSpeed(), velocity.z);
if (Layout_Main.JUMP_ACTIVE == false)
Layout_Main.JUMP_SW = false;
}
rigidbody.AddForce(new Vector3(0, -gravity * rigidbody.mass, 0));
}
// Jump
float CalculateJumpVerticalSpeed()
{
return Mathf.Sqrt(2 * jumpHeight * gravity);
}
}
Unity 介面設計:
Canvas 物件:
Player 物件:
所先需要幾個步驟:
1. 註冊帳號
2. 下載並安裝 Git for Window
3. 配置 Git
4. 連接 GitHub
5. 創建本地倉庫上傳
6. 上傳
又嘗試用Unity 做其他事情,最近看到班表這個有趣的事情,之前有貼過固定班格式與如何讀取日期的文章。
想要挑戰一下,完美的功能,如: 有日期、公司、選擇班別,班表內容是否超過當日的營業時間與休假跟加班計算....等功能。
本人比較懶,因此很少調整Unity 設計畫面,大致上都以程式碼部分直接調整,以下所使用的方式由Interface方式來呈現。
-----以下成功畫面-----
------------接下來就是 程式碼部份了------------
ExcelClass
腳本 (C#) :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class ExcelClass
{
public abstract class ClassInterface
{
public abstract class Preset
{
public abstract void classFixed(int year, int month, string companyName, string unit, int staffNumber);
public abstract void excelSave(int staffNumber);
}
public abstract class Formula
{
public abstract void createClass(int year, int month, string companyName, string unit, int staffNumber, int operAtingHours,
bool dayShift, bool night, bool bigNight);
public abstract void excelSave(int satffNumber);
}
}
}
PresetClass 腳本
using System.IO;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
public class PresetClass : ExcelClass.ClassInterface.Preset
{
// 建立資料位置
private string folderPath = @"D:\班表\";
private string filePath;
// 檔案類別
FileInfo fileInfo;
Calendar.GetCalender getCalender = new GetCalender();
// excel 組件
public static ExcelPackage EXCEL_PACKAGE;
public static ExcelWorksheet WORKSHEET;
// Excel 固定格式 (年、職位、天、資料寫入縱)
int companyNameYear = 1;
int positionNumber = 2;
int dayExcelNuber = 3;
int dataExcelNum = 4;
public static List<Data_date> GET_Data = new List<Data_date>();
public override void classFixed(int year, int month, string companyName, string unit, int staffNumber)
{
GET_Data.Clear();
GET_Data = getCalender.calendarData(year, month, 1);
if (!Directory.Exists(folderPath + @"\" + unit))
Directory.CreateDirectory(folderPath + @"\" + unit);
// 判斷檔案是否存在
if (fileExist(unit, year, month))
{
fileInfo.Delete();
fileInfo = new FileInfo(filePath);
}
EXCEL_PACKAGE = new ExcelPackage(fileInfo);
WORKSHEET = EXCEL_PACKAGE.Workbook.Worksheets.Add(getCalender.calendarData(year, month, 1)[0].month + "月");
// 寫入公司名稱
WORKSHEET.Cells[companyNameYear, 1].Value = GET_Data[0].year + "年" + GET_Data[0].month + "月 " + companyName + " (" + "單位: " + unit + ")";
WORKSHEET.Cells[companyNameYear, 1, 1, GET_Data.Count + 3].Merge = true;
// 寫入部分(單位)
WORKSHEET.Cells[positionNumber, 1].Value = unit;
WORKSHEET.Cells[positionNumber, 1, positionNumber, GET_Data.Count + 3].Merge = true;
// 表格上色
TABLE_COLOR(positionNumber, 1, System.Drawing.Color.Yellow);
foreach (var dayweekData in GET_Data)
{
WORKSHEET.Cells[dayExcelNuber, 1].Value = "員工";
// 天與週次
WORKSHEET.Cells[dayExcelNuber, Int32.Parse(dayweekData.day) + 1].Value = dayweekData.week + dayweekData.day;
// 休假
WORKSHEET.Cells[dayExcelNuber, Int32.Parse(dayweekData.day) + 2].Value = "休假";
// 表格上色
TABLE_COLOR(dayExcelNuber, GET_Data.Count + 2, System.Drawing.Color.Red);
//加班
WORKSHEET.Cells[dayExcelNuber, Int32.Parse(dayweekData.day) + 3].Value = "加班";
// 輸入員工姓名
for (int x = 0; x < staffNumber; x++)
WORKSHEET.Cells[dataExcelNum + x, 1].Value = "輸入姓名";
// 自動調整距離
WORKSHEET.Cells[WORKSHEET.Dimension.Address].AutoFitColumns();
}
}
// excel save
public override void excelSave(int staffNumber)
{
EXCEL_STYLE(1, 1, staffNumber + 3, GET_Data.Count + 3);
EXCEL_PACKAGE.Save();
}
// 判斷檔案
bool fileExist(string unit, int year, int month)
{
filePath = folderPath + @"\" + unit + @"\" + year.ToString() + "年" + month.ToString() + "月" + ".xlsx";
fileInfo = new FileInfo(filePath);
bool fileExist = fileInfo.Exists;
return fileExist;
}
// 表格顏色
public static void TABLE_COLOR(int fromRow, int fromCol, System.Drawing.Color color)
{
WORKSHEET.Cells[fromRow, fromCol].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
WORKSHEET.Cells[fromRow, fromCol].Style.Fill.BackgroundColor.SetColor(color);
}
public static void EXCEL_STYLE(int fromRow, int fromCol, int toRow, int toCol)
{
// 字形
WORKSHEET.Cells.Style.Font.Name = "標楷體";
// 文字大小
WORKSHEET.Cells.Style.Font.Size = 14;
// 水平置中
WORKSHEET.Cells.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
// 垂直中
WORKSHEET.Cells.Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
// 表格框線
WORKSHEET.Cells[fromRow, fromCol, toRow, toCol].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Medium;
WORKSHEET.Cells[fromRow, fromCol, toRow, toCol].Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Medium;
WORKSHEET.Cells[fromRow, fromCol, toRow, toCol].Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Medium;
WORKSHEET.Cells[fromRow, fromCol, toRow, toCol].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Medium;
}
}
FormulaClass 腳本
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using OfficeOpenXml;
public class FormulaClass : ExcelClass.ClassInterface.Formula
{
// 檔案類別
FileInfo fileInfo;
// Excel 固定格式 (資料寫入縱)
int dataExcelNum = 4;
ExcelClass.ClassInterface.Preset presetClass = new PresetClass();
public override void createClass(int year, int month, string companyName, string unit, int staffNumber, int operAtingHours,
bool dayShift, bool night, bool bigNight)
{
presetClass.classFixed(year, month, companyName, unit, staffNumber);
int checkExcelNum = dataExcelNum + staffNumber;
int classStateNum = 0;
string className1 = "D";
string className2 = "E";
string className3 = "N";
int dayShiftAdd = 0;
int nightAdd = 0;
int bigNightAdd = 0;
// 營業時數
PresetClass.WORKSHEET.Cells[checkExcelNum + 1, 1].Value = "營業時間 ( " + operAtingHours + "小時 )";
PresetClass.TABLE_COLOR(checkExcelNum + 1, 1, System.Drawing.Color.Red);
PresetClass.WORKSHEET.Cells[checkExcelNum + 1, 1].AutoFitColumns(50);
// 狀態1: 3班都選擇(三班制)
if (dayShift == true && night == true && bigNight == true)
{
// 白班
for (int x = 2; x <= 6; x++)
{
classState(checkExcelNum, x, toggleMessage(dayShift, className1 + classTable(dayShiftAdd)), dayShiftAdd);
dayShiftAdd += 1;
}
// 小夜班(晚班)
for (int x = 7; x <= 11; x++)
{
classState(checkExcelNum, x, toggleMessage(night, className2 + classTable(nightAdd)), nightAdd);
nightAdd += 1;
}
// 大夜班(夜班)
for (int x = 12; x <= 16; x++)
{
classState(checkExcelNum, x, toggleMessage(bigNight, className3 + classTable(bigNightAdd)), bigNightAdd);
bigNightAdd += 1;
}
classStateNum = 1;
}
// 狀態2: 2班都選擇 - 白班,晚班(二班制)
if (dayShift == true && bigNight == true && night != true)
{
// 白班
for (int x = 2; x <= 6; x++)
{
classState(checkExcelNum, x, toggleMessage(dayShift, className1 + classTable(dayShiftAdd)), dayShiftAdd);
dayShiftAdd += 1;
}
// 大夜班(夜班)
for (int x = 7; x <= 11; x++)
{
classState(checkExcelNum, x, toggleMessage(bigNight, className3 + classTable(bigNightAdd)), bigNightAdd);
bigNightAdd += 1;
}
classStateNum = 2;
}
if (dayShift == true && night != true && bigNight != true)
{
// 白班
for (int x = 2; x <= 6; x++)
{
classState(checkExcelNum, x, toggleMessage(dayShift, className1 + classTable(dayShiftAdd)), dayShiftAdd);
dayShiftAdd += 1;
}
classStateNum = 3;
}
// 加班公式
overtimeFormula(checkExcelNum, classStateNum, staffNumber, operAtingHours);
}
public override void excelSave(int satffNumber)
{
PresetClass.EXCEL_STYLE(1, 1, satffNumber + 3, PresetClass.GET_Data.Count + 3);
PresetClass.EXCEL_PACKAGE.Save();
}
// 加班公式
void overtimeFormula(int checkExcelNum, int classStateNum, int staffNumber, int operAtingHours)
{
// 橫向
for (int x = 0; x < staffNumber; x++)
{
// 加班
PresetClass.WORKSHEET.Cells[dataExcelNum + x, PresetClass.GET_Data.Count + 3].Formula = formulaHorizontal(1, dataExcelNum + x, 2);
PresetClass.WORKSHEET.Cells[dataExcelNum + x, PresetClass.GET_Data.Count + 2].Formula = formulaHorizontal(2, dataExcelNum + x, 2);
}
for (int x = 0; x < PresetClass.GET_Data.Count; x++)
{
// 3班
if (classStateNum == 1)
{
// 檢查營業時間
PresetClass.WORKSHEET.Cells[checkExcelNum + 1, x + 2].Formula = formula_vertical_openBusiness(checkExcelNum, x + 2, classStateNum);
var cont = PresetClass.WORKSHEET.ConditionalFormatting.AddGreaterThan(PresetClass.WORKSHEET.Cells[checkExcelNum + 1, x + 2]);
cont.Style.Font.Color.Color = System.Drawing.Color.Red;
cont.Formula = operAtingHours.ToString();
int dayShiftTable = 0;
int nightTable = 0;
int bigNightTable = 0;
// D班含加班
for (int i = 2; i <= 6; i++)
{
PresetClass.WORKSHEET.Cells[checkExcelNum + i, x + 2].Formula = formulaVerticalClassName(dataExcelNum, x + 2, "\"D"
+ classTable(dayShiftTable) + "\"", "\"D" + classTable(dayShiftTable) + "\"", staffNumber);
dayShiftTable += 1;
}
// E班含加班
for (int i = 7; i <= 11; i++)
{
PresetClass.WORKSHEET.Cells[checkExcelNum + i, x + 2].Formula = formulaVerticalClassName(dataExcelNum, x + 2, "\"E"
+ classTable(nightTable) + "\"", "\"E" + classTable(nightTable) + "\"", staffNumber);
nightTable += 1;
}
// N班含加班
for (int i = 12; i <= 16; i++)
{
PresetClass.WORKSHEET.Cells[checkExcelNum + i, x + 2].Formula = formulaVerticalClassName(dataExcelNum, x + 2, "\"N"
+ classTable(bigNightTable) + "\"", "\"N" + classTable(bigNightTable) + "\"", staffNumber);
bigNightTable += 1;
}
// 畫線
PresetClass.EXCEL_STYLE(checkExcelNum + 1, 1, checkExcelNum + 16, PresetClass.GET_Data.Count + 1);
}
// 2班
if (classStateNum == 2)
{
// 檢查營業時間
PresetClass.WORKSHEET.Cells[checkExcelNum + 1, x + 2].Formula = formula_vertical_openBusiness(checkExcelNum, x + 2, classStateNum);
var cont = PresetClass.WORKSHEET.ConditionalFormatting.AddGreaterThan(PresetClass.WORKSHEET.Cells[checkExcelNum + 1, x + 2]);
cont.Style.Font.Color.Color = System.Drawing.Color.Red;
cont.Formula = operAtingHours.ToString();
int dayShiftTable = 0;
int bigNightTable = 0;
// D班含加班
for (int i = 2; i <= 6; i++)
{
PresetClass.WORKSHEET.Cells[checkExcelNum + i, x + 2].Formula = formulaVerticalClassName(dataExcelNum, x + 2, "\"D"
+ classTable(dayShiftTable) + "\"", "\"D" + classTable(dayShiftTable) + "\"", staffNumber);
dayShiftTable += 1;
}
// N班含加班
for (int i = 7; i <= 11; i++)
{
PresetClass.WORKSHEET.Cells[checkExcelNum + i, x + 2].Formula = formulaVerticalClassName(dataExcelNum, x + 2, "\"N"
+ classTable(bigNightTable) + "\"", "\"N" + classTable(bigNightTable) + "\"", staffNumber);
bigNightTable += 1;
}
// 畫線
PresetClass.EXCEL_STYLE(checkExcelNum + 1, 1, checkExcelNum + 11, PresetClass.GET_Data.Count + 1);
}
if (classStateNum == 3)
{
// 檢查營業時間
PresetClass.WORKSHEET.Cells[checkExcelNum + 1, x + 2].Formula = formula_vertical_openBusiness(checkExcelNum, x + 2, classStateNum);
var cont = PresetClass.WORKSHEET.ConditionalFormatting.AddGreaterThan(PresetClass.WORKSHEET.Cells[checkExcelNum + 1, x + 2]);
cont.Style.Font.Color.Color = System.Drawing.Color.Red;
cont.Formula = operAtingHours.ToString();
int dayShiftTable = 0;
// D班含加班
for (int i = 2; i <= 6; i++)
{
PresetClass.WORKSHEET.Cells[checkExcelNum + i, x + 2].Formula = formulaVerticalClassName(dataExcelNum, x + 2, "\"D"
+ classTable(dayShiftTable) + "\"", "\"D" + classTable(dayShiftTable) + "\"", staffNumber);
dayShiftTable += 1;
}
// 畫線
PresetClass.EXCEL_STYLE(checkExcelNum + 1, 1, checkExcelNum + 6, PresetClass.GET_Data.Count + 1);
}
}
}
// 公式 Excel 縱向(班別名稱)
string formula_vertical_openBusiness(int rol, int col, int classState)
{
string result = "";
string dayShiftResult = "";
string nightResult = "";
string bigNightResult = "";
int dayShiftNum = 8;
int nightNum = 8;
int bigNightNum = 8;
int dayShiftNum1 = 12;
int bigNightNum1 = 12;
// 3班制
if (classState == 1)
{
// 白班
for (int x = 2; x <= 6; x++)
{
dayShiftResult += "IF(" + PresetClass.WORKSHEET.Cells[rol + x, col] + "<> 0, " + dayShiftNum + ",0) +";
dayShiftNum += 1;
}
// 小夜(晚班)
for (int x = 7; x <= 11; x++)
{
nightResult += "IF(" + PresetClass.WORKSHEET.Cells[rol + x, col] + "<> 0, " + nightNum + ",0) +";
nightNum += 1;
}
// 大夜(夜班)
for (int x = 12; x <= 16; x++)
{
bigNightResult += "IF(" + PresetClass.WORKSHEET.Cells[rol + x, col] + "<> 0," + bigNightNum + " ,0) +";
bigNightNum += 1;
}
result = dayShiftResult + nightResult + bigNightResult;
}
// 兩班制
if (classState == 2)
{
// 白班
for (int x = 2; x <= 6; x++)
{
dayShiftResult += "IF(" + PresetClass.WORKSHEET.Cells[rol + x, col] + "<> 0," + dayShiftNum1 + " ,0) +";
dayShiftNum1 += 1;
}
// 大夜(夜班)
for (int x = 7; x <= 11; x++)
{
bigNightResult += "IF(" + PresetClass.WORKSHEET.Cells[rol + x, col] + "<> 0," + bigNightNum1 + " ,0) +";
bigNightNum1 += 1;
}
result = dayShiftResult + bigNightResult;
}
// 一班制
if (classState == 3)
{
// 白斑
for (int x = 2; x <= 6; x++)
{
dayShiftResult += "IF(" + PresetClass.WORKSHEET.Cells[rol + x, col] + "<> 0," + dayShiftNum + ",0) +";
dayShiftNum += 1;
}
result = dayShiftResult;
}
result = result.Remove(result.LastIndexOf("+"), 1);
return result;
}
// 公式: Excel 縱向(班別名稱)
string formulaVerticalClassName(int rol, int col, string className, string className2, int staffNumber)
{
string result = "";
for (int x = 0; x < staffNumber; x++)
{
string str = "IF(OR(" + PresetClass.WORKSHEET.Cells[rol + x, col] + "=" + className + ", +"
+ PresetClass.WORKSHEET.Cells[rol + x, col] + "=" + className2 + "), 1, 0) + ";
result += str;
}
result = result.Remove(result.LastIndexOf("+"), 1);
return result;
}
// 公式: Excel 橫向
string formulaHorizontal(int state, int rol, int col)
{
string result = "";
// 加班狀態
for (int x = 0; x < PresetClass.GET_Data.Count; x++)
{
if (state == 1)
{
string str = "IF(OR(" + PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"D1\"," + PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"E1\","
+ PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"N1\"), 1) + IF(OR(" + PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"D2\","
+ PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"E2\"," + PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"N2\"), 2) + IF(OR("
+ PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"D3\"," + PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"E3\","
+ PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"N3\"), 3) + IF(OR(" + PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"D4\","
+ PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"E4\"," + PresetClass.WORKSHEET.Cells[rol, col + x] + "= \"N4\"), 4) +";
result += str;
}
// 假別
if (state == 2)
{
string str = "IF(OR(" + PresetClass.WORKSHEET.Cells[rol, col + x] + "=\"休\"," + PresetClass.WORKSHEET.Cells[rol, col + x] + "=\"特\","
+ PresetClass.WORKSHEET.Cells[rol, col + x] + "=\"病\", " + PresetClass.WORKSHEET.Cells[rol, col + x] + "=\"公\","
+ PresetClass.WORKSHEET.Cells[rol, col + x] + "=\"喪\"," + PresetClass.WORKSHEET.Cells[rol, col + x] + "=\"婚\","
+ PresetClass.WORKSHEET.Cells[rol, col + x] + "=\"公病\"," + PresetClass.WORKSHEET.Cells[rol, col + x] + "=\"事\","
+ PresetClass.WORKSHEET.Cells[rol, col + x] + "=\"災\",),1)+";
result += str;
}
}
result = result.Remove(result.LastIndexOf("+"), 1);
return result;
}
// 班別區分顏色
void classState(int checkExcelNum, int frequency, string message, int addClassTable)
{
PresetClass.WORKSHEET.Cells[checkExcelNum + frequency, 1].Value = message;
if (addClassTable.Equals(0))
PresetClass.TABLE_COLOR(checkExcelNum + frequency, 1, System.Drawing.Color.Orange);
else
PresetClass.TABLE_COLOR(checkExcelNum + frequency, 1, System.Drawing.Color.Yellow);
}
// 加班訊息表示
string classTable(int table)
{
return (table.Equals(0)) ? "" : table.ToString();
}
// toggle 布林為訊息
string toggleMessage(bool toggleBool, string message)
{
return (toggleBool == true) ? message : "";
}
}