Как стать автором
Обновить
6
0

Пользователь

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

Я понимаю, что статья написана после первых часов опыта работы с Kotlin и тут в основном задаются вопросы к сообществу, но эта форма подачи…
«Котлин не изучал, но никак не удержусь полить его тонной ховна, кажется, это модно».
А может стоит всё-таки сначала поизучать язык? Ах, хотя нет, зачем.

1) Банально запоролись уже на втором аргументе про null-safety. Ну и то, что кто-то привык к си — вообще не аргумент и кричать про бесполезность null-safety немного стрёмно. Как минимум это дополнительный инструмент построения более стабильной и прозрачной архитектуры.

image
И вышеприведенный код отлично компилируется и работает.
Другой вопрос в приведении типа к non-null — да, согласен насчет синтаксиса, код получается малость «экспрессивный».

2) Чем вам for-то так не угодил? Синтаксисом? Объёмом генерируемого кода? Посмотрите в сторону того как современные компиляторы оптимизируют код — в большинстве случаев ваш цикл превратится в обычный ваш «сишный» for.

3) Аннотации же нужны, декларирующие о null-ability типа! И по дефолту котлин вам разрешает использовать код из java без каста к non-null, но предупреждает, что вы можете выстрелить себе в ногу. Может всё-таки вы будете сначала искать хоть какую-то информацию перед написанием статей?
Это замечательно компилируется без каких-либо ошибок или предупреждений, запускается и с грохотом схлопытвается cо стандартным NullPointerException т.к. тут Kotlin не проверяет ничего и нигде. И где обеща..., тьфу, декларируемая безопасность?


4) Ну, наверное, за введение оператора "?:", чтобы избежать конфузов. Поясняю: в котлине есть оператор, который оценивает выражение слева, и если оно возвращает null, то отдаёт выражение справа. То, чего вам так не хватало в пункте 2 про null-safety.
Чем не угодил оператор "?:"?

За что ампутировали оператор "?:"?

Что усмотрели вредного в таких конструкциях?


5) Чтобы не было конфузов с boxing-ом типов? Скажу, что меня тоже бесит постоянно конвертить даблы во флоаты и обратно, но это плата за код, который работает именно так как мне надо и не выплёвывает сюрпризов.
За что убили автоматическое приведение типов?


6) Вам ничего не говорит пунктик про то, что котлин полностью обратносовместим с Java? Kotlin нигде не позиционируется как «офигенно крутой язык, меняющий jvm и все ещё компилирующийся в Java-совместимый байткод». Противоречие видите? Не под силу Kotlin изменить работу JVM и добавить туда ваши пресловутые шаблоны.

Правда, есть одна клёвая фишка — reified. Сродни тому, о чём вы так молите (о да, вы сможете скастить объект в ваш generic-type в рантайме!), работает правда только с inline методами (угадайте почему?).

В котлин-generics меня раздражает разве что in\out, особенно когда начинал осваивать язык, ловил разрыв шаблона.
Бог с ней с Java т.к. меня лично ее проблемы не волнуют. Меня волнует ущербность шаблонов конкретно в Kotlin, который позиционируется как другой язык, а не препроцессор для Java и, в результате, кивать на ее недостатки по меньшей мере бессмысленно.


7) А если вот так?
image
то с картами все значительно печальнее:

val tree = mapOf(
    Pair("dir1", mapOf(Pair("file1", 0), Pair("file2", 1))),
    Pair("dir2", mapOf(
      Pair("dir21", mapOf(Pair("file1", 0), Pair("file2", 1))),
      Pair("dir22", mapOf(Pair("file1", 0), Pair("file2", 1))))) )



P.S. Вы бы ещё на отсутствие checked exceptions пожаловались.
Если не секрет, сколько тогда было новичку и какой опыт он имел? В годах.
>(1+oldByte-1)
Серьёзно? Может, я что-то упускаю, но нельзя ли это записать «несколько проще»?
--Не та ветка
Не знаю, насколько это применимо к «реальной практике», но:
Когда писал свой буфер глубины для изометрического движка, который строился на обработке пикселей процессором (велосипед от скуки, развлекал себя), как раз пригодилась замена if'а, выкидывающего пиксель, на нехитрую формулу с альфой двух пикселей. Прирост был, т.к. пикселей было много (:
Очень интересно, а где про это можно поподробнее почитать? Я вот хочу удариться в программирование шейдеров (освещения, отражения, преломления и прочего), но копипастить формулы вообще никак не хочется, гораздо интереснее ведь изучить материал.
Под спойлером полностью обновленный код.
Не знаю как тут работает обновление статей, там внизу кнопочка опубликовать. Оно ведь не сделает новый топик мне, как в случае если я редактирую черновик?
Методы определения переходов
public int setPointTransition(World world, int[] temp, int x, int y, int corner, int c, int i) {
		for (int k = 0; k < 4; k++)
			if ((corner >> k & 1) == 1) {
				int idx = 8+k;
				int storage = 0;
				storage = (idx & 0xF) << 4 | (i & 0xF);
				temp[k] = storage;
				int t = 0;
				for (int l = 0; l < 4; l++) {
					t = (t << 8) | temp[l] & 0xFF;
				}
				world.setTransition(x, y, t);
				c++;
			}
		return c;
	}
	
	public void setDiagonalTransition(World world, int[] temp, int x, int y, int corner, int i) {
		if ((corner >> 0 & 1) == 1 && (corner >> 2 & 1) == 1) {
			int idx = 12+1;
			int storage = 0;
			storage = (idx & 0xF) << 4 | (i & 0xF);
			temp[0] = storage;
			temp[2] = storage;
			int t = 0;
			for (int l = 0; l < 4; l++) {
				t = (t << 8) | temp[l] & 0xFF;
			}
			world.setTransition(x, y, t);
		}
		else if ((corner >> 1 & 1) == 1 && (corner >> 3 & 1) == 1) {
			int idx = 12;
			int storage = 0;
			storage = (idx & 0xF) << 4 | (i & 0xF);
			temp[1] = 0;
			temp[3] = storage;
			int t = 0;
			for (int l = 0; l < 4; l++) {
				t = (t << 8) | temp[l] & 0xFF;
			}
			world.setTransition(x, y, t);
			
		}
	}
	
	public void setEdgeTransition(World world, int[] temp, int x, int y, int corner, int i) {
		for (int offset = 0; offset < 4; offset++) {
			boolean isSide = true;
			for (int k = 0; k < 2; k++) {
				if ((corner >> ((k + offset) % 4) & 1) != 1)
					isSide = false;
				else if (k == 1 && isSide)  {
					int idx = (offset+1)%4;
					int storage = 0;
					storage = (idx & 0xF) << 4 | (i & 0xF);
					temp[offset] = 0;
					temp[(offset+1)%4] = storage;
					int t = 0;
					for (int l = 0; l < 4; l++) {
						t = (t << 8) | temp[l] & 0xFF;
					}
					world.setTransition(x, y, t);
				}
			}
		}
	}
	
	public void setCornerTransition(World world, int[] temp, int x, int y, int corner, int i) {
		for (int offset = 0; offset < 4; offset++) {
			boolean isCorner = true;
			for (int k = 0; k < 3; k++) {
				if ((corner >> ((k + offset) % 4) & 1) != 1)
					isCorner = false;
				else if (k == 2 && isCorner)  {
					int idx = 4+offset;
					int storage = 0;
					storage = (idx & 0xF) << 4 | (i & 0xF);
					temp[offset] = 0;
					temp[(offset+1)%4] = 0;
					temp[(offset+2)%4] = storage;
					int t = 0;
					for (int l = 0; l < 4; l++) {
						t = (t << 8) | temp[l] & 0xFF;
					}
					world.setTransition(x, y, t);
				}
			}
		}
	}


Обновление тайла
public void updateTransitionMap(World world, int x, int y) {
		int w = 16, h = 16;
		int[] temp = new int[4];
		for (int i = 0; i < 4; i++)
			temp[i] = 0;
		
		if (tileID > 0) {
			for (int i = 1; i <= tilesNum; i++) {
				int corner = getTransitionCornerFor(world, x, y, i);
				int c = 0;
				if (corner > 0) {
					c = setPointTransition(world, temp, x, y, corner, c, i);
					
					if (c == 2) 
						setEdgeTransition(world, temp, x, y, corner, i);
					
					if (c == 2) 
						setDiagonalTransition(world, temp, x, y, corner, i);
					
					if (c == 3) 
						setCornerTransition(world, temp, x, y, corner, i);
				}	
			}
		}
	}


Отрисовка
public void renderTile(World world, int x, int y) {
		int w = 16, h = 16;
		
		int s = 0;
		if (tileID > 0) {
			for (int i = 1; i <= tilesNum; i++) {
				boolean isFullTile = false;
				int corner = getTransitionCornerFor(world, x, y, i);
				int c = 0;
				if (corner > 0) {
					for (int k = 0; k < 4; k++)
						if ((corner >> k & 1) == 1) {
							c++;
							if (c == 4)
								isFullTile = true;
						}
				}
				
				int fill = getFillCornerFor(world, x, y, i);
				if (fill > 0)
					for (int k = 0; k < 4; k++)
						if ((fill >> k & 1) == 1) {
							c++;
						}
				
				if (c == 4) {
					GRenderEngine.drawTextureQuad(x*16, y*16, 128, 144+96, 0, 48*(i-1), 16, (i-1)*48+16);
					if (isFullTile)
						return;
				}
			}
			

			for (int j = 1; j <= tilesNum; j++) {
				for (int i = 0; i < 4; i++) {
					int t = world.getTransition(x, y);
					int src = ((t >> (3-i)*8) & 0xFF);
					int idx = src >> 4 & 0xF;
					int id = src & 0xF;
					int u = (idx%8)*16, v = 16 + 16*(idx/8) + (id-1)*48,
					u1 = u + w, v1 = v + h;
					if (id == j) {
						GRenderEngine.drawTextureQuad(x*16, y*16, 128, 144+96, u, v, u1, v1);
					}
				}
			}
		}
	}

Поставил в редактор тайлы из старого доброго WC3 и заметил тучу багов.
Самые плохие я уже устранил, надо было очищать все ненужные углы после создания смежных тайлов, т.к. они рисовались поверх нужной текстуры и создавался невообразимый хаос.
image
Сейчас осталась одна проблема — отсортировать углы. Скоро допишу и выложу код под спойлер.
Вообще про результат с точки зрения работоспособности и правильной отрисовки.
Кстати говоря, я пересмотрел свой код, немножко поменял условия. От последнего костыля я, вроде, избавился. Стоило перечитать свою же статью.
Код
public void renderTile(World world, int x, int y) {
	int w = 16, h = 16;	
	int s = 0;
	if (tileID > 0) {
		for (int i = 1; i <= tilesNum; i++) {
			boolean isLowestTile = false;
			int corner = getTransitionCornerFor(world, x, y, i);
			int c = 0;
			if (corner > 0) {
				for (int k = 0; k < 4; k++)
					if ((corner >> k & 1) == 1) {
						c++;
						isLowestTile = true;	//if we have at least one neighbor tile of this type - set this to lowest at this cell
					}
			}
			
			int fill = getFillCornerFor(world, x, y, i);
			if (fill > 0)
				for (int k = 0; k < 4; k++)
					if ((fill >> k & 1) == 1) {
						c++;
					}
				
			if (c == 4 && isLowestTile) {
				GRenderEngine.drawTextureQuad(x*16, y*16, 128, 144, 0, 48*(i-1), 16, (i-1)*48+16);
				break;
			}
		}
			
		for (int i = 0; i < 4; i++) {
			int t = world.getTransition(x, y);
			int src = ((t >> (3-i)*8) & 0xFF);
			int idx = src >> 4 & 0xF;
			int id = src & 0xF;
			int u = (idx%8)*16, v = 16 + 16*(idx/8) + (id-1)*48,
			u1 = u + w, v1 = v + h;
			if (id != 0) {
				GRenderEngine.drawTextureQuad(x*16, y*16, 128, 144, u, v, u1, v1);
			}
		}
	}
}


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

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность