regulflash http://regulflash Mon, 21 Jan 2013 19:48:46 +0000 ru-RU hourly 1 http://wordpress.org/?v=3.5 Матрица преобразований для гуманитариев http://regulflash/pages/matrica-preobrazovanij-dlya-gumanitariev/ http://regulflash/pages/matrica-preobrazovanij-dlya-gumanitariev/#comments Mon, 21 Jan 2013 19:43:46 +0000 admin http://regulflash/?p=470 Сегодня передо мной стала задача сделать интересную задачу — поворот лодки с персонажем внутри с использованием имеющейся графики. При этом при повороте персонаж должен оставаться на «том же месте» в лодке:

Да, для этого понадобится использовать матрицу преобразований. Но как её получить? Оказывается есть безумно простой метод. Первым делом нужно создать шаблонный MovieClip в Flash IDE:

1. Создаем шаблонный спрайт (можно даже простой прямоугольник — большой роли это не играет). Я дал имя этому экземпляру «map».

2. Преобразуем, подгоняя его для каждого варианта поворот лодки:

Далее, все что нам нужно — это считать матрицу преобразований этого спрайта! Вот и весь фокус:

var map:DisplayObject = _boatAsset.getChildByName("map");
var transformMatrix:Matrix = map.transform.matrix;
var transformedPoint:Point = transformMatrix.transformPoint(_targetPoint);

Вот как это в результате работает:

Ссылка на исходник:

https://github.com/Regul777/transformation_matrix

]]>
http://regulflash/pages/matrica-preobrazovanij-dlya-gumanitariev/feed/ 0
Удаление старых ненужных веток git http://regulflash/pages/udalenie-staryx-nenuzhnyx-vetok-git/ http://regulflash/pages/udalenie-staryx-nenuzhnyx-vetok-git/#comments Sat, 07 Jul 2012 14:34:09 +0000 admin http://www.regul-flash.com/?p=461

Лирическое отступление В текущем проекте у нас на почти каждую задачу приходится по отдельной git ветке и за недолгое время жизни проекта начали скапливаться ветки, которые уже давно находятся в релизе (ветка master). Я искал скрипт, который бы мог «почистить» ветки гита. Тем, более, что при удалении ветки мы знаем — есть ли в ней «несмерженные» коммиты.

Я нашел замечательный скрипт на сайте http://devblog.springest.com/a-script-to-remove-old-git-branches. Подробное описание можно найти на этой странице. Я лишь приведу свой вариант скрипта:


# This has to be run from master
echo git checkout master

# Update our list of remotes
echo git fetch
echo git remote prune origin

# Remove local fully merged branches
git branch --merged master | grep -v 'master\|hotfix$' | xargs git branch -d

# Show remote fully merged branches
echo "The following remote branches are fully merged and will be removed:"
git branch -r --merged master | sed 's/ *origin\///' | grep -v 'master\|hotfix$'

read -p "Continue (y/n)? "
if [ "$REPLY" == "y" ]
then
 # Remove remote fully merged branches
 git branch -r --merged master | sed 's/ *origin\///' \
 | grep -v 'master\|hotfix$' | xargs -i% git push origin :%
 echo "Done!"
 say "Obsolete branches are removed"
fi

Скрипт я положил в файл git-obsolete и теперь его можно смело запускать из git консоли. После запуска будут удалены старые ветки на локальном и удаленном репозитории.

]]>
http://regulflash/pages/udalenie-staryx-nenuzhnyx-vetok-git/feed/ 0
Guiber Prototype http://regulflash/pages/guiber-prototype/ http://regulflash/pages/guiber-prototype/#comments Sat, 19 Nov 2011 13:38:38 +0000 admin http://www.regul-flash.com/?p=440 Что такое Guiber? Это Graphic User Interface Builder. Точнее, это всего-лишь прототип и попытка решить одну маленькую проблему, которую я заметил уже не в одном проекте.

Как вы собираете интерфейс? Точнее, как вы подбираете координаты для элементов/картинок/кнопок/текстовых полей и т.п.? Я видел и xml-файл(или любой другой конфигурационный файл), который программист заполняет вручную и потом некий класс на основании этого располагает элементы, пробовал и создание gui в Flash IDE и потом уже «натягивание» функционала в коде, которое тоже далеко не идеально, видел и задание значений x/y вручную прямо в коде. Xml и ручное введение равным образом имеют негативную сторону — нужно каждый раз запускать и «прицеливаться» чтобы построить интерфейс. Во Flash IDE, конечно, можно делать интерфейс, но в этом подходе есть ряд мелкий недостатков. Возможно есть и четвертый и пятый метод, о котором я не знаю. Но у меня (и не у меня одного) нет никакого желания вместо того, чтобы создавать информационные решения подбирать координаты x и y для элементов интерфейса. (Я сейчас не говорю о Flex).

Этот пост написан в основном, чтобы получить фидбек и узнать, насколько подобное решение будет кому-то полезно.

Итак, что делает Guiber.

Guiber получает на вход swc-библиотеки, позволяет расположить элементы и генерирует as3/xml расположения этих элементов. Т к. это прототип, делается это все очень примитивно и урезанно.

Рассмотрим пример. Путь у нас будет библиотека с 4 элементами:


Создадим swc-файл AssetsLibrary.swc:

package {
	public class Assets {
		[Embed(source="../assets/background.png")]
		public var BackgroundAsset:Class;

		[Embed(source="../assets/blueButton.png")]
		public var BlueButtonAsset:Class;

		[Embed(source="../assets/orangeButton.png")]
		public var OrangeButtonAsset:Class;

		[Embed(source="../assets/closeButton.png")]
		public var CloseButtonAsset:Class;

	}
}

Теперь этот файл нужно положить в папку swc в папке Guiber’а. Запускаем Guiber и нажимаем Load SWC и располагаем элементы.

После этого остается только нажать Project->Generate AS3 code и мы получим сгенерированный код:

package com.guiber.assets {
	import flash.display.Sprite;
	public class UnknownAsset extends Sprite {
			public function UnknownAsset() {
				super();
				init();
			}
			
			public function init():void {
				// instance460
				var instance460:Assets_BackgroundAsset = new Assets_BackgroundAsset();
				instance460.name = "instance460";
				instance460.x = 1;
				instance460.y = 81;
				addChild(instance460);
				
				// instance491
				var instance491:Assets_BlueButtonAsset = new Assets_BlueButtonAsset();
				instance491.name = "instance491";
				instance491.x = 15;
				instance491.y = 252;
				addChild(instance491);
				
				// instance522
				var instance522:Assets_OrangeButtonAsset = new Assets_OrangeButtonAsset();
				instance522.name = "instance522";
				instance522.x = 170;
				instance522.y = 252;
				addChild(instance522);
				
				// instance553
				var instance553:Assets_CloseButtonAsset = new Assets_CloseButtonAsset();
				instance553.name = "instance553";
				instance553.x = 283;
				instance553.y = 96;
				addChild(instance553);
				
			}
	}
}

На этом действия прототипа заканчивается. Спасибо всем за внимание. Жду с нетерпением feedback!

]]>
http://regulflash/pages/guiber-prototype/feed/ 0
Создание своего Java Socket Server. Первый контакт http://regulflash/pages/java-socket-server-pervyj-kontakt/ http://regulflash/pages/java-socket-server-pervyj-kontakt/#comments Sat, 10 Sep 2011 23:54:58 +0000 admin http://www.regul-flash.com/?p=362 Итак, пришло время того самого момента, для чего мы все это затеяли — сделать соединение между клиентом и сервером.

В этой части мы создадим сервер при помощи библиотеки Netty, сделаем библиотеку на AS3 и проверим её. Чтобы понять процесс остановимся на простой реализации — клиент будет отправлять серверу сообщение, а сервер будет отправлять его обратно (это называется echo-сервер).

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

Создаем java-socket сервер.

Создание сервера на Netty — процесс очень простой. Достаточно раз понять архитектуру этой библиотеки. Подробно с работой этой библиотеки можно познакомиться на сайте проекта.

Создаем новый канал.

Первым делом создаем фабрику для создания и управления Каналами и связанными ресурсами. Она будет обрабатывать все I/O запросы и генерировать ChannelEvent, которые мы уже будем обрабатывать

private static void initServer() {
	factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
	initGeneralChannelHandler();
}

Дальше создаем и настраиваем сам канал:

private static void initGeneralChannelHandler() {
	// Configure the server.
	ServerBootstrap bootstrap = new ServerBootstrap(factory);
	generalChannelHandler = new GeneralChannelHandler();

	// Set up the pipeline factory.
	bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
		public ChannelPipeline getPipeline() {
			return Channels.pipeline(generalChannelHandler);
		}
	});

	//Socket options
	bootstrap.setOption("child.tcpNoDelay", true);
	bootstrap.setOption("child.keepAlive", true);

	// Bind and start to accept incoming connections.
	bootstrap.bind(new InetSocketAddress(properties.getInt("server.port")));
}

ServerBootstrap является вспомогательным классом для настройки сервера. Использовать его необязательно, но это удобный стандартный вариант для создания канала. Итак, мы создаем и настраиваем ChannelPipelineFactory: при каждом новом соединении будет вызываться getPipeline() — в нашем случае это наш созданный класс GeneralChannelHandler (о нем будет написано ниже). Также можно указать специфические параметры канала (bootstrap.setOption(«child.*», …)). И последним делом мы указываем порт по которому будет происходить соединение — этот параметр мы берем из файла condif.xml:

<entry key="server.port">9777</entry>

Теперь подробней об GeneralChannelHandler.

GeneralChannelHandler должен быть наследником SimpleChannelHandler. Этот класс является обработчиком практически всех событий, которые могут происходить с сокетами. В нем и происходит основная магия — это мост между логикой сервера и Netty. В нашем примере мы переопределим 2 события:

  1. Событие получения сообщения: messageReceived
    В нем мы будем отправлять в канал клиента то, что получили от него.
  2. Событие появления исключения: exceptionCaught
    Будем записывать с лог все ошибки, которые будут генерироваться сервером.

На самом деле это все делается элементарно:

public class GeneralChannelHandler extends SimpleChannelHandler {

	private static final Logger logger = Logger.getLogger(GeneralChannelHandler.class);

	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
		// Send back the received message to the remote peer.
		e.getChannel().write(e.getMessage());
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
		// Log the exception
		logger.error("Exception", e.getCause());
	}

}

Все — теперь у нас есть echo-сервер сервер. Можно подключиться по telnet и убедиться в его работе: любое передаваемое на сервер сообщение будет возвращаться обратно.

Создаем swc-библиотеку.

Для библиотеки я использовал следующую архитектуру, которая мне показалась уместной (JSS — Java Soket Server):
JSSApi — основной класс для работы с нашим java-сервером. Сейчас он просто создает экземпляр класса соединения и делегирует основную работу JSSConnection. Сейчас в этом нет никакого смысла но нейрон, отвечающий за программирование говорит, что должна быть разница между «Соединением» и «Api».

public class JSSApi extends EventDispatcher{

	private var _connection:JSSConnection;

	public function JSSApi(debug:Boolean = false) {
		_connection = new JSSConnection(this, debug);
	}

	/*---------------------------- Delegated methods ------------------------*/
	...

}

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

public class JSSConnection {

	public function JSSConnection(dispatcher:IEventDispatcher, debug:Boolean = false) {
		_dispatcher = dispatcher;
		_debug = debug;
		createSocketAndAddHandlers();
	}

	...

	public function connect(host:String, port:int):void {
		_host = host;
		_port = port;

		try {
			log("Connect to " + _host + ":" + _port);
			_socket.connect(_host, _port);
		} catch (error:SecurityError) {
			log("Security error: " + error);
			_dispatcher.dispatchEvent(new JSSEvent(JSSEvent.SECURITY_ERROR, error.toString()));
		} catch (error:Error) {
			log("Connection error: " + error);
			throw error;
		}
	}

	...

	public function sendRequest(request:String):void {
		if (_socket != null && _socket.connected) {
			request += "\n";

			try {
				_socket.writeUTFBytes(request);
				_socket.flush();
				log("Message sent: " + request.toString());
			} catch(error:Error) {
				log("Error sending data: " + error);
			}

		} else {
			if (_isConnected) {
				dispatchConnectionLost(ClientDisconnectionReason.SOCKED_CONNECTED_FAIL);
			} else {
				throw new Error("Sending request without connection");
			}
		}
	}

	...

	private function handleSocketData(event:ProgressEvent):void {
		receiveData(_socket.readUTFBytes(_socket.bytesAvailable));
	}

	private function receiveData(msg:String):void {
		log("Message received: " + msg);
		_dispatcher.dispatchEvent(new JSSEvent(JSSEvent.RECEIVE_DATA, msg));
	}


	...

}

Компилируем swc библиотеку для работы с сервером. Теперь осталось убедиться, что наш сервер работает. Для этого создадим тестовый клиент и добавить его в доверенные (добавить в FlashPlayerTrust):

public class Flash_client extends Sprite {
	private var _jss:JSSApi;

	public function Flash_client() {

		_jss = new JSSApi(true);
		_jss.addEventListener(JSSEvent.CONNECT_TO_SERVER_SOCKET, handleConnect)
		_jss.addEventListener(JSSEvent.RECEIVE_DATA, handleReceiveData)

		trace("Connecting...");
		_jss.connect("localhost", 9777);

	}

	private function handleConnect(event:JSSEvent):void {
		trace("Connected");
		var messageToServer:String = "Hello!";
		trace("Sending Data: " + messageToServer);
		_jss.sendRequest(messageToServer);

	}

	private function handleReceiveData(event:JSSEvent):void {
		var messageFromServer:String = String(event.data);
		trace("Received: " + messageFromServer);
	}
}

В результате в консоли клиента мы увидим успешно отработанный сценарий (строки с временем — это служебный trace сгенерированный классом JSSConnection):

[trace] Connecting...
[trace] 23:28:08.691 Connect to localhost:9777
[trace] 23:28:08.865 Connected: [Event type="connect" bubbles=false cancelable=false eventPhase=2]
[trace] Connected
[trace] Sending Data: Hello!
[trace] 23:28:08.869 Message sent: Hello!
[trace] 23:28:08.874 Message received: Hello!
[trace] Received: Hello!

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

Исходный код.

Полный код проекта всегда можно будет взять из репозитория на Google code. Коммит с приведенной выше версией находится тут.

]]>
http://regulflash/pages/java-socket-server-pervyj-kontakt/feed/ 0
Создание своего Java Socket Server. Создание заготовки. Код в студию! http://regulflash/pages/java-socket-server-template/ http://regulflash/pages/java-socket-server-template/#comments Fri, 02 Sep 2011 20:08:21 +0000 admin http://www.regul-flash.com/?p=340 Написание сервера работа довольно объемная, поэтому описание функций я планирую делать методом добавления новой функциональности в демо-версию сервера.

Начнем с небольшой заготовки, которая будет содержать:

  • логгер
  • считывание параметров
public class JavaServer extends BaseJavaServerLoggedClass {

	public static JavaServerProperties properties;

	public static void main(String[] args) {
		prepare();
		info("String server...");
	}

	private static void prepare() {
		try {
			loadProperties();
			initLogger();
		} catch (Exception e) {
			System.out.println(e.getMessage());
			System.exit(-1);
		}
	}

	private static void loadProperties() throws Exception {
		properties = new JavaServerProperties();
		properties.loadProperties();
	}

	private static void initLogger() {
		org.apache.log4j.PropertyConfigurator.configure(properties.getProperty("log4j.propertyFileName"));
	}
}

Тут все предельно просто:
1. в методе initLogger() мы инициализируем логгер. Сами методы логера спрятаны в классе BaseJavaServerLoggedClass, чтобы не отвлекать от основного

public class BaseJavaServerLoggedClass {

	protected static final Logger logger = Logger.getLogger(JavaServer.class);

	protected static void info(String msg) {
		if (logger != null) {
			logger.info(msg);
		}
	}

	protected static void exception(String msg, Throwable t) {
		if (logger != null) {
			String message = "\n:::::::::::::::::::::::::::::::::::::::::::::::::::\n" + msg;
			logger.error(message, t);
		}
	}
}

2. в методе loadProperties() мы загружаем настройки сервера из файла config.xml при помощи класса JavaServerProperties. В дальнейшем мы будем считывать оттуда различные параметры сервера:

public class JavaServerProperties {

	private Properties properties;

	public void loadProperties() throws Exception {
		properties = readPropertiesFromFile();
	}

	public Properties readPropertiesFromFile() throws Exception {
		Properties properties = new Properties();
		FileInputStream fis = new FileInputStream("./config/config.xml");
		properties.loadFromXML(fis);
		return properties;
	}

	public String getProperty(String key) {
		return properties.getProperty(key);
	}

	public boolean getBoolen(String key) {
		String property = getProperty(key);
		return property.equals("true");
	}

	public int getInt(String key) {
		return Integer.parseInt(getProperty(key));
	}

	public long getLong(String key) {
		return Long.parseLong(getProperty(key));
	}

	public float getFloat(String key) {
		return Float.parseFloat(getProperty(key));
	}
}

В config.xml, к примеру считываем расположения файла настроек логгера в BaseJavaServerLoggedClass.initLogger():

properties.getProperty("log4j.propertyFileName")

config.xml выглядит примерно так:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>Demo Java Soket Server Configuration</comment>
        
        <!--General Configuration-->
        <entry key="general.isDebugMode">true</entry>
        <entry key="log4j.propertyFileName">./config/log4j.properties</entry>

        <!--Server-->
        <entry key="server.port">9777</entry>
        <entry key="server.policyPort">9778</entry>
        <entry key="server.statPort">8083</entry>

</properties>

Настройки log4j.properties можно найти в документации в этой библиотеке.

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

02 сен 2011 22:59:18,070 INFO  [main] demo.server.JavaServer     - String server...

И после приложение завершит свою работу.
На самом деле это ещё не сервер. Но терпение — все будет.

Исходный код.

Полный код проекта всегда можно будет взять из репозитория на Google code. Коммит с приведенной выше версией находится тут.

]]>
http://regulflash/pages/java-socket-server-template/feed/ 1
Создание своего Java Socket Server. Теория. Из ActionScript3 в Java. http://regulflash/pages/java-socket-server/ http://regulflash/pages/java-socket-server/#comments Sat, 13 Aug 2011 11:48:03 +0000 admin http://www.regul-flash.com/?p=259 Некоторое время я сомневался стоит ли писать статью подобного типа. Во-первых, флеш-программистам она будет не очень полезна, т.к. она больше про яву, а опытные ява-программисты, мне кажется, знают все то, о чем я собираюсь написать. Но тем не менее это опыт, которым я хочу поделиться. Надеюсь, кому-то это будет полезным. Также, в этой части будет только теоретическое изложение советов и не будет самого кода сервера.  Данная статья является лишь теоретической и не содержит в себе код, но тем не менее содержит много букв.

Я флеш-программист, и мой опыт работы с явой исчисляется где-то месяцем. Эта статья типа «написание Java Socket сервера глазами флеш-программиста».

Предыстория.

