Показать сообщение отдельно
Старый 28.07.2010, 14:44   #9
Hurrit
Мастер
 
Аватар для Hurrit
 
Регистрация: 27.01.2008
Адрес: Россия, СКФО, ЧР, Грозный
Сообщений: 1,144
Написано 578 полезных сообщений
(для 2,207 пользователей)
Ответ: Делаем квест на Xors3D

Внимание: В данной версии используется новая ревизия Xors3D. Так что, не забудьте обновиться.

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

Первые три буквы будут obj, для обозначения того, что это рабочий объект.
Затем, будет идти номер типа объекта, это будет 7 (кстати, это новый тип объекта).
И, последние три цифры будут означать ID объекта.

Затем, использую ID объекта, мы получим файл с текстом для NPC. К примеру, для NPC с ID 013, текст будет носить имя "13.txt". Структура текста будет такой:

Сначала будет идти первая фраза NPC c ID 001. После, с этими же ID будут выходить варианты ответа для игрока. У каждого варианта ответа будет свой ID для ответа. Если ID равен 100, то диалог обрывается. Звучит сложно, но давайте посмотрим, как это выглядит на практике:

001 Чего надо?
001 Привет! 002
001 Ничего. 100
002 Привет. Так, чего надо?
002 Как открыть дверь? 003
002 Спасибо, ничего. 100
003 Найди ключ!
003 Спасибо за совет! 100


Смотрите, если игрок ответит "Привет!", то высветиться фраза "Привет. Так, чего надо?", а если выберит "Ничего.", то диалог закроется, и в таком духе. Попробуем написать код:

Function UpdatePlayer()
	mxspd#=xMouseXSpeed()*0.05 ; Получаем координаты передвижения мышки по Х
	myspd#=xMouseYSpeed()*0.05 ; Получаем координаты передвижения мышки по Y
	
	If inv_draw=0 xMoveMouse xGraphicsWidth()/2,xGraphicsHeight()/2 ; Передвигаем мышку в центр окна
	If xEntityPitch(camera)+myspd<-89 xRotateEntity camera,-89,0,0 ; Проверяем угол поворота камеры по X
	If xEntityPitch(camera)+myspd>89 xRotateEntity camera,89,0,0 ; Проверяем угол поворота камеры по X
	xRotateEntity camera,xEntityPitch(camera)+myspd,0,0 ; Поворачиваем камеру по X
	xRotateEntity player,0,xEntityYaw(player)-mxspd,0 ; Поворачиваем камеру по Y
	
	If xKeyDown(KEY_W) xMoveEntity player,0,0,0.5
	If xKeyDown(KEY_S) xMoveEntity player,0,0,-0.5
	If xKeyDown(KEY_A) xMoveEntity player,-0.5,0,0
	If xKeyDown(KEY_D) xMoveEntity player,0.5,0,0
	If xMouseHit(2) inv_draw=1-inv_draw ; Если нажата правая кнопка мыши, то меняем значение inv_draw на обратное
	
	If inv_draw=1 Then ; Если inv_draw=1, то отрисовываем и обновляем наш инвентарь
		InventoryDraw()
		InventoryUpdate()
	EndIf
	
	If dialog<>0 Then ; Если мы пикнули какой-нибудь NPC, то начинается диалог с NPC, ID у которого равен dialog
		If first_open=1 Then ; Если, это первое (Прим.: не самое первое, а первое после того, как был пикнут NPC) открытие диалога, то
			npc_text=ReadFile(dialog+".txt") ; Открываем текст для NPC с его ID
			first_open=0 ; Меняем переменную, дабы наш файл больше не открывался

			i=1 ; Это нужно для цикла
	
			While Not Eof(npc_text) ; Пока наш текст не закончиться
				string_npc$=ReadLine(npc_text) ; Считываем строчку
	
				render(i)=New npc ; Создаем новое поле в render()
					render(i)\id=Int(Left(string_npc,3)) ; Выдаем ему ему ID
					
					If Int(Right(string_npc,3))<>0 Then ; Если сбоку есть ID (Прим.: это надо для того, чтобы определять где ответы)
						render(i)\next_id=Int(Right(string_npc,3)) ; Выдаем для ответа ID следующей фразы NPC, в случае, если выберут этот ответ
						render(i)\npc_string=Mid(string_npc,5,Len(string_npc)-8) ; Ну и конечно же, даем ему его текст
					Else
						render(i)\npc_string=Mid(string_npc,5,Len(string_npc)) ; В против случае, просто выдаем текст для фразы NPC
					EndIf	
				i=i+1 ; Это необходимо для того, чтобы не перезаписалась уже записанная строка render()
			Wend		
			CloseFile(npc_text) ; После обработки текста, закрываем файл
		EndIf		
		
		For i=1 To 100 ; Пробегаемся по всему render()
			 If render(i)<>Null Then ; Если поле render(i) заполнено
				If render(i)\id=start_id Then ; И его ID совпадает с ID первой фразы NPC
					xText 100,20*i,render(i)\npc_string ; Тогда, пишем фразу
					
					If RectsOverlap(xMouseX(),xMouseY(),1,1,150,20*i,100,24) Then ; Если мышка находится над строкой
						If xMouseDown(1) And (render(i)\next_id<>0) start_id=render(i)\next_id ; И левая клавиша мышки зажата, а также, ID следующей фразы не равна 0 (необходимо для определения ответа), тогда следующая фраза NPC равна render(i)\next_id
						If start_id=100 Then ; Если start_id=100
							For render(i)=Each npc ; Тогда, зачищаем весь render()
								Delete render(i)
							Next
							dialog=0 ; И закрываем диалог
						EndIf
					EndIf
				EndIf
			EndIf
		Next
	EndIf
	
	If selected_obj<>0 xDrawImage selected_obj,600,100 ; Если у нас имеется выбранный предмет, то отрисовываем его
	If win=1 Then ; Если win равен 1, то 
		xText 400,300,"Game Over",True ; Показывать надпись "Game Over"
	EndIf
	
	Select xKeyDown(KEY_LCONTROL)
		Case True
			xPositionEntity camera,0,5,0
			
		Case False
			xPositionEntity camera,0,15,0
	End Select
	
	If xKeyHit(KEY_E) Then
		xCameraPick(camera,xMouseX(),xMouseY()) ; Делаем пик камерой
		picked=xPickedEntity() ; Даем picked'у значение "пойманного" нами объекта
		picked_name$=xEntityName(picked) ; Получаем имя picked'a
	EndIf
	
	If picked<>0 Then ; Проверяем, равен ли picked 0
		If Instr(picked_name,"obj") Then ; Проверяем, есть ли в имени picked'a "obj"
			id=Mid(picked_name,5,3) ; Получаем ID объекта
				Select obj(id)\obj_type ; Узнаем, какой тип объекта мы пикнули
				
					Case 1 ; Если тип 1, то
						If xAnimating(obj(id)\entity)=0 Then ; Проверяем, играет ли сейчас какая-нибудь анимация
							Select obj(id)\time ; Узнаем, какая была последняя анимация
								Case 0 ; Если закрытия, то проигрываем открывание
									xAnimate obj(id)\entity,3,1,1
									obj(id)\time=1 ; Меняем состояние
								Case 1
									xAnimate obj(id)\entity,3,1,2 ; Если открытия, то проигрываем закрывание
									obj(id)\time=0 ; Меняем состояние
							End Select					
						EndIf
						
					Case 2
						InventoryAddItem(id) ; Добавляем в инвентарь картинку с ID объекта
						xHideEntity obj(id)\entity ; Скрываем объект
						
					Case 3
						If selected_id=obj(id)\id_object Then ; Проверяем, сходится ли ID объекта выбранного из инвентаря, с ID объектом, который надо применять для данного предмета
							xAnimate obj(id)\entity,3,1,1 ; Если да, то проигрываем анимацию
							xFreeImage inv(selected_num)\image ; Удаляем предмет из инвентаря
							
							If id=12 Then ; Если ID равен ID последней двери, то
								win=1 ; Присвоить переменной win значение 1
							EndIf
							
							selected_id=0 ; Обнуляем ID выбранного предмета
							inv(selected_num)\id=0
							selected_num=0
						EndIf
						
						
					Case 4
						If selected_id=obj(id)\id_object Then ; Проверяем, сходится ли ID объекта выбранного из инвентаря, с ID объектом, который надо применять для данного предмета
							xAnimate obj(obj(id)\id_child1)\entity,3,1,1  ; Если да, то проигрываем анимацию объекта номер 1
							xShowEntity obj(obj(id)\id_child2)\entity ; И показываем объект номер 2
							xFreeImage inv(selected_num)\image ; Удаляем предмет из инвентаря
							selected_id=0 ; Обнуляем ID выбранного предмета
							inv(selected_num)\id=0
							selected_num=0
						EndIf

					Case 7
						dialog=id ; Даем dialog ID пикнутого NPC
						first_open=1 ; Это описанно выше
						start_id=1 ; Даем start_id ID первой фразы NPC
						
				End Select
		EndIf
	EndIf
	
End Function
Также, нам необходимо добавить следующие строчки:

Global dialogfirst_opennpc_textstart_id

Dim render
.npc(100)

Type npc
    Field id
%, next_id%
    
Field npc_string$
End Type 
Также, давайте увеличим шрифт, чтобы лучше читалось:

xSetFont xLoadFont("Arial Cyr",24,True
Примечание: Вставьте эту строчку где-то после globals.

Вот и всё. Вы можете улучшить алгоритм, добавить больше возможностей, всё по Вашему усмотрению. Удачи!
Вложения
Тип файла: rar Quest.rar (170.1 Кб, 1077 просмотров)
(Offline)
 
Ответить с цитированием
Эти 9 пользователя(ей) сказали Спасибо Hurrit за это полезное сообщение:
Артем Валерьевич (01.08.2010), baton4ik (01.08.2010), Coover (10.02.2012), drave (28.07.2010), Gector (29.05.2012), pax (28.07.2010), Randomize (11.10.2011), Skaner (03.02.2012), St_AnGer (28.07.2010)