Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   www.boolean.name > Программирование игр для компьютеров > BlitzMax > FAQ и уроки

Ответ
 
Опции темы
Старый 19.10.2009, 08:48   #1
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,374
Написано 489 полезных сообщений
(для 882 пользователей)
Разрывание рисунка на куски и растворение

Здравствуйте!

Здесь пример того, как можно спецэффектно рвать рисунки на куски или растворять их не просто альфой.

Реализовано два типа "деформации" рисунка - взрыв и растворение.
Создавать куски можно как заблаговременно, например, в момент загрузки уровня, так и "на лету". Но создание на лету тормозит систему на время своей работы.
Куски получаются посредством попиксельного копирования цветов из исходного рисунка в рисунок куска. Медленно? Ещё бы! (для ускорения и есть предварительная загрузка в кеш)

Управление:
-левая кнопка мыши - создать взрыв
-правая кнопка мыши - создать растворение
-Esc - выход

Псевдокод использования:
1. создаем заранее:
взрыв_растворение.СоздатьВКеш(исходныйРисунок, ширина куска, высота куска, тип{Взрыв,Растворение})
а затем там где нужно создать эффект:
взрыв_растворение.Запуск(Х, У)

2. создаем в реальном времени:
взрыв_растворение.СоздатьПрямЩас(исходныйРисунок, ширина куска, высота куска, тип{Взрыв,Растворение}, Х, У)

Для примера возьмем такой рисунок:
Нажмите на изображение для увеличения
Название: pointer.png
Просмотров: 380
Размер:	14.1 Кб
ID:	8000

Что есть в примере:
-класс TParticle - для хранения информации о кусках и их рисования
-класс TExplosion - для создания и управления кусками
-код, показывающий как этим воспользоваться

Скрины из данного примера:
исходный рисунок:
Нажмите на изображение для увеличения
Название: pic1.png
Просмотров: 403
Размер:	14.9 Кб
ID:	8001

взрыв:
Нажмите на изображение для увеличения
Название: pic2.png
Просмотров: 421
Размер:	32.1 Кб
ID:	8002

растворение:
Нажмите на изображение для увеличения
Название: pic3.png
Просмотров: 392
Размер:	19.5 Кб
ID:	8003

Теперь - непосредственно к исходнику.
В коде имеются комментарии для увеличения степени понятности; их вполне может хватить. Итак,

Strict

AppTitle = "Разрывание и растворение рисунка"

'загружаем наш подопытный рисунок
Local img:TImage = LoadImage("pointer.png")


'создаем окно
Graphics(800, 600, 0, 60)

HideMouse()

'создаем экземпляр объекта "взрыв"
Local expl:TExplosion = New TExplosion

'заранее создаем будущие осколки из исходного рисунка
'параметры: рисунок, ширина осколков, высота осколков, тип осколков
expl.fnPreCreate(img, Rand(5, 15), Rand(5, 15), TParticle.KIND_EXPLOSION)


SetClsColor 100, 100, 200

SetBlend ALPHABLEND

'главный цикл
While Not KeyHit(KEY_ESCAPE)
	
	'сбрасываем в исходное состояние альфу, поворот и масштаб
	SetAlpha 1
	SetTransform
	
	'по щелчку левой кнопки мыши запускаем наш ранее кешированный взрыв
	If(MouseHit(1) > 0)
		'указываем координаты левого верхнего угла
		expl.fnStart(MouseX(), MouseY())
	EndIf
	
	'по щелчку правой кнопки - "на лету" создаем "растворение" рисунка
	'на время разбиения на куски прога подвисает, поэтому рекомендуется заранее (на этапе загрузки) создавать нарезку
	If(MouseHit(2) > 0)
		'параметры: исходный рисунок, ширина кусков, высота кусков, тип "растворение", координаты левого верхнего угла
		expl.fnCreate(img, Rand(5, 15), Rand(5, 15), TParticle.KIND_RASTVORENIE, MouseX(), MouseY())
	EndIf
	
	'обновление взрыва/растворения
	'если идет анимация, то функция вернет true - исходный рисунок не рисуем
	'если анимации нет, то вернет false - и будет нарисован исходный рисунок
	If(expl.fnUpdate() = False) DrawImage (img, MouseX(), MouseY())
	
	Flip
	Cls
Wend

End


'класс КУСОК, содержит картинки и параметры рисования этих картинок
Type TParticle
	Field img:TImage 'картинка
	Field x:Float, y:Float 'координаты
	Field dx:Float, dy:Float 'смещение по X и Y (скорость)
	Field alpha:Float, scale:Float, angle:Float 'альфа, масштаб и поворот
	Field dAlpha:Float, dScale:Float, dAngle:Float 'их приращение
	Field dir 'направление вращения картинки
	Field kind 'тип куска
	
	Global KIND_EXPLOSION = 1 'для взрыва
	Global KIND_RASTVORENIE = 2 'для растворения
	
	
	'создание экземпляра
	'параметры: указатель на рисунок, координаты х-у, тип, скорость по х-у,начальные значения альфы, масштаба и поворота
	Function fnCreate:TParticle(img:TImage, x:Float, y:Float, knd, dx:Float = 0, dy:Float = 0, alpha:Float = 1.0, scale:Float = 1.0, angle:Float = 0)
		Local p:TParticle = New TParticle
		p.img = img
		p.x = x
		p.y = y
		p.dx = dx
		p.dy = dy
		p.fnSetKind(knd) 'эта функция ставит параметры в зависимости от типа
		p.alpha = alpha
		p.scale = scale
		p.angle = angle
		p.dir = 1 - 2 * (Rand(100) < 50) 'случайное направление вращения (dir = -1 или 1)
		Return p
	End Function
	
	'устанавливаем параметры в зависимости от типа	
	Method fnSetKind(knd)
		
		kind = knd
		
		'для взрава значения побольше, для растворения - поменьше
		If(kind = KIND_EXPLOSION)
			dx = Rnd(- 2.0, 2.0)
			dy = Rnd(- 2.0, 2.0)
			dAlpha = -0.015
			dScale = 0.03
			dAngle = 3.5
			
		Else 'If(kind = KIND_RASTVORENIE)
			dx = Rnd(- 0.02, 0.02)
			dy = Rnd(- 0.02, 0.02)
			dAlpha = -0.007
			dScale = 0.01
			dAngle = 0.3
			
		EndIf
		
	End Method
	
	'обновления куска
	'здесь все значения нужно умножать на коэффициент,
	'равный koef#=fpsEtalon#/fpsReal#
	'чтобы на разномощных компах одинаково выглядело
	Method fnUpdate()
		x:+dx
		y:+dy
		alpha:+dAlpha
		scale:+dScale
		angle:+dAngle * dir
	End Method
	
	'рисование картинки с ее альфой, масштабом и поворотом
	'а также с внешним смещением по х-у
	Method fnDraw(x0:Float = 0, y0:Float = 0)
		SetAlpha alpha
		SetTransform angle, scale, scale
		DrawImage img, x0 + x, y0 + y
	End Method
		
End Type


'класс ВЗРЫВ (он же и растворение)
Type TExplosion
	Field list:TList = New TList 'список кусков рисунка
	Field listCashed:TList = New TList 'список кешированных кусков рисунка
	Field x:Float, y:Float 'координаты левого верхнего угла, относительно которого рисовать
	Field image:TImage 'указатель на исходный рисунок
	Field cashed 'флаг - кешировали или нет
	Field animate 'флаг - идет анимация или нет
	
	'"врЕменная" переменная для циклов for ... eachin ...
	Global part:TParticle
	
	
	'кеширование кусков
	Method fnPreCreate(pimage:TImage, sizeX:Float, sizeY:Float, kind)
		image = pimage
		'создаем куски из указанного рисунка, указанного размера и типа
		listCashed = fnCreateParticles(image, sizeX, sizeY, kind)
		cashed = True 'устанавливаем флаг, ибо сделали дело
	End Method
	
	
	'запуск анамации - используется для старта из кешированного списка
	Method fnStart(px:Float, py:Float)
		
		'если не кешировали или уже идет анимация - выходим
		If(cashed = False Or animate = True) Return
		
		Local p:TParticle 'это для кусков-копий кешированных
		
		'позицию запоминаем
		x = px
		y = py
		
		'проходим по списку кешированных кусков
		'создаем их копиии и добавляем в список
		For part = EachIn listCashed
			p = New TParticle
			p.x = part.x
			p.y = part.y
			p.dir = part.dir
			p.dx = part.dx
			p.dy = part.dy
			p.alpha = part.alpha
			p.angle = part.angle
			p.scale = part.scale
			p.dAlpha = part.dAlpha
			p.dAngle = part.dAngle
			p.dScale = part.dScale
			p.img = part.img
			list.AddLast(p)
		Next
		
		animate = True '"включаем" анимацию
		
	End Method
	
	
	'создание кусков "на лету"
	'даем функции рисунок, ширину, высоту и тип кусков, и координаты откуда все рисовать
	Method fnCreate(pimage:TImage, sizeX:Float, sizeY:Float, kind, px:Float, py:Float)
		
		'если уже идет анимация - выходим
		If(animate = True) Return
		
		image = pimage
		x = px
		y = py
		
		'создаем куски
		list = fnCreateParticles(image, sizeX, sizeY, kind)
		animate = True 'поехали!
		
	End Method
	
	
	'создание кусков - возвращает список с кусками
	'даем функции исходный рисунок + ширину, высоту и тип кусков
	Function fnCreateParticles:TList(img1:TImage, sizeX:Float, sizeY:Float, kind)
		Local lst:TList = New TList
							
		Local imgW, imgH, ix, iy, px, py
		Local pix1:TPixmap, pix2:TPixmap 'через пиксмапы будем попиксельно копировать точки из исходного в куски
		Local img2:TImage 'это для указывания на очередной кусок
		
		'реальная ширина и высота создаваемого куска
		'нужна для того, чтобы правильного размера крайние куски сделать
		Local wd, hg
		
		'запомним размеры исходного рисунка в переменные, для удобства
		imgW = img1.width
		imgH = img1.height
		
		'блокируем исходный рисунок для работы с его точками
		'и получаем пиксмап
		pix1 = LockImage(img1)
		
		'пробегание по координате Y
		'iy - хранит номер строки
		While(iy * sizeY < imgH)
			
			'проверка - выйдем ли мы следующим проходим за границы исходного рисунка
			'если да, то значит кусок нужно делать не на всю высоту sizeY, а поменьше
			'чтоб он как раз до края получился
			If((iy + 1) * sizeY > imgH)
				hg = imgH - iy * sizeY
			Else
				hg = sizeY
			EndIf
			
			'обнуляем номер столбца
			ix = 0
		
			'пробегание по координате Х
			'iх - хранит номер столбца
			While(ix * sizeX < imgW)
				
				'проверка - выйдем ли мы следующим проходим за границы исходного рисунка
				'если да, то значит кусок нужно делать не на всю ширину sizeХ, а поменьше
				'чтоб он как раз до края получился
				If((ix + 1) * sizeX > imgW)
					wd = imgW - ix * sizeX
				Else
					wd = sizeX
				EndIf
					
				'создаем рисунок для очередного куска размером (wd x hg) точек
				img2 = CreateImage(wd, hg, 1, DYNAMICIMAGE | FILTEREDIMAGE)
				'блокируем рисунок и получаем его пиксмап
				pix2 = LockImage(img2)
				
				'(столько циклов, аж дух захватывает!)
				'здесь мы попиксельно копируем инфу о цветах из исходного рисунка в рисунок куска
				For py = 0 Until hg
					For px = 0 Until wd
						'в пиксмап куска пишем в позицию px,py
						'а из исходного читаем со смещением ix*sizeX,iy*sizeY
						WritePixel(pix2, px, py, ReadPixel(pix1, ix * sizeX + px, iy * sizeY + py))
					Next
				Next
				'разблокируем рисунок куска
				UnlockImage(img2)
				'ставим ему смещения рисования в центр
				MidHandleImage(img2)
				'добавляем кусок в список
				'отнимать от х координаты (sizeX - wd) * 0.5
				'и от у координаты (sizeY - hg) * 0.5
				'нужно для того, чтобы крайние куски не съехали в сторону
				'когда их размер меньше чем sizeX*sizeY - из-за midhandl'а
				'и еще 0.5 от размера прибавляем, опять же компенсируя сдвиг midhandl'a
				lst.AddLast(TParticle.fnCreate(img2, ix * sizeX - (sizeX - wd) * 0.5 + sizeX * 0.5, iy * sizeY - (sizeY - hg) * 0.5 + sizeY * 0.5, kind))
				
				ix:+1
			Wend
			iy:+1
		Wend
		
		'разблокируем исходный рисунок
		UnlockImage(img1)
		
		'возвращаем список
		Return lst
		
	End Function

	
	'обновление
	Method fnUpdate()
		
		'если анимация не включена, то выходим, возвращая false
		If(animate = False) Return False
		
		'пробегаем по всем кускам из списка
		For part = EachIn list
			'обновляем и рисуем каждый
			part.fnUpdate()
			part.fnDraw(x, y)
			'проверяем - не пора ли удалить кусок?
			If(part.alpha <= 0)
				list.Remove(part)
				part = Null
			EndIf
		Next
		
		'если кусков больше нет, то останавливаем анимацию
		If(list.IsEmpty())
			animate = False
		EndIf
		
		'возвращает true, а после удаления последнего - false
		'это не столь важно, здесь можно просто return true поставить
		Return animate
		
	End Method
	
End Type
Во вложении исходник и подопытный рисунок.
Вот и всё!
Вложения
Тип файла: rar pixAlpha.rar (17.9 Кб, 182 просмотров)
(Offline)
 
Ответить с цитированием
Эти 8 пользователя(ей) сказали Спасибо Жека за это полезное сообщение:
ABTOMAT (19.10.2009), johnk (19.10.2009), moka (20.10.2009), Nex (19.10.2009), NitE (19.10.2009), Randomize (15.04.2010), SubZer0 (29.12.2009), Данил (19.10.2009)
Старый 19.10.2009, 20:33   #2
ABTOMAT
Ференька
 
Аватар для ABTOMAT
 
Регистрация: 25.01.2007
Адрес: улица Пушкина дом Колотушкина
Сообщений: 10,453
Написано 5,278 полезных сообщений
(для 15,253 пользователей)
Ответ: Разрывание рисунка на куски и растворение

Нельзя ли выложить скомпиленное? Так заинтересовало, что даже посмотреть захотелось, а БМакса нет-с За урок спасибо. Идея оригинальная, использует преимущества аппаратного рендера БМакса и не сложна в реализации.
__________________
Мои проекты:
Анальное Рабство
Зелёный Слоник
Дмитрий Маслов*
Различие**
Клюква**

* — в стадии разработки
** — в стадии проектирования
Для проектов в стадии проектирования приведены кодовые имена

(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
moka (20.10.2009)
Старый 20.10.2009, 00:45   #3
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,861 пользователей)
Ответ: Разрывание рисунка на куски и растворение

Очень хороший пример, и интересная реализация.
Поддерживаю предыдущего оратора - скомпиленную ехе'шку хочется.
Если указать фрэймворк, и заинклудить что нада, будет очень лёгкая ехе.
(Offline)
 
Ответить с цитированием
Старый 20.10.2009, 03:04   #4
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,374
Написано 489 полезных сообщений
(для 882 пользователей)
Ответ: Разрывание рисунка на куски и растворение

Прицепил архив с exe-шником и новым исходником.

В новом коде небольшие изменения: в класс TParticle добавил поле deep, эта переменная аналогична переменной dir, только та для направления вращения, а эта для направления масштабирования, т.е. задает - увеличивать картинку или уменьшать при анимации.
Так же принимает случайное значение - или 1, или -1.
deep = 1 - 2 * (Rand(100) < 50)

Для получения результата в функции обновления куска приращение масштаба умножается на значение этой переменной:
scale:+dScale * deep

Теперь часть осколков летит к смотрящему, приближаясь, а часть - отдаляется, тем самым объёмность прослеживается чётче.
Отдаление только для взрыва, для растворения некрасиво с ним.

Спасибо за беседу
Вложения
Тип файла: rar pixAlpha2.rar (154.5 Кб, 211 просмотров)
(Offline)
 
Ответить с цитированием
Эти 3 пользователя(ей) сказали Спасибо Жека за это полезное сообщение:
moka (20.10.2009), Nex (20.10.2009), teremochek (03.07.2010)
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +1, время: 16:25.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com