Страницы

Поиск по вопросам

Показаны сообщения с ярлыком разработка-игр. Показать все сообщения
Показаны сообщения с ярлыком разработка-игр. Показать все сообщения

среда, 15 апреля 2020 г.

Игра нарды на Java

#java #алгоритм #разработка_игр

                    
Здравствуйте! Подскажите, можно ли написать игру нарды в настольном приложение! Подскажите,
как в java создать доску, фишки и камни для игры?
Опишите, пожалуйста, алгоритм игры нарды или дайте ссылку по разработке игры нарды?    


Ответы

Ответ 1



Учи java Swing, тебе этого будет достаточно, что бы сделать интерфейс, правила игры, смотри в другом месте, если делать игру - не примитивной, камни, фишки и тд, надо будет нарисовать или стырить =)

понедельник, 13 апреля 2020 г.

Готовые наборы тайлсетов для игр

#c_sharp #xna #графика #разработка_игр #2d

                    
Доброго времени суток, Хэшкод.

В свободное от работы время начал потихоньку изучать xna. Подготовил двумерный изометрический
тайловый движок, даже нашел подходящий редактор под него, однако осталась одна проблема
- нашел очень мало нормальных тайлсетов. Художник и дизайнер из меня, прямо скажу,
аховый, так что вариант "нарисовать самому" я оставляю на самый крайний случай. При
попытке найти что-то в сети в основном получаю какой-то лохматый "ужос"... В общем
- не нашел.

Собственно у меня вопросы:


Есть ли сайты, на которых есть нормальные тайлсеты?
Есть ли нормальные редакторы для создания тайсетов? (можно конечно и в Paint-е(Gimp-е/Photoshop-е)
что-то наваять, но с моими навыками "рисования"... в общем, хотелось бы что-то более
специализированное)


Пример тайлсета, если кто не знает, что это такое:


[upd] Да, вопрос получился конечно не по программированию, но извиняюсь. Больше мне
спрашивать негде.
    


Ответы

Ответ 1



Вы когда нибудь пробовали собрать toolbar для оконного приложения с помощью сайта который представляет бесплатные иконки от разных людей? Ваш toolbar получится не ахти, так как все иконки будут нарисованы разными людьми в разном стиле и цветовой гамме. Даже если вы будете долго копаться на нескольких таких сайтах в поисках единого стиля, то наврятли получится что-то стоящее, т.к. совершенно не факт что вы найдете даже готовый набор полностью удовлетворяющий вашим нуждам. Тоже самое и с тайлсетом. Их все должен рисовать один человек в одном стиле по одному документу, на gamedev.ru и фриланс сайтах есть десятки людей которые с радостью возьмутся выполнить такой заказ по вполне адекватной цене(реальная рыночная цена тому что вы приводите в качестве примера не больше 100-300 рублей за полоску), да и качество будет вполне ничего, если вы конечно потрудитесь отобрать достойного кандидата. В качестве редактора можно использовать Photoshop и 3DSMax ну или Blender и GIMP если вы красноглазик. Специальный редактор для тайлсетов это плохая идея потому что непонятно чем собственно тайлсет отличается от обычной картинки. Самому рисовать их ни в коем случае нельзя, так как если у вас нет хотя бы пары лет опыта работы с графическими редакторами и хотя бы зачатков умений художника, то в лучшем случае у вас получится результат которым можно только пугать других людей. С другой стороны с попытки с 50ой может и получится что-нибудь хорошее, но тогда вы просто потеряете время. Правда есть и альтернативный вариант: http://lunar.lostgarden.com/labels/free%20game%20graphics.html http://hasgraphics.com/ http://cgtextures.com/ http://blogoscoped.com/archive/2006-08-08-n51.html http://www.freewebs.com/teh_pro/sprites.htm http://www.spriters-resource.com/ http://www.flyingyogi.com/fun/spritelib.html http://www.gamedev.net/topic/272386-sprites-sprites-and-more-sprites/ P.S. Собирать игры в качестве хобби это плохая идея, так как это требует очень много свободного времени и усилий. Нужно либо делать это нормально либо вообще не делать.

Ответ 2



Что касается сайтов с нормальными тайлсэтами - никогда не встречал, что касается редакторов - такие, безусловно, есть, но они никак не изменяют того факта, что нужно уметь рисовать, учитывая их более ограниченный функционал, большего смысла в них не вижу, разве что, обычно, удобно сразу рисовать сэт. Вообще, для того, что-бы научится хоть более менее нормально рисовать оные, великих навыков художника не требуется, все, чему нужно научится - базовым навыкам передачи светотени и объема. К тому-же, нет людей, которые не умеют рисовать, есть только те, которые не научились. Плюс ко всему, если рисовать не на бумаге, можно сделать, допустим, размерность 2к*2к px, при уменьшении которой, многие косяки изображения исчезнут, главное правильно передать объем и более менее правильно светотень. Даже если совсем не будет получатся - можно поискать начинающего художника и попросить нарисовать его, но, повторюсь - такое рисование не требует великих навыков, другой вопрос в том, достаточно ли у вас времени и желания?..

суббота, 11 апреля 2020 г.

Как генерировать объекты за экраном с заданным промежутком

#spritekit #xcode #разработка_игр #objective_c #ios7

                    
Приветствую всех! Делаю игру на spritekit с бесконечным уровнем (like Doodle jump)и
возникла проблема:
Не могу понять как генерировать платформы за экраном так, чтобы новые генерировались
только после того, как предыдущая платформа уехала на определенное расстояние?
Вот пример кода для генирации платформ
- (void)addPlatforms
{
    int random = arc4random() % (int)(self.frame.size.width-80)+100;

    // right end platform
    SKSpriteNode *rightEndPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"leftPlatform"];
    rightEndPlatform.size = CGSizeMake(16, 16);
    rightEndPlatform.physicsBody =
    [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(rightEndPlatform.size.width,
rightEndPlatform.size.height - 5)];
    rightEndPlatform.position = CGPointMake(random, 0);

    // left end platform
    SKSpriteNode *leftEndPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"rightPlatform"];
    leftEndPlatform.size = CGSizeMake(16, 16);
    leftEndPlatform.physicsBody =
    [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(leftEndPlatform.size.width,
leftEndPlatform.size.height - 5)];
    leftEndPlatform.position = CGPointMake(rightEndPlatform.position.x - PLATFORM_RANGE,
rightEndPlatform.position.y);

    // left platform
    SKSpriteNode *leftPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"centerPlatform"];
    leftPlatform.size = CGSizeMake(leftEndPlatform.position.x, 16);
    leftPlatform.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:leftPlatform.frame.size];
    leftPlatform.position =
    CGPointMake(leftEndPlatform.position.x - leftPlatform.size.width/2,
                leftEndPlatform.position.y);

    // right platform
    SKSpriteNode *rightPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"centerPlatform"];
    rightPlatform.size = CGSizeMake(self.frame.size.width+rightEndPlatform.position.x, 16);
    rightPlatform.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rightPlatform.frame.size];
    rightPlatform.position =
    CGPointMake(rightEndPlatform.position.x + rightPlatform.size.width/2,
                rightEndPlatform.position.y);

    // add to the scene
    [self addChild:rightEndPlatform];
    [self addChild:leftEndPlatform];
    [self addChild:leftPlatform];
    [self addChild:rightPlatform];

    // add platforms to array
    [platformArray addObject:rightEndPlatform];
    [platformArray addObject:leftEndPlatform];
    [platformArray addObject:leftPlatform];
    [platformArray addObject:rightPlatform];

    for (int i = 0; i < [platformArray count]; i++)
    {
        SKSpriteNode *sprite = [platformArray objectAtIndex:i];
        sprite.physicsBody.usesPreciseCollisionDetection = YES;
        sprite.physicsBody.dynamic = NO;
        sprite.name = [NSString stringWithFormat:@"beforePlayer"];
    }
}

Генерирую платформу, потом напротив через промежуток другую платформу и достраиваю
от краев экрана до этих платформ линии, получая стенку с проходом.
Далее двигаю созданную конструкцию
-(void)update:(CFTimeInterval)currentTime
{
    for (int i = 0; i < [platformArray count]; i++)
    {
        SKSpriteNode *platform = [platformArray objectAtIndex:i];
        platform.position = CGPointMake(platform.position.x, platform.position.y
+ PLATFORM_SPEED);
        if (platform.position.y > self.frame.size.height+100)
        {
            [platform removeFromParent];
        }
    }
}

а генерация платформ происходит по времени
timer = [NSTimer scheduledTimerWithTimeInterval:TIME_INTERVAL target:self selector:@selector(addPlatforms)
userInfo:nil repeats:YES];

Вот и вопрос, вообще правильно ли я делаю или есть лучше вариант, как генерировать
платформы не по времени а по расстоянию (первая сгенерированная платформа уехала на
100 единиц , тогда генерируем вторую, вторая уехала на 100 единиц- генерируем третью и т.д)
Спасибо за внимание!    


Ответы

Ответ 1



Сразу прошу прощения, не стал вчитываться в код, (как известно, разбирать чужой код это, как лезть кому-то в душу) ). Наиболее изящный, по моему скромному мнению, выход из этой ситуации таков: 1) Остановите движение платформ, временно закомментировав соответствующую часть кода в update 2) На неподвижном экране создайте максимально возможное число платформ (на нужном Вам расстоянии друг от друга). Это легко сделать, с помощью цикла for. 3) Сдвиньте точку генерации первой из платформ на нужное расстояние за экраном. 4) Далее, в методе update начинайте двигать платформы (кстати, доступ к платформе можно получить, присвоив ей имя (если не знаете как, я напишу)) и, при этом, как только платформа пройдет нужное расстояние (то, что между каждой из платформ) за экран, Вам необходимо переместить ее в начальную точку (в ту, в которой происходила генерация первой платформы). При выполнении данного алгоритма у Вас получится непрерывный "поток" платформ, причем без наложений и дополнительной генирации (то макимальное число платформ вы просто перемещаете "по кругу") Надеюсь, у меня получилось донести до Вас мысль об общем построении таких конструкций. Если нужно что-то описать подробней, пишите, не стесняйтесь.

воскресенье, 29 марта 2020 г.

Игра змейка, проблема реализации

#python #python_3x #разработка_игр


Начал писать консольную змейку, сталкивался с многими проблемами, но данную проблему
не могу пока что решить. Проблема в том, что как только игра начинается всё в порядке,
края правильно рисуются, но стоит взять фрукт так сразу происходит какая-то ахинея
и правая сторона уходит на несколько клеточек вправо.

import threading
import random
import os
from pynput import keyboard
from time import sleep


def draw():
    global score
    global fruitX
    global fruitY
    global snake

    os.system("clear")

    # top
    for i in range(0, width + 1):
        print("#", end='')
    print()

    # all mid
    for i in range(0, height):
        for j in range(0, width):
            if (j == 0) or (j == width - 1):
                print("#", end='')
            for k in snake:
                if (i == k[1]) and (j == k[0]):
                    print("G", end='')
                elif (i == fruit[0][1]) and (j == fruit[0][0]):
                    print('*', end='')
                else:
                    print(' ', end='')
        print()

    # bot
    for i in range(0, width + 1):
        print("#", end='')
    print()

    print(f"Total score: {score}")


def input():
    with keyboard.Listener(on_release=on_release) as listener:
        listener.join()


def on_release(key):
    global gameOver
    global snake

    ka = 0

    if key == keyboard.Key.esc:
        gameOver = True

    if key == keyboard.KeyCode.from_char('w'):
        for k in snake:
            snake[ka][1] -= 1
        ka += 1

    if key == keyboard.KeyCode.from_char('s'):
        for k in snake:
            snake[ka][1] += 1
        ka += 1

    if key == keyboard.KeyCode.from_char('d'):
        for k in snake:
            snake[ka][0] += 1
        ka += 1

    if key == keyboard.KeyCode.from_char('a'):
        for k in snake:
            snake[ka][0] -= 1
        ka += 1


def logic():
    global score
    global fruit
    global snake

    # Got a fruit
    if (snake[0][0] == fruit[0][0]) and (snake[0][1] == fruit[0][1]):
        score += 1
        snake.append([snake[0][0] - 1, snake[0][1]])
        fruit.pop()

    if len(fruit) == 0:
        fruit.append((random.randint(1, width - 1),
                      random.randint(1, height - 1)))


if __name__ == "__main__":
    gameOver = False
    width = 20
    height = 20

    snake = [[width / 2 - 1,
              height / 2 - 1]]

    fruit = [(random.randint(1, width - 1),
              random.randint(1, height - 1))]
    score = 0

    t_input = threading.Thread(target=input, name='InputThread')
    t_input.start()

    # Main game
    while not gameOver:
        sleep(0.1)
        draw()
        logic()


