|
Полезные функции Выкладываем полезные функции, чтоб не изобретать велосипед заново... |
10.04.2012, 11:08
|
#1
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Правильная загрузка конфиг файла
Сегодня начал писать загрузку конфигураций и мне понравилось что получилось
Я сделал так, что если какой-нибудь умник залезет править конфиги и накосячит, то файл просто удаляется и пишется новый с дефаулт конфигами
Global fileConfig Global fileConfigError=False Global graphicsW Global graphicsH Global graphicsD Global graphicsM Global cameraViewSens# Const cameraViewSensMin#=0.5 Const cameraViewSensMax#=5 Const cameraViewSensDefault#=2 LoadFileConfig() ;загрузка файла настроек Function LoadFileConfig() fileConfig=OpenFile("config.ini") ;-----------eсли файл есть--------------------------- If fileConfig<>0 Then graphicsW=ReadLine(fileConfig) graphicsH=ReadLine(fileConfig) graphicsD=ReadLine(fileConfig) If GfxMode3DExists(GraphicsW,GraphicsH,GraphicsD)=False Then fileConfigError=True graphicsM=ReadLine(fileConfig) If GraphicsM<0 Or GraphicsM>3 Then fileConfigError=True cameraViewSens#=ReadLine(fileConfig) If cameraViewSens<cameraViewSensMin Or cameraViewSens>cameraViewSensMax Then fileConfigError=True If fileConfigError=False Then Graphics3D GraphicsW,GraphicsH,GraphicsD,GraphicsM If fileConfigError=True Then DeleteFile fileConfig : fileConfig=0 EndIf ;-----------если файла нет--------------------------- If fileConfig=0 Then ;считываем все поддерживаемые видео режимы For i=1 To CountGfxModes3D() If GfxMode3DExists(GfxModeWidth(i),GfxModeHeight(i),GfxModeDepth(i)) Then modeN=modeN+1 Next Graphics3D GfxModeWidth(modeN),GfxModeHeight(modeN),GfxModeDepth(modeN),1 ;выставляем самый высокий видео режим GraphicsW=GraphicsWidth() GraphicsH=GraphicsHeight() GraphicsD=GraphicsDepth() GraphicsM=1 cameraViewSens=cameraViewSensDefault fileConfig=WriteFile("config.ini") WriteLine(fileConfig,GraphicsW) WriteLine(fileConfig,GraphicsH) WriteLine(fileConfig,GraphicsD) WriteLine(fileConfig,GraphicsM) WriteLine(fileConfig,cameraViewSens) EndIf ;------------------------------------------------------------ CloseFile fileConfig End Function
__________________
|
(Offline)
|
|
10.04.2012, 13:56
|
#2
|
Разработчик
Регистрация: 09.08.2006
Адрес: Украина
Сообщений: 431
Написано 65 полезных сообщений (для 53 пользователей)
|
Ответ: Правильная загрузка конфиг файла
Кул. Было б круче увидеть набор функций для файла конфигов такого типа:
config.ini
GrWidth=1024
GrHeight=768
GrDeepth=32
GrMode=2
Я имею в виду, чтоб можно было записать все как выше, а можно было б написать так: (и не было б разницы для программы)
GrDeepth=32
GrWidth=1024
;бла бла бла - комментарий
GrHeight=768 GrMode=2
А в случае фейла каких либо параметров - генерировать новые.
|
(Offline)
|
|
10.04.2012, 14:30
|
#3
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Ответ: Правильная загрузка конфиг файла
Это просто "длясебятина" )
Мне такая заморочка не нужна.
Тем более такой подход не избавит от правки кода при изменении полей (я про то что все равно придется в коде прописывать откат), короче я к тому что такой подход жизнь особо не облегчит в конфиг файле, а вот загрузчике уровня, где может быть сотни объектов с десятком параметром, без твоей методы не обойтись!
Суть я раскрыл, а кому надо уже доработают
__________________
|
(Offline)
|
|
10.04.2012, 15:03
|
#4
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Ответ: Правильная загрузка конфиг файла
что-то типа (код грязненький)
Const CfgLoader__SEP$="="
Type TOneCfgParam
Field Name$
Field Value$
End Type
Function CfgLoader_CreateParam.TOneCfgParam(Name$,Val$)
;DebugLog Name+"="+Val
Local OCP.TOneCfgParam=New TOneCfgParam
OCP\Name=Name
OCP\Value=Val
Return OCP
End Function
Function CfgLoader_GetParam.TOneCfgParam(Name$)
For OCP.TOneCfgParam=Each TOneCfgParam
If OCP\Name=Name
Return OCP
EndIf
Next
Return Null
End Function
Function CfgLoader_GetParamVal$(Name$)
Local OCP.TOneCfgParam=CfgLoader_GetParam(Name)
If OCP=Null
RuntimeError "Param "+Name+" not found!"
EndIf
Return OCP\Value
End Function
Function CfgLoader_ParseParam.TOneCfgParam(OneLine$)
Local I%=Instr(OneLine,CfgLoader__SEP,1)
Local Name$=Left(OneLine,I-1)
Local Value$=Right(OneLine,Len(OneLine)-I)
Return CfgLoader_CreateParam(Name,Value)
End Function
Function CfgLoader_LoadCfgFromFile(FileName$)
Local File%=ReadFile(FileName)
If File=False
RuntimeError "File "+FileName+" not found!"
EndIf
Local OneLine$
While Not Eof(File)
OneLine=ReadLine(File)
CfgLoader_ParseParam(OneLine)
Wend
CloseFile(File)
End Function
Сообщение от cfg.txt
WinXSize=800
WinYSize=600
|
CfgLoader_LoadCfgFromFile("cfg.txt")
Global WinXSize%=Int(CfgLoader_GetParamVal("WinXSize"))
Global WinYSize%=Int(CfgLoader_GetParamVal("WinYSize"))
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
Эти 3 пользователя(ей) сказали Спасибо impersonalis за это полезное сообщение:
|
|
10.04.2012, 16:34
|
#5
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Ответ: Правильная загрузка конфиг файла
Прикольно!
Мне до такого еще далеко...
Объясните пожалуста, зачем нужна точка в функции CfgLoader_ParseParam.TOneCfgParam(OneLine$)
Т.е. функция пишется специально для этого типа?
И еще, я сейчас пишу загрузчик уровня, прокоментируйте пожалуста какие недостатки и подводные камни могут быть
Function LoadLevel(levelName) sx#=0.0 sy#=0.0 sz#=0.0 Select levelName Case levelNameMain file=OpenFile("main.lev") End Select While Not Eof(file) s$=ReadLine(file) ;ищет объект If StrLeft(s,"ground")=True Then sEntity=CreateTerrain(256) If StrLeft(s,"tree")=True Then tree.tree=New tree : tree\entity=LoadMesh("tree.b3d") ;ищет параметр If StrLeft(s,"x")=True Then MoveEntity sEntity,FloatRight(s),0,0 If StrLeft(s,"y")=True Then MoveEntity sEntity,0,FloatRight(s),0 If StrLeft(s,"z")=True Then MoveEntity sEntity,0,0,FloatRight(s) Wend CloseFile file End Function Function StrLeft%(Str1$,Str2$) If Left(Str1,Len(Str2))=Str2 Then Return True End Function Function FloatRight#(S$) s=Trim(s) ReadThis%=True res$="" tmp$="" For i=0 To Len(S)-1 simbol$=Mid(S,Len(s)-i,1) If ReadThis=True If (Asc(simbol)>=48 And Asc(simbol)<=57) Or simbol="." Then res=simbol+res Else ReadThis=False EndIf EndIf Next Return Float(res) End Function
__________________
|
(Offline)
|
|
11.04.2012, 05:48
|
#6
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Правильная загрузка конфиг файла
Сообщение от burovalex
Прикольно!
Мне до такого еще далеко...
Объясните пожалуста, зачем нужна точка в функции CfgLoader_ParseParam.TOneCfgParam(OneLine$)
Т.е. функция пишется специально для этого типа?
|
После имени любой функции нужно ставить тип возвращаемого ей значения, или ничего не ставить, если не нужно ничего возвращать:
MyIntegerFunction%() - для интовых якобы можно не ставить, оно по умолчанию int
MyFloatFunction#()
MyStringFunction$()
Т.к. пользовательские типы данных определяются через точку:
myTypeVariable.MyTypeName = new MyTypeName
то чтобы вернуть из функции пользовательский тип, нужно через точку указать его после имени функции.
Вышеуказанная функция возвращает в качестве результата данные типа TOneCfgParam.
Сообщение от burovalex
И еще, я сейчас пишу загрузчик уровня, прокоментируйте пожалуста какие недостатки и подводные камни могут быть
|
Мне более удобным кажется хранение уровня в структурированном виде типа такого:
tree {
model="models\tree1.3ds"
scale=x#,y#,z#
position=x#,y#,z#
rotation=x#,y#,z#
и любые параметры тут
}
По такому формату ты проверяешь текущую считанную строку на совпадение с "tree {" и далее пробуешь выцепить все возможные параметры, которые может иметь дерево, пока не дойдёшь до строки, содержащей "}" - на этом перестаёшь дереву что-то искать, начинаешь искать новые ключевые слова: "слово[i] {", и т.д.
Названия параметров отделены от значений символом "=", поэтому считанную строку разбиваешь на две - до равно и после (в блице функция Instr). Значения могут содержать несколько значений, разделить их можно запятой (как выше для x,y,z) или точкой с запятой или ещё чем-нибудь. По этому символу разобьёшь строку и получишь все параметры.
Сохранять такую структуру данных можно сразу из редактора карт.
По коду твоему.
Вместо такого:
Select levelName
Case levelNameMain
file=OpenFile("main.lev")
End Select
While Not Eof(file)
я бы написал такое:
Local fileName$ = ""
Select levelName
Case levelNameMain
fileName = "main.lev"
End Select
If(FileType(fileName) <> 1) Then RuntimeError("File "+fileName+" not found. Reinstall program.")
file=OpenFile(fileName)
While Not Eof(file)
Ещё - для перевода строки в число можно писать вот так:
intVal = Int(str$)
floatVal = Float(str$)
если строка начинается не с числа, то получишь ноль. Поэкспериментируй, передавая разные параметры.
|
(Offline)
|
|
11.04.2012, 12:05
|
#7
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Ответ: Правильная загрузка конфиг файла
Спасибо! Полезно!
Вот только мне не нравится что значения надо будет считывать через запятую, может проще в строку все писать
tree {
positionX=2
positionY=3
positionZ=4
}
В таком варианте нет сложности, т.к. можно узнать позицию объекта, и прочитав строку positionX - выполнить PositionEntity ent,positionX,entityY(ent),entityZ(ent).
А вот с масштабом такое не проканает, потому что нету такой функции типа EntityScaleX() или чтото вроде..
И вот хз че делать
__________________
|
(Offline)
|
|
11.04.2012, 13:12
|
#8
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Правильная загрузка конфиг файла
Зачем разделять? Это только усложнит.
Псевдокод:
Local entityKind$ ;чтоб знать кому параметры устанавливать, можно int-ом сделать
Local bReadParams% ;флаг - состояние чтения ключевых слов (false) или параметров (true)
Local strLine$, cmdName$, ;текущая строка, считанная из файла, имя параметра
Local tree.TTree ;ссылка на текущее создаваемое дерево, и так перечисляешь здесь все возможные типы создаваемых объектов. по хорошему тут должен быть тип базового класса, но классов тю-тю в блитце
Local entity% ;можно один указатель на все создаваемые модельки сделать, и его присваивать
Dim cmdParams$(0) ;пустой пока, сюда будем вставлять параметры типа x,y,z. приходится делать глобальный массив, т.к. в блитце нельзя возвращать массив из функций, массивы всегда глобальные. чтоб освободить память пишешь в "любом" месте Dim cmdParams$(0) - размер ноль.
................
strLine = ReadLine(file)
If(bReadParams = False) ;если не параметры, то ключевые слова ищем
If(strLine = "tree {")
;тут создаём например
tree = New TTree
entityKind = "tree"
bReadParams = True ;дальше будем параметры читать
strLine = ReadLine(file) ;чтоб не пропускать цикл сразу следующую строку читаем
EndIf
If(bReadParams = True)
cmdName = GetCmdName(strLine) ;возвращает значение до символа "=", твоя функция
If(cmdName = "}") ;параметры кончились
If(entityKind = "tree")
tree\ent = entity ;присваиваем дереву
Else If(.....)
EndIf
entity = 0 ;временного объекта теперь нет, он стал деревом :)
Else ;читаем общие для всех моделек параметры
GetCmdParams(strLine, ",") ;твоя функция, разбивает то что после "=" по символу,
;идущему вторым параметром функции, и записывает в массив, размерность массива внутри функции переопределяется в зависимости
;от количества найденных символов-разделителей
;например для параметра "model" массив будет размерностью 1 и содержать путь к модельке (например, ты можешь хоть чё вставить)
If(cmdName = "model")
entity = LoadMesh(cmdParams(0))
EndIf
;
If(entity <> 0)
Else If(cmdName = "position")
PositionEntity entity,Float(cmdParams(0),Float(cmdParams(1),Float(cmdParams(2)
Else If(cmdName = "scale")
ScaleEntity entity,Float(cmdParams(0),Float(cmdParams(1),Float(cmdParams(2)
Else
;и т.д.
EndIf
EndIf
;плюс проверка наличия индивидуальных параметров, присущих только деревьям (и другим уникальным объектам)
If(entityKind = "tree")
If(cmdName = "enable_wind") ;воздействует ли ветер
tree\bWindEnable = Int(cmdParams(0))
EndIf
EndIf
EndIf
EndIf
EndIf
Последний раз редактировалось Жека, 11.04.2012 в 13:15.
Причина: комментарий к Dim дописал
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
11.04.2012, 16:39
|
#9
|
Разработчик
Регистрация: 04.04.2012
Сообщений: 468
Написано 37 полезных сообщений (для 60 пользователей)
|
Ответ: Правильная загрузка конфиг файла
Прикольно написал!!
Всё доступно и понятно! Спасибо большое!! Буду делать
__________________
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
12.04.2012, 05:09
|
#10
|
Дэвелопер
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений (для 886 пользователей)
|
Ответ: Правильная загрузка конфиг файла
Как говорится, "Обращайтесь!"
|
(Offline)
|
|
12.04.2012, 07:34
|
#11
|
Разработчик
Регистрация: 27.06.2009
Адрес: Рязань-Москва
Сообщений: 471
Написано 401 полезных сообщений (для 1,072 пользователей)
|
Ответ: Правильная загрузка конфиг файла
Давно пользуюсь набором функций - не помню кто их автор и где я их взял, но удобно
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 22:58.
|