Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   организация кода в игре (http://www.flasher.ru/forum/showthread.php?t=208013)

Dmitriy154 27.05.2014 21:58

организация кода в игре
 
Подскажите, пожалуйста, каким образом лучше организовать код в игре.
Допустим игра танки. Одним танком управляет игрок, другими компьютер.
В игре 3 вида танков.
Я сделал общий класс Tank, куда включил такие свойства как скорость, прочность и т.д. Затем, расширил этот класс тремя другими, представляющими разные виды танков, в которых различные свойства скорости и прочности.
Но у меня возникли вопросы:
1. У трех танков есть метод movie(), который должен управляться игроком или компьютером, в зависмости от того, какой танк выберет пользователь. ТАК каким образом дать знать программе, что этот танк должен управляться игроком?
использовать флажок или дополнительные классы?
2. Для управления танком игроком необходимо зарегистрировать слушатели клавиш клавиатуры и слушатель Enter_FRAME. У меня вопрос, где лучше регистрировать слушатели в конструкторе классов танков либо в главном классе main?
Подскажите, хоть примерно, так как опыта еще не имею.

in4core 27.05.2014 23:05

1. Флажок ясное дело, сами подумайте причем тут доп сущность. Из за одного параметра ее не создают. Если бы у вас был конфиг или какой то контроллер где все обрабатывалось и проверялось, тогда да. А так - флажок в моделе танка. ( надеюсь модели то у вас есть ?! )
2. В main - вообще кода быть не должно кроме controller.init() или как кому нравится. Регистрировать интер-фрейм лучше во вьюшках танка, вполне, клавиатуру тоже можно, хотя я бы этим занялся в контроллере, где происходила бы обработка нажатий и дальнейший посыл куда надо.

caseyryan 28.05.2014 07:38

Цитата:

В main - вообще кода быть не должно кроме controller.init() или как кому нравится.
Для того, чтобы понять как все работает, и более менее разобраться в коде, то можно для начала и в Main писать всю логику, ничего страшного в этом не вижу. Все эти вьюшки и контроллеры новичку ни к чему. Со временем все это придет.
Цитата:

Регистрировать энтер-фрейм лучше во вьюшках танка, вполне, клавиатуру тоже можно, хотя я бы этим занялся в контроллере, где происходила бы обработка нажатий и дальнейший посыл куда надо.
У меня для этого вообще отдельный класс используется, в котором есть статический метод isDown(keyCode:uint):Boolean
и для ENTER_FRAME тоже отдельный класс. Но все это в данном случае можно и в Main добавить, чтобы лишний раз себе голову не засорять.

Цитата:

ТАК каким образом дать знать программе, что этот танк должен управляться игроком?
Заводим переменную
Код AS3:

private var _playerTank:Tank = null;

И при выборе танка, допустим он выбирается щелчком мыши, записываем ссылку на него в эту переменную
Код AS3:

private function onClick(e:MouseEvent):void {
  if (e.target is Tank) { // допустим у танка есть метод isPlayer():Boolean который показывает, может ли игрок воспользоваться этим танком
        var targetTank:Tank = e.target as Tank;
        if (targetTank.isPlayer()) {
            _playerTank = targetTank;
        }
  }
}

Ну а дальше, в обработчике ENTER_FRAME проверяем (предположим, используются флаги upPresed, downPressed и т.д., для определения нажатия клавиш)
Код AS3:

private function onEnterFrame(e:Event):void {
  if (upPressed) {
        if (_playerTank) { // проверяем не null ли ссылка
            _playerTank.movie(); // movie - это не правильное название метода, так как movie переводится как фильм. Правильнее было бы назвать метод move()
        }
  }
}


Dmitriy154 28.05.2014 10:15

Спасибо вам!
Если можно в двух словах объясните про контроллеры и вьюшки, или ссылку дайте.
Вопрос - если исспользовать отдельный класс для событий Enter_FRAME, то какой класс он должен рассширять? Может EventDispatcher. И в блоке кода этого класса, как я понимаю, должны вызываться методы move() и другие, или генерироваться событие Event?
Прошу заранее прощение, если глупость написал.

LifeIsRhythm 28.05.2014 12:03

Цитата:

Вопрос - если исспользовать отдельный класс для событий Enter_FRAME, то какой класс он должен рассширять?
Класс может и ничего не расширять, но он должен получить ссылку на stage, которую уже и нужно подписывать под EF. В этом классе должен быть метод insert ( добавить ) с параметром, тип у которого будет интерфейс обязующий, что в добавляемом классе точно будет метод move.

Добавлено через 26 минут
Код AS3:

package 
{
        public interface IEnterFrame
        {
                function move():void;
        }
}

Код AS3:

package 
{
        public class SimpleClass implements IEnterFrame
        {
                public function SimpleClass() { }
                public function move():void { }
        }
}

Код AS3:

package 
{
        import flash.display.Stage;
        import flash.events.Event;
 
        public class EnterFameClass
        {
                private var _stage:Stage;
                private var _objects:Array = [];
                private var _count:int;
 
                public function EnterFameClass(stage:Stage)
                {
                        _stage = stage;
                }
 
                public function start():void
                {
                        _stage.addEventListener(Event.ENTER_FRAME, stage_enterFrameHandler);
                }
 
                public function stop():void
                {
                        _stage.removeEventListener(Event.ENTER_FRAME, stage_enterFrameHandler);
                }
 
                public function insert(object:IEnterFrame):void
                {
                        if (_objects.indexOf(object) != -1) return;
 
                        _objects[_count++] = object;
                }
 
                public function remove(object:IEnterFrame):void
                {
                        var index:int = _objects.indexOf(object);
 
                        if (index == -1) return;
 
                        _objects.splice(index, 1);
 
                        _count--;
                }
 
                private function stage_enterFrameHandler(event:Event):void
                {
                        for (var i:int = 0; i < _count; i++)
                        {
                                _objects[i].move();
                        }
                }
        }
}


caseyryan 28.05.2014 13:28

Цитата:

IEnterFrame
Какое-то не очень название для интерфейса.
Существует негласное (ну или даже не совсем не гласное) правило, что название интерфейса должно быть прилагательным, а название класса существительным в единственном числе
Я бы назвал интерфейс IUpdatable, а в нем бы создал один метод update()

LifeIsRhythm, ваш код не рабочий
Цитата:

Код AS3:

public function insert(object:IEnterFrame):void
                {
                        if (_objects.indexOf(object) == -1) return; // никогда не добавит новый объект, так как условие будет всегда выполняться, тут == надо заменить на >
 
                        _objects[_count++] = object; // вот тут тоже не понятно, лучше push() использовать. Все равно будет ячейка создаваться
                }
 
                public function remove(object:IEnterFrame):void
                {
                        _objects.splice(_objects.indexOf(object), 1); // если объект отсутствует, в массиве, то он снесет другой, и массив сместится. Нужна проверка, а есть ли такой в массиве, перед тем, как удалять
          // да и _count тогда надо обновить, чего тут не происходит
                }


Цитата:

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

LifeIsRhythm 28.05.2014 14:18

Исправил :D

ChuwY 28.05.2014 14:24

Не обязательно иметь ссылку на stage, чтобы слушать enterframe.
Можно создать внутри любой DisplayObject и подписаться на него.

LifeIsRhythm 28.05.2014 14:30

Цитата:

Не обязательно иметь ссылку на stage, чтобы слушать enterframe.
В контексте отдельного класса enterframe, она, как мне кажется, необходима.

caseyryan 28.05.2014 14:46

Цитата:

В контексте отдельного класса enterframe, она, как мне кажется, необходима.
Совсем нет. Любой DO может слушать событие ENTER_FRAME
Цитата:

Сообщение от LifeIsRhythm (Сообщение 1166794)
Исправил :D

Этот код все равно будет кишеть ошибками, как говорят американцы the code is error prone.
Переменная _count там вообще нафиг не нужна. Наверняка попадется тот случай, когда она каким-то чудом не будет равна длине массива.
Вместо нее лучше использовать _object.length; (хотя здесь вообще не надо знать длину массива нигде)
А цикл с этого
Код AS3:

for (var i:int = 0; i < _count; i++) 
                        {
                                _objects[i].move();
                        }

заменить на этот
Код AS3:

for (var i:String in _objects) {
    _objects[i].move();
}


LifeIsRhythm 28.05.2014 14:53

Цитата:

Совсем нет. Любой DO может слушать событие ENTER_FRAME
Да, я это знаю и остается только добавить, что он должен быть добавлен в дисплей лист..

ZackMercury 28.05.2014 15:00

Если вы делаете игру без MVC, то слушать ENTER_FRAME должен класс игры(который содержит игровую область).
Вешается обычно слушатель как и все другие действия - при init().
Он вызывает у всех своих внутренних элементов, которые движутся метод update(), в котором изменяется анимация и позиция персонажа.

caseyryan 28.05.2014 15:11

Цитата:

Сообщение от LifeIsRhythm (Сообщение 1166805)
Да, я это знаю и остается только добавить, что он должен быть добавлен в дисплей лист..

Нет.
Код AS3:

package  {
 
        import flash.display.Sprite;
        import flash.events.Event;
 
        public class TestClass extends Sprite {
 
                public function TestClass() {
                        var s:Sprite = new Sprite();
                        s.addEventListener(Event.ENTER_FRAME, onEnterFrame)
                }
 
                private function onEnterFrame(e:Event):void {
                        trace("enter frame"); // трейс срабатывает
                }
 
        }
}


LifeIsRhythm 28.05.2014 15:30

Сорри! Прежде чем ответить, я тоже сделал тест, но по какой-то мистической причине событие не вызывалось.

Нашел причину -
Код AS3:

package 
{
        import flash.display.Sprite;
        import flash.events.Event;
        public class Juggler extends Sprite
        {
 
                public function Juggler()
                {
                        super.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
                }
 
                private function enterFrameHandler(event:Event):void
                {
                        trace(event.type);
                }
        }
}

Код AS3:

package
{
        import flash.display.Sprite;
        import flash.events.Event;
 
        public class TestClass extends Sprite
        {
                public function TestClass()
                {
                        //var juggler:Juggler =  new Juggler();// так диспатчит
                        // но в спешки я сделал так -
                        new Juggler()
                        // неужели GC так быстро срабатывает?
                        // И какая разница между первым вариантом и вторым ???
                        //ведь в обоих случаях объект локальный...
                }
 
        }
}


FlasherEgor 28.05.2014 16:57

Мистика в том, что вы не добавили Juggler в список отображения методом addChild().
Если я не ошибаюсь...

А нет, ошибаюсь:
Цитата:

отправляется непосредственно целевому элементу независимо от того, находится он в списке отображения или нет.

Rzer 28.05.2014 17:56

А вдруг твой танк завтра будет из сети управляться? Или игрок из танка пересядет в подводную лодку. Всё как в жизни: Танк - он и в Африке танк, класс один. А какой водитель им управляет это уже другое дело. Получается три класса: Tank - с методами управления, AIDriver, PlayerDriver (который слушает клавиатуру и рулит танком, вызывая у него функции turnLeft(), gear(), break(), shoot()). А дальше вызывать player.setVehicle(tank). Причём игрока в академии научили рулить всеми устройствами которые могут ездить взад вперёд и поворачивать, поэтому у танка должен быть интерфейс IVehicle и Классы водителей работают именно с IVehicle, а не с конкретным танком.

ZackMercury 28.05.2014 18:59

Подпишусь под словами Rzer, всё правильно сказал.
И ещё добавлю, что вместо turnLeft можно сделать функцию, которая будет медленно поворачивать дупло танка влево-вправо, через ENTER_FRAME, и вторую функцию, которая будет давать целевой угол поворота. Функция по ENTER_FRAME будет плавно поворачивать тыкву танка в нужную сторону в зависимости от целевого угла.

caseyryan 28.05.2014 21:36

Цитата:

поэтому у танка должен быть интерфейс IVehicle и Классы водителей работают именно с IVehicle, а не с конкретным танком.
Это геморрой. Сам на эти грабли наступал. Лучше сделать базовый класс общий, Vehicle extends Sprite и от него наследовать все остальное. Не нужен там интерфейс. Так как при необходимости подписать его на события или добавить в дисплей лист надо будет приводить к соответствующему типу, потому что нужных методов у IVehicle нет. Вопрос: зачем тут нужен интерфейс тогда?
Я говорю это не по наслышке. Я просто делал игру Война Икс в вк (пришлось сейчас отключить из-за нерентабильности), и там сделал именно с интерфейсами (в точности как у вас описано). Ох и натерпелся я в ней проблем из-за этого

in4core 29.05.2014 04:11

Цитата:

Я говорю это не по наслышке. Я просто делал игру Война Икс в вк (пришлось сейчас отключить из-за нерентабильности), и там сделал именно с интерфейсами (в точности как у вас описано). Ох и натерпелся я в ней проблем из-за этого
Да не нужны в ас3 интерфейсы , не партесь, это все для максимальной чистоты кода, не больше, а вот проблем типа addChild - навалом.

ZackMercury 29.05.2014 04:31

Ну, я люблю мечтать, что когда-нибудь напишу игру, построенную на интерфейсах, как идеал. Кажется, это так здорово. До сих пор ни разу их не использовал.
А насчёт приведения типов... Разве не по иерархической структуре всё это собирается?
Например, класс, реализующий методы интерфейса IPickable, называется Thing. Thing наследуется от Sprite. Яблоко наследуется от класса Thing. Неужели для добавления в DisplayList нужно приводить тип as DisplayObject? Я прост не пользовался интерфейсами никогда)
Код AS3:

addChild(new Apple());


caseyryan 29.05.2014 08:03

Цитата:

Неужели для добавления в DisplayList нужно приводить тип as DisplayObject? Я прост не пользовался интерфейсами никогда)
Естественно. Класс - это класс, а интерфейс - это интерфейс, ему пофиг какая иерархия у классов, которые его применяют.
Другое дело. что интерфейсы тоже могут друг друга расширять.
Цитата:

Да не нужны в ас3 интерфейсы , не партесь, это все для максимальной чистоты кода, не больше, а вот проблем типа addChild - навалом.
А как тебе такая ситуация: есть какой-то большой дисплей объект, который подгружается в программу только по требованию, и вкопмиливать его класс в приложение не хочется из-за существенного увеличения объема файла. Как тогда быть? И вот тут то приходят на помощь интерфейсы. Можно применить этому классу какой-то интерфейс, и вкомпилить в программу только этот интерфейс. А потом просто при загрузке перевести загруженный объект в тот же applicationDomain и проверить а применяет ли он указанный интерфейс. И уже точно будешь уверен, что у него есть набор всех нужных методов.

MikroAcse 29.05.2014 10:52

Цитата:

Да не нужны в ас3 интерфейсы
:o :o :o
Ничего себе заявления. Давай ты останешься с ними сам.
А вот есть случаи, когда без них не обойтись.

