[1.8] EntityBullet - Классическая пуля

329
13
В продолжении темы про пулю. Как и обещал, выкладываю реализацию пули, но только для 1.8. Переделать для 1.7.* не составит труда.

Собственно, виновник торжества:
Код:
public class EntityBullet extends EntityThrowable
{
    // Урон от попадания
    int damage;
    
    public EntityBullet(World world)
    {
        super(world);
    }
    
    // Наш кастомный конструктор для пули
    // par1world  -  мир в котором будет пуля
    // par2EntityLivingBase - тот, кто осуществил выстрел
    // par3Velocity - скорость полёта пули
    // par4Accuracy - разброс при стрельбе
    // par5Damage - урон от попадания
    public EntityBullet(World par1world, EntityLivingBase par2EntityLivingBase, float par3Velocity, float par4Accuracy, int par5Damage)
    {
        super(par1world, par2EntityLivingBase);
        this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, par3Velocity, par4Accuracy);
        this.damage = par5Damage;
    }
    
    // Перезаписываем то, что происходит при попадании
    @Override
    protected void onImpact(MovingObjectPosition par1MovingObjectPosition)
    {
        // Если это произошло на сервере
        if (!this.worldObj.isRemote)
        {
            // Если мы попали в Entity и этот Entity - живой объект
            if (par1MovingObjectPosition.entityHit instanceof EntityLivingBase)
            {
                // Наносим ему урон и сбрасываем задержку на урон
                par1MovingObjectPosition.entityHit.attackEntityFrom(new DamageSource("bullet"), this.damage);
                par1MovingObjectPosition.entityHit.hurtResistantTime = 0;
            }
            // И затем пуля исчезает
            this.setDead();
        }
    }
}

Регистрируем в CommonProxy:
Код:
EntityRegistry.registerModEntity(EntityBullet.class, "bullet", 4, MyYOBAMod.instance, 64, 20, true);

И вызываем пулю в любом из предметов:
Код:
@Override
public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer player)
{
    if(!world.isRemote)
    {
        // Можно поиграть с параметрами Скорости, Разброса, Урона
        world.spawnEntityInWorld(new EntityBullet(world, player, 3.0F, 1.0F, 4));
    }
    return itemStack;
}

Вопросы? Идеи? Предложения?
 
329
13
krok написал(а):
Код:
(par1MovingObjectPosition.entityHit) != null && (par1MovingObjectPosition.entityHit instanceof EntityLiving)

На нулл проверять не надо,лучше EntityLiving замени на EntityLivingBase.Да и тут тоже почти не расписано
  1. Согласен. Убрал проверку на null.
  2. Поясни, в чем разница между EntityLiving и EntityLivingBase?
 
808
3
124
Нифига себе "ничего не написано". Тут три с половиной строки кода, и ко всем есть достаточно понятные комментарии. Даже про hurtResistantTime не забыли.
Туториал хорош, если не обращать внимания на элементарность :D
 
808
3
124
TaoGunner написал(а):
krok написал(а):
Код:
(par1MovingObjectPosition.entityHit) != null && (par1MovingObjectPosition.entityHit instanceof EntityLiving)

На нулл проверять не надо,лучше EntityLiving замени на EntityLivingBase.Да и тут тоже почти не расписано
  1. Согласен. Убрал проверку на null.
  2. Поясни, в чем разница между EntityLiving и EntityLivingBase?
EntityLiving - все "живые" сущности кроме игрока, EntityLivingBase - с игроком.
 
2,955
12
Ибо EntityLiving - всякие там AI, навигаторы и так далее. У игрока нет AI, очевидно.
 
329
13
GloomyFolken написал(а):
Туториал хорош, если не обращать внимания на элементарность :D
Это на туториал не тянет. :)

Dragon2488 написал(а):
Ну во-первых, игрок - не EntityLiving, Он экстендит EntityLivingBase.
Точно, блин. Спасибо. Пуля по отношению к игрокам была пацифистом. Исправил.

Agravaine написал(а):
Если ставить par3Velocity большое число, то пуля на клиенте летит фиг знает куда, хотя на сервере домажит энтити правильно.
Попробовал с параметром 4.0F и 5.0F. Не заметил. Если такое наблюдается - есть мысли почему и как исправить?
 
1,990
18
105
Урась, код без костылей.
Перенёс.
[merge_posts_bbcode]Добавлено: 20.06.2015 20:42:03[/merge_posts_bbcode]

Есть одна мысль. Пуля после апдейта сразу попадает в цель, в итоге за один апдейт она успевает сбить сущность и НЕ ПОСЫЛАЕТ свою позицию на клиенты, клиенты же делают интерполяцию, а т.к. интерполяцию делать не к чему, то она, возможно, делается к точке 0, 0, 0.
 
329
13
Oldestkon написал(а):
Урась, код без костылей.
Перенёс.
[merge_posts_bbcode]Добавлено: 20.06.2015 20:42:03[/merge_posts_bbcode]

Есть одна мысль. Пуля после апдейта сразу попадает в цель, в итоге за один апдейт она успевает сбить сущность и НЕ ПОСЫЛАЕТ свою позицию на клиенты, клиенты же делают интерполяцию, а т.к. интерполяцию делать не к чему, то она, возможно, делается к точке 0, 0, 0.

  1. Убрал else в коде пули, она же в любом случае исчезает. :)
  2. Про интерполяцию не понял. К чему ты клонишь?
 
1,990
18
105
Пуля на клиентах получает позицию с сервера. Но не получать же её каждый тик? Пару раз в секунду - норм. Но если так обновлять пулю, будет очень некрасиво выглядеть всё. Поэтому делают интерполяцию между настоящей позицией и предыдущей.
Так вот, пуля после спавна посылает свою позицию, а следующую не успевает, т.к. за один (или несколько, до отправки позиции) апдейтов уже врезалась в другую сущность и умерла (setDead), в итоге клиент берет интерполированную позицию между двумя точками, но одна из них не является истинной и может быть либо предыдущей позицией, либо вообще левой точкой уровня {0, 0, 0} и пуля улетает в егеря.

Ну да это всё предположения, проблема может быть и в другом.
 
329
13
Oldestkon написал(а):
Пуля на клиентах получает позицию с сервера. Но не получать же её каждый тик? Пару раз в секунду - норм. Но если так обновлять пулю, будет очень некрасиво выглядеть всё. Поэтому делают интерполяцию между настоящей позицией и предыдущей.
Так вот, пуля после спавна посылает свою позицию, а следующую не успевает, т.к. за один (или несколько, до отправки позиции) апдейтов уже врезалась в другую сущность и умерла (setDead), в итоге клиент берет интерполированную позицию между двумя точками, но одна из них не является истинной и может быть либо предыдущей позицией, либо вообще левой точкой уровня {0, 0, 0} и пуля улетает в егеря.

Ну да это всё предположения, проблема может быть и в другом.
Вот что по этому поводу накопал. Кусок из Entity.class :
Код:
    public void setPositionAndRotation(double x, double y, double z, float yaw, float pitch)
    {
        this.prevPosX = this.posX = x;
        this.prevPosY = this.posY = y;
        this.prevPosZ = this.posZ = z;
        // И так далее...
    }
Как видно, этот метод присваивает одинаковые значения текущей и предыдущей позиции. Возможно в том случае (или в том версии Minecraft) который был описан выше, он не использовался. Я только что поставил скорость пули 8.0F и пострелял по слизням: в 1.8 либо починили, либо неправильно тестирую.
 

necauqua

когда-то был anti344
Администратор
1,216
27
172
Ну если бы интерполяция привязывалась к той самой точке, а не к нулям, то пуля и не улетала-бы, всё было-бы куда проще.
 

tox1cozZ

aka Agravaine
8,456
598
2,892
Ну просто когда стреляешь, то даже когда спавнишь частици на позиции пули, то они летят фиг знает куда, как и модель пули на клиенте. Хотя физически, на сервере, она попадает туда, куда ты целился.
 

svk

1,185
2
При автоматическом огне, они пересекаются сами с собой и уничтожаются.
[merge_posts_bbcode]Добавлено: 20.06.2015 22:59:47[/merge_posts_bbcode]

И ещё - ничего, что сначала наносится урон, а потом сбрасывается счётчик, может стоит сделать наоборот?
 
329
13
svk написал(а):
При автоматическом огне, они пересекаются сами с собой и уничтожаются.
[merge_posts_bbcode]Добавлено: 20.06.2015 22:59:47[/merge_posts_bbcode]

И ещё - ничего, что сначала наносится урон, а потом сбрасывается счётчик, может стоит сделать наоборот?
Допиши проверку на то, что объект, с которым взаимодействует твоя пуля - не её соседка.

Код:
if ((par1MovingObjectPosition.entityHit instanceof EntityLivingBase) && (par1MovingObjectPosition.entityHit != EntityBullet))

Как ты организовал автоматический огонь?
 

svk

1,185
2
Мне нахрена? В моей пуле такая стоит, я тебе говорю - допиши
[merge_posts_bbcode]Добавлено: 20.06.2015 23:05:21[/merge_posts_bbcode]

А что насчёт 2?
 
1,990
18
105
svk написал(а):
При автоматическом огне, они пересекаются сами с собой и уничтожаются.
this.setDead();
Обернуть в
if (!(par1MovingObjectPosition.entityHit instanceof EntityBullet))
    this.setDead();

svk написал(а):
И ещё - ничего, что сначала наносится урон, а потом сбрасывается счётчик, может стоит сделать наоборот?
Ничего. Абсолютно непринципиально. Считай что одна ветка в выполнении кода - момент. В данном случае, по крайней мере.
 

svk

1,185
2
Почему? Если проверка стоит в самом методе нанесения урона? Разве это не выполнится первым?
 
Сверху