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

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

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

Ответ
 
Опции темы
Старый 04.02.2010, 12:55   #1
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,374
Написано 489 полезных сообщений
(для 882 пользователей)
Пример 1. Обработка мышки. Класс TMouse

Обновил пример. Что нового:
- обработка колёсика мышки
- возможность обрабатывать все доступные кнопки мышки - состояния хранятся в массиве
- методы для получения значений полей класса, чтобы "случайно" не присвоить значение
- получение скоростей перемещения
- сброс нажатий (flush)

Количество кнопок для обработки указывается при создании экземпляра мышки:
Global mouse:TMouse = TMouse.fnCreate(3)
Получение состояний - по номеру кнопки:
If(mouse.fnKeyUp(1) = True)
----------------------------------------------------------------

Что можно сделать, используя данный класс:

• Определение текущих координат мышки (X, Y, Z)
• Определение момента нажатия кнопок мыши (hit)
• Определение нажатого состояния кнопок мыши (down)
• Определение момента отпускания кнопок мышки (up)
• Определение координат последнего щелчка (для каждой кнопки)
• Ограничение области перемещения мышки в виде прямоугольника
• Установка фиксированной позиции мышки для текущего прохода цикла

Работа показана на примере программы, рисующей отрезки.

Суть – при нажатии левой кнопки мышки создаётся отрезок, первая часть которого принимает координаты щелчка, а вторая «привязывается» к текущим координатам мышки. Удерживая нажатой левую кнопку мышки, можно изменять положение конца отрезка. При отпускании кнопки рисование текущего отрезка завершается, и он добавляется в список.

На экране показывается дополнительная информация о состоянии мышки.

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

Примечание: нет обработки колёсика мышки (кому надо - добавят легко).

Скриншот:
Нажмите на изображение для увеличения
Название: mouse1.jpg
Просмотров: 388
Размер:	19.9 Кб
ID:	8976

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

Strict

Framework brl.d3d7max2d
Import brl.pngloader



'параметры экрана
Global screenW = 600
Global screenH = 700
Global screenD = 0
Local screenHertz = 75
Local screenFlags = GRAPHICS_BACKBUFFER


'заголовок окна приложения
AppTitle = "Использование класса TMouse"

'создаем окно
SetGraphicsDriver(D3D7Max2DDriver())
Graphics (screenW, screenH, screenD, screenHertz, screenFlags)


'флаг для условия выхода из игрового цикла 
Global onRunning = True

'кнопки
Global keyEsc, keySpace, keyClose


'прячем стандартный курсор и ставим в середину окна
HideMouse()
MoveMouse(screenW * 0.5, screenH * 0.5)

'создаем "мышку" для обработки нажатий и прочего
Global mouse:TMouse = TMouse.fnCreate(3)
Local img:TImage = LoadImage("pointer.png")
mouse.fnSetPointer(img)
mouse.fnSetBounds(250, 200, 255, 300, False)


Local cntHit1, cntHit2, cntUped1, cntUped2


Global painter:TPainter = New TPainter


'главный цикл
While (onRunning = True)
	
	'получаем новые нажатия кнопок
	fnCheckKeyInput()
	
	'если нажали на крестик "закрыть" или Esc - выход
	If(keyEsc = True Or keyClose = True)
		onRunning = False
		Exit
	EndIf

	'вкл/выкл ограничивающий прямоугольник
	If(keySpace = True) mouse.onUseBounds = Not(mouse.onUseBounds)
	
	'обновляем мышку
	mouse.fnUpdate()
	'рисуем ограничивающий прямоугольник
	mouse.fnDrawBounds()
	
	If(mouse.fnKeyHit(1) = True)
		cntHit1:+1
		'тут что-нибудь делаем по нажатию левой кнопки мыши
	EndIf
	
	If(mouse.fnKeyHit(2) = True) cntHit2:+1
	If(mouse.fnKeyUp(1) = True) cntUped1:+1
	If(mouse.fnKeyUp(2) = True) cntUped2:+1
	
	SetColor(255, 255, 255)
	
	DrawText("cntHit1 = " + cntHit1, 20, 20)
	DrawText("cntHit2 = " + cntHit2, 20, 40)
	
	DrawText("mouseDown(1) = " + mouse.fnKeyDown(1), 20, 80)
	DrawText("mouseDown(2) = " + mouse.fnKeyDown(2), 20, 100)
	
	DrawText("cntUped1 = " + cntUped1, 20, 140)
	DrawText("cntUped2 = " + cntUped2, 20, 160)
	
	DrawText("curX = " + mouse.x, 20, 200)
	DrawText("curY = " + mouse.y, 20, 220)
	
	DrawText("hitX(1) = " + mouse.fnGetHitX(1), 20, 260)
	DrawText("hitY(1) = " + mouse.fnGetHitY(1), 20, 280)
	
	DrawText("Space - on/off bound rect", 20, 320)
	
	painter.fnUpdate(mouse.x, mouse.y)
	painter.fnDraw()
	
	'рисуем мышку
	mouse.fnDraw()
	
	Flip(0)
	Cls()
			
Wend


End



'проверка состояния нажатых кнопок
Function fnCheckKeyInput()
	keyEsc = (KeyHit(KEY_ESCAPE) > 0)
	keySpace = (KeyHit(KEY_SPACE) > 0)
	keyClose = AppTerminate()
	
End Function



'класс мышки
Type TMouse
	Field x, y, z
	Field mHitX[], mHitY[]
	Field mHit[]
	Field mDown[]
	Field mUp[]
	Field pointer:TImage
	Field visible = True
	Field blockX, blockY, blockZ
	
	Field btnCount
	Field speedX, speedY, speedZ
	
	Field bx, by, bw, bh 'ограничивающая область
	Field onUseBounds
	
	Global k
	
	
	'"конструктор с параметром"
	Function fnCreate:TMouse(btnCnt = 3)
		Local m:TMouse = New TMouse
		m.btnCount = btnCnt
		m.mHit = New Int[btnCnt]
		m.mDown = New Int[btnCnt]
		m.mUp = New Int[btnCnt]
		m.mHitX = New Int[btnCnt]
		m.mHitY = New Int[btnCnt]
		Return m
	End Function
	
	
	'обновление
	Method fnUpdate()
		
		If(blockX = False)
			x = MouseX()
			speedX = MouseXSpeed()
		EndIf
		
		If(blockY = False)
			y = MouseY()
			speedY = MouseYSpeed()
		EndIf
		
		If(blockZ = False)
			z = MouseZ()
			speedZ = MouseZSpeed()
		EndIf
		
		blockX = False
		blockY = False
		blockZ = False
		
		'корректировка позиции
		fnCorrectPosByBounds()
		
		For k = 0 Until btnCount
			mUp[k] = mDown[k]
			mHit[k] = (MouseHit(k + 1) > 0)
			mDown[k] = MouseDown(k + 1)
			
			If(mHit[k] = True)
				mHitX[k] = x
				mHitY[k] = y
			EndIf
			
			If(mUp[k] = True And mDown[k] = False)
				mUp[k] = True
			Else
				mUp[k] = False
			EndIf
			
		Next
		
	End Method
	
	
	'корректировка позиции - возвращаем в допустимую область
	Method fnCorrectPosByBounds()
		If(onUseBounds = False) Return
		
		If(x < bx) x = bx
		If(y < by) y = by
		If(x > bx + bw) x = bx + bw
		If(y > by + bh) y = by + bh
		MoveMouse(x, y)
	
	End Method
		
	
	'блокировка на 1 ход в указанной позиции
	Method fnBlock(px, py, pz = -1)
				
		If(px >= 0)
			x = px
			blockX = True
		EndIf
		If(py >= 0)
			y = py
			blockY = True
		EndIf
		If(pz >= 0)
			z = pz
			blockZ = True
		EndIf
		
		MoveMouse(x, y)
		
	End Method
	
	
	'установка картинки указателя мыши
	Method fnSetPointer(img:TImage)
		pointer = img
	End Method
	
	
	'рисование
	Method fnDraw(dx = 0, dy = 0)
		If(visible = False Or pointer = Null) Return
		
		SetAlpha(1)
		SetColor(255, 255, 255)
		DrawImage(pointer, x + dx, y + dy)
		
	End Method
	
	
	'рисование ограничивающего прямоугольника
	Method fnDrawBounds()
		If(onUseBounds = True)
			SetColor(155, 155, 155)
			DrawLine(bx, by, bx + bw, by)
			DrawLine(bx + bw, by, bx + bw, by + bh)
			DrawLine(bx + bw, by + bh, bx, by + bh)
			DrawLine(bx, by + bh, bx, by)
		EndIf
	End Method
	
	
	'показать указатель
	Method fnShow()
		visible = True
	End Method
	
	
	'скрыть указатель
	Method fnHide()
		visible = False
	End Method
	
	
	'ограничивающая область
	Method fnSetBounds(px, py, pw, ph, use = True)
		bx = px
		by = py
		bw = pw
		bh = ph
		onUseBounds = use
	End Method
	
	
	'проверка - щелчок кнопки
	Method fnKeyHit(button)
		If(button < 1 Or button > btnCount) Return False
		Return mHit[button - 1]
	End Method
	
	
	'проверка - удержание нажатой кнопки
	Method fnKeyDown(button)
		If(button < 1 Or button > btnCount) Return False
		Return mDown[button - 1]
	End Method
	
	
	'проверка - отпускание кнопки
	Method fnKeyUp(button)
		If(button < 1 Or button > btnCount) Return False
		Return mUp[button - 1]
	End Method
	
	
	'Х-координата последнего нажатия кнопки
	Method fnGetHitX(button = 1)
		If(button < 1 Or button > btnCount) Return - 1
		Return mHitX[button - 1]
	End Method
	
	
	'У-координата последнего нажатия кнопки
	Method fnGetHitY(button = 1)
		If(button < 1 Or button > btnCount) Return - 1
		Return mHitY[button - 1]
	End Method
	
	
	'возвращение координаты Х
	Method fnGetX()
		Return x
	End Method
	
	
	'возвращение координаты Y
	Method fnGetY()
		Return y
	End Method
	
	
	'возвращение координаты Z
	Method fnGetZ()
		Return z
	End Method
	
	
	'возвращение скорости по Х
	Method fnGetSpeedX()
		Return speedX
	End Method
	
	
	'возвращение скорости по Y 
	Method fnGetSpeedY()
		Return speedY
	End Method
	
	
	'возвращение скорости по Z
	Method fnGetSpeedZ()
		Return speedZ
	End Method
	
	
	'сброс состояний всех кнопок
	Method fnFlush()
		FlushMouse()
		For k = 0 Until btnCount
			mHit[k] = False
			mDown[k] = False
			mUp[k] = False
		Next
	End Method
	
End Type



'рисовалка линий
Type TPainter
	Field x0:Float, y0:Float
	Field lineWidth = 2
	Field curLine:TLine
	
	Global list:TList = New TList 'список для отрезков
	Global line:TLine
	Global linesCount
	
	
	'обновление
	Method fnUpdate(x:Float, y:Float)
		
		'при щелчке мыши создаём новую линию
		If(mouse.fnKeyHit(1) = True)
			curLine = TLine.fnCreate(x, y, x, y)
		EndIf
		
		'двигаем конец за мышкой
		If(curLine <> Null) curLine.fnSetEnd(x, y)
		
		'при отпускании кнопки мыши добавляем линию в список
		If(mouse.fnKeyUp(1) = True)
			list.AddLast(curLine)
			linesCount:+1
			curLine = Null
		EndIf
		
	End Method
	
	
	'рисование
	Method fnDraw()
		SetColor(255, 255, 255)
		SetLineWidth (lineWidth)
		For line = EachIn list
			line.fnDraw(x0, y0)
		Next
		line = Null
		
		If(curLine <> Null) curLine.fnDraw(x0, y0)
	End Method
	
	
	'сдвинуть начало координат
	Method fnMove(dx:Float, dy:Float)
		x0:+dx
		y0:+dy
	End Method
	
End Type



'линия
Type TLine
	Field x1:Float, x2:Float, y1:Float, y2:Float
	
	'конструктор с параметрами
	Function fnCreate:TLine(x1:Float, y1:Float, x2:Float, y2:Float)
		Local ln:TLine = New TLine
		ln.x1 = x1
		ln.y1 = y1
		ln.x2 = x2
		ln.y2 = y2
		Return ln
	End Function
	
	
	'установка начальных координат
	Method fnSetStart(x:Float, y:Float)
		x1 = x
		y1 = y
	End Method
	
	
	'установка конечных координат
	Method fnSetEnd(x:Float, y:Float)
		x2 = x
		y2 = y
	End Method
	
	
	'рисование
	Method fnDraw(x0:Float, y0:Float)
		DrawLine(x0 + x1, y0 + y1, x0 + x2, y0 + y2)
	End Method
	
End Type
Вложения
Тип файла: rar TMouse_src.rar (3.9 Кб, 177 просмотров)
Тип файла: rar TMouse_src_i_exe.rar (164.3 Кб, 172 просмотров)

Последний раз редактировалось Жека, 05.02.2010 в 04:48. Причина: Дополненил пример.
(Offline)
 
Ответить с цитированием
Эти 3 пользователя(ей) сказали Спасибо Жека за это полезное сообщение:
G.A.D (04.02.2010), Randomize (05.02.2010), SBJoker (09.02.2010)
Старый 04.02.2010, 16:13   #2
G.A.D
Разработчик
 
Регистрация: 28.02.2009
Сообщений: 434
Написано 44 полезных сообщений
(для 96 пользователей)
Ответ: Пример 1. Обработка мышки. Класс TMouse

Молодец!
но зачем?
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Жека (05.02.2010)
Старый 05.02.2010, 00:06   #3
Randomize
[object Object]
 
Аватар для Randomize
 
Регистрация: 01.08.2008
Адрес: Планета Земля
Сообщений: 4,134
Написано 2,327 полезных сообщений
(для 6,472 пользователей)
Ответ: Пример 1. Обработка мышки. Класс TMouse

При выходе мышки за пределы получается "дрыганье".
Отнимай от позиции x и y MouseXSpeed() и MouseYSpeed().
Стандартно на мыши 3 кнопки, но бывает и больше так что по хорошему использовать массив.
Курсор - картинка внутри класса тоже не очень корректно.
Придётся переписывать класс если курсор динамический (анимационный и меняется от определённых событий)
__________________
Retry, Abort, Ignore? █
AMD Ryzen 7 1700X x8 3.4Ghz; 16Gb ram; Radeon RX 570
AMD Athlon II x4 2.6Ghz; 8Gb ram; Nvidia Geforce GTX 750 Ti
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Жека (05.02.2010)
Старый 05.02.2010, 05:11   #4
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,374
Написано 489 полезных сообщений
(для 882 пользователей)
Ответ: Пример 1. Обработка мышки. Класс TMouse

Сообщение от G.A.D
Молодец!
но зачем?
Мне удобнее, когда все переменные для мышки в одном классе. Создал экземпляр и обращайся к ним через точечку.
И новичкам может пригодиться.

Сообщение от Randomize
При выходе мышки за пределы получается "дрыганье".
Отнимай от позиции x и y MouseXSpeed() и MouseYSpeed().
Рисуемая картинка курсора не имеет склонности дёргаться, а системный курсор - да, т.к. он рисуется самой системой. Для него самое то отнимать скорость

Сообщение от Randomize
Стандартно на мыши 3 кнопки, но бывает и больше так что по хорошему использовать массив.
Я тоже так думал. Сделал.

Сообщение от Randomize
Курсор - картинка внутри класса тоже не очень корректно.
Придётся переписывать класс если курсор динамический (анимационный и меняется от определённых событий)
Для таких случаев просто координаты понадобятся. Ну или обработку состояний в классе мышки дописать, тогда всё мышиное в одном месте будет.
Переносимость в другой проект - легко, т.к. изменения незначительными окажутся.

Картинка внутри класса не оч корректна из-за нестыковки с менеджером ресурсов или что-то ещё?
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Randomize (09.02.2010)
Старый 05.02.2010, 08:03   #5
Randomize
[object Object]
 
Аватар для Randomize
 
Регистрация: 01.08.2008
Адрес: Планета Земля
Сообщений: 4,134
Написано 2,327 полезных сообщений
(для 6,472 пользователей)
Ответ: Пример 1. Обработка мышки. Класс TMouse

Создай обьект TCursor
От которого сделай два класса наследника.
TAnimateCursor
TStaticCursor
Хотя по хорошему мышь и курсор должны быть на разных уровнях абстрауции.
__________________
Retry, Abort, Ignore? █
AMD Ryzen 7 1700X x8 3.4Ghz; 16Gb ram; Radeon RX 570
AMD Athlon II x4 2.6Ghz; 8Gb ram; Nvidia Geforce GTX 750 Ti
(Offline)
 
Ответить с цитированием
Старый 05.02.2010, 10:44   #6
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,374
Написано 489 полезных сообщений
(для 882 пользователей)
Ответ: Пример 1. Обработка мышки. Класс TMouse

Они мне не нужны.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Randomize (09.02.2010)
Старый 09.02.2010, 13:24   #7
Randomize
[object Object]
 
Аватар для Randomize
 
Регистрация: 01.08.2008
Адрес: Планета Земля
Сообщений: 4,134
Написано 2,327 полезных сообщений
(для 6,472 пользователей)
Ответ: Пример 1. Обработка мышки. Класс TMouse

За MouseUP спасибо :D
Сейчас понадобилось и чтоб голову не ломать взял кусочек твоего кода.

Кстати заметил тут:
Global k
переменная "k" спользуется для цикла.
For k = 0 Until btnCount
Не легче бы избавится от этого глобала так:
For Local k% = 0 Until btnCount
Или тебя беспокоит, что локальная переменная будет каждый раз создаватся?
__________________
Retry, Abort, Ignore? █
AMD Ryzen 7 1700X x8 3.4Ghz; 16Gb ram; Radeon RX 570
AMD Athlon II x4 2.6Ghz; 8Gb ram; Nvidia Geforce GTX 750 Ti
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Жека (10.02.2010)
Старый 09.02.2010, 17:20   #8
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,429
Написано 3,453 полезных сообщений
(для 6,859 пользователей)
Ответ: Пример 1. Обработка мышки. Класс TMouse

Делать проверку на зажатие каждый цикл - затратно.
Зажатие проверяй Только после нажатия, и до отжатия.
Если будешь релизовывать класс для клавиатуры, используй GetChar.Функции получения инпута, не такие и шустрые.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Жека (10.02.2010)
Старый 10.02.2010, 05:35   #9
Randomize
[object Object]
 
Аватар для Randomize
 
Регистрация: 01.08.2008
Адрес: Планета Земля
Сообщений: 4,134
Написано 2,327 полезных сообщений
(для 6,472 пользователей)
Ответ: Пример 1. Обработка мышки. Класс TMouse

0-1 ms на выполнение Mouse.Update()
__________________
Retry, Abort, Ignore? █
AMD Ryzen 7 1700X x8 3.4Ghz; 16Gb ram; Radeon RX 570
AMD Athlon II x4 2.6Ghz; 8Gb ram; Nvidia Geforce GTX 750 Ti
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Nex (10.02.2010)
Старый 10.02.2010, 10:44   #10
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,374
Написано 489 полезных сообщений
(для 882 пользователей)
Ответ: Пример 1. Обработка мышки. Класс TMouse

Сообщение от Randomize Посмотреть сообщение
За MouseUP спасибо :D
Сейчас понадобилось и чтоб голову не ломать взял кусочек твоего кода.
Вот и хорошо

Сообщение от Randomize Посмотреть сообщение
Или тебя беспокоит, что локальная переменная будет каждый раз создаватся?
Что-то вроде того. Для одного места использования особого смысла нет, а для нескольких я стараюсь делать глобальные.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
Randomize (10.02.2010)
Ответ


Опции темы

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

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


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


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