in4core 29.05.2014 14:42

Цитата:

А вот есть случаи, когда без них не обойтись.
Нет таких случаев. То есть ты не сможешь привести такой пример. Так как без интерфейсов код скомпилится так же :)

ChuwY 29.05.2014 15:05

Есть случаи, когда с ними проще и удобнее.
Пара случаев, которые вспоминаются тут же (нет времени вспоминать больше):
1. Интерфейс IClearable для объектов, которые мы берем и возвращаем из пула, да и не только.
Сами объекты могут быть, как въюшками, так и моделями и общие предки им ни к чему, а интерфейс помогает.
2. Библиотеки для поиска пути и прочего подобного.
Некоторые методы могут принимать контейнер, от которого требуются определенные методы доступа.
Иногда контейнер уже есть и проще реализовать интерфейс, дописав необходимые методы.

in4core 29.05.2014 16:39

Цитата:

Есть случаи, когда с ними проще и удобнее.
Удобнее и проще - это тоже сомнительное утверждение. Проще когда КОД простой, а не когда накручено всякой чуши , интерфейсов и Н паттернов. Лично я к этому уже пришел, вы возможно еще нет, поэтому утверждаете обратное.
Как говорил один умный человек : (не дословно) Даже самый простой проект в котором начинают использовать MVC и прочее - скорее всего перерастет из маленькой проблемы в постоянную головную боль.
*
Это я не к тому, что давай те писать все в Меин, нет, организация кода по правилам ООП должна быть обязательно, но наворачивать - смысла нет, только себе хуже.
Цитата:

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

