Игровая логика на заказ

Портфолио, резюме, поиск работы

Игровая логика на заказ

Сообщение Meth 31 май 2017, 15:00

Программист C#
Работаю с Unity3D уже 5 лет.
Занимаюсь игровой логикой: Геймплей, механика, ИИ, физика, UI, UX и т.п. (не работаю с networking)
Пишу с комментариями, визуализирую код в инспекторе, название переменных/классов/методов соответствуют логике;
Логические отступы, регионы и т.п. имеются.
Цена варьируется в зависимости от сложности задачи.
Пишу в соответствии с вашими условиями/предпочтениями - от них цена не зависит, но от них может зависеть сложность.
Писать на cortexmethod@yandex.ru.

Пример ИИ скрипта и его короткая демонстрация:
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class fightAI : MonoBehaviour {
    public bool seenPlayer;
    public GameObject player;
    public TrailRenderer[] allTrail;
    Animator anim;
    [Header("Типы атак")]
    public List<AttackType> attackType;
    [Header("Коллайдер оружия")]
    public Collider weapon;
    public Collider specialWeapon;

    [Header("Части тела")]
    public Collider[] myGibs;
    [Header("ХП'бар")]
    public Image[] HPimg;
    public GameObject pickHP;
    [Header("Контроллеры ходьбы")]
    public float runX;
    public float runY;
    [Header("Шанс агрессии")]
    [Range(1,100)]
    public float aggressive;
    [Header("Запас здоровья")]
    public int maxHP;
    public int HP;
    int hpBack;
    [Header("Скорость поворота")]
    public float rotateSpeed;
    [Header("Множитель урона")]
    public int damageMultiple;
    [Header("Скорость принятия решений")]
    public float reactSpeed;
    [Header("Границы дистанций")]
    public float[] distance;
    [Header("Действия")]
    public List<WhatIDoDoing> Doing;

    #region AIhelp
    int attackNow;
    int animNow;
    bool checkAN { get { return attackType[animNow].AnimationAttack.Length > (attackNow + 1); } }// проверяет переполнение AnimationAttack
    int getDamage { get { return attackType[animNow].damageForAttack[attackNow]; } } // получает значение урона
    int getStrenght { get { return attackType[animNow].strenghtBeat[attackNow]; } } // получает значение силы
    float getStunTime { get { return attackType[animNow].stunTime[attackNow]; } } // получает значение времени стана
    int getAttackClip { get { return attackType[animNow].AnimationAttack[attackNow]; } } // получает следующее значение анимации
    bool SwitchTrail { set { allTrail[attackType[animNow].trailNum].enabled = value; } } // переключает trail
    bool getLowerDistance { get { return Vector3.Distance(gameObject.transform.position, player.transform.position) < distance[0]; } } // сравнивает минимальную дистанцию с дистанцией игрока
    bool getHighestDistance { get { return Vector3.Distance(gameObject.transform.position, player.transform.position) > distance[1]; } } // сравнивает максимальную дистанцию с дистанцией игрока
    bool IsAttack // Если я атакую
    {
        get
        {
            bool t = false;
            if (anim.GetCurrentAnimatorStateInfo(0).IsTag("fight"))
                t = true;
            return t;
        }
    }
    //переменные сета
    int damageNow;
    float stunNow;
    int strNow;
    //умер ли "я"
    bool dieN;
    #endregion
    /* Класс, который собирает все или некоторые анимации атак в сет, с дополнительными
     * параметрами:
     урон на каждую анимацию сета
     сила на каждую анимацию сета
     время стана на каждую анимацию сета
     защита во время сета
     какой трейл от меча поставить*/

    [System.Serializable]
    public class AttackType : System.Object
    {
        [Header("Номера параметра attack")]
        public int[] AnimationAttack;
        [Header("Урон во время анимаций")]
        public int[] damageForAttack;
        [Header("Сила удара")]
        public int[] strenghtBeat;
        [Header("Время стана")]
        public float[] stunTime;
        [Header("Степень защиты во время атаки")]
        public float resistance;
        [Header("Какой трейл включать")]
        public int trailNum;
    }
    /* Класс, представляющий собой действия, которые носитель будет выполнять, конечно,
     * в определенных в скрипте ситуациях
     Выбор атаки и шанс на нее
     Куда идти
     Идти, прыгать, стоять
     Доп. команды */

    [System.Serializable]
    public class WhatIDoDoing : System.Object
    {
        [Header("Действия в AttackType (если нет, то -1) и шанс")]
        public int AttackType;
        [Range(1,100)]
        public int chanceToAttack;
        [Header("Настройки runX и runY")]
        [Range(-1.00f, 1.00f)]
        public float runXnow;
        [Range(-1.00f, 1.00f)]
        public float runYnow;
        [Header("Идти(0) или прыгать(1), или не делать ничего(-1)")]
        [Range(-1,1)]
        public int Do;
        [Header("Дополнительные действия (ключевые слова)")]
        public string[] otherAction;
        public string[] param;

    }
    // Use this for initialization
    void Start () {
        HP = maxHP;
        player = GameObject.FindWithTag("Player");
        StartCoroutine("move");
        anim = gameObject.GetComponent<Animator>();
        //Выключаю коллайдеры частей тела
        foreach (var a in myGibs)
            a.enabled = false;
        //...и включаю им кинематику
        foreach (var a in myGibs)
            a.GetComponent<Rigidbody>().isKinematic = true;
        hpBack = HP;
    }
       
        // Update is called once per frame
        void Update () {
        #region HUD
        var rt = HPimg[0].transform as RectTransform;
        rt.sizeDelta = new Vector2((HP * 872) / maxHP, rt.sizeDelta.y);
        var rt2 = HPimg[1].transform as RectTransform;
        rt2.sizeDelta = Vector2.Lerp(rt2.sizeDelta, new Vector2((hpBack * 872) / maxHP, rt.sizeDelta.y), 12 * Time.deltaTime);
        pickHP.transform.LookAt(new Vector3(
            player.GetComponent<Control>().Cam.transform.position.x,
            player.GetComponent<Control>().Cam.transform.position.y,
            player.GetComponent<Control>().Cam.transform.position.z));
        #endregion
        #region WeaponSetting
        weapon.GetComponent<weaponAI>().damage = damageNow;
        weapon.GetComponent<weaponAI>().strenght = strNow;
        weapon.GetComponent<weaponAI>().timeStun = stunNow;
        weapon.GetComponent<weaponAI>().mult = damageMultiple;
        #endregion
        #region Other
        gameObject.transform.eulerAngles = new Vector3(0, gameObject.transform.eulerAngles.y, 0);
        if (dieN)
            return;
        if (HP <= 0)
            die();
        //Параметры ходьбы в аниматоре
        anim.SetFloat("runX",
            Mathf.Lerp(anim.GetFloat("runX"), runX, 10 * Time.deltaTime)
            );
        anim.SetFloat("runY",
            Mathf.Lerp(anim.GetFloat("runY"), runY, 10 * Time.deltaTime)
            );
        #endregion
        //Если "я" вижу игрока
        if (seenPlayer)
        {
            //Переключить в аниматоре
            anim.SetBool("aim", true);
            //Если "я" атакую, то я не поворачиваюсь за игроком
            if (!IsAttack)
                gameObject.transform.rotation = Quaternion.Lerp(gameObject.transform.rotation, Quaternion.LookRotation(player.transform.position - gameObject.transform.position), rotateSpeed * Time.deltaTime);
           
            //Не соблюдены дистанции
            #region BadDistance
            //Игрок слишком близко
            if (getLowerDistance)
            {
                //Doing[0] - Если игрок слишком близко
                //Идти в соответствии с переменной в этом классе
                runX = Doing[0].runXnow;
                //Если есть какой-то параметр
                if (Doing[0].otherAction.Length >= 1)
                    //... и он записан в коде (снизу)
                    if (Doing[0].otherAction[0] == "randomY")
                    {
                        //... исполнять его
                        runY = Doing[0].runYnow + Random.Range(
                            -(float)System.Convert.ToInt32(Doing[0].param[0]),
                            (float)System.Convert.ToInt32(Doing[0].param[0])
                            );
                    }
                    else { }
                else //... или нет
                    runY = Doing[0].runYnow;
            }
            //Игрок слишком далеко
            if (getHighestDistance)
            {
                //Doing[1] - Если игрок слишком далеко
                int w = Random.Range(0, 100);
                //Если есть атака - атаковать
                if (Doing[1].AttackType != -1)
                    if (Doing[1].chanceToAttack >= w)
                        SetAttackType(-1, Doing[1].AttackType);
                //Идти в соответствии с переменными в этом классе
                runX = Doing[1].runXnow;
                runY = Doing[1].runYnow;
            }
            #endregion
        }
        else
        {
            //Если "я" его не вижу, то ничего и не делаю
            anim.SetBool("aim", false);
        }

        /*
        attack [1...3] - это удара
        attack [100, 200] - спец удары и перекаты
    */

    //Если я атакую и перекатываюсь, то я только атакую
        if (IsAttack && anim.GetInteger("attack") >= 100)
        {
            anim.SetInteger("attack", 100);
        }
        }
    #region WEAPONset
    //Активировать оружие
    public void weaponOn()
    {
        weapon.enabled = true;
        SwitchTrail = true;
    }    
    //Деактивировать оружие
    public void weaponOff()
    {
        weapon.enabled = false;
        SwitchTrail = false;
    }
    //Переключение на следующую стадию анимации
    public void NextAn()
    {
        //Закончился ли сет анимаций
        if (checkAN)
            attackNow++;
        anim.SetInteger("attack", getAttackClip);
        damageNow = getDamage;
        strNow = getStrenght;
        stunNow = getStunTime;
    }
    //снятие режима атаки
    public void attackOff(int num)
    {
        if (num == anim.GetInteger("attack"))
            anim.SetInteger("attack", 0);
    }
    #endregion
    #region AI
    //Атака
    public void SetAttackType(int tp, int howBeat)
    {
        //Какую анимацию из AttackType "я" выбираю
        animNow = howBeat;
        //Устанавливаю изначальный кадр
        attackNow = 0;
        //Получаю урон из соотв. анимации
        damageNow = getDamage;
        //Получаю силу из соотв. анимации
        strNow = getStrenght;
        //Получаю время стана из соотв. анимации
        stunNow = getStunTime;
        //Запускаю
        anim.SetInteger("attack", getAttackClip);
    }
    //Ходьба
    public IEnumerator move()
    {
        while (true)
        {
            yield return new WaitForSeconds(reactSpeed);
            //Если заметил игрока
            if (seenPlayer)
            {
                //Если соблюдены дистанции между игроком и "мной"
                if (!getLowerDistance && !getHighestDistance)
                {
                    //шанс на агрессию
                    int fightt = Random.Range(0, 100);
                    //Если не повезло - выбор куда идти (вправо или влево)
                    if (fightt > aggressive)
                    {
                        int moveTo = Random.Range(2, 4);
                        runX = Doing[moveTo].runXnow;
                        runY = Doing[moveTo].runYnow;
                    }
                    //Если повезло
                    else
                    {
                        //Выбрать случайный тип атаки
                        SetAttackType(-1, Random.Range(0, attackType.ToArray().Length));
                    }
                }
                //Если игрок подошел слишком близко
                if (getLowerDistance)
                {
                    //Шанс на агрессию в Действии[0] (параметр ChanceToAttack)
                    int w = Random.Range(0, 100);
                    //Если ли вообще "удары" в таком случае (когда игрок подошел)
                    if (Doing[0].AttackType != -1)
                        //Если есть - проверяет, повезло ли
                        if (Doing[0].chanceToAttack >= w)
                            //Устанавливает атаку на номер ее анимации в AttackType
                            SetAttackType(-1, Doing[0].AttackType);
                }
            }
        }
    }
    #endregion
    //Специальная атака
    public void specAttack(int swc)
    {
        //переключатель коллайдера спец. атаки
        switch (swc)
        {
            case 1:
                specialWeapon.enabled = true;
                anim.SetInteger("attack", 0);
                break;
            case 2:
                specialWeapon.enabled = false;
                break;
        }
    }
    void HPBackUpd()
    {
        hpBack = HP;
    }
    //Смерть
    void die()
    {
        //Отключаю спец. атаку
        specialWeapon.enabled = false;
        dieN = true;
        //Выключаю контроллер
        gameObject.GetComponent<CharacterController>().enabled = false;
        //Делаю его оружие "самостоятельным"
        weapon.transform.parent = null;
        weapon.isTrigger = false;
        weapon.enabled = true;
        weapon.gameObject.AddComponent<Rigidbody>();
        weapon.GetComponent<weaponAI>().enabled = false;
        //Останавливаю все кроутины
        StopAllCoroutines();
        //Выключаю аниматор
        anim.enabled = false;
        //Включаю коллайдеры частей тела
        foreach (var a in myGibs)
            a.enabled = true;
        //Выключаю им кинематику
        foreach (var a in myGibs)
            a.GetComponent<Rigidbody>().isKinematic = false;
        //Делаю "удар" по случайной части тела
        myGibs[Random.Range(0, myGibs.Length)].GetComponent<Rigidbody>().AddForceAtPosition(-gameObject.transform.forward * 600, player.transform.position, ForceMode.Impulse);
    }
    //Метод для аниматора
    void CB() { }
}

 

Скрытый текст:
Изображение
Изображение
Изображение

Для лучшего результата стоит конкретно описать задачу, которую вы мне ставите.
(я также могу чего-нибудь спросить, если понадобиться)
Основам программирования не учу.
Meth
UNец
 
Сообщения: 2
Зарегистрирован: 31 май 2017, 10:28

Re: Игровая логика на заказ

Сообщение samana 31 май 2017, 16:33

Meth писал(а):Программист C#
Работаю с Unity3D уже 5 лет.

Ни в коем случае не буду критиковать ваши умения, но просто удивлён, что в Update столько GetComponent-ов. Все говорят, что компоненты надо кешировать, странно, что у вас это не на автомате получается.
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск

Re: Игровая логика на заказ

Сообщение Meth 31 май 2017, 19:14

Я учился по видеоурокам и документациям - мог много чего упустить.
Спасибо, я, действительно, не знал как это влияет на оптимизацию, но благодаря вам я прочитал об этом.
Meth
UNец
 
Сообщения: 2
Зарегистрирован: 31 май 2017, 10:28


Вернуться в Ищу Работу

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3