Unity¤Ë´ØÏ¢¤¹¤ëµ­»ö¤Ç¤¹

¡¡¥ª¡¼¥È¥Ð¥È¥ë·Ï¤Î¥·¥¹¥Æ¥à¤ò UniRx ¤òÍøÍѤ·¤Æ¼ÂÁõ¤¹¤ë¥µ¥ó¥×¥ë¤Ë¤Ê¤ê¤Þ¤¹¡£¡¡
°ìÄê»þ´Ö·Ð²á¤´¤È¤Ë»ØÄꤷ¤¿ÈÏ°ÏÆâ¤Ë¹¶·âÂоݤ¬¤¤¤ë¤³¤È¤ò³Îǧ¤·¡¢Âоݤ¬¤¤¤ë¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¤¦¤Á¤ÎºÇ¤â¥×¥ì¥¤¥ä¡¼¤Ë¶á¤¤ÂоݤË1²ó¹¶·â¤ò¹Ô¤¤¤Þ¤¹¡£
¤³¤ì¤ò¼«Æ°Åª¤Ë·«¤êÊÖ¤·¤Þ¤¹¡£
¡¡
¡¡±þÍѤ¹¤ë¤³¤È¤Ç¥ô¥¡¥ó¥Ñ¥¤¥¢¥µ¥Ð¥¤¥Ð¡¼¥º¤ä¥¢¡¼¥Á¥ã¡¼ÅÁÀâ¤Ê¤É¤Î¤è¤¦¤Ê¥ª¡¼¥È¥Ð¥È¥ë¥·¥¹¥Æ¥à¤Îº¬´´¤È¤·¤ÆÍøÍѲÄǽ¤Ç¤¹¡£

¡¡¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤È´ðÄ쥯¥é¥¹¤òºîÀ®¤·¤¿¾å¡¢MVP ¥Ñ¥¿¡¼¥ó¤òºÎÍѤ·¡¢Model¡¢View¡¢Presenter ¤Î£³¤Ä¤òºîÀ®¤·¤Þ¤¹¡£



ISetup ¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹




using UnityEngine;

/// <summary>
/// ½é´üÀßÄ궦Ä̲½ÍѤΥ¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹
/// </summary>
public interface ISetup {
    void SetUp(GameObject entityObject = null);
}



BarBase



using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

/// <summary>
/// Slider ÍÑ´ðÄ쥯¥é¥¹
/// </summary>
public class BarBase : MonoBehaviour {

#pragma warning disable 0649
    [SerializeField] protected CanvasGroup canvasGroup;  // TODO ¤¢¤È¤Ç TextViewBase ¤È ViewBase ¤È¤·¤Æ¶¦Ä̲½¤¹¤ë
    [SerializeField] protected Canvas canvas;            // ¤¢¤È¤Ç TextViewBase ¤È¶¦Ä̲½¤¹¤ë
    [SerializeField] protected Slider slider;
#pragma warning restore 0649


    /// <summary>
    /// ¥¹¥é¥¤¥À¡¼É½¼¨¹¹¿·
    /// </summary>
    /// <param name="currentValue"></param>
    public virtual void UpdateBar(float currentValue) {
        slider.DOValue(currentValue, 0.1f).SetEase(Ease.Linear).SetLink(gameObject);
    }

    /// <summary>
    /// ½é´üÀßÄê
    /// </summary>
    /// <param name="maxValue"></param>
    public virtual void SetUpView(float maxValue) {
        slider.maxValue = maxValue;

        if (canvas.worldCamera == null) {
            canvas.worldCamera = Camera.main;
        }
    }

    /// <summary>
    /// ¥¹¥é¥¤¥À¡¼É½¼¨
    /// </summary>
    public virtual void ShowBarView() {
        //canvasGroupTextView.alpha = 1.0f;
        canvas.enabled = true;
    }

    /// <summary>
    /// ¥¹¥é¥¤¥À¡¼Èóɽ¼¨
    /// </summary>
    public virtual void HideBarView() {
        //canvasGroupTextView.alpha = 0f;
        canvas.enabled = false;
    }


    public Transform GetCanvasTran() {
        return canvas.transform;
    }
}



Model



using UniRx;

/// <summary>
/// ¹¶·â½èÍý Model
/// </summary>
public class AttackModeModel {

    public ReactiveProperty<float> CurrentActionGaugePoint;
    private readonly CompositeDisposable disposables = new();

    public float MaxActionGaugePoint { get; private set; }
    public float AttackSpeed { get; private set; }
    public int Atk { get; private set; }
    public int Inte { get; private set; }
    public int Def { get; private set; }
    public int Mdef { get; private set; }

    public float AttackRange { get; private set; }
    public DamageType DamageType { get; private set; }
    
    public eAttribute AttributeType { get; private set; }

    public int MinDmg { get; private set; }


    public AttackModeModel(float attackSpeed, int atk, float attackRange) { }

    /// <summary>
    /// ¥³¥ó¥¹¥È¥é¥¯¥¿
    /// </summary>
    /// <param name="maxAttackPoint">ConstData ¤«¤é»²¾È(300)</param>
    /// <param name="spd">ConstaData ¤«¤é»²¾È(199) + spd</param>
    /// <param name="atk"></param>
    /// <param name="inte"></param>
    /// <param name="def"></param>
    /// <param name="mdef"></param>
    /// <param name="attackRange">¹¶·âÈÏ°Ï</param>
    /// <param name="damageType">¹¶·â¤Î¥¿¥¤¥×¡£ÊªÍý¤«ËâË¡</param>
    /// <param name="attributeType">¹¶·â¤Î°À­</param>
    /// <param name="minDmg">ºÇ¾®¥À¥á¡¼¥¸ÃÍPlayer = 0</param>
    public AttackModeModel(float spd, int atk, int inte, int def, int mdef, float attackRange, DamageType damageType, eAttribute attributeType, int minDmg = 0) {
        CurrentActionGaugePoint = new(0f);

        MaxActionGaugePoint = ConstData.MAX_ACTION_GAUGE_POINT;
        AttackSpeed = ConstData.ATTACK_SPEED_OFFSET + spd;

        Atk = atk;
        Inte = inte;
        Def = def;
        Mdef = mdef;

        AttackRange = attackRange;
        DamageType = damageType;
        AttributeType = attributeType;

        MinDmg = minDmg;
    }


    /// <summary>
    /// ¥¢¥¯¥·¥ç¥ó¥²¡¼¥¸ÃͤΥꥻ¥Ã¥È
    /// </summary>
    public void ResetActionGaugePoint() {
        CurrentActionGaugePoint.Value = 0f;
    }

    /// <summary>
    /// ¥ª¥Ö¥¸¥§¥¯¥È(¥¤¥ó¥¹¥¿¥ó¥¹)¤¬ÇË´þ¤µ¤ì¤ë¤È¤­¤ËCompositeDisposable¤ÎDispose¤â¸Æ¤Ó½Ð¤¹
    /// </summary>
    public void Dispose() {
        // Dispose ¥á¥½¥Ã¥É¤¬¸Æ¤Ð¤ì¤¿¤È¤­¤Ë¡¢CompositeDisposable ¤Ë´Þ¤Þ¤ì¤ëÁ´¤Æ¤Î¥¹¥È¥ê¡¼¥à¤¬¼«Æ°Åª¤Ë²òÊü
        disposables.Dispose();
    }
}



View



/// <summary>
/// ¹¶·â½èÍý View
/// </summary>
public class ActionGuageBar : BarBase {

    /// <summary>
    /// ½é´üÀßÄê
    /// </summary>
    /// <param name="maxValue"></param>
    public override void SetUpView(float maxValue) {
        base.SetUpView(maxValue);

        // ½é´üÃͤò 0 ¤ËÀßÄê
        slider.value = 0;

        // ±£¤¹
        HideBarView();
    }

    /// <summary>
    /// ¹¶·â¥²¡¼¥¸¤Îɽ¼¨¹¹¿·
    /// </summary>
    /// <param name="currentValue"></param>
    public override void UpdateBar(float currentValue) {
        slider.value = currentValue;
    }
}




Presenter


using UnityEngine;
using UniRx;
using UniRx.Triggers;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// ¹¶·â½èÍý Presenter
/// </summary>
public class AttackModePresenter : ISetup {

    private LifeBase attackTarget;
    private ReactiveProperty<bool> IsAttackReady = new(false);

    private AttackModeModel myAttackModeModel;
    private ActionGuageBar attackModeView;

    private HpBar hpBarView;
    private AttackRangeCollider attackRangeCollider;

    /// <summary>
    /// ¥³¥ó¥¹¥È¥é¥¯¥¿
    /// </summary>
    public AttackModePresenter() {}

    /// <summary>
    /// ¥³¥ó¥¹¥È¥é¥¯¥¿
    /// </summary>
    /// <param name="spd"></param>
    /// <param name="attackPower"></param>
    /// <param name="attackRange"></param>
    public AttackModePresenter(float spd, int atk, int inte, int def, int mdef, float attackRange, DamageType damageType, eAttribute attributeType, int minDmg = 0) {
        myAttackModeModel = new(spd, atk, inte, def, mdef, attackRange, damageType, attributeType, minDmg);
    }

    /// <summary>
    /// ½é´üÀßÄê
    /// </summary>
    /// <param name="entityObject"></param>
    public void SetUp(GameObject entityObject) {

        // entityObject ¤«¤é¹¶·âÍѤΥǡ¼¥¿¤ò»²¾È¤·¤Æ¤â¤é¤¦
        if (entityObject.TryGetComponent(out attackModeView)) {
            attackModeView.SetUpView(ConstData.MAX_ACTION_GAUGE_POINT);
        }

        // Hp ¼èÆÀ
        LifeBase myLife;
        if (!entityObject.TryGetComponent(out myLife)) {
            return;
        }

        myAttackModeModel = myLife.AttackModeModel;

        // HpBar ¼èÆÀ
        if (entityObject.TryGetComponent(out hpBarView)) {
            hpBarView.SetUpView(myLife.Hp.Value);
        }

        // Hp ¤Î¹ØÆÉ Hp ¥²¡¼¥¸¹¹¿·
        myLife.Hp.Subscribe(hp => hpBarView.UpdateBar(myLife.Hp.Value)).AddTo(entityObject);

        // ¹¶·âÈÏ°ÏÍѤΥ³¥é¥¤¥À¡¼¤Î¼èÆÀ¤¬¤Ç¤­¤Ê¤¤¾ì¹ç¡¢½èÍý¤·¤Ê¤¤
        if (!entityObject.TryGetComponent(out attackRangeCollider)) {
            return;
        }

        // ¹¶·âÈϰϤΥ³¥é¥¤¥À¡¼¤Î¥µ¥¤¥º¤òÀßÄê
        attackRangeCollider.SetUpColliderRange(myAttackModeModel.AttackRange);

        // ¥â¥Ã¥¯ÍÑ
        if (myLife.EntityType == EntityType.Enemy) {

            return;
        }

        // ¹¶·âÂоݤȤʤ륿¥°¤òÀßÄê
        string tag = myLife.GetTargetEntityType().ToString();

        // ¹¶·âÂоݤÎõº÷
        entityObject.UpdateAsObservable()
            .Subscribe(_ => SearchAttackTarget(entityObject, tag));

        // ¿¯ÆþȽÄê¤Î¹ØÆÉ ¼«Æ°¹¶·â½àÈ÷
        //attackRangeCollider.AttackRange.OnTriggerStay2DAsObservable()
        //    .Where(col => attackTarget == null)
        //    .Where(col => col.transform.TryGetComponent(out attackTarget))  // ¥³¥é¥¤¥À¡¼¤Ø¤Î¿¯ÆþȽÄê
        //    .Where(_ => myLife.CheckTarget(attackTarget.EntityType))        // ¹¶·âÂоݤ«È½Äê
        //    .Subscribe(col => {
        //        // ¹¶·â½àÈ÷³«»Ï¤È¥²¡¼¥¸É½¼¨
        //        IsAttackReady.Value = true;
        //        attackModeView.ShowBarView();

        //        Debug.Log($"¹¶·â½àÈ÷ ³«»Ï {attackTarget}");
        //    });

        // ¤¤¤Ê¤¯¤Ê¤Ã¤¿È½Äê¤Î¹ØÆÉ ¼«Æ°¹¶·âÄä»ß
        //attackRangeCollider.AttackRange.OnTriggerExit2DAsObservable()
        //    .Where(col => col.transform.TryGetComponent(out attackTarget))  // ¥³¥é¥¤¥À¡¼¤Ø¤Î¿¯ÆþȽÄê
        //    .Where(_ => myLife.CheckTarget(attackTarget.EntityType))        // ¹¶·âÂоݤ«È½Äê
        //    .Subscribe(col => StopAttack());

        // Update ¤Î¹ØÆÉ
        entityObject.UpdateAsObservable()
            .Where(_ => IsAttackReady.Value)
            .Where(_ => myAttackModeModel.CurrentActionGaugePoint.Value < myAttackModeModel.MaxActionGaugePoint)
            .Subscribe(_ => {
                // ¹¶·â¥²¡¼¥¸¤Î²Ã»»
                myAttackModeModel.CurrentActionGaugePoint.Value += myAttackModeModel.AttackSpeed * Time.deltaTime;

                // ¹¶·â¥²¡¼¥¸¤Î View ¹¹¿·
                attackModeView.UpdateBar(myAttackModeModel.CurrentActionGaugePoint.Value);
            });

        // ¹¶·â¥²¡¼¥¸¤Î¹ØÆÉ
        myAttackModeModel.CurrentActionGaugePoint
            .Where(_ => attackTarget)
            .Where(currentActionGaugePoint => currentActionGaugePoint >= myAttackModeModel.MaxActionGaugePoint)
            .Subscribe(_ => {
                if (attackTarget == null) {
                    // ¥¢¥¯¥·¥ç¥ó¥²¡¼¥¸¥ê¥»¥Ã¥È
                    myAttackModeModel.ResetActionGaugePoint();
                } else {
                    // ¼«Æ°¹¶·â
                    AutoAttack();
                }
            })
            .AddTo(entityObject);

        // Ç˲õ»þ¤Î¹ØÆÉ
        entityObject.OnDestroyAsObservable().Subscribe(_ => myAttackModeModel.Dispose());

        // TODO ̾Á°É½¼¨


        //Debug.Log($"{this} Setup ´°Î»");
    }

    /// <summary>
    /// ¼«Æ°¹¶·â
    /// </summary>
    private void AutoAttack() {
        //Debug.Log("¼«Æ°¹¶·â");

        // °À­·¸¿ô»»½Ð
        float attributeRate = BattleCalculater.CalcAttributeRate(myAttackModeModel.AttributeType, attackTarget.AttackModeModel.AttributeType);
        //Debug.Log($"°À­ÊäÀµ : {attributeRate}");

        //Debug.Log($"¹¶·âÎÏ : {myAttackModeModel.Atk}");
        //Debug.Log($"ÃÎÎÏ : {myAttackModeModel.Inte}");
        //Debug.Log($"ËɸæÎÏ : {attackTarget.AttackModeModel.Def}");

        // ¸½ºß¤Î¹¶·â¥¿¥¤¥×¤ò¸µ¤Ë¥À¥á¡¼¥¸·×»»
        int damage = myAttackModeModel.DamageType == DamageType.atk
            ? BattleCalculater.CalcAtkDamage(myAttackModeModel.Atk, myAttackModeModel.Inte, attributeRate, attackTarget.AttackModeModel.Def)      // ʪÍý¥À¥á¡¼¥¸
            : BattleCalculater.CalcInteDamage(myAttackModeModel.Inte, myAttackModeModel.Atk, attributeRate, attackTarget.AttackModeModel.Mdef);   // ËâË¡¥À¥á¡¼¥¸

        Debug.Log($"ºÇ½ª¥À¥á¡¼¥¸ : {damage}");

        // ¥¢¥¯¥·¥ç¥ó¥²¡¼¥¸¥ê¥»¥Ã¥È
        myAttackModeModel.ResetActionGaugePoint();

        // ¹¶·âÂоݤ¬»Ä¤Ã¤Æ¤¤¤ë¤«³Îǧ
        if (attackTarget == null) {
            Debug.Log("¹¶·âÂоݾüº");
            return;
        }
        
        // ¥À¥á¡¼¥¸Ãͤò¥Õ¥í¡¼¥Èɽ¼¨¡£¥ª¥Ö¥¸¥§¥¯¥È¥×¡¼¥ëÍøÍÑ
        attackTarget.ShowFloatingView(damage);
        
        //FloatingView floatingView = (FloatingView)FloatingViewGenerator.instance.GetObjectFromPool(attackTarget.transform.position, attackTarget.transform.rotation);
        //floatingView.SetUpView(damage.ToString());

        // Hp ·×»»¡£ÂоݤΠ»Ä hp ¤¬ 0 °Ê²¼¤Ê¤é
        if (!attackTarget.CalcLife(-damage)) {
            // ¼«Æ°¹¶·âÄä»ß
            StopAttack();
        }

        //Debug.Log("¹¶·â´°Î»");
    }

    /// <summary>
    /// ¼«Æ°¹¶·âÄä»ß
    /// </summary>
    private void StopAttack() {
        attackTarget = null;

        // ¹¶·âÄä»ß¡£¥¢¥¯¥·¥ç¥ó¥²¡¼¥¸¥ê¥»¥Ã¥È¤È¥²¡¼¥¸Èóɽ¼¨
        IsAttackReady.Value = false;
        myAttackModeModel.ResetActionGaugePoint();
        attackModeView.HideBarView();

        //Debug.Log("¹¶·âÄä»ß");
    }

    /// <summary>
    /// ¹¶·âÎϤʤɤΥǡ¼¥¿¹¹¿·
    /// </summary>
    /// <param name="attackModeModel"></param>
    public void UpdateAttackModel(AttackModeModel attackModeModel, GameObject entityObject) {
        myAttackModeModel = attackModeModel;
        myAttackModeModel.Dispose();

        // ¹¶·â¥²¡¼¥¸¤Î¹ØÆɤä¤êľ¤·
        myAttackModeModel.CurrentActionGaugePoint
            .Where(_ => attackTarget)
            .Where(currentActionGaugePoint => currentActionGaugePoint >= myAttackModeModel.MaxActionGaugePoint)
            .Subscribe(_ => AutoAttack())
            .AddTo(entityObject);
        Debug.Log("¹¹¿·");
    }

    /// <summary>
    /// ¹¶·âÂоݤÎõº÷
    /// </summary>
    /// <param name="entityObject"></param>
    /// <param name="tag"></param>
    private void SearchAttackTarget(GameObject entityObject, string tag) {

        // OverlapCircleAll ¥á¥½¥Ã¥É¤òÍøÍѤ·¤Æ¡¢ÈÏ°ÏÆâ¤Î¥³¥é¥¤¥À¡¼ÉÕ¤­¤Î¥ª¥Ö¥¸¥§¥¯¥È¤ò¼èÆÀ
        //Collider2D[] hitColliders = Physics2D.OverlapCircleAll(entityObject.transform.position, myAttackModeModel.AttackRange / 2);
        //List<GameObject> objList = new();

        //// ÇÛÎóÆâ¤ÎÍ×ÁǤò£±¤Ä¤º¤Ä¼è¤ê½Ð¤¹
        //foreach (Collider2D collider in hitColliders) {
        //    // »ØÄꤵ¤ì¤¿¥¿¥°¤ò»ý¤Ä¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¤«È½Äê¡£¤½¤ì¤ò¹¶·âÂоݸõÊä¤È¤·¤Æǧ¼±
        //    if (collider.gameObject.CompareTag(tag)) {
        //        objList.Add(collider.gameObject);
        //    }
        //}

        // ¾åµ­¤ò LINQ ¤Çµ­½Ò
        List<GameObject> objList = Physics2D.OverlapCircleAll(entityObject.transform.position, myAttackModeModel.AttackRange / 2)
            .Where(collider => collider.CompareTag(tag))
            .Select(collider => collider.gameObject)
            .ToList();

        // ¼èÆÀ¤·¤¿¥²¡¼¥à¥ª¥Ö¥¸¥§¥¯¥È¤¬ 0 ¤Ê¤é¹¶·âÂоݤθõÊä¤Ê¤·
        if (objList.Count == 0) {
            Debug.Log("¹¶·âÂоݤʤ·");
            StopAttack();
            return;
        }

        // ºÇ¤â¶á¤¤¥ª¥Ö¥¸¥§¥¯¥È¤Îµ÷Î¥¤òÂåÆþ¤¹¤ë¤¿¤á¤ÎÊÑ¿ô
        //float nearDistance = 0;

        // ¸¡º÷¤µ¤ì¤¿ºÇ¤â¶á¤¤¥²¡¼¥à¥ª¥Ö¥¸¥§¥¯¥È¤òÂåÆþ¤¹¤ë¤¿¤á¤ÎÊÑ¿ô
        //GameObject searchTargetObj = null;

        // objs¤«¤é£±¤Ä¤º¤ÄobjÊÑ¿ô¤Ë¼è¤ê½Ð¤¹
        //foreach (GameObject obj in objList) {

        //    // obj¤Ë¼è¤ê½Ð¤·¤¿¥²¡¼¥à¥ª¥Ö¥¸¥§¥¯¥È¤È¡¢¤³¤Î¥²¡¼¥à¥ª¥Ö¥¸¥§¥¯¥È¤È¤Îµ÷Î¥¤ò·×»»¤·¤Æ¼èÆÀ
        //    float distance = Vector3.Distance(obj.transform.position, entityObject.transform.transform.position);

        //    // nearDistance¤¬0(ºÇ½é¤Ï¤³¤Á¤é)¡¢¤¢¤ë¤¤¤ÏnearDistance¤¬distance¤è¤ê¤âÂ礭¤¤Ãͤʤé
        //    if (nearDistance == 0 || nearDistance > distance) {

        //        // nearDistance¤ò¹¹¿·
        //        nearDistance = distance;

        //        // searchTargetObj¤ò¹¹¿·
        //        searchTargetObj = obj;
        //    }
        //}

        // ¾åµ­¤ò LINQ ¤Çµ­½Ò¡£ºÇ¤â¶á¤¤ÂоݤòÃê½Ð
        GameObject searchTargetObj = objList
            .OrderBy(obj => Vector3.Distance(obj.transform.position, entityObject.transform.position))
            .FirstOrDefault();

        //ºÇ¤â¶á¤«¤Ã¤¿¥ª¥Ö¥¸¥§¥¯¥È¤ò¹¶·âÂоݤȤ¹¤ë
        attackTarget = searchTargetObj.GetComponent<LifeBase>();

        // ¹¶·â½àÈ÷³«»Ï¤È¥²¡¼¥¸É½¼¨
        IsAttackReady.Value = true;
        attackModeView.ShowBarView();

        Debug.Log($"¹¶·â½àÈ÷ ³«»Ï {attackTarget}");
    }
}


¡ãPhysics2D.OverlapCircleAll¡ä


¡¡»ØÄꤷ¤¿ÈÏ°ÏÆâ¤Ë¥³¥é¥¤¥À¡¼¤òŸ³«¤·¡¢¤½¤ÎÈÏ°ÏÆâ¤Ë¤¢¤ë¥³¥é¥¤¥À¡¼¤ò¼èÆÀ¤·¤ÆÇÛÎó¤ËÂåÆþ¤¹¤ë¥á¥½¥Ã¥É¤Ç¤¹¡£

¡¡¥ì¥¤¥ä¡¼¤Ç»ØÄꤷ¡¢GC ¤ò¾¯¤Ê¤¯¤¹¤ë OverlapCircleNonAlloc ¥á¥½¥Ã¥É¤â¤¢¤ê¤Þ¤¹¡£


https://docs.unity3d.com/ja/current/ScriptReferenc...

https://docs.unity3d.com/ja/current/ScriptReferenc...


·Ò¤®¹þ¤ß


¡¡¾åµ­¤Î¥¯¥é¥¹¤ò¥×¥ì¥¤¥ä¡¼¤äŨ¤Î¥¯¥é¥¹¤È¤Ä¤Ê¤®¹ç¤ï¤»¤ë¤³¤È¤Ç¡¢¶¦Ä̤ι¶·â½èÍý¤òºîÀ®¤¹¤ë¤³¤È¤¬²Äǽ¤Ç¤¹¡£

¤³¤Î¥Ú¡¼¥¸¤Ø¤Î¥³¥á¥ó¥È

UniRX¤ò»È¤¦¤È¤É¤ó¤Ê¤È¤³¤í¤¬¤¤¤¤¤Ç¤¹¤«¡©

»ä¤Ï´Ú¹ñ¿Í¤Ç¡¢¸½ºß2D Action RPG¤òºî¤Ã¤Æ¤¤¤Þ¤¹¡£

¾ðÊó¤òõ¤·¤Æ¤¤¤ëÅÓÃæ¡¢»ä¤¬Ë¾¤à¾ðÊó¤È»÷¤¿¾ðÊó¤ò¸«¤Ä¤±¤¿¤è¤¦¤Ê¤Î¤Ç¡¢¤ªÊ¹¤­¤·¤¿¤¤¤Î¤Ç¤¹¤¬¡¢UniRX¤Ë¤Ï¤É¤Î¤è¤¦¤Ê¥á¥ê¥Ã¥È¤¬¤¢¤ë¤Î¤Ç¤·¤ç¤¦¤«¡©

ÉÔËܰդʤ¬¤é¤ª¼ê¿ô¤ò¤ª¤«¤±¤·¤Æ¿½¤·Ìõ¤¢¤ê¤Þ¤»¤ó¡£

0
Posted by kor_user 2024ǯ04·î27Æü(ÅÚ) 02:36:17 ÊÖ¿®

¥³¥á¥ó¥È¤ò¤«¤¯


¡Öhttp://¡×¤ò´Þ¤àÅê¹Æ¤Ï¶Ø»ß¤µ¤ì¤Æ¤¤¤Þ¤¹¡£

ÍøÍѵ¬Ìó¤ò¤´³Îǧ¤Î¤¦¤¨¤´µ­Æþ²¼¤µ¤¤

Menu



´ðÁÃ

µ»½Ñ/Ãμ±(¼ÂÁõÎã)

3D¥¢¥¯¥·¥ç¥ó¥²¡¼¥à

2D¤ª¤Ï¤¸¤­¥²¡¼¥à(ȯŸÊÔ)

2D¶¯À©²£¥¹¥¯¥í¡¼¥ë¥¢¥¯¥·¥ç¥ó(ȯŸÊÔ)

2D¥¿¥Ã¥×¥·¥å¡¼¥Æ¥£¥ó¥°(³ÈÄ¥ÊÔ)

¥ì¡¼¥¹¥²¡¼¥à(È´¿è)

2DÊüÃÖ¥²¡¼¥à(ȯŸÊÔ)

3D¥ì¡¼¥ë¥¬¥ó¥·¥å¡¼¥Æ¥£¥ó¥°(±þÍÑÊÔ)

3Dæ½Ð¥²¡¼¥à(È´¿è)

2D¥ê¥¢¥ë¥¿¥¤¥à¥¹¥È¥é¥Æ¥¸¡¼

3D¥¿¥Ã¥×¥¢¥¯¥·¥ç¥ó(NavMeshAgent »ÈÍÑ)

2D¥È¥Ã¥×¥Ó¥å¡¼¥¢¥¯¥·¥ç¥ó(¥«¥¨¥ë¤Î°Ù¤Ë¡Á¡¢¥Ü¥³¥¹¥«¥¦¥©¡¼¥ºÉ÷)

VideoPlayer ¥¤¥Ù¥ó¥ÈϢư¤Î¼ÂÁõÎã

VideoPlayer ¥ê¥¹¥ÈÆ⤫¤é¥à¡¼¥Ó¡¼ºÆÀ¸¤Î¼ÂÁõÎã(ȯŸ)

AR ²èÁüÉÕ¤­¥ª¥Ö¥¸¥§¥¯¥ÈÀ¸À®¤Î¼ÂÁõÎã

AR ¥ê¥¹¥ÈÆ⤫¤éÀ¸À®¤Î¼ÂÁõÎã(ȯŸ)

2D¥È¥Ã¥×¥Ó¥å¡¼¥¢¥¯¥·¥ç¥ó(¥µ¥Ð¥¤¥Ð¡¼É÷)

private



¤³¤Î¥µ¥¤¥ÈÆâ¤ÎºîÉʤϥæ¥Ë¥Æ¥£¤Á¤ã¤ó¥é¥¤¥»¥ó¥¹¾ò¹à¤Î¸µ¤ËÄ󶡤µ¤ì¤Æ¤¤¤Þ¤¹¡£

´ÉÍý¿Í/Éû´ÉÍý¿Í¤Î¤ßÊÔ½¸¤Ç¤­¤Þ¤¹