12 заметок с тегом

советы

Ubuntu + IntelliJ IDEA

Здесь я оставлю напоминалку о том, что нужно настроить, чтобы хоткеи нормально работали в ИнтеллиЖ на Убунту, и разные мелочи.

Починить Ctrl+Alt+Left / Right, Ctrl+Shift+Up / Down
Settings -> Keyboard -> Shortcuts — убрать оттуда конфликтующие сочетания клавиш.

Починить Alt + ` (VCS operations popup)
Взято отсюда: http://askubuntu.com/questions/132304/how-to-disable-alt

  1. sudo apt-get install compizconfig-settings-manager
  2. CompizConfig Settings Manager -> Desktop -> Ubuntu Unity Plugin -> Switcher
  3. «Key to flip through windows in the switcher» сменить с disabled на что-то другое.

Починить Alt + Left Click (inspect object)

  1. CompizConfig Settings Manager -> Window Management -> Move Window
  2. Initiate Window Move — поставить какое-то дикое мышкосочетание, которое не сделать случайно. Disabled не отключает эту опцию, а возвращает её к «Alt + LMB» по умолчанию.

Установить Consolas
http://slicks.name/ubuntu/ubuntu-consolas-font-install.html

Меню в заголовке окна, а не на верхней панели
Settings -> Appearance -> Behavior -> Show the menus for a window -> In the window’s title bar.

Super + M чтобы сворачивать все окна

  1. /usr/share/unity/scopes/music.scope — удалить строку shortcut=m;
  2. Settings -> Keyboard -> Shortcuts -> Navigation -> Hide all normal windows

Простой веб-сервер

  1. sudo apt-get install python-twisted-core
  2. twistd -n web -p 8000 —path .
2016   советы

Как остановить setTimeout()

Вообще, использование setTimeout() не слишком желательно, потому как странно ведёт себя с памятью, но в некритичных для производительности местах — вполне можно.

А для остановки setTimeout() (т. е. когда после его вызова необходимо остановить таймер, чтобы указанный метод не выполнился по таймауту) используется метод clearTimeout() — вот так:

var timeoutId: uint = setTimeout(myMethod, 1000);
clearTimeout(timeoutId);

А чтобы пост был интереснее, вот вам фото котейки в шапочке.

2013   советы

Observer — паттерн, который изменит вашу жизнь

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

Кстати, слышал любопытное мнение: «Если у тебя есть класс, в названии которого есть слово Manager — значит, у тебя, скорее всего, проблемы с архитектурой приложения».

Вот как можно подступиться к этой проблеме:

  • сделать его синглтоном, и обращаться к нему из нужных мест в программе;
  • передавать ссылку на него каждому заинтересованному классу;
  • наоборот, передавать ему ссылку на каждый класс, в котором AchievementsManager заинтересован;
  • использовать Automated Dependency Injection;
  • использовать паттерн Observer.

Вариант с синглтоном не очень ужасен, но что, когда нам понадобиться сделать ещё несколько подобных по принципу действия механизмов? Плодить ещё синглтоны? Так себе решение. Передавать ссылки друг на друга между объектами — выглядит довольно криво, и быстро превратит код в гору мусора. Automated Dependency Injection — красиво и изящно, но несколько сложно в реализации.

И вот здесь нам приходит на помощь паттерн Observer («Наблюдатель»). Я расскажу о несколько упрощённой его вариации, немного похожей на то, как это устроено во фреймворке PureMVC и использующей стандартный EventDispatcher флэша.

(о том, как делать «по-правильному», я рекомендую прочесть в книге William Sanders, Chandima Cumaranatunge — ActionScript 3.0 Design Patterns или — если знаете украинский язык — в замечательной «Дизайн-патерни — просто, як двері» за авторством Андрея Будая)

Итак, в первую очередь создаём некий синглтон (да, увы; но только один), который будет у нас центральным эвентдиспетчером.

import flash.events.EventDispatcher;
public class CentralEventDispatcher extends EventDispatcher
{
	private static var _instance: Observable;

	public function CentralEventDispatcher() { }

	public function broadcastMessage(name: String, content: Object = null):void
	{
		dispatchEvent(new GameEvent(name, content));
	}

	static public function get instance():CentralEventDispatcher 
	{
		if (!_instance) _instance = new CentralEventDispatcher();
		return _instance;
	}
}

Затем делаем NotificationEvent. Это — обычный Event, в котором есть два поля: String name и Object body. Первое используем для того, чтобы получатели событий понимали, от кого и о чём оно; во втором (опционально) находится полезная нагрузка.

import flash.events.Event;
public class NotificationEvent extends Event 
{
	public var name: String;
	public var body: Object;

	public function NotificationEvent(name:String, body: Object = null, bubbles:Boolean=false, cancelable:Boolean=false) 
	{ 
		super(name, bubbles, cancelable);
		this.name = name;
		this.body = body;
	} 

	public override function clone():Event 
	{ 
		return new NotificationEvent(name, body, bubbles, cancelable);
	} 

	public override function toString():String 
	{ 
		return formatToString("NotificationEvent", "name", "body", "bubbles", "cancelable", "eventPhase"); 
	}
}

Эти два класса — всё, что необходимо для того, чтобы организовать Observer. Теперь разберёмся, как этим добром пользоваться.

Когда какому-то классу нужно поставить другие о чём-то в известность, мы делаем так:

public class Game 
{
	public static const NAME: String = "Game";
	public static const SOMETHING_INTERESTING_HAPPENED: String = NAME + "SomethingInterestingHappened"
	public static const ANOTHER_THING_HAPPENED: String = NAME + "AnotherThingHappened"

	public function Game() 
	{
		CentralEventDispatcher.instance.broadcastMessage(SOMETHING_INTERESTING_HAPPENED);
		CentralEventDispatcher.instance.broadcastMessage(ANOTHER_THING_HAPPENED, {payload:String("Some random stuff")});
	}
}

А в других классах, которые должны узнавать об этих событиях, просто подписываемся на них при помощи addEventListener. Только нюанс в том, что отсылает их не экземпляр класса Game, в котором событие происходит, а CentralEventDispatcher, так что именно на него нам и нужно подписаться.

public class AchievementsManager 
{
	public function AchievementsManager() 
	{
		CentralEventDispatcher.instance.addEventListener(Game.SOMETHING_INTERESTING_HAPPENED, onNotification);
		CentralEventDispatcher.instance.addEventListener(Game.ANOTHER_THING_HAPPENED, onNotification);
	}

	private function onNotification(e:NotificationEvent):void 
	{
		switch (e.name) 
		{
			case Game.SOMETHING_INTERESTING_HAPPENED:
				trace("I am AchievementsManager and I received SOMETHING_INTERESTING_HAPPENED notification");
			break;

			case Game.ANOTHER_THING_HAPPENED:
				trace("I am AchievementsManager and I received ANOTHER_THING_HAPPENED notification", {payload:String("Some random stuff")});
				trace("And here is its body contents: " + e.body['payload']);
			break;
			}
		}
}

Вот так. Таким образом, мы можем добавить сколько угодно классов, которые могут слушать любые событие, происходящие в любых концах приложения, при этом ничего не зная об объектах, эти события порождающих — они должны знать только о CentralEventDispatcher.

Очевидный недостаток этого подхода, помимо необходимости держать синглтон — это постоянная генерация Event’ов, что не обрадует GC.

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

2013   советы

Крохотная заметка о видимости параметров функций

Раньше не решался передавать методу параметр, имя которого совпадает с переменной класса — боялся конфликтов. Оказалось — совершенно зря.

public var someVar: int = 42;

public function someFunction(someVar: String = "hello"):void
{
  // для простоты предположим, что вызвали метод без параметров
  trace(someVar); // выведет "hello"
  trace(this.someVar); // выведет "42"
}

Вот так.

2013   советы

FlashDevelop — AIR Mobile App закрывается при переходе в другое окно

Короткая запись об абсолютно очевидной вещи, до которой я, однако, допёр далеко не сразу и, судя по проектам, в которые заглядывал, некоторые коллеги-программисты тоже не обращали на это внимание.

Когда мы создаем во FlashDevelop проект из шаблона AIR Mobile AS3 App, после его запуска на тест окно AIR Debug’а автоматически закрывается при переходе к любому другому окну.

Напрягает, но я почему-то всегда думал, что это какая-то особенность AIR Debug Player, и даже не обращал внимания на причину, лежащую на самом видном месте: необходимо закомментировать строку stage.addEventListener(Event.DEACTIVATE, deactivate); в классе Main, которая и отвечает как раз за автозакрытие нашего приложения при переключении на любое другое (что крайне желательно для мобильных устройств).

2013   советы

О Красной Шапочке, дипломе, jvm.ini и -Xmx128m

Здравствуйте, друзья!

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

Ну, например, я защитил на «отлично» дипломный проект, закончив-таки заочно университет и получив диплом специалиста по компьютерным системам и сетям. Познакомился лично с донельзя приятным парнем Виктором ’Komizart’ Солодиловым и, пусть и без личной встречи, но всё равно чуть ближе узнал других интересных коллег-разработчиков.

В последнее время поработал в качестве фрилансера для базирующейся в Санкт-Петербурге компании над интерактивной AIR-книгой под iPad. Получил много бесценного опыта касательно AIR для iOS, потому как специфика проекта заметно отличалась от обычной флеш-игрушки. Столкнулся с некоторыми загадочными и неприятными «чудесами» Flash CS Pro 5.5/6 и любопытными нюансами, о которых, пока не позабыл, надо будет в ближайшее время написать. Несмотря на то, что я много тупил и выдавал результат не так быстро, как хотелось бы, заказчик относился к этому с терпимостью и пониманием, со своей стороны охотно идя на компромиссы ради того, чтобы совместно сделать продукт, за который не будет стыдно.

К сожалению, приложение иногда вываливается на первом iPad, будучи убитым осью из-за того, что выжирает чересчур много памяти, но на iPad2 /3 ведёт себя прилично. В ближайшем апдейте планирую устранить первую проблему, а пока работаю с этим же заказчиком над новой сказкой. Будет здорово.

А вот над играми в последние месяца полтора не работал вообще — как-то категорически не хватает времени. Вкупе с недавней сменой фулл-тайм работы, вернувшей меня от нерегулярных 12-часовых дежурств к стандартному 8-часовому рабочему дню, снова периодически стал поздними ночами засыпать прямо за рабочим столом, уткнувшись носом в клавиатуру :-).

Ну и чтобы хоть что-то полезное было в посте — вот краткая заметка: если при компиляции Flash CS сообщает, что «The Java Virtual Machine used for ActionScript 3.0 compilation ran out of memory... Open jvm.ini in editor» — соглашайтесь. Откроется коротенький конфигурационный файл в две строчки. Необходимо отредактировать вторую, увеличив число в параметре. Причём, если вписать мало — ошибка не уйдёт, а если вписать много — то флеш вообще перестанет компилить даже самые крошечные проекты. Метод проб и гуглежа дал результат: сразу вписываем «-Xmx348m» — это максимум.

Спасибо за внимание. Мне очень приятно, что вы читаете этот блог! Оставайтесь со мной, а я постараюсь быть не слишком нудным :-).

2012   мысли   советы

Одноуровневые сложные if против вложенных if

(Заранее прошу прощения за, возможно, неправильно используемые мной термины.)

Сегодня из любопытства решил проверить, какой if работает быстрее: одноуровневый сложный, вида: «if (condition1 && condition2) {actions}» или вложенный (nested), вида: «if (condition1) {if (condition2) {actions}}».

Взял для эксперимента три простых условия — банальное сравнение чисел.

private function firstFunction():void
{
  if (5 < 10 && 11 > 4 && 12 == 12)
  {
    var a: Boolean = false;
  }
}

private function secondFunction():void
{
  if (5 < 10) {
    if (11 > 4) {
      if (12 == 12) {
        var a: Boolean = false;} } }
}

Первый опыт: все три возвращают «истину». Соответственно, мы должны каждый раз полностью пройти по каскаду. Выполняю эти функции в цикле по 80 тысяч раз. Выполнил по пять раз, сохранил время, затем нашёл среднее. Результат: 1962 против 2390 миллисекунд, т. е. при проходе по всему каскаду проверок вложенный if работает на 20% медленнее.

Другой опыт: изменил знак в первом условии с «меньше» на «больше» — чтобы первая проверка уже возвращала «ложь» и остальные две не выполнялись. Повторил запуск приложения. Результат: 1693 против 1708, т. е. при отсутствии необходимости прохода по каскаду проверок вложенный и сложный if отработали за одинаковое время.

2012   советы

Учим 32битное приложение грамотно использовать память в 64битной Windows

В работе с Flash CS5.5 я столкнулся с проблемой, связанной с обработкой больших (>130 Мб) fla с обилием векторной анимации. Периодически при попытке сохранения или при операциях вроде копирования/вставки Flash выдавал мне окно с сообщением о недостаточном объёме памяти. «Алоэ! Ты в своём уме?», — удивлённо бормотал я, глядя на 4 Гб оперативной памяти и столько же — файла подкачки. Да и диспетчер задач как бы показывал, что Flash.exe откушал всего около 1,5 Гб.

Небольшой гуглёж подсказал, что, оказывается, 32битная Windows не видит не только свыше 4 Гб ОЗУ, но и их-то не все может использовать, а только около 3,5 Гб. Не совсем поняв, как это относится к моей ситуации (флэш-то, вон, только полтора берёт, остальная память, за вычетом скушанного самой Windows да всяким фоновым софтом навроде антивируса, остаётся неиспользованной), решил, что 32битная Windows просто жалеет отдавать всю доступную память флэшу.

Погуглив ещё, узнал, что да, действительно, 32битная Windows имеет ограничение на максимальную выделяемую каждому процессу память, на которое и наткнулся флэш (справедливости ради должен отметить, что немного поднять этот предел можно вроде как добавив параметр в boot.ini).

«Ладно, может, тебе так больше понравится», — почесал репу ваш покорный слуга и переустановил ОС на Windows 7 x64. А для надежности ещё и 8 Гб ОЗУ в материнскую плату запихнул. ОС установилась, все 8 Гб увидела, все драйверы приняла, оборудование и софт отлично работают.

«Отлично», — думаю, и уже руки потираю, — «сейчас поставлю себе 64битный флэш, и буду с какими хошь файлами работать». За этим обнаружилась следующая проблема: в природе не существует 64битной версии Flash CS Pro. Photoshop — есть; Premiere Pro и After Effects, вон, вообще только 64битные; а вот флэша 64битного — нет. Т. е. флэш как бы при всём желании не сумеет использовать больше, чем те самые полтора-или-около-того-гигабайт, выделяемых 32битной ОС (а 32битные приложения на 64битной ОС работают, как известно, в режиме совместимости, не имея возможности использовать преимущества 64 бит).

Со слабой надеждой всё же попробовал выполнить во Flash CS5.5 вызывавшее ошибку действие (мало ли, мол, а вдруг произойдёт чудо!) — выделил все символы в library, сделал Copy, создал ещё один файл и, не закрывая первый, нажал Paste. Память, потребляемая Flash.exe медленно выросла примерно до 1,5 Гб, затем остановилась. Ещё через минуту вывалилось знакомое сообщение о нехватке памяти.

Бросился донимать Гугл расспросами, как же мне, мол, быть. На форуме flashgamedev.ru увидел одну тему, посвящённую вопросу использования 64битных ОС, но о моей проблеме в ней не было ни слова. Просто упоминалось, что Flash работает одинаково на 32 и на 64 системе. «Ага, я уже заметил», — с лёгкой досадой пробурчал себе под нос.

А потом наткнулся на решение своей проблемы! Нашлась утилита с незамысловатым названием «4Gb patch», которая каким-то образом патчит 32битный exe’шник, заставляя его работать с памятью вплоть до 4 Гб. В описании утилиты значится: «In order to achieve this, a flag has to be set in the file’s internal format. This is, of course, very easy for insiders who do it every day with the CFF Explorer. This tool was written because not everybody is an insider, and most probably a lot of people don’t even know that this can be achieved.». С некоторым сомнением, предварительно тщательно обнюхав утилиту со всех сторон антивирусом и спросив гугл, доверяет ли он автору, запустил её. Сделав бэкап, указал на C:\Program Files (x86)\Adobe\Adobe Flash CS5.5\Flash.exe. Бодро сделав своё дело менее, чем за секунду, софтина отчиталась, что всё замечательно, можно проверять.

Результат действительно порадовал. Теперь при копипасте всего содержимого библиотеки в новый проект Flash.exe скушал около 2,1 Гб памяти, и успешно завершил действие. Затем, как в старом анекдоте про сибирских мужиков и немецкую бензопилу, я попробовал повторить операцию, создав ещё один файл. Flash взял 3,5 Гб памяти и тоже справился с задачей. Правда, когда я, вконец обнаглев, попытался сделать это в третий раз, приложение вывалилось с ошибкой. Ну да и ладно, я Crysis на флэше делать не собираюсь, мне 3,5 Гб хватит с головой.

Прилагаю скриншоты диспетчера задач на пике потребления памяти во время копирования-вставки. Flash.exe — это пропатченный экзешник, Flash_32.exe — это его бекапная копия до применения патча.

До:

После:

Спасибо за внимание!

UPD: Нашёл в каком-то FAQ по памяти.

Помните, что максимальное количество оперативной памяти, которое 32-битная версия Windows может выделить приложению составляет 2Гб по умолчанию и 2,7Гб, если ОС запущена с ключами /PAE и /3GB в boot.ini, а приложение откомпилировано с поддержкой такой возможности. Поэтому использование более 3Гб оперативной памяти совместно с 32-битными «десктопными» (не серверными!) ОС в подавляющем большинстве случаев совершенно не оправдано.

2011   советы

Проверка Flash-приложением наличия звуковой карты

Сегодня, работая над проектом не за своей обычной машиной, а за подвернувшимся под руку Windows-сервером, я случайно узнал о любопытном но, к счастью, документированном нюансе класса Sound. Если в системе отсутствует звуковая карта, то после попытки воспроизведения звука метод play() возвращает null, что может стать причиной ошибки, генерируемой отлично работавшим на других машинах кодом.

Приведу пример:

var music: Sound = new GameMusic;
var musicSoundChannel: SoundChannel = new SoundChannel();
musicSoundChannel = music.play(); // строка выполняется, но после неё musicSoundChannel == null
musicSoundChannel.stop(); // и вот здесь будет null pointer error

Указанный выше код отлично работает на машине со звуковой картой, но на системе без неё поведёт себя как отмечено в комментариях.

Чтобы избежать подобной ситуации, я предлагаю добавлять при запуске приложения небольшую проверку:

var testSound: Sound = new BlankTestSound; // какой-нибудь тестовый звук
var musicSoundChannel: SoundChannel = new SoundChannel();
musicSoundChannel = testSound.play(); // делаем тестовый запуск звука
if (menuMusicSoundChannel)
{
  trace("Звук есть!");
  musicSoundChannel.stop(); // всё, проверку мы прошли, тестовый звук можно тормозить
}
else
{
  trace("Грусьть и пичяль, звука нет"); // звука нет, потому больше в игре аудио воспроизводить не пытаемся
}

Я согласен, что сейчас практически не встретишь устройство без хоть какого-нибудь звука, однако, думаю, включить этот нюанс в чек-лист не помешает.

2011   советы

О доминантной стратегии и цветах для жены

Мне очень нравится данное в книге «Andrew Rollings and Ernest Adams on Game Design» описание и пример доминантной стратегии. Ниже — сокращенный перевод:

Доминантная стратегия — это стратегия, превосходящая остальные и являющаяся лучшей при любых обстоятельствах. Это не означает, что она гарантирует победу, но по крайней мере она должна гарантировать отсутствие проигрыша (если быть точным, то победу гарантирует сильная доминантная стратегия, а слабая доминантная стратегия — отсутствие проигрыша).

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

Давайте поищем пример использования доминантной стратегии в реальной жизни.

Вы возвращаетесь домой после рабочего дня и внезапно задаётесь вопросом: а разве не сегодня день рождения вашей жены? Купить ли цветы?

Возможные риски следующие: если у вашей жены действительно день рождения сегодня, и вы покупаете цветы, то вы получаете 10 очков за то, что помните, когда у неё день рождения — что хорошо, но, в общем-то, от вас и ожидалось. Если вы ошиблись, день рождения у неё не сегодня, но цветы вы купили, то за приятный сюрприз и вашу заботу даётся 20 очков.

Также вы можете предположить, что день рождения у вашей жены не сегодня, и не купить цветы. Если вы ошиблись, и у неё всё же день рождения сегодня, то вы лишаетесь 100 очков. Если же вы не купили цветы, и её день рождения не сегодня, то всё нормально — вы не получаете, но и не лишаетесь очков.

Получаем следующую табличку:

День рождения сегодня День рождения не сегодня
Купить цветы 10 20
Не покупать цветы -100 0

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

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

Таким образом, для того, чтобы ставить игрока перед нормальным выбором, из нашей игры необходимо убрать эту доминантную стратегию, добавив цветам определённую стоимость. Таким образом, их покупка в день, не являющийся днём рождения жены, будет иметь негативную отдачу. Дополнительно, нам будет необходимо определить некоторый курс обмена между деньгами и получаемыми у жены очками.

2011   советы
Ctrl + ↓ Ранее