ChuwY 29.05.2014 16:49

Я 95% времени работаю в команде и рассуждаю именно с такой точки зрения.

Цитата:

Кто мешает просто дописать методы без интерфейса ?
Проблема в том, что контейнер твой, а библиотека сторонняя и универсальная.
Она понятия не имеет о твоем классе.

caseyryan 29.05.2014 17:12

Цитата:

Сообщение от in4core (Сообщение 1166934)
Нет таких случаев. То есть ты не сможешь привести такой пример. Так как без интерфейсов код скомпилится так же :)

Сань, от части ты прав, но ты же сам понимаешь, что реально бывают случаи, когда с интерфейсами намного проще и понятнее.
Бывает так, что в конструктор передаются разные объекты, которые могут расширять совсем разные базовые классы, допустим один расширяет Sound, а другой Sprite. Расширить один они не могут (ну, если не Object).
Но у них есть общий метод, например update();, который должен дальше вызываться. И метод должен гарантировано быть. Вот тут реально использовать интерфейс лучше и удобнее, чем Object в конструкторе

in4core 29.05.2014 17:27

Цитата:

Сань, от части ты прав, но ты же сам понимаешь, что реально бывают случаи, когда с интерфейсами намного проще и понятнее.
Бывает так, что в конструктор передаются разные объекты, которые могут расширять совсем разные базовые классы, допустим один расширяет Sound, а другой Sprite. Расширить один они не могут (ну, если не Object).
Но у них есть общий метод, например update();, который должен дальше вызываться. И метод должен гарантировано быть. Вот тут реально использовать интерфейс лучше и удобнее, чем Object в конструкторе
Кость, да я и не спорю. Я просто говорю о том, что не стоит зарываться в это с головой и рассуждать так, что ИФейс это жизнь. Твой пример самый частый, когда нужны Ифейсы, но и самый редкий в жизни. То есть случаи есть - где это удобнее и красивее, но их настолько мало и они всплывают редко, что в общей рутине - просто исчезают из вида. Сложно сказать опять же, кому как, раньше я тоже везде их сувал по делу и не по делу, а потом почувствовал рельаное неудобство и перестал ими пользоваться вообще. В крайнем случае я вместо Object - сделаю * no type и успокоюсь :) Вообщем каждый для себя решает сам, тут не поспоришь, сколько людей, столько и мнений

ZackMercury 29.05.2014 18:02

А это уже холивар :)
В общем, пусть ТС сам попробует использовать интерфейсы и если ему не понравится - пусть также как и вы от них откажется.


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

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.