2022年5月15日 星期日

Visual Studio Code 編譯C#

使用 Visual Studio Code 編譯C# 方法:


  • 再來  Visual Studio Code 新增資料夾到工作區















  • 終端機 打上: dotnet new console









  • 終端機會開始執行

  • 就能進行撰寫 C#


2022年1月20日 星期四

Unity 居家照顧小工具 (待更新)

Unity 練習UI 腳本,因此做了一個小型居家照顧小工具,主要家人工作關係,都要計算,就拿來當練習玩玩。

專案會持續更新.....會弄到導航計算公里數功能。

專案 GitHub

顯示結果:

本文 只提供場景的UI 功能程式。

主頁

Main

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);
    }
}

------------------------

服務時間計算

ServiceTime

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);
    }
}

------------------------

單位換算

TimeConvert

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);
    }
}

------------------------

週次計算

 

WeekTimeConvert

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);
    }
}

2022年1月12日 星期三

外部Dll 匯入Unity

外部 Dll 都屬於非Unity的套件,加上Unity API 依賴 .net 架構,所以每一個版本Unity 支援的 .NET 版本 會有些不同。

因此 我們要對於專案的設定如下:

※ 匯入Dll 檔案,非Unity內部功能,會導致錯誤,因此要更改。

Unity 2019 LTS - 2020 做法: 

image

Unity 環境下執行可正常,發佈不正常的情況下,大多數都是缺少:

  • I18N.CJK.dll
  • I18N.dll
  • I18N.MidEast.dll
  • I18N.Other.dll
  • I18N.Rare.dll
  • I18N.West.dll

那些dll檔案在Unity 安裝路徑下都能找的到,以下路徑 2019 LTS 路徑

路徑:  C:\Program Files\Unity 2019.4.34f1\Editor\Data\MonoBleedingEdge\lib\mono\unityjit

就能尋找的到了。

 

 

 

 

2021年12月20日 星期一

(Simple) Chinese Hyphenation for Unity - 斷詞

本篇使用自然語言處理其中最基礎的一環,就是斷詞。斷詞方法有很多,這裡只舉長詞優先。長詞優先,主要中文特性的規範存在「字→詞→句」構成。需要由詞的部分開始下手。

所先需要資料庫存放詞語數據,再由演算法比對的方式來呈現。得到結果後就可以做出各式各樣的功能 (如: 關鍵字搜尋)。

GitHub 專案

 

 

 

 

 

 

 

 

 

 

 

 

 

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;
    }
}

設計介面:

  • System - (Unity UI Text)
  • UserMessage - (Unity UI Text)
  • InputMessage - (Unity UI InputField)
  • Enter - (Unity UI Button)
  • Exit - (Unity UI Button)
  • Result - (Unity UI Text)
  • ResultMessage - (Unity UI Image)
    • Message - (Unity UI Text)
  • Horizontal - (Unity UI Scrollbar) 

以下3張圖片:

  • ResultMessage - (Unity UI Image) 組件設定
    • Message - (Unity UI Text) 組件設定
  • Horizontal - (Unity UI Scrollbar) 組件設定

image

image

image

2021年12月16日 星期四

Joystick Layout for Unity3D

常常看到手機遊戲都有Joystick 圖示來控制角色移動,按鈕控制角色: 跳躍,攻擊.....等等的功能,大概花時間研究了一下,可以用UnityUI的屬性方式來進行。

操作之前,我們可以理解成介面都是由圖片方式來進行與操作者互動。

GitHub 專案


例如:

  • 角色攻擊,玩家就會去點擊攻擊的指令,那個指令就可以當成是一個按鈕方式來進行觸發。
  • 按鈕圖示可以換成攻擊圖片與做出點擊按鈕震動動畫效果與玩家進行人機互動方式呈現。

Joystick 圖示

以上圖示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 - Unity UI(一定要)
  • FixedJoystick - Unity UI (Image)
    • Handle - Unity UI (Image) - 當FixedJoystick子物件
      • Handle 設定Width: 50, Height: 50
  • Jump_Btn - Unity UI (Image)
  • EventSystem - Unity UI (一定要)
  • Player - 3D物件(本文使用Unity內建物件)
  • Plane - 3D物件(本文使用內建物件)

image

Canvas 物件: 

  • 插入Layout_Main腳本

螢幕擷取畫面 2021-05-19 045114

Player 物件:

  • 插入Player腳本

image

2021年12月12日 星期日

GitHub 教學

所先需要幾個步驟:

  1. 註冊帳號
  2. 下載及安裝 Git fo Window
  3. 配置 Git
  4. 連接 GitHub
  5. 創建本地倉庫
  6. 上傳

1. 註冊帳號

2. 下載並安裝 Git for Window

3. 配置 Git

  • 打開 Git Bash

未命名       

  image

  • 建立SSH key 輸入指令: 
    • $ ssh-keygen -t rsa -C "your_email@youremail.com"
    • 再按Enter
  • 成功畫面:
  • image
  • 自動建立路徑 : 本文路徑
  • image

4. 連接 GitHub

  • 登入 GitHub 官網 → 使用者 → Setting
  • 未命名
  • 點(New SSH Keys) 綠色按鈕,並把 id_rsa.pub 檔案內容貼到以下面畫面,再打上Title 名稱。
  • 未命名
  • 成功畫面
  • image

 

5. 創建本地倉庫上傳

  • 再回到Git Bash 打上兩個指令
  • $git config --global user.name "Your Name"  
    • 檢查 $git config --global user.name
  • $git config --global user.email "email@example.com"
    • 檢查 $git config --global user.email
  • image
  • 再到 GitHub 點New repository
  • 未命名
  • 未命名
  • 再到命令提示字元,打下指令:
  • cd /d D:/GitHub/Code
    • cd /d 路徑名稱 (GitHub 存儲庫存放位置)
  • git clone git@github.com:gsp40213/PuchCard.git
    • git clone (GutHub 存儲庫 SSH 位置)
    • image
  • 再按下Enter後再輸入yes,再按Enter,路徑就可以看到建立GitHub 存儲庫資料,在命令提示字元輸入: dir
  • image
  • image

6. 上傳

  • 再把相關檔案丟到GitHub 存儲庫位置
  • image
  • 再到命令提示字元打上: git status
    • ​​​​​​路徑(GitHub存儲庫本機位置)一定要正確,否則會讀不到)
  • image
  • 再打上命令提示字元: git add -a 
  • image
  • 再輸入 git commit  -m "自行定義"
  • image
  • 再輸入: git push
  • image
  • 檢查官方是否上傳成功:
  • image

2021年12月11日 星期六

Unity 建立班表

又嘗試用Unity 做其他事情,最近看到班表這個有趣的事情,之前有貼過固定班格式與如何讀取日期的文章。

想要挑戰一下,完美的功能,如: 有日期、公司、選擇班別,班表內容是否超過當日的營業時間與休假跟加班計算....等功能。

本人比較懶,因此很少調整Unity 設計畫面,大致上都以程式碼部分直接調整,以下所使用的方式由Interface方式來呈現。

GitHub 相關位置

-----以下成功畫面-----

 

 

 

 

 

 

 

 

 

 

 

 

------------接下來就是 程式碼部份了------------

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 : "";
    }
}