Можете не кидать готовый код, можно просто объяснить что не так. Если всё уж так
плохо, то подскажите что переучить заново, или попрактиковаться снова. Учился по книге
Билл Любанович "Простой Python"

    


Ответы

Ответ 1



но стоит взять фрукт так сразу происходит какая-то ахинея и правая сторона уходит на несколько клеточек вправо Смотрите, у вас когда рисуется змейка заодно рисуются фрукт и пустое пространство, что странно -- это ведь разные объекты. ... for k in snake: if (i == k[1]) and (j == k[0]): print("G", end='') elif (i == fruit[0][1]) and (j == fruit[0][0]): print('*', end='') else: print(' ', end='') ... Поэтому, когда змейка берет фрукт, у змеи становится два блока и тот цикл два раза прогоняется и получается в два раза больше пространства Решил другим подходом рисовать поле -- сначала составить матрицу, заполнить ее, а после отрисовать: import threading import random import os from pynput import keyboard from time import sleep def clear(): if os.name == 'posix': os.system('clear') else: os.system('cls') def draw(): global score global snake board = [] for _ in range(width): board.append([' ' for _ in range(height)]) # Top for i in range(width): board[0][i] = "#" # Left for i in range(height): board[i][0] = "#" # Right for i in range(height): board[i][width - 1] = "#" # All mid for i, j in snake: board[j][i] = 'G' for i, j in fruit: board[j][i] = '*' # Bottom for i in range(width): board[height - 1][i] = "#" clear() print() for row in board: print(''.join(row)) print(f"Total score: {score}") def keyboard_listener(): with keyboard.Listener(on_release=on_release) as listener: listener.join() def on_release(key): global gameOver global snake ka = 0 if key == keyboard.Key.esc: gameOver = True if key == keyboard.KeyCode.from_char('w') or key == keyboard.Key.up: for k in snake: snake[ka][1] -= 1 ka += 1 if key == keyboard.KeyCode.from_char('s') or key == keyboard.Key.down: for k in snake: snake[ka][1] += 1 ka += 1 if key == keyboard.KeyCode.from_char('d') or key == keyboard.Key.right: for k in snake: snake[ka][0] += 1 ka += 1 if key == keyboard.KeyCode.from_char('a') or key == keyboard.Key.left: for k in snake: snake[ka][0] -= 1 ka += 1 def logic(): global score global fruit global snake print(f'snake={snake} fruit={fruit}') # Got a fruit if snake[0][0] == fruit[0][0] and snake[0][1] == fruit[0][1]: score += 1 snake.append([snake[0][0] - 1, snake[0][1]]) fruit.pop() if not fruit: fruit.append((random.randint(1, width - 1), random.randint(1, height - 1))) if __name__ == "__main__": gameOver = False width = 20 height = 20 snake = [[width // 2 - 1, height // 2 - 1]] fruit = [(random.randint(1, width - 1), random.randint(1, height - 1))] score = 0 t_input = threading.Thread(target=keyboard_listener, name='InputThread') t_input.start() # Main game while not gameOver: draw() logic() sleep(0.1) PS. Вам нужно будет подумать как движение змейки организовать, пока только голова движется PPS Этот код с этим может выдать странный результат snake = [[width / 2 - 1, height / 2 - 1]] / -- это деление с остатком, после него будет вещественное число. Поэтому, нужно делить через //

Где указать лицензию MIT для браузерной игры?

#разработка_игр #лицензирование


Суть лицензии в том что просто нужно вставить письмо.

В игре есть пользовательское соглашение и политика конфиденциальности. Также нажав
на правую кнопку перейти в папку source , можно посмотреть код игры, там можно указать
этот текст в текстовом файле.

А какое наказание может быть если эту лицензию не соблюсти?
    


Ответы

Ответ 1



Разместите ссылку рядом со ссылками на пользовательское соглашение, и прям так и назовите "Лицензия MIT". А какое наказание может быть если эту лицензию не соблюсти? Такое же как и за любую другую: запрет на использование и компенсация судебных издержек правообладателя. Возмещение убытка в данном случае не грозит, т.к. код и так предоставляется бесплатно.

четверг, 19 марта 2020 г.

Определение столкновений в Android

#разработка_игр #android #java


Столкнулся с проблемой, не могу отловить столкновение двух прямоугольников. Пытался
сделать это при помощи intersects(), но оно требует два прямоугольника внутри метода,
а мне нужно отловить только столкновение с одним прямоугольником. Вот что я пишу:
  Iterator i = enemy.iterator();
          while(i.hasNext()) {
              Enemy e = i.next();
              if(((Ball) ball).getRect().intersects((e.getRect())))
              {
                  i.remove();
              }
          }

Чего оно хочет не знаю, должно работать, в уроках на ютубе видел что там применяется
один объект и все было нормально... В чем трабла?
UPDATE:
Значит так. Enemy и Ball - это два класса; балл - это пуля, которая должна убивать
врага, соответственно, энеми - это враг, которого должен убивать бал. Мне нужно отловить
столкновение этих двух объектов, отлавливать пытаюсь при помощи intersects, который
требует иметь два прямоугольника, хотя в видеоуроке, который я смотрел, повествователь
туториала используется всего лишь один объект класса, второй используется для вызова
интерсекта, как в моем примере кода. Вот и вопрос, чем отличается его интерсект от моего?
Вот его урок Пишем 2D игру на java - Часть 7.
Ошибка которую мне выдает когда я начинаю компилировать 

The method intersects(Rect, Rect) in the type Rect is not applicable for the arguments
(Rect)

UPDATE 2:
Нашел я способ который решает мою проблему, возможно кому нибудь пригодится. Я почти
полностью видоизменил код, вот как он выглядит:
private void testCollision() {
        Iterator i = enemy.iterator();
        Iterator b = ball.iterator();

          while(i.hasNext() && b.hasNext()) {
              Enemy enemies = i.next();
              Ball balls = b.next();

              if (Math.abs(balls.x - enemies.x) <= (balls.width + enemies.width) / 2f
                      && Math.abs(balls.y - enemies.y) <= (balls.height + enemies.height)
/ 2f) {
                        i.remove();
                        b.remove();
              }
          }
    }

balls.x - enemies.x - центральная граница нашего объекта.
UPDATE 3:
Снова открываю тему так как у меня возникла проблема, 

"нужно вернуть итератор снова на
первый элемент, потому что он уже
загнан предыдущим проходом на
последний и hasNext() ивозвращает
false."

Это цитата одного человека который пытался мне объяснить как исправить ошибку, но
так и не смог объяснить. Может кто-то сможет мне сказать как это сделать? Код я использую
тот же. 
После прочтения этой цитаты несколько раз - у меня сломался мозг    


Ответы

Ответ 1



@dajver, Сами пишете что ошибка при компиляции : The method intersects(Rect, Rect) in the type Rect is not applicable for the arguments (Rect) Это значит, что метод Rect.intersects() хочет два аргемента (оба типа Rect). Видимо надо написать (если ищем пересечение прямоугольной пули с прямоугольным врагом): if( ((Ball)ball).getRect().intersects(e.getRect(),((Ball)ball).getRect()) ) { i.remove(); break; // это если одна пуля может уложить только одного врага }

Ответ 2



вы бы ошибку выложили, скорее всего у ball нету метода getRect. продолжая читать мысли: сделайте этот метод в Ball, возвращая прямоугольник описанного ball или вписанного. осмелюсь предположить что x, y это центр ball. А Rect это координаты верхней левой и правой нижней точек следовательно должно быть чтото типа: public Rect getRect() { new Rect(x - width/2, y - height / 2, x + width/2, y + height / 2) }

воскресенье, 15 марта 2020 г.

Транзакции в коде

#алгоритм #разработка_игр #исключения #best_practice


Есть примерно такой код:

ПриВыходеИзВарпРежима()
{
  ДобавитьКораблиВКосмос();
  УстановитьУНихДефолтныеКоординаты();
  ...
  ВключитьЩиты();
  ОбнаружитьПротивников();
}


В методе ВключитьЩиты произошла ошибка, а значит, я хочу всё откатить назад.
С базами данных всё легко, там есть транзакции. А как быть с кодом? 
Может придумали что-то? Чтобы не писать кучу обратных шагов.
    


Ответы

Ответ 1



Попробуйте написать ваш код в стиле «опасные изменения — безопасный коммит» + иммутабельность. // изменения локальные корабли' = создать корабли с дефолтными координатами и включённым щитом(); локальный космос' = космос.ДобавитьКораблиИВернутьНовыйКосмос(корабли'); ... локальные противники' = обнаружить противников в (космос'); // безопасный коммит космос = космос' противники = противники' Если какая-то часть из изменений вылетит — она затрагивает лишь локальные объекты, которые съест garbage collector или RAII. Если все объекты у вас иммутабельны, то новый локальный космос — не расходная штука: он делит большую часть своих объектов со старым космосом.

Ответ 2



Для решения такой задачи используется паттерн Memento (Хранитель). С его помощью Вы сохраняете состояние объекта перед началом операций. А в случае ошибки - записываете сохраненное состояние обратно. Осталось только отловить наличие ошибки. Беспроигрышный вариант - через возвращаемые значения. Еще можно воспользоваться исключениями. Но в данном случае они не очень к месту, так как это вовсе даже не исключительная ситуация, а вполне себе игровая логика. Они только добавят лишние тормоза. И размажут логику по коду не хуже, чем это делает goto.

Ответ 3



Не совсем понятно, что именно вы хотите откатить назад. Состояние переменных, измененных в методе, в котором произошла ошибка? Если так, то самый простой путь - это сохранить состояние всех нужных вам переменных перед вызовом метода ВключитьЩиты(). После чего, в случае ошибки, использовать вернуться к сохраненному состоянию.

Ответ 4



Я видел такую методику. Перед выполнением критичного кода, делаем копию всех переменных/объектов. Потом выполняем код. Если произошла ошибка, то просто восстанавливаем все назад. В С++ это можно сделать удобно, если написать правильные конструкторы копирования. В чистом Си я видел другой прием. Хитрая череда goto. Где то так. ПриВыходеИзВарпРежима() { if (!ДобавитьКораблиВКосмос()) { goto space; } if (!УстановитьУНихДефолтныеКоординаты()) { goto coord; } ... if (!ВключитьЩиты()) { goto guard; } if (!ОбнаружитьПротивников()) {goto anemi;} return ok; anemi: ПровестиДиагностикуВторогоУровня(); guard: ПерекалиброватьЩиты(); coord: УбратьДефолтныеКоординаты(); space: УбратьКораблиСКосмоса(); return bad; } То есть, если происходит ошибка - переходим по goto на обработчики "откатки в к нормальному состоянию". Да, я вижу, что Вы не хотите писать "обратные шаги", но иногда без них просто невозможно.

суббота, 7 марта 2020 г.

Реализация прироста ресурсов в реал-тайме в браузерной (мобильной) ММО стратегии

#разработка_игр


Как реализуют игровую механику в браузерных или мобильных ММО стратегий, на подобии
марш империй, vikings, ikariam и.т.д, а точнее как им удается осуществлять прирост
ресурсов в реал-тайме? Сервер запускается и обрабатывает каждую учетную запись прибавляя
рассчитанное количество ресурсов в цикле каждую секунду?
    


Ответы

Ответ 1



Могу предположить, что данные о приросте в секунду у каждого пользователя для каждого ресурса хранятся на их серверах. Сервера мониторят последние таймстэмпы пользователей (от последнего совершенного действия, связанного с ресурсами, например, их трата, или заход\выход из приложения). Рассчитывается все по формуле (currentTimestamp - lastTimestamp) * RPS (Resources Per Second), а затем все это записывается в БД А если пользователь находится в сессии постоянно, то этот прирост ресурсов просто "рисуется". И когда юзер начинает с ними какое-то действие (Например, купил что-то и они потратились), сервер добавляет к прошлому значению ресурсов новые (по вышеупомянутой формуле) и уже изменяет значение ресурсов (Вычитает, или добавляет) и сохраняет в БД. Соот-но lastTimestamp присваивается currentTimestamp и так до следующего действия

среда, 4 марта 2020 г.

Как создать адаптивниый дизайн в Unity3D

#c_sharp #unity3d #разработка_игр


Нужно настройти меню под 2 режима смартфона landscape и portrait, вот примерно что
должно получиться.


Подскажите как решить проблему
    


Ответы

Ответ 1



Есть официальные доки, конкретно под iOS/Android советы. Проверяйте Screen.orientation и грузите необходимые сцены/префабы в зависимости от текущего режима.

среда, 26 февраля 2020 г.

Полиморфная функция должна выполнить определенное действие в зависимости от того, объект какого подкласса в нее передали

#ооп #разработка_игр #полиморфизм


Делаю игру. Есть общий класс Creature, от него наследуются Monster и Human. Есть
класс Tile (игровая клетка), от нее наследуются DivineTrap (божественная ловушка) и
DivineWall (божественная стена). 

Опустим тот момент, что логичнее было бы вместе наследования применить композицию
(ловушку или стену сделать, как поле игровой клетки), данный пример я привел, чтобы
описать следующую проблему. 

У нас есть 4 разных поведения: 


Monster не может пройти на Tile, если он типа DivineWall, а если это DivineTrap,
то монстр, передвинувшись на него, погибает. 
Human может проходить на DivineWall и DivineTrap беспрепятственно. 


Собственно, подобрались к проблеме: если бы у нас был только один тип существа, к
примеру, Monster, мы могли бы воспользоваться полиморфизмом и позволить клетке в зависимости
от ее типа обработать ход существа. Т.е. если клетка - ловушка, она позволяет монстру
пройти на себя, а потом убивает его. Если клетка - стена, она не пропускает монстра.
Но, поскольку у нас два вида существа (Human и Monster), то клетка должна учитывать
тип существа, которое пытается зайти на эту клетку. Если же клетка позволит существу
самостоятельно обработать эту ситуацию, то получается замкнутый круг: ведь существо
должно знать тип клетки, на которую оно ступает.

Понятно, что можно прервать замкнутый круг, задействовав instanseof. Или опросить
состояние объекта. Но мне хотелось бы знать, как называется моя проблема в ООП, и каковы
методы ее решения. Потому что я не уверен, что instanceof и опрос состояния наилучшие
решения.
    


Ответы

Ответ 1



Ваша проблема кроется в нарушении, как минимум принципа единственной ответственности. Клетка не должна позволять или запрещать проходить на себя, пропускать людей и убивать монстров. Клетка, если можно так выразиться, объект-справочник. Она должна знать свои координаты на карте и то, что на ней находится (некий объект-сущность: игрок, монстр, стена, ловушка, ресурсы.. что угодно) и предоставлять эту информацию по требованию других объектов (например, при поиске кратчайшего пути опрашиваем все соседние клетки и анализируем, куда лучше пойти). Если Вы будете добавлять в "клетку" логику, это будет смешиванием ответственностей. Далее: ... логичнее было бы вместе наследования применить композицию (ловушку или стену сделать, как поле игровой клетки)... Это было бы не просто логичнее, наследование здесь семантически некорректно. Ведь если Вы моделируете рабочее место пользователя, вы же не будете монитор, клавиатуру и мышь наследовать от стола только потому, что эти объекты находятся на столе. Ведь так? С ловушкой или стеной, которая находится на клетке, похожая ситуация. Поэтому ловушка должна быть объектом на поле, но не полем. Ближе к проблеме.. не думаю, что у этой проблемы есть какое-то конкретное название и конкретное решение. Это просто проблема проектирования, и методы ее решения зависят от того, чего вы хотите добиться своей программой. Что касается варианта решения, согласен с @Кирилл Малышев по поводу паттерна посетитель. Хотя с другой стороны эту логику можно также реализовать в классах Monster и Human, сделав, например, метод die (умереть) защищенным и вызывать его в случае, когда хп становится равным 0 (в данном случае я имею ввиду эти классы базовыми для конкретных типов монстров и людей). Ловушки же в свою очередь будут только снимать хп. Классы людей могут иметь иммунитет к божественным ловушкам, а монстры - к демоническим. Реализовав такую логику, можно запросто добавить босса, например, с иммунитетом к любым ловушкам. Все зависит от того, насколько детально Вам нужно проработать проект.

Ответ 2



Хороший вопрос. Я не знаю как называется в теории данный паттерн, но я бы решал это таким образом: У нас есть три сущности: Клетка Creature Реакция В соответствии с этим и нужно строить структуру классов. 1 и 2 уже расписаны в вопросе. Остался базовый класс "Реакция" В конструктор должны быть переданы объекты 1 и 2. В зависимости от сочетания типов этих двух объектов создается нужный экземпляр потомка от базового класса Реакция. Ну и потомок реализует уже необходимое действие.

Стрельба на опережение

#python #разработка_игр


Кратко опишу проблему. Есть поле (плоскость, по которой в любых направлениях двигаются
объекты), герой (он передвигается по полю в соответствием нажатия игроком клавиш) и
бот (он должен стоять на месте и стрелять в героя). 

У героя нам известны: координаты (x, y) и скорость движения (она постоянная).

У бота нам известны: координаты (x, y) и скорость его пули.

Задача состоит в том, чтобы научить бота стрелять на опережение. То есть, я могу
заставить бота стрелять в какую-то точку (могу привести код, если нужно); но в случае,
если эта точка двигается, вероятность попасть в нее очень мала.

Для удобства приведу входные и выходные данные:

ВХОДНЫЕ ДАННЫЕ: скорость движения пули и героя, текущие координаты героя, координаты
бота.

ВЫХОДНЫЕ ДАННЫЕ: направление(от 0 до 360 градусов), в котором должна полететь пуля
бота (разумеется, начальный xy пули совпадает с xy бота); ИЛИ координаты того места,
куда должен целиться бот, чтобы попасть в героя

Мне нужна формула по входным данным (код на python).
    


Ответы

Ответ 1



Можно решать систему уравнений относительно неизвестных t и f hx0 + hvx * t = bx0 + bv * cos(f) * t hy0 + hvy * t = by0 + bv * sin(f) * t hx0 - x-координата героя hvx - x-компонент скорости героя bx0 - x-координата пушки bv - значение скорости пули t - время f - угол пушки Maple подсказывает, что можно найти t как корень квадратного уравнения (hvy^2+hvx^2-bv^2) * t^2 + (2*hvy*hy0+2*hx0*hvx-2*by0*hvy-2*hvx*bx0) * t + (hy0^2+by0^2-2*hy0*by0+bx0^2-2*hx0*bx0+hx0^2) = 0 и подставить его для нахождения угла. Подставив t в первое уравнение, найдём косинус, а из второго - синус, из их комбинации уже вычислим угол f = atan2(sin(f), cos(f)) (Если использовать, например, только косинус и взять арккосинус - то получим результат с точностью до знака)

вторник, 25 февраля 2020 г.

Хаки к играм и их создание

#разработка_игр #взлом


Возник такой вопрос, ответ на который хочется уточнить. Иногда можно встретить различные
"хаки" к играм, к примеру в warcraft 3/dota пишут различные maphack: запускаем приложение
и оно, к примеру, показывает в цифрах скорость регенерации health points, открывает
всю карту и т.п.

В Call Of Duty : Modern Warfare 3 можно запустить приложение и сделать inject dll
файла в запущенных экзэшник игры, после чего бот ходит и стреляет за тебя, в смысле
стоит лишь, чтобы враг попал в область видимости - бот сразу же точно сам стреляет
и убивает.

Почему возник вопрос... Я-то в игры играю редко, но само то, как делаются такие хаки
- стало интересно, задумался... Как это они так делают? Что ли как-то модифицируют
какие-то игровые значения или что? Reverse Engineering может быть?

Допустим, как в Modern Warfare 3 выделяет оппонента издалека красным квадратом -
как? Как программа знает об этом? И что вообще даст inject dll файла?

А как заставляет бота стрелять автоматически..

Сложно ли это и что за сферы нужно учить? (может кому-то вопрос покажется легким
или даже тупым, но я, к сожалению, не профи в этом деле, поэтому хотел бы задать такой
вот вопрос)
    


Ответы

Ответ 1



Допустим, как в Modern Warfare 3 выделяет оппонента издалека красным квадратом - как? Если очень примитивно, то на карте вы расположены с определенными координатами. Между машинами играющих идет постоянный обмен пакетами, в которых содержаться координаты всех игроков. Именно поэтому вы и видите или не видите каждого игрока в определенный промежуток времени. Но эти координаты предназначены в первую очередь для машины, которая должна знать, где "отрисовать" того или иного игрока. Хак перехватывает эти пакеты и "рассказывает" вам где кто находится, даже если он не в поле вашего зрения. А подсветить красным квадратиком - уже дело техники ))

Ответ 2



Сильно упрощенно пример отрисовки прямоугольника можно представить следующим образом. Исходный код игры: class GlobalContext { static GameDev.IGame Game = new GameDev.Game(); // ..... } Злоумышленник разрабатывает следующий код: namespace GameHack { // наследуемся от класса разработчика игры class Game : GameDev.Game { protected override DrawPlayer(PlayerInfo pi) { // рисуем все что было раньше base(pi); // получаем координаты прямоугольника, ограничивающего модель игрока Coordinates border = this.GetPlayerBorderRectangle(pi); // рисуем закрашенный прямоугольник по этим координатам this.DrawBar(border, Color.Red); } } } И при inject dll внедряет в программу этот код и выполняет дополнительно следующий: GlobalContext.Game = new GameHack.Game(); Таким образом при отрисовке изобретать велосипед не обязательно, а можно использовать уже готовую функциональность игры. Злоумышленнику достаточно лишь добавить небольшой штрих в урпавлении программой. В моем примере для создания этого штриха использовался шаблон проектирования декоратор. Кстати мультиплеер в МВ2 был реализован на .NET и за него отвечал интерфейс IWNet. "Сторонние разработчики" создали свою реализацию интерфейса IWNet и назвали ее AlterIWNet. Альтернативный мультиплеер AlterIWNet - пример высокоуровневого хака игры :). Ссылку дать не могу, т.к. на данный момент насколько я понял этот проект прекратил свое существование.

пятница, 14 февраля 2020 г.

Как создают изометрические игровые карты браузерных игр?

#php #javascript #jquery #разработка_игр


Более чем уверен, что используется PHP и jQuery/JavaScript.

Вопрос в следующем: как строится именно карта игрового мира?
Была идея создавать массив со случайными цифрами, например 1 - земля, 2 - дерево
и тд., но непонятно толком как все это разместить у клиента в браузере, да еще и сохранять
все в базе данных.

Кто-нибудь подскажет?

P.S:
Пока задавал вопрос, пришла мысль.
Можно создать массив (как я предлагал выше), а потом повернуть камеру под определенный
угол, и должна получиться графика какая-никакая. Но вот как сохранить все в БД..
    


Ответы

Ответ 1



Вам нужно начать изучение с базы, основ. Что такое серверные языки программирования и как они работают: PHP, Node, ASP.NET, JSP и др. Не сразу сами языки изучать а понять что вообще такое серверный язык и как идёт взаимодействие с клиентом-браузером. Что такое клиентский JavaScript код и как он взаимодействует с сервером, и как вообще браузер взаимодействует с сервером. Как работает отображение игровой анимации в браузере, там есть разные варианты: Canvas, WebGL, SVG, ... Понять что некоторые вещи лучше делать не самому а использовать готовые движки. Есть варианты браузерных движков. Базы данных, их взаимодействие с серверным и клиентским кодом. Математика и геометрия. Я не говорю что вы это всё не знаете, но из вашего вопроса ясно что есть большие пробелы в знаниях основ веб программирования, с них и надо начать изучение. Эту всю информацию невозможно написать в одном ответе, это долгая работа в изучении технологий. По ходу изучения придётся решать много тестовых и обучающих задач. Добавлено Карты и механика движения в играх может быть реализована по-разному. Самый просто вариант который был в первых стратегических играх это дискретная карта сетка - двумерный массив. Соответственно в одном месте может находиться только один объект карты, и это либо проходная зона, либо стенка. На проходной зоне может стоять юнит. Столкновения и движение рассчитывается очень просто. Про камеру в такой ситуации особенно говорить не стоит, так как имеет место плоский вид сверху, или немного под углом, но угол жёстко зафиксирован. Вариант уже не с дискретной картой, где объекты на карте имеют форму круг или квадрат, и могут размещаться в любой точке координат, координаты могут быть любые дробные числа. Столкновения уже рассчитываются математически. Карта в такой ситуации это набор объектов с их координатами. Возможно даже 3D. Вариант где формы объектов произвольные. Наиболее сложный расчёт столкновений и движения по карте. Конечно это не все варианты, и у каждого варианта есть много нюансов которые в рамках этого поста нету смысла описывать.

четверг, 13 февраля 2020 г.

Как удалить старые сцены из билда Unity?

#разработка_игр #unity3d


Как удалить старые сцены из билда Unity?


    


Ответы

Ответ 1



Выделите сцену которую хотите удалить, и нажмите кнопку(на клавиатуре!)delete.

воскресенье, 9 февраля 2020 г.

Рассчитать траекторию пули

#разработка_игр #алгоритм #java


Пишу игру и нужно рассчитать траекторию полета пули. Пишу для тачскрина и траектория
создается в зависимости от точки касания, позиции пальца на экране, но получается что
работает только на вторые 45 градусов из первой половины экрана, вот как выглядит. 
А мне нужно, что бы стреляло в любую точку. Помогите, пожалуйста, как рассчитать?
Вот как я сделал, что бы оно так летало:
angle = Math.atan((y - gameView.shotY) / (x - gameView.shotX)); //позиция начальная
- координата косания

x = (int)(x + xSpeed * Math.cos(mAngle));
y = (int)(y + ySpeed * Math.sin(mAngle));

Достиг того эффекта, а нужно что бы равномерно летело. Заранее спасибо!    


Ответы

Ответ 1



У меня выдавало странные результаты пока не конвертнул тип данных для x, y к double. проблема в неявном конвертировании типов в первой формуле. попробуй так: angle = Math.atan ( (double) (y - viewY) / (x - viewX) ) ; UPDATE: что, где, когда: Если я правильно понял то происходит следующее (y - viewY) и (y - viewY) int. При делении результат неявно конвертируется к типу int (здесь и отрезается дробная часть). После чего он неявно конвертируется к типу double для передачи в функцию atan. проверить можно так: System.out.println ( 5 / 3 ) ; System.out.println ( (double) 5 / 3 ) ;

Ответ 2



Помимо angle = Math.atan ( (double) (y - viewY) / (x - viewX) ) ; надо (int) заменить Math.round x = Math.round(x + xSpeed * Math.cos(mAngle)); y = Math.round(y + ySpeed * Math.sin(mAngle));

среда, 29 января 2020 г.

Защита игры от взлома

#разработка_игр #клиент_сервер #защита


Никогда не разрабатывал игры, интересует такой вопрос, допустим есть клиент игры
в котором есть персонаж "лучник" который стреляет со скоростью 1 выстрел в 1 секунду,
если с помощью программы(например hlapex) поймать пакет который отвечает за выстрел,
и отсылать его каждые 0.1 то лучник получается будет делать 10 выстрелов в 1 секунду?
То есть на сервере нужно проверять когда был последний выстрел и если следующий выстрел
слишком быстро произошел, то блокировать этот выстрел? Или я что-то не понимаю и выстрелы
не отправляются? Вообщем может кто-то объяснить?
    


Ответы

Ответ 1



Все верно. Учитывай время между запросами. Блокируй если "выстрелы" приходят при меньшем таймауте чем разрешено.

Ответ 2



Насколько я знаю, хорошей практикой считается не отправка на сервер пакета с действием как например "Выстрел", а отправка пакета "Начал стрельбу" по нажатию клавиши и "Закончил стрельбу" по отпусканию клавиши. Скорость атаки, количество выстрелов и всё остальное при этом будет считаться на сервере, пока идёт стрельба. Как минимум такой подход защитит от ситуации, описанной в вашем вопросе.

вторник, 28 января 2020 г.

Создание игр для android [закрыт]

#android #разработка_игр


        
             
                
                    
                        
                            Закрыт. Этот вопрос не по теме. Ответы на него в данный
момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы он соответствовал тематике «Stack Overflow на русском».
                        
                        Закрыт 4 года назад.
                                                                                
           
                
        
Купил планшет) И сразу же захотелось замутить игру. Как создавать и прочее хотел
бы узнать из вашего личного опыта.
Вопросы примерно следующие.

Какой нужен софт и нужен ли?
Где можно найти хороший мануал по
   движку?
Где можно скачать исходники хотя бы
   для понятия основ?
На чём тестировать?
Информация о различии версий android?
Прочие ваши рекомендации...

Спасибо)    


Ответы

Ответ 1



Из движков могу посоветовать: AndEngine, LibGDX сойдут отлично для простой 2D игры. Cocos2d-Android-1 мне не понравился. Если интересно опишу отдельно почему. То что предложили выше - платные и очень навороченные, а тут есть много нюансов. Сомневаюсь, что стоит начинать с них особенно если нет опыта в геймдеве или точного плана, то игра взлетит и как самое главное. Также, нужно учить OpenGL ES(подмножество OpenGL) и связанную с этим математику. Очень помогает для понимания. Игры тестировать лучше на устройствах с сами популярными разрешениями. Сам столкнулся с такой проблемой не так давно. На эмулятор например придется ставить эмуляцию аксселерометра или еще что-то Начать стоит с установки Eclipse + плагинов для Android от гугла и ваш друг это - developer.android.com Там есть все необходимое для изучения основ и куча примеров приложений, хотя они так же есть и в установленном вами SDK(при условии, что была поставлена соответствующая галочка). Кроме того куча примеров можно найти в гугле.

Ответ 2



http://developer.android.com/ Рекомендую.

Ответ 3



Начни отсюда отсюда И можешь еще заглянуть сюда Сам по этим урокам учился

Ответ 4



Если интересует конкретный игровой движок для очень крутых игр (а я чувствую что вы в этом профи), то рекомендую Unity3D или Unreal Engine

Как рисовать 2D пользовательский интерфейс в игре поверх 3D?

#java #opengl #разработка_игр #gui #lwjgl


Я создал 3D игру наподобие Minecraft на языке Java при помощи библиотеки LWJGL. Так
же могу передвигаться по миру, смотреть вверх, вниз, оглядываться, и так далее. А как
отобразить панель, наподобие той, которую я выделил красным цветом на прикреплённом
рисунке? 



Допустим, эти квадратики я нарисовал в Paint'е и сохранил в файле panel.png, но как
её отобразить?

Напишите примерный исходный код.
    


Ответы

Ответ 1



В коде инициализации экрана (перед главным циклом) написать следующий код: GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL11.glMatrixMode(GL11.GL_MODELVIEW); GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glLoadIdentity(); GL11.glOrtho(0, Display.getWidth(), Display.getHeight(), 0, 1, -1); GL11.glMatrixMode(GL11.GL_MODELVIEW); Texture i4 = TextureLoader.getTexture("PNG", new FileInputStream("textures" + File.separator + "myTexture.png")); А в главном цикле следующее: while (!Display.isCloseRequested()) { GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); i4.bind(); GL11.glBegin(GL11.GL_QUADS); // Координаты и разрешение текстуры GL11.glTexCoord2f(0F, 0F); GL11.glVertex2f(100F, 100F); GL11.glTexCoord2f(1F, 0F); GL11.glVertex2f(100F + (float) i4.getTextureWidth(), 100F); GL11.glTexCoord2f(1F, 1F); GL11.glVertex2f(100F + (float) i4.getTextureWidth(), 100F + (float) i4.getTextureHeight()); GL11.glTexCoord2f(0F, 1F); GL11.glVertex2f(100F, 100F + (float) i4.getTextureHeight()); GL11.glEnd(); }

Ответ 2



Создайте отдельный контейнер для спрайтов, закреплённый относительно камеры и разместите в нём спрайты пользовательского интерфейса. В качестве контейнера можно использовать поростой прямоугольник с текстурой (канвой). С текстурой (канвой) можно оперировать через PixelWriter и PixelReader, перерисовывая области на плоскости. Либо можно сделать аналог Group из JavaFX, так же закрепить его экземпляр относительно камеры и уже добавлять 3D элементы интерфейса. UPD: Посмотрите обсуждение здесь https://github.com/LWJGL/lwjgl3/issues/101 UPD2: Вот здесь вопрос уже обсуждался https://gamedev.stackexchange.com/questions/18468/making-a-hud-gui-with-opengl-lwjgl (Кратко: человек отрисовывает мир, а потом уже интерфейс поверх мира только и всего). UPD3: И ещё одна рекомендация здесь https://gamedev.stackexchange.com/a/29284 - использовать готовую библиотеку для GUI в LWJGL - Nifty (http://void256.github.io/blog/ -> https://github.com/nifty-gui/nifty-gui)

Ответ 3



В общем подход такой: Рисуем игру в объемной проекции (перспектива и т.п.) Переключаем проекцию на ортографическую Выключаем буфер глубины Рисуем интерфейс

Ответ 4



В андроиде есть FrameLayout для отображения одного контента поверх второго, думаю такая штука есть и в вашей отрасли

воскресенье, 26 января 2020 г.

Загрузка и хранение изображений в Java

#java #изображения #разработка_игр #libgdx


У меня есть определенная текстура var1.jpg, и необходимо вывеси ее на экран. Проблема
в том, что если при инициализации переменной, хранящей текстуру, указать просто var1.jpg,
то программа файл не находит, а если указать полный путь, то все норм.

Собственно, сам вопрос: как сделать так, чтобы текстура вызывалась, к примеру, из
пакета, который будет находиться внутри самой программы? То есть чтобы в итоге получилось
так: есть программа program.jar, в которой есть 2 пакета - com.start и com.image; при
работе программа загружала изображения, лежащие в com.image, а сами классы программы
находились в com.start, при этом не важно, в какой директории находится непосредственно
program.jar.
    


Ответы

Ответ 1



Точно не скажу, путь должен быть примерно таким "src\com\image\var1.jpg"

пятница, 24 января 2020 г.

Как изменить улучшить код?

#c_sharp #разработка_игр #инспекция_кода


Есть игра, много персонажей. У каждого есть свои уникальные приемы, например

Бутылка шампанского

1. метнуть пробкой сквозь противника перекручиваясь через себя
2. залить пол алкоголем, заставив противника подскользнуться упасть


или 

Варвар

1. Кинуть топор вверх, через секунду топор прилетит в голову сопернику
2. Усыпить соперника рогом шляпы в глаз


Для каждого персонажа для кастомных приемов есть свой класс, в котором есть три метода:
beforeAttack, afterAttack, UpdateAttack. Где beforeAttack и  afterAttack вызываются
лишь один раз до приема и после, а UpdateAttack обновляется 1 раз в кадр (то есть много).
Эти классы наследуются от главного, который и контролирует процесс, примерно выглядит так:

abstract class CommonCustom {

    public virtual void beforeAttack() {}
    public virtual void afterAttack() {}
    public virtual void UpdateAttack() {}

    public virtual void ApplyAll() {
        // тут некое условие, чтоб этот метод вызывался лишь раз!
        beforeAttack();

        // вызывается много раз пока идет прием
        UpdateAttack();

        // тут некое условие, чтоб этот метод вызывался лишь раз!
        afterAttack();
    }
}


Суть проблемы: т.к. у меня есть три метода и у каждого персонажа может быть несколько
приемов, то получается так, что в каждом методе я пишу switch/case, например:

class Test : CommonCustom {
    public virtual void beforeAttack() {
        switch attackType {
            case beerAttack: //do smth
                 break;
            case capAttack: //do smth
                 break;
            // и т.д.
        }
    }
    public virtual void afterAttack() {
        switch attackType {
            case beerAttack: //do smth
                 break;
            case capAttack: //do smth
                 break;
            // и т.д.
        }
    }
    public virtual void UpdateAttack() {
        switch attackType {
            case beerAttack: //do smth
                 break;
            case capAttack: //do smth
                 break;
            // и т.д.
        }
    }
}


Можно ли что-то как-то сделать, чтоб не писать в каждом методе swith, а как-то единообразить
всё это дело? Может быть как-то добавить еще классы, которые надо имплементировать
или еще что-то.
    


Ответы

Ответ 1



Я бы сделал интерфейс IAttack: public interface IAttack { public void PreAttack(); public void Attack(); public void PostAttack(); } BeerAttack и другие реализуют этот интерфейс: public class BeerAttack : IAttack { public void PreAttack() { //специфическая логика пива } public void Attack() { //специфическая логика пива } public void PostAttack() { //специфическая логика пива } } Потом вот так: class Test : CommonCustom { public virtual void beforeAttack(IAttack attack) { attack.PreAttack(); } public virtual void afterAttack(IAttack attack) { attack.PostAttack(); } public virtual void UpdateAttack(IAttack attack) { attack.Attack(); }

Ответ 2



При любом раскладе вам придется расписать эту пару сотен сценариев, в скриптах ли, классах, кейсах.. Ваша задача найти такой вариант, который будет максимально удобным, с минимумом повторений и возможностей ошибиться, с необходимой вам степенью кастомизации и масштабируемости. Напишите десять сценариев, вычлените все общее. Выберите вариант. Кейсы, и как их развитие - Полиморфизм Сделать класс действия, отнаследовать от него классы действий (по типам). Использовать классы действий согласно типам действий прописанным в данных. Удобно кодить, но неудобно настраивать. Дата-дривен Когда вы все действия пропишите в данных игры и будет один класс который будет их выполнять. Достаточно жесткая структура. Что-то среднее межды хардкодом и скриптами (см. ниже) Скриптовые языки, типа Lua. Отличные возможности по моддингу игры и масштабируемости. Не нужно перекомпилировать чтобы изменить какую-то мелочь.