Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование игр для компьютеров > Unity > Общие вопросы

Общие вопросы вопросы не попадающие ни в один из доступных разделов

Ответ
 
Опции темы
Старый 17.06.2012, 00:18   #1
pie
ПроЭктировщик
 
Аватар для pie
 
Регистрация: 04.11.2011
Сообщений: 176
Написано 19 полезных сообщений
(для 64 пользователей)
Универсальный скрипт оружия

Всем привет! Решил написать небольшой тутор. Он будет направлен в сторону шутеров от первого лица. А конкретнее к скриптингу оружия в таких играх.
В этом туторе мы напишем универсальный скрипт оружия. Особенностью данного скрипта наверное является то что в нем будут реализованы различные режимы стрельбы (одиночными, очередями с отсечкой по 3 выстрела и непрерывными очередями). Так же в туториале будет показанно как правильно использовать модели и их анимации.
Модель оружия: Glock 17 скаченная с интернета для игры CSS. Декомпилированная и экспортированная в формат fbx. Вам этого делать не нужно. Просто скачайте готовую основу ТУТ.
Приступим к написанию скрипта. Создаем С# скрипт и называем его weapon.cs. Содержание с описанием:

using UnityEngine;
using System.Collections;

public class 
weapon MonoBehaviour {

    public 
int maxAmmo 100;                            // количество дополнительных патронов
    
public int maxAmmoInClip 30;                        // емкость магазина
    
public int gunAmmo 0;                                // количество патронов в магазине
    
    // режимы стрельбы
    
public bool SingleShoot true;                        // одиночными
    
public bool BurstAuto true;                        // очередями с отсечкой по 3 выстрела
    
public bool FullAuto true;                        // непрерывними очередями
    
    
public AudioClip fireSound;                            // звук выстрела
    
    
public AnimationClip idle;                            // анимация бездействия
    
public AnimationClip fire;                            // анимация выстрела
    
public AnimationClip reload;                        // анимация перезарядки
    
    
AudioSource audio;                                    // переменная для хранения компонента AudioSource который мы добавим позже
    
Animation anim;                                        // переменная для хранения компонента Animation который мы добавим позже
    
    
public int modes 0;                                // переменная для определения режимов стрельбы
    
public bool canShoot true;                        // триггер
    
public int currentMode;                                // текущий режим стрельбы
    
public int bulletsToGo;                                // переменная необходимая для реализации режима стрельбы очередями с отсечкой по 3 выстрела
    
    
public void Awake()
    {
        
audio gameObject.AddComponent<AudioSource>();    // добавляем компонент AudioSource
        
anim gameObject.GetComponent<Animation>();    // ищем компонент Animation у нашего оружия (да да, именно ищем, а не добавляем)
        
        
anim.wrapMode WrapMode.Loop;                    // настраиваем компонент Animation, а конкретно зацикливаем анимации
        
anim[reload.name].wrapMode WrapMode.Clamp;    // анимацию перезарядки останавливаем на последнем кадре после воспроизведения 
        
anim[fire.name].wrapMode WrapMode.Clamp;        // анимацию выстрела останавливаем на последнем кадре после воспроизведения 
        
anim[idle.name].layer = -1;                        // меняем слой анимации бездействия, это нам позволяет воспроизводить другие анимации поверх этой
        
anim.Stop();                                    // останавливаем все анимации
        
        
GunModes(SingleShootBurstAutoFullAuto);        // используем метод GunModes для определения какие режимы стрельбы у нас доступны
        
        
int B 0;                                        // временная переменная для определения текущего режима стрельбы
        
while (BitRead(modesB) == 0){B++;}            // если данный режим не поддерживается, то проверяем следующий режим
        
currentMode B;                                // как найдем первый поддерживаемый режим назначаем его текущим

        
gunAmmo maxAmmoInClip;                        // кладем в магазин патроны в колистве емкости магазина
    
}
    
    public 
void Update ()
    {
        
// анимация бездействия воспроизводится все время
        
anim.CrossFade(idle.name);
        
        
// при нажатии на левую кнопку мыши и если нам разрешено стрелять
        
if (Input.GetMouseButtonDown(0) & canShoot) {
            
// выключаем триггер (то есть уже стрелять нельзя)
            
canShoot false;
            
// если текущий режим стрельбы очередью с отсечкой по 3 выстрела, то переменной bulletsToGo
            // присваиваем значение равное 2 (то есть 0, 1, 2 - три выстрела)
            
if (currentMode == 1){bulletsToGo 2;}
            
// стреляем
            
Shoot();
        }
        
        
// переключение между режимами стрельбы с помощью Num1, Num2 и Num3
        
if (Input.GetKeyDown(KeyCode.Keypad1)){ChangeGunMode(0);}
        if (
Input.GetKeyDown(KeyCode.Keypad2)){ChangeGunMode(1);}
        if (
Input.GetKeyDown(KeyCode.Keypad3)){ChangeGunMode(2);}
    }
    
    
// Метод стрельбы
    
public void Shoot () {
        
// уменьшаем количество патронов в магазине
        
gunAmmo--;
        
// воспроизводим звук выстрела
        
audio.PlayOneShot(fireSound);
        
// воспроизводим анимацию выстрела
        
anim.CrossFadeQueued(fire.name0.3fQueueMode.PlayNow);
        
// (услови №1) если патронов в магазине меньше 1...
        
if (gunAmmo 1)
        {
            
// выключаем триггер (то есть стрелять уже нельзя)
            
canShoot false;
            
// если количество дополнительных патронов больше 0...
            
if (maxAmmo 0)
                
// то перезаряжаем оружие
                
StartCoroutine(CoroutineReload());
        }else{
// если условие №1 не выполняется...
            // то переходим к сопрограмме связанной со стрельбой
            
StartCoroutine(CoroutineShoot());        
        }        
    }
    
    
// index0 - стрельба одиночными
    // index1 - стрельба очередью с отсечкой по 3 выстрела
    // index2 - непрерывными очередями
    
public void GunModes (bool index0bool index1bool index2){
        if (
index0){modes BitOn(modes0);}
        if (
index1){modes BitOn(modes1);}
        if (
index2){modes BitOn(modes2);}
    }
    
    
// index0 -  переменная для определения режимов стрельбы
    // index1 - режим стрельбы (0, 1, 2)
    
public int BitOn (int index0int index1){
        return 
index0 | (<< index1);
    }

    public 
int BitRead (int modesint B){
        return (
modes & (<< B)) >> B;
    }
    
    
// index0 - режим стрельбы (0, 1, 2)
    
public int ChangeGunMode (int index0){
        if (
BitRead(modesindex0) == 1){currentMode index0;}
        return 
index0;
    }
    
    
// сопрограмма стрельбы
    
public IEnumerator CoroutineShoot(){
        
// текущий режим стрельбы
        
switch (currentMode){
            
// стрельба одиночными
            
case 0:
                
// небольшая задержка
                
yield return new WaitForSeconds(0.1f);
                
// разрешаем стрелять
                
canShoot true;
                
// выходим с сопрограммы
                
yield break;
            break;

            
// стрельба очередью с отсечкой по 3 выстрела
            
case 1:
                
// небольшая задержка
                
yield return new WaitForSeconds(0.1f);
                
// если еще не все выстрелы произвели...
                
if (bulletsToGo 0){
                    
// то уменьшаем нашу переменную
                       
bulletsToGo--;
                    
// и еще раз стреляем
                    
Shoot();
                   }else{
// если все выстрелы уже произвели...
                    // то небольшая задержка
                    
yield return new WaitForSeconds(0.1f);
                    
// разрешаем стрелять
                    
canShoot true;
                    
// выходим с сопрограммы
                    
yield break;
                }
            break;
            
            
// стрельба очередью
            
case 2:
                
// небольшая задержка
                
yield return new WaitForSeconds(0.1f);
                
// если зажата левая кнопка мыши
                
if (Input.GetButton ("Fire1"))
                {
                    
// стреляем
                    
Shoot();
                  }else{ 
// если не зажата левая кнопка мыши...
                    // включаем триггер (стрелять можно)
                    
canShoot true;
                    
// выходим с сопрограммы
                    
yield break;
                }
            break;
        }
    }
    
    
// сопрограмма перезарядки
    
public IEnumerator CoroutineReload(){
        
// воспроизводим анимацию перезарядки
        
anim.PlayQueued(reload.name);
        
// делаем задержку равную длине анимации перезарядки + 0.5 секунд
        
yield return new WaitForSeconds(reload.length 0.5f);
        
        
// вводим временную переменную (она служит для красоты перезарядки)
        
var ammo 0;
        
// если у нас были патроны в магазине то нашей временной переменной присваиваем значение оставшихся патронов
        
if (gunAmmo 0){ammo gunAmmogunAmmo 0;}
        
// (условие №2)если дополнительных патронов меньше чем максимальная емкость магазина...
        
if (maxAmmoInClip maxAmmo){
            
// (условие №3) если количество дополнительных патронов + оставшихся в магазине больше максимальной емкости магазина...
            
if (maxAmmo ammo maxAmmoInClip){
                
// то кладем в магазин патроны в каличестве максимального его объема
                
gunAmmo maxAmmoInClip;
                
// а дополнительные патроны считаем по формуле: дополнительные патроны = дополнительные патроны + оставшиеся патроны - объем магазина
                
maxAmmo maxAmmo ammo maxAmmoInClip;
            }else{
// если условие №3 не выполняется...
                // то кладем в магазин патроны в количетсве равное дополнительные патроны + те что остались
                
gunAmmo maxAmmo ammo;
                
// а дополнительные патроны приравниваем нулю
                
maxAmmo 0;
            }
        }else{
// если условие №2 не выполняется...
            // то кладем в магазин патроны в каличестве максимального его объема
            
gunAmmo maxAmmoInClip;
            
// а дополнительные патроны считаем по формуле: дополнительные патроны = дополнительные патроны - объем магазина + оставшиеся
            
maxAmmo maxAmmo maxAmmoInClip ammo;
        }
        
// включаем триггер (стрелять можно)
        
canShoot true;
    }

Переходим к подготовке сцены. Переносим модель оружия на камеру.


Если у Вас слетели материалы то вот правильный порядок их расположения чтобы Вы сами их накидали:


Настраиваем объект оружия следующим образом (вы можете менять только положение, остальное советую оставить без изменения):


Почему именно так? Координаты мы правим чтобы оружие более красиво смотрелось в руках. Масштаб увеличили под размера контроллера. Почему масштаб по x -5? Ответ прост: чтобы мы стали праворукими (по стандарту в css все оружия леворукие). Почему угол поворота по y 270? Потому что все анимации в css находятся под углом 90 градусов к модели. А тогда почему не 90, а 270? Потому что мы масштаб по x сделали отрицательным. Если сделать положительным то нужно поставить 90.

Переносим созданный скрипт на наш объект:


У Вас должно получиться вот это в инспекторе:


Переносим анимации fire, idle и reload на одноименные переменные:


В итоге должно получиться так:


Естественно glock не стреляет беспрерывной очередью, но нам же для учебных целей, так что научим его это делать.

Запускаем сцену. Должно все работать.

За корявость написания кода не ругать. Что поделать, такой уж криворукий.

Спасибо за внимание!
(Offline)
 
Ответить с цитированием
Эти 7 пользователя(ей) сказали Спасибо pie за это полезное сообщение:
Android (17.06.2012), Andvrok (26.06.2012), cahekp (17.06.2012), is.SarCasm (17.06.2012), maffo (24.12.2012), Nuprahtor (17.06.2012), pax (20.06.2012)
Старый 23.06.2012, 12:46   #2
pie
ПроЭктировщик
 
Аватар для pie
 
Регистрация: 04.11.2011
Сообщений: 176
Написано 19 полезных сообщений
(для 64 пользователей)
Ответ: Универсальный скрипт оружия

Избавляемся от мучений переноса каждой анимации на соответствующую переменную. Добавляем новый метод и внутри пишем:

public void Reset() {
        if (
idle==null)
        {
            var 
idleAnimState animation["idle"];
            if(
idleAnimState!= nullidle idleAnimState.clip;
        }
        if (
fire==null)
        {
            var 
fireAnimState animation["fire"];
            if(
fireAnimState!= nullfire fireAnimState.clip;
        }
        if (
reload==null)
        {
            var 
reloadAnimState animation["reload"];
            if(
reloadAnimState!= nullreload reloadAnimState.clip;
        }
    } 
Он автоматически назначает переменным одноименные названия клипов анимации при перемещении скрипта на объект оружия. Спасибо pax'у за помощь.
(Offline)
 
Ответить с цитированием
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 09:48.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com