До того, как мы написали свой сервер в нашем проекте Doom Forge Game мы использовали готовое решение для мультиплеерных игр — Smart Fox Server. Сервер сделан хорошо, в нем много возможностей, но нам пришлось столкнуться с некоторыми проблемами в его работе, которые решались тяжелым общением с безинициативной службой поддержки и решение проблемы могло занимать не меньше месяца (если проблема вообще решалась). Так что опыт использования Smart Fox Server у меня был печальный.

Из ActionScript3 в Java

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

Отличие 1. Переменные. Java — сначала тип, потом имя.

AS3:

var str:String = “Hello”;

Java:

String str =  “Hello”;

Отличие 2. В Java есть перегрузка методов, а во флеше нет.

В Java можно сделать так (и это круто):

<br />
public class MyClass{<br />
	public void find(int id){…};<br />
	public void find(String name){…};<br />
}<br />

В AS3 приходится делать приблизительно так:

<br />
public class MyClass{<br />
	public function findById(int id):void{…};<br />
	public function findByName(String name):void{…};<br />
}<br />

Отличие 3. В Java нельзя сделать ссылку на функцию, а в AS3 можно.

В AS3 мы пишем так (и это круто):

<br />
public function connect():void{<br />
	target.addEventListener(Event.CONNECT, handleConnect)<br />
}<br />
public function handleConnect(event:Event):void {<br />
	…<br />
}<br />

В java приходится для каждого слушателя создавать отдельный класс:

<br />
IRequestHandler handler = new Handler();<br />
addRequestHandler(Request.PUBLIC_MESSAGE, handler);<br />

А dispatcher, зная интерфейс хенжлера, знает какую функцию нужно вызвать и что в неё передать:

<br />
public interface IRequestHandler {<br />
	void handleRequest(String command, Object data, Session session);<br />
}<br />

Отличие 4. В Java можно указать какое исключение может сгенерировать метод:

void handleRequest(String command, Object data, Session session) throws Exception;

И нам прийдется обязательно обработать это исключение. И это круто. В AS3 мыможем либо прочитать документацию/asdoc либо только догадываться о наличии исключения.

Отличие 5. Многопоточность.

Конечно, вписывать это отличие в один ряд с предыдущими отличиями равносильно списку дел

«1) подписать контракт слияния компаний. 2) купить корм для рыбок».

На самом деле, это Огромное отличие. Суть его очень проста. Это выполнение кода в несколько параллельных потоков. Представьте, дорогие флешеры, что у вас в памяти не одна несколько запущенных флешек, только отисовуют они одну флешку и память у них общая. Т.е. в тот момент, пока в одном потоке вы перебираете список соперников, другой поток в это время добавляет или удаляет что-то из этого списка.

Если ещё проще – это как несколько людей в одной комнате(где люди это потоки, а предметы — это данные): пока Лена считает яблоки на столе, Ира в это время съедает парочку, и к моменту когда Лена досчитает яблоки, полученное значение не будет соответствовать реальности. Есть масса методов избежать проблем в подобных ситуациях — запретить Ире есть яблоки, пока они считаются; сделать так, чтобы яблоки, которые считает Лена и яблоки, которые есть Ира – это были разные яблоки и так далее. Также это может поразить кучу других проблем, к примеру deadlock: Ира ждет пока Лена досчитает яблоки, а Лена ждет пока Ира наестся в конце-то концов — и получается, что они блокируют друг-друга и никто ничего не делают. Но это очень обширная тема и её нужно изучать отдельно.

Начнем.

Итак, нам нужно сделать socket-сервер для чата. Первым делом я начал искать в просторах интернета и натолкнулся на ряд старей:

http://www.broculos.net/en/article/how-make-multi-client-flash-java-server

http://habrahabr.ru/blogs/java/69136/

— Супер! Как все просто! Это то что нужно, — подумал я и внедрил это в жизнь. Вроде все предельно просто. Эти статьи полезно изучить для того чтобы знать основы. Делаем. Все работает, работает отлично… до тех пор пока вы живете в мире без ошибок сети, без зла и насилия, и у вас только 2 подключенных пользователея. Как я понял позже, это пример сфирического коня в вакууме…

Что взять в дорогу. Мой выбор библиотек.

NIO

Первое, что я понял для себя — не стоит напрямую работать с сокетами. Если использовать готовое решение для работы с сокетами можно избежать кучи проблем с многопоточностью, deadlock, избавит от необходимости писать уже давно написанные вещи. Я выбрал Netty по рекомендации одного хорошего java-программиста, но не берусь утверждать, что это самый лучший вариант.

Логирование

Для логирования я использовал готовое и распространенное решение  - loj4g.

База данных

Работа с базой данных является тривиальной задачей для явы. Хотелось бы лишь посоветовать использовать пул соединений. Я использовал DBCP.

Протокол

Для простоты будем использовать JSON формат.

Статистика сервера

RRD4j — это простая библиотека для работы с rrd-базой.

Суть работы с сокетами — элементарное объяснение (вдруг кто не знает).

Итак, что такое сокеты. Я думаю, тут можно применить метафору телефонных разговоров. Клиент «звонит» по номеру (ip) серверу. Между ними устанавливается связь и они могут обмениваться информацией. Но все что они могут передавать друг-другу это звук (В случае компьютера — текст, а точнее нолики и единички). По «телефону» может говорить как клиент так и сервер и каждый будет слышать другого. Если кто-то положит трубку или связь оборвется где-то на линии — столько не кричи — твой собеседник тебя не услышит. Сокеты работают точно также.

В чем отличие от http-протокола? На самом деле, когда вы открываете веб-страницу ваш браузер создает сокет-соединение и посылает серверу команду «дай мне такую-то страницу» (Делает он это в http формате). Сервер в ответ посылает текст страницы и по окончании закрывает соединение («кладет трубку»). Что увидеть это воочию можно открыть telnet, подсоединиться к любому сайту и послать комманду «GET /» . Именно так и работает ваш браузер.

]]>
http://regulflash/pages/java-socket-server/feed/ 1
StarSeeker http://regulflash/pages/starseeker/ http://regulflash/pages/starseeker/#comments Sat, 30 Oct 2010 18:20:30 +0000 admin http://www.regul-flash.com/?p=126

]]>
http://regulflash/pages/starseeker/feed/ 4
Через тернии к звездам. Оптимизация кода ActionScript3. http://regulflash/pages/cherez-ternii-k-zvezdam-optimizaciya-koda/ http://regulflash/pages/cherez-ternii-k-zvezdam-optimizaciya-koda/#comments Wed, 22 Sep 2010 22:33:21 +0000 admin http://www.regul-flash.com/?p=135 Эта статья посвящена оптимизации ActionScript3 на примере создания эффекта «полета сквозь звезды»(на подобии старого скринсейвера Windows). Мне этот эффект необходим был для игры. Эффект должен был служить фоном и поэтому требовалось чтобы он был как можно менее ресурсоемким.

Я не изобретаю никакие новые приемы оптимизации, я лишь приведу пример их применения на практике. Для начала я поискал в интернете готовые решения и наткнулся на решение, которое визуально меня устраивало: http://www.lemlinh.com/flash-source-starfield-generator/. Открыв код мы обнаружим, что эти Звездочки — это MovieClip’ы (крик ужаса за кадром). Каждый флеш-разработчик понимает, что кроме отображения «точки» на каждую «Звездочку-MovieClip» вешается куча свойств и методов класса MovieClip. И чем больше звезд — тем хуже. Я ничего не хочу сказать об авторе — просто для нам требуется другое.

Ясно, что в такой ситуации прийдется сделать все с самому и с нуля. Ничего гениального в нашей реализации нет:

  1. создать массив точек stars:Array
  2. в каждом кадре:
  • …просчитать новое положение каждой точке по суперсложной математической формуле (умножение).
  • …нарисовать каждую точку на экране.

Сразу оговорюсь, я использую собственный метод получения случайного значения в классе Tools.Utils.as:

public static function rand(lowValue:Number, hightValue:Number, round:Number = 1):Number{
	return lowValue + Math.floor(Math.random() * (hightValue-lowValue)*round)/round;
}

Реализуем наш нехитрый алгоритм и получаем класс StarFieldBad.as. Код нам не важен. Но именно такой код я написал бы до того, как начал закомиться с методами оптимизации когда.

Звезд у нас будет меньше чем на небе, создадим их всего 2000 (реально их хватит 100-200, но нам для теста нужно побольше):

background = new StarFieldBad(_game.STAGE.stageWidth, _game.STAGE.stageHeight, 2000);
addChild(background);

Выполнение инициализации не является критическим параметром, т.к. создание объекта делается не часто. Но все же среднее время создания: 7,42ms.

Критическим показателем в нашем случае является время выполнения кадра: 9,1095ms.

Вроде бы и подход не самый страшный, и звезды не создаются каждый раз, но на самом деле это все не верх совершенства. Итак, пойдем по порядку.

bitmapData.lock()

В коде не хватает использования метода lock() и unlock(). Добавляем их. (Подробнее «Работа с пикселами» на сайте Adobe.)

В итоге время выполнения стало: 8,9753ms. (Печально, маленький прирост)

Цикл FOR

...for (var i:int = 0; i &lt; stars.length; i++) // Проходимся по всем звездам...

Цикл при каждом проходе обращается к объекту и его свойству. Заодно заменяем цикл for на цикл while:

var i:uint = starsCount;// Итератор звезд
while ( --i &gt; -1)// Проходимся по всем звездам
...

Время выполнения: 7,5379ms. (Удивительно большой прирост)

По возможности избегайте использования оператора квадратной скобки

Например у нас внутри циклов происходят подобные операции:

stars[i].x += (stars[i].x - fieldWidth/2) * 0.01;
...

Заменяем оператор квадратные скобки на ссылку в локальной переменной (имеет смысл, если мы обращаемся к переменной много раз):

var star:Point;// Ссылка на мат. модель звезды
while ( --i &gt; -1)// Проходимся по всем звездам
{
	star = stars[i];
	star.x += (star.x - halfWidth) * 0.01;
	...

Время выполнения: 4.4279ms. (Невероятно большой прирост. Видимо, ещё сказывается большой объем массива)

По возможности используйте класс Vector вместо класса Array

Заменяем Array на Vector.<Point>. «В проигрыватель Flash Player 10 добавлен класс Vector, который обеспечивает более быстрый доступ для чтения и записи, чем класс Array.» (источник)

stars = new Vector.&lt;Point&gt;(starsCount, true);

Время выполнения: 3.0963ms.

Избавляем Flash от ненужных повторяющихся вычислений

Можно заранее просчтитать значения таких выражений как «fieldWidth / 2» на «halfWidth» или «fieldHeight+offset» на «fieldWidthWithOffset» и сохранить их в переменные, тем самым избавив флеш от ~20000 лишних операций деления и сложения(это в нашем примере) за кадр:

public function StarField(width:int, height:int, count:uint)
{
	fieldWidthWithOffset = fieldWidth = width;
	fieldHeightWithOffset = fieldHeight = height;
	
	fieldWidthWithOffset += offset;
	fieldHeightWithOffset += offset;

	halfWidth = fieldWidth / 2;
	halfHeight = fieldHeight / 2;
	...

Время выполнения: 2.9642ms. (ну, большого прироста никто и не обещал)

Другие приемы оптимизации

Далее я опущу описание других методов, которые мало сказались на производительности (но это не значит, что нужно ими пренебрегать!):

  • Определение переменных вне цикла.
  • Встраивание кода для уменьшения числа вызовов функций в коде.

В итоге время выполнения скрипта было уменьшено с 9,7753ms до 2.9405ms. А это более чем в 3 раза! И время инициализации сократилось в 2 раза — с 7,42ms до 3,26ms.

Файл Tools.Utils.as.

Исходный файл StarFieldBad.as.

Итоговый файл StarField.as

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

Пару ссылок по теме:

Оптимизация производительности для платформы Flash Platform

http://www.rozengain.com/blog/2007/05/01/some-actionscript-30-optimizations/

И конечно, Google

]]>
http://regulflash/pages/cherez-ternii-k-zvezdam-optimizaciya-koda/feed/ 2
Оптимизация производительности для платформы Flash Platform http://regulflash/pages/optimizaciya-proizvoditelnosti-dlya-platformy-flash-platform/ http://regulflash/pages/optimizaciya-proizvoditelnosti-dlya-platformy-flash-platform/#comments Mon, 06 Sep 2010 14:46:01 +0000 admin http://www.regul-flash.com/?p=115 Советы по оптимизации производительности Flash платформы:

http://help.adobe.com/ru_RU/as3/mobile/index.html

Всем Flash’ерам и AS3 программистам читать обязательно! Никогда не думал что справка может быть такой содержательной.

]]>
http://regulflash/pages/optimizaciya-proizvoditelnosti-dlya-platformy-flash-platform/feed/ 1
Компилируйте код в Flash Develop, а графику в Flash IDE http://regulflash/pages/kompilirujte-kod-v-flash-develop-a-grafiku-v-flash-ide/ http://regulflash/pages/kompilirujte-kod-v-flash-develop-a-grafiku-v-flash-ide/#comments Tue, 31 Aug 2010 17:32:19 +0000 admin http://www.regul-flash.com/?p=80 Хочу поделиться навыками организации работы с flash, которые я получил на свой недолгий опыт flash-разработчика. Я думаю, эти рекомендации прежде всего будут полезны новичкам. Статья касается прежде всего разработки flash-игр.

Говорить я буду о работе с Flash IDE, Flash Develop(AS3) и GIT.

Flash IDE — используйте для работы с графикой.

FlashDevelop — для кода.

GIT — для контроля версий.

Статья 1. Компилируйте код в Flash Develop, а графику в Flash IDE.

Если вы разрабатываете более-менее сложную по коду игру, вам много приходится работать с кодом. Если вы правите as-файлы в Flash Develop, а потом компилируете игру в Flash IDE — это ваша первая ошибка. Я раньше тоже так делал. Теперь я делаю графику в Flash IDE и экспортирую её в swc-файл. Потом редактирую код в Flash Develop и компилирую его через Flex.

Этот подход дает следующие преимущества:

  • Компилируется в разы быстрее. Компиляция происходит значительно быстрее, за счет того, что графика уже «готова к употреблению».
  • Flash Develop подхватывает классы из SWC. В коде доступны классы из библиотеки. Не скажу, что это больше преимущество, но это плюс.
  • Работает debug. Удивительная вещь! Раньше у меня отладка сводилась к применению trace, а теперь можно делать полноценную отладку! В случаях ошибки также Flash Develop переключается на отладку и останавливает работу на строке с ошибкой.

Пример.

  • Если у вас стоит старая версия FlashDevelop — смело удалите все пользовательские файлы(Tools->Application files) приложения и перезапустите программу.
  • Ещё понадобится Java, .NET2-3.

Всем своим сердцем я надеюсь, что у вас уже установлен Flex SDK.  Если нет — устанавливаем (Скачать Flex 4). Установленным должен быть и FlashDevelop (Скачать FlashDevelop). Там же есть инструкция по настройке.

Открываем FlashDevelop. Выбираем Project->New Project… и создаем проект «AS3 Project».

После этого должен получится примерно такой состав проекта:

Компилируем его (Enter+Ctrl). Если появилось пустое окно Flash Player — значит все работает правильно. Если нет, внимательно читайте окошко Output(там может быть намек на ошибку), и пишите в комментариях.

Настраиваем Flash IDE. Создаем новый AS3 проект. Создаем для проверки Символ в библиотеке.

Файл сохраняем в  проекте, в папке «lib». Заходим в Flash IDE->Файл(File)->Параметры публикации(Public settings)->Вкладка «Flash»->Ставим галку «Экспортировать SWC-файл». Публикуем проект(Alt+Shift+F12). В папке lib должен появится файл swc:

Как мы видим, в проекте FlashDevelop появился файл swc с списком классов в нем. Теперь необходимо его подключить: Project->Properties->Compiter Options->Добавляем в SWC Libraries наш swc файл.

Для проверки попробуем использовать класс из swc-файла в нашем коде (Main.as):

private function init(e:Event = null):void {
...
addChild( new myMovieClipClass());
}

Компилируем, и видим, что все получилось:

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

Продолжение следует.

P.S.

Решил переделать то, что начал делать, под этот метод. Раньше в библиотеке был мувиклип button, для него был прописан и создан класс (ui.MyButton) с определенной функциональностью. Вот вкомпилил я этот мувиклип в swc. Ну не получается у меня создать экземпляр этого символа из библиотеки, и чтобы у него был весь этот функционал. Создается я так понял просто экземпляр класса ui.MyButton. Направь на правильный путь плиз.

Весь вопрос в том, что получается ты вкладываешь функциональную часть в swc файл(логику в графику), а потом опять эту графику опять вкладываешь в логику. Это не правильно с точки зрения похода. Я понимаю, что это накладывает некоторые ограничения на процесс разработки, но тебе нужно добавлять ui.MyButton уже непосредственно в коде, программно задавая им позиции.
К примеру, у меня есть MovieClip mcLevelMapLightClass, а функциональность я уже добавляю в FlashDevelop:

public class LevelMapLight extends mcLevelMapLightClass

Дальше я знаю 2 варианта:
1. Считывать положения конкретных MovieClip на сцене и заменять их уже функциональными с соотв. положением.
2. Сделать конфигурацию (я сделал в XML) положений элементов и добавлять их в соотв. с этой конфигурацией.
Конечно, проще накидать элементы в Flash IDE. А тут приходится это делать кодом. Сначала непривычно. Но в большинстве случаев это занимает не так много работы, как кажется.

Пример:


// Создаем положения для кнопок
var btnConf:XML = <root>
	<item x="63" y="267" />
	<item x="150" y="267" />
	<item x="195" y="249" />
	<item x="195" y="288" />
	<item x="232" y="288" />
	<item x="232" y="249" />
	<item x="269" y="267" />
	<item x="360" y="267" />
	<item x="360" y="222" />
	<item x="415" y="210" />
	<item x="415" y="325" />
	<item x="475" y="325" />
	<item x="535" y="325" />
	<item x="535" y="210" />
	<item x="475" y="210" />
	<item x="475" y="265" type="big" />
</root>

// Создаем кнопки согласно конфига
for (var i:int = btnConf.item.length() - 1; i >= 0 ; i-- ) {
	// Создаем экземпляр кнопки
	var newButton:LevelMapLight = new LevelMapLight();
	
	// Присваиваем ей имя
	newButton.name = "mcBtn" + Math.round(i+1);
			
	// Устанавливаем положение
	newButton.x = btnConf.item[i].@x;
	newButton.y = btnConf.item[i].@y;
	
	// Сохраняем кое-какие данные			
	newButton.userData = i + 1;

	// Добавляем обработчик, который вызовется по нажатию
	newButton.click_hendler = function(e:MouseEvent):void {
		Game.instance.currentLevelNumber = e.currentTarget.userData;
		startGame();
	}

	//Добавляем на сцену				
	addChild(newButton);
}


]]>
http://regulflash/pages/kompilirujte-kod-v-flash-develop-a-grafiku-v-flash-ide/feed/ 2