Общий таймер

4,167
68
693
Здравствуйте всем )
Надеюсь, меня не побьют за такие вопросы, но я не могу прописать адекватно работающий таймер...

Ситуация следующая: есть блок, при касании которого медленно повышается здоровье.
Код следующий:
Код:
    private static int tick = 0;

    public void onEntityCollidedWithBlock(World world, int x, int y, int z, Entity entity)
    {
    if (entity instanceof EntityPlayer) {

        if (player.getHealth() < player.getMaxHealth() && player.getHealth() > 1)
        {
            tick += 1;
                
            if (tick > 900)
        {
                tick = 0; player.setHealth(player.getHealth() + 1);
        }
            }
           }
    }

Всё просто и понятно и даже работает, здоровье медленно прибавляется. Однако, если игрок стоит одновременно на нескольких таких блоках, то каждый из них прибавляет единицу к таймеру и исцеление в разы ускоряется...
Как мне этого избежать? Другая конструкция таймера? Опять, же эвенты?

И ещё, по этому же эффекту... В определённые моменты увеличение здоровья как будто бы не срабатывает и откатывается на пол сердечка назад. Из-за чего такое может происходить? Подозреваю, что тут нужна проверка на сервер.

Спасибо )
 
Если тебе не нравиться, то что два блока дают двойной эффект игроку, то я думаю лучше использовать эвент TickEvent.PlayerTickEvent и проверять, стоит-ли игрок в этом блоке (блоках).
 
Я так и подумал... А как звучит эта проверка?
Проверять координаты игрока и блока? Или есть у игрока что-то типа CollidedWithBlock?
player.isCollided что-то не пойму как работает.
[merge_posts_bbcode]Добавлено: 19.11.2015 01:41:22[/merge_posts_bbcode]

Кстати, как эвенты действуют при объявлении общих переменных?
Типа:
Код:
private static int tick = 0;


Если есть такая переменная и не один, а несколько игроков... и все стоят на подобных блоках. В этом случает таймер не будет ускоряться?
 
С модификатором static точно будет.
И почитай основы, там как раз это пояснено.
 
Возможно, тебе надо было что-то этого:
Код:
FMLCommonHandler.instance().bus().register(new Event());
Код:
public class Event {

    private int tick = 0;

    @SubscribeEvent
    public void updatePlayer(TickEvent.PlayerTickEvent event) {
        EntityPlayer player = event.player;
        if (player != null) {

            ++tick;

            if (tick > 30 * 20) {
                tick = 0;
                if (player.getHealth() < player.getMaxHealth()) {
                    AxisAlignedBB boundingBox = player.boundingBox;
                    boolean flag = false;

for (int x = (int)Math.floor(boundingBox.minX); x <= (int)Math.ceil(boundingBox.maxX); ++x)
for (int y = (int)Math.floor(boundingBox.minY); y <= (int)Math.ceil(boundingBox.maxY); ++y)
for (int z = (int)Math.floor(boundingBox.minZ); z <= (int)Math.ceil(boundingBox.maxZ); ++z)
                                if (player.worldObj.getBlock(x, y, z) == Blocks.water) {
                                    flag = true;
                                    break;
                                }

                    if (flag) {
                        player.setHealth(player.getHealth() + 1);
                        player.addChatMessage(new ChatComponentText("Health Up on 0,5."));
                    }

                }
            }

        }
    }

}
 
Ох ты ж!
Возможно и это... Как-то сложновато, правда... Как я понял, ты проверяешь коллизию с блоком вообще со всех сторон от игрока.

А реально, просто узнать координаты ног игрока? Просто блок у меня с уменьшенным баундинбоксом, то есть в нём немного утопаешь, как в песке душ. И вот если узнать именно координаты ног, то это и будут координаты блока )

Я поковыряюсь в коде, конечно. Но завтра ) Спасибо.
 
У Тимахи код тоже не совсем правильный, с точки зрения таймера.
Он, как я понял, должен быть локальным для каждого игрока, а тут чем больше игроков стоит на блоке - тем быстрее тикает таймер. Проблема как была, так и осталась.
Есть довольно простое решение, можно просто хранить хешмапу, где ключ - ник игрока, а значение - тики таймера.
Заодно подправил код проверки блока под твой случай.
Код:
public class Event {

    private HashMap<String, Integer> playerTickMap;
    private static final int TIMER_PERIOD = 30 * 20;
    
    public Event() {
        playerTickMap = new HashMap<String, Integer>();
    }

    @SubscribeEvent
    public void updatePlayer(TickEvent.PlayerTickEvent event) {
        EntityPlayer player = event.player;
        if (player != null) {
            String username = player.getCommandSenderName(); //так достаётся ник, если не ошибаюсь
            int tick = playerTickMap.get(username); //если не найдёт такой записи, вернёт 0
            tick = (tick + 1) % TIMER_PERIOD;
            playerTickMap.put(username, tick);
            
            Block block = player.worldObj.getBlock((int)player.posX, (int)player.posY, (int)player.posZ);
            if (tick == 0 && block == Blocks.water) {
                player.heal(1);
                player.addChatMessage(new ChatComponentText("Healed half a heart!"));
            }
        }
    }
}
 
Oldestkon, да, ты прав. Но тогда будет лучше сделать, только со стороны сервера или иначе будет рас-синхронизация на обоих сторонах в работе этой хешмапы.
И думаю, что на стороне клиента эта хешмапа будет лишней.
Я подобный код использовал с IExtendedEntityProperties, чтобы не просто суммировалось, но и чтобы с каким-то процентом из этой суммы не давалось на излечение (или на другие эффекты). Особенно когда куча предметов и блоков пытаются игрока излечить. Но я этот код не дописал.
 
Oldestkon, слушай, я пока не тестил, просто попробовал разобраться.
Не очень понимаю, каким образом тик будет равен нулю, если сам тик - это остаток от деления тик+1?
Я, может, не силён в математике... Но ты хочешь сказать, что через 600 таких прибавлений и делений он обнулиться?

Не бейте, я новичок.
 
kiss_5kb.1447928775.png
 
В упор не вижу ничего, что бы указывало на то, что
если верить этому сайту http://javascript.ru/arithmetic 2 % 5 будет не 2... -_-
Там всё правильно написано.
7 % 2 == 1 (раскрою действия: 7 / 2 = 3, 3*2 = 6, 7-6 == 1)
2 % 5 == 2 (раскрою действия: 2 / 5 = 0, 0*5 = 0, 2-0 == 2)
 
Назад
Сверху