• Home
  • About
    • Muru Chen photo

      Muru Chen

      Game programmer, Game designer, photographer & Interactive media artist

    • Learn More
    • Email
    • LinkedIn
    • Github
  • Games
  • OpenGL
  • Interactive Arts

Maho Shojo Simulation

Reading time ~2 minutes

VR hand tracker game on Steam Vive

Role: Programmer and designer

Platform: C# + Unity + Steam Vive + VR

Demo

Collaborated with programmer and designer Huijie Bao, artist Sandra Liu, artist Wenbo Guo, sound designer Yu’an Tan.

Made a Monster Manager for designer to add custom monsters.

· Used custom struct. So that designer can configure custom monster easily.

image screenshot of Inspector

Quick Time Event system.

· An easily used QTE system. Other programer can add a new QTE event by on interface. This system contains trigger event, condition, success event, fail event, qte time, etc.


namespace QuickTimeEventNamespace {
    public enum QuickTimeEventState { run, success, fail, start }
    public class QuickTimeEvent
    {
        public QuickTimeEvent(float timeInterval_, Action OnTriggerEvent_, Action SucceedEvent_, Action FailureEvent_, Func PassCondition_, bool bContinuous_, Action OnUpdateEvent_)
        {
            timeInterval = timeInterval_;
            OnTriggerEvent = OnTriggerEvent_;
            SucceedEvent = SucceedEvent_;
            FailureEvent = FailureEvent_;
            PassCondition = PassCondition_;
            bContinuous = bContinuous_;
            OnUpdateEvent = OnUpdateEvent_;
        }
        public float timeInterval { get; set; }
        public Action OnTriggerEvent { get; set; }
        public Action SucceedEvent { get; set; }
        public Action FailureEvent { get; set; }
        public Func PassCondition { get; set; }
        public bool bContinuous { get; set; }
        public Action OnUpdateEvent { get; set; }

        public QuickTimeEventState state = QuickTimeEventState.start;

        public void Update()
        {
            if (state != QuickTimeEventState.run)
            {
                return;
            }
            bool result = PassCondition();
            if (OnUpdateEvent != null)
            {
                OnUpdateEvent();
            }            
            if (result)
            {
                Debug.Log("qte success! play success event!");
                SucceedEvent();
                state = QuickTimeEventState.success;
                QTEMgr.Instance.ContinueQTE();
            }
        }

        public void StartQTE()
        {
            //Debug.Log("Start QTE!!!");
            OnTriggerEvent();
            state = QuickTimeEventState.run;
            TimeMgr.Instance.AddDelayEvent(timeInterval, QTEFail);
        }

        public void QTEFail()
        {
            Debug.Log("state: " + state);
            if (state != QuickTimeEventState.run)
            {
                return;
            }
            FailureEvent();
            state = QuickTimeEventState.fail;
            QTEMgr.Instance.ContinueQTE();
        }
    }


    public class QTEMgr : MonoBehaviour
    {
        public static QTEMgr Instance = null;
        public float QTEInterval;
        private int currentQTEIndex = 0;
        private List QTEQueue = new List();
        private QuickTimeEvent currentQTE;

        // --------------------------example-------------------------------
        private int currentNum;
        public TMP_Text baseValueText;
        public GameObject successText;
        public GameObject failureText;
        private int userInput = -99;
        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(this.gameObject);
            }
            else
            {
                Instance = this;
            }
        }

        // Start is called before the first frame update
        void Start()
        {

        }

        // Update is called once per frame
        void Update()
        {
            if (currentQTE == null)
            {
                return;
            }
            currentQTE.Update();
        }

        public void AddNewQTE(float timeInterval_, Action OnTriggerEvent_, Action SucceedEvent_, Action FailureEvent_, Func PassCondition_, bool bContinuous_, Action OnUpdateEvent_)
        {
            QTEQueue.Add(new QuickTimeEvent(timeInterval_, OnTriggerEvent_, SucceedEvent_, FailureEvent_, PassCondition_, bContinuous_, OnUpdateEvent_));
        }

        public void StartNewQTE()
        {
            currentQTE = QTEQueue[currentQTEIndex];
            currentQTE.StartQTE();
        }

        public void ContinueQTE()
        {
            currentQTE = null;
            currentQTEIndex++;
            if (currentQTEIndex >= QTEQueue.Count)
            {
                return;
            }
            QuickTimeEvent nextQTE = QTEQueue[currentQTEIndex];
            if (!nextQTE.bContinuous)
            {
                return;
            }
            TimeMgr.Instance.AddDelayEvent(QTEInterval, StartNewQTE);
        }
</code>
</pre>

## Main Gameplay


gameVR Share Tweet +1