[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
ДеЦЦкий сад "ПандЁнок"
serg-kkzДата: Воскресенье, 23.05.2021, 18:57 | Сообщение # 301
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
И да чтоб геометрия не пере прикрывалась во время анимации, можно задать порядок рендеринга плиткам, или раскидать их со смещение по высоте.

В этом подходе есть логический косяк, вместо списка self.replace нужно использовать словарь.
И прежде чем добавить в словарь нод плитки, нужно делать проверку не наличие такого элемента.


ООП  -  

Сообщение отредактировал serg-kkz - Воскресенье, 23.05.2021, 19:07
 
serg-kkzДата: Воскресенье, 23.05.2021, 19:59 | Сообщение # 302
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Исправил все баги.

Код
from direct.showbase.ShowBase import ShowBase
from panda3d.core import CollisionTraverser, CollisionHandlerQueue, CollisionNode, CollisionRay, BitMask32
from direct.interval.LerpInterval import LerpPosInterval

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        base.disableMouse()
        camera.setPos(0, 0, 5)
        camera.setHpr(-90, -90, -90)

        self.replace = {}

        node = loader.loadModel("a")
        node.reparentTo(render)
        node.setPos(-0.6, 0.6, 0)
        node.setCollideMask(BitMask32.bit(1))

        node1 = loader.loadModel("b")
        node1.reparentTo(render)
        node1.setPos(-0.6, -0.6, 0)
        node1.setCollideMask(BitMask32.bit(1))
        
        base.accept('mouse1', self.pick)

        self.CurPicker = CollisionTraverser()
        #self.CurPicker.showCollisions(render)
        self.CurPickerOr = CollisionHandlerQueue()
        CurPickerNod = CollisionNode('mouseRay')
        CurPickerCam = camera.attachNewNode(CurPickerNod)
        CurPickerNod.setFromCollideMask(BitMask32.bit(1))
        self.CurPickerRay = CollisionRay()
        CurPickerNod.addSolid(self.CurPickerRay)
        self.CurPicker.addCollider(CurPickerCam, self.CurPickerOr)

    def pick(self):
       if base.mouseWatcherNode.hasMouse():
           mpos = base.mouseWatcherNode.getMouse()
           self.CurPickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
           self.CurPicker.traverse(render)
           self.CurPickerOr.sortEntries()
           
           if (self.CurPickerOr.getNumEntries() > 0):
            info = self.CurPickerOr.getEntry(0)

            self.replace[info.getIntoNodePath().getName()] = info.getIntoNodePath()

            if len(self.replace) >=2:
                replace = list(self.replace.values())
                LerpPosInterval(nodePath = replace[0], other = render, blendType = 'easeInOut', duration = 0.2, pos = replace[1].getPos(render)).start()
                LerpPosInterval(nodePath = replace[1], other = render, blendType = 'easeInOut', duration = 0.2, pos = replace[0].getPos(render)).start()
                self.replace = {}

game = Game()
game.run()


ООП  -  

Сообщение отредактировал serg-kkz - Воскресенье, 23.05.2021, 22:26
 
serg-kkzДата: Воскресенье, 23.05.2021, 22:30 | Сообщение # 303
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Похоже, что окончательное решение должно заключаться в отключении функции щелчка до тех пор, пока интервалы не будут завершены. Для этого сделайте их членами класса и используйте задачу для отслеживания их статуса. Затем луч снова может обнаруживать плитки.

В данный момент логика ломается при частом нажатием по плиткам.


ООП  -  
 
donidenis55Дата: Вторник, 25.05.2021, 14:22 | Сообщение # 304
Рядовой
Группа: Пользователи
Сообщений: 3
Награды: 0
Репутация: 0
Статус: Offline
Ребят сделал код. Управление шутер. Все работает. Только летаю по карте и проваливаюсь. Поправьте код-)

from direct.showbase.ShowBase import ShowBase
from panda3d.core import Plane, Vec3, Point3

from panda3d.core import CollisionTraverser, CollisionNode, CollisionSphere
from panda3d.core import CollisionHandlerQueue, CollisionRay, CollisionHandlerFloor
from panda3d.core import Filename, AmbientLight, DirectionalLight
from panda3d.core import PandaNode, NodePath, Camera, TextNode

from panda3d.core import CollideMask
from direct.task import Task
from math import pi, sin, cos

from panda3d.core import CollisionHandlerFloor, CollisionNode, CollisionRay, CollisionHandlerPusher, CollisionSphere, CollisionPlane

import panda3d.core as p3d
p3d.load_prc_file_data('', '''win-size 1280 720
multisamples 1
show-frame-rate-meter 1
sync-video 0''')

import configparser

FT_MIPMAP = p3d.SamplerState.FT_linear_mipmap_linear
FT_LINEAR = p3d.SamplerState.FT_linear
TS_NORMAL = p3d.TextureStage.M_normal
TS_NORMAL_GLOSS = p3d.TextureStage.M_normal_gloss
TS_MODULATE = p3d.TextureStage.M_modulate
F_SRGB = p3d.Texture.F_srgb
F_SRGBA = p3d.Texture.F_srgb_alpha
F_RGB = p3d.Texture.F_rgb
F_RGBA = p3d.Texture.F_rgba
M_MSAA= p3d.AntialiasAttrib.M_multisample

"""direct - это часть Panda3D, написанная на Python core - это C++ с привязками Python)
ShowBase-это одноэлементный класс, который настраивает окно, диспетчер задач и все
другие общие вещи, которые вы можете (или не можете) использовать.
Вам не нужно его использовать, но вы, вероятно, захотите использовать или использовать его, даже если вы этого не хотите.
Он также устанавливает себя и кучу других вещей в здания, так что
ключевые объекты (например, узел рендерин доступны в любом месте вашего код"""

# Класс контроллера мыши и клавы
class Controller():
# Конструктор
def __init__(self):

#self.cTrav = CollisionTraverser()
#self.pusher = CollisionHandlerPusher()
# Значение шага перемещения клавы
self.key_step = 0.2
# Значение шага поворота мыши
self.mouse_step = 0.2
# Координаты ценра экрана
self.x_center = base.win.getXSize()//2
self.y_center = base.win.getYSize()//2
# Перемещаем указатель мыши в цетре экрана
base.win.movePointer(0, self.x_center, self.y_center)
# Отключаем стандарное управление мышкой
base.disableMouse()
# Устанавливает поле зрения обьекта
base.camLens.setFov(30)






# Устанавливает текущее значение ориентациии камеры
self.heading = 0
self.pitch = 0

# Запускаем задачу контроля камеры
taskMgr.doMethodLater(0.02, self.controlCamera, "camera-task")


# Регистрируем на нажатие клавиши "Esc"
# Событие закрытия приложения
base.accept("escape", base.userExit)

# Устанавливаем клавиши управления перемещения камеры
# Словарь хранящий флаги нажатия клавиш
self.keys = dict()

# Заполняем словарь
for key in ['a', 'd', 'w', 's', 'e', 'q']:
# Создаем запись в словаре
self.keys[key] = 0
# Регестрируем событие на нажатие клавиш
base.accept(key, self.setKey, [key, 1])
# Регестрируем событие на отжатие клавиш
base.accept(key+'-up', self.setKey, [key, 0])

# Метод установки состояния клавиш
def setKey(self, key, value):
self.keys[key] = value

# Метод управления положением и ориентации камеры
def controlCamera(self, task):
# Расчитывем управлением и ориентации камерры
move_x = self.key_step * (self.keys['d'] - self.keys['a'])
# Добавьте перемещение камеры вперед, назад, вверх, вниз
move_y = self.key_step * (self.keys['w'] - self.keys['s'])
move_z = self.key_step * (self.keys['e'] - self.keys['q'])

# Смещаем позицию камеры относительно предыдущего положения камеры
base.camera.setPos(base.camera, move_x, move_y, move_z)


#collisionNode = base.camera.attachNewNode(collisionNode)
# Получаем новое положение курсора мыши
new_mouse_pos = base.win.getPointer(0)
new_x = new_mouse_pos.getX()
new_y = new_mouse_pos.getY()
# Пробуем установить курсор в цетре экрана
if base.win.movePointer(0, self.x_center, self.y_center):
# Расчитайте поворот камеры по горизонтали
self.heading = self.heading - (new_x - self.x_center) * self.mouse_step
# Расчитайте поворот камеры по диагонали
self.pitch = self.pitch - (new_y - self.y_center) * self.mouse_step
# Устанавливаем новую ориентацию камеры
base.camera.setHpr(self.heading, self.pitch, 0)

# Сообщаем о необходимости повторного запуска камеры
return task.again

if __name__ == '__main__':
p3d.load_prc_file_data('', '''win-size 1280 720')
multisamples 1
show-frame-rate-meter 1
sync-video 0''')

class App(ShowBase):
def __init__(self):

super().__init__()

base.cTrav = CollisionTraverser()
# Create a handler for the events.
self.collHandler = CollisionHandlerQueue()

#p3d.get_model_path().append_directory('..')

# Load a model of a empty room
#smiley = self.loader.load_model('models/room_industrial')

self.set_background_color(0.0, 0.0, 0.0)
self.render.set_shader_auto()
self.render.set_antialias(M_MSAA)


smiley = loader.loadModel('models/world.egg.pz')
smiley.reparent_to(self.render)

smiley = base.render.attachNewNode("Floor NodePath")
# Create a collision plane solid.
collPlane = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0)))
# Call our function that creates a nodepath with a collision node.
#floorCollisionNP = self.makeCollisionNodePath(smiley, collPlane)
# Get the collision node the Nodepath is referring to.
#floorCollisionNode = floorCollisionNP.node()
# The floor is only an into object, so just need to set its into mask.
#floorCollisionNode.setIntoCollideMask(floorMask)

# Create a collision sphere. Since the models we'll be colliding
# are basically the same we can get away with just creating one
# collision solid and adding the same solid to both collision nodes.
collSphere = CollisionSphere(0, 0, 0, 1.5)



fromObject = base.camera.attachNewNode(CollisionNode('colNode'))
fromObject.node().addSolid(CollisionSphere(0, 0, 0, 1))

pusher = CollisionHandlerPusher()
pusher.addCollider(fromObject, base.camera, base.drive.node())



self.controller = Controller()

# run all the code

app=App()
app.run()







 
serg-kkzДата: Вторник, 25.05.2021, 18:34 | Сообщение # 305
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
donidenis55, отредактируй код с помощью панели как я просил тебя выше в посте, или используй bb теги.

Что касается твой проблемы, у тебя до сих пор нет функции для нахождения точки пересечения луча и плоскости.


ООП  -  

Сообщение отредактировал serg-kkz - Вторник, 25.05.2021, 23:59
 
serg-kkzДата: Вторник, 25.05.2021, 19:13 | Сообщение # 306
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Вот хороший пример для этого.

Прикрепления: 9314164.zip (34.2 Kb) · 6543889.jpg (121.5 Kb)


ООП  -  

Сообщение отредактировал serg-kkz - Вторник, 25.05.2021, 19:14
 
serg-kkzДата: Вторник, 25.05.2021, 19:37 | Сообщение # 307
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Вот рабочий пример.

Код
from direct.showbase.ShowBase import ShowBase
from panda3d.core import CollisionTraverser, CollisionNode, CollisionRay, CollisionHandlerQueue

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        self.keyMap = {"forward": 0, "back": 0}

        self.accept("w", self.setKey, ["forward", True])
        self.accept("w-up", self.setKey, ["forward", False])
        
        self.accept("s", self.setKey, ["back", True])
        self.accept("s-up", self.setKey, ["back", False])

        terrain = loader.loadModel("colltest")
        terrain.reparentTo(render)
        terrain.setCollideMask(1)

        self.player = loader.loadModel("panda")
        self.player.reparentTo(render)

        fromObject = self.player.attachNewNode(CollisionNode('colNode'))
        fromObject.setZ(1)
        fromObject.node().addSolid(CollisionRay(0, 0, 0, 0, 0, -1))
        fromObject.node().setFromCollideMask(1)

        self.queue = CollisionHandlerQueue()

        self.collTrav = CollisionTraverser()
        self.collTrav.addCollider(fromObject, self.queue)

        taskMgr.add(self.update, 'update')

    def setKey(self, key, value):
        self.keyMap[key] = value

    def update(self, task):
        dt = globalClock.getDt()

        self.collTrav.traverse(render)
        self.queue.sortEntries()

        if (self.queue.getNumEntries() > 0):
            info = self.queue.getEntry(0)
            self.player.setPos(info.getSurfacePoint(render))
            
        if self.keyMap["forward"]:
            self.player.setY(self.player, -10 * dt)
            
        if self.keyMap["back"]:
            self.player.setY(self.player, 10 * dt)

        return task.cont

game = Game()
game.run()
Прикрепления: 1608665.egg (432.2 Kb)


ООП  -  

Сообщение отредактировал serg-kkz - Вторник, 25.05.2021, 23:57
 
fron_de_befДата: Суббота, 29.05.2021, 15:41 | Сообщение # 308
Сержант
Группа: Пользователи
Сообщений: 36
Награды: 0
Репутация: 5
Статус: Offline
Я вас так и не поблагадорил за помощь, спасибо. Я смог разобраться сам и сделал так, как я изначально задумывал, может не так изящно как у вас, но для меня сойдет.
Прикрепления: 7832786.zip (316.2 Kb)
 
serg-kkzДата: Суббота, 29.05.2021, 16:06 | Сообщение # 309
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Не стоит благодарностей за такой пустяк, однако если в моем варианте присвоить duration = 0, будет тоже самое.

ООП  -  
 
donidenis55Дата: Четверг, 03.06.2021, 09:52 | Сообщение # 310
Рядовой
Группа: Пользователи
Сообщений: 3
Награды: 0
Репутация: 0
Статус: Offline
Ребят всем привет. Так и не научился в код вставлять здесь. (bb) Посмотрите пожалуйста код. Камера летает. Как приземлить?
И скользить по не ровнастям?... Нигде нет скрина на управление от первого лица. Давайте вместе сделаем это. Как оседлать камеру?


Код
from panda3d.core import loadPrcFileData

confVars = '''
window-title Моя деревня
'''

from direct.showbase.ShowBase import ShowBase
from panda3d.core import CollisionTraverser, CollisionHandlerPusher
from panda3d.core import CollisionNode, CollisionSphere, CollisionInvSphere

import panda3d.core as p3d
p3d.load_prc_file_data('', '''win-size 800 600
                            multisamples 1
                            show-frame-rate-meter 1
                            sync-video 0''')

import configparser

FT_MIPMAP = p3d.SamplerState.FT_linear_mipmap_linear
FT_LINEAR = p3d.SamplerState.FT_linear
TS_NORMAL = p3d.TextureStage.M_normal
TS_NORMAL_GLOSS = p3d.TextureStage.M_normal_gloss
TS_MODULATE = p3d.TextureStage.M_modulate
F_SRGB = p3d.Texture.F_srgb
F_SRGBA = p3d.Texture.F_srgb_alpha
F_RGB = p3d.Texture.F_rgb
F_RGBA = p3d.Texture.F_rgba
M_MSAA= p3d.AntialiasAttrib.M_multisample

"""direct - это часть Panda3D, написанная на Python core - это C++ с привязками Python)
ShowBase-это одноэлементный класс, который настраивает окно, диспетчер задач и все
другие общие вещи, которые вы можете (или не можете) использовать.
Вам не нужно его использовать, но вы, вероятно, захотите использовать или использовать его, даже если вы этого не хотите.
Он также устанавливает себя и кучу других вещей в здания, так что
ключевые объекты (например, узел рендерин доступны в любом месте вашего код"""

# Класс контроллера мыши и клавы
class Controller():
   # Конструктор
   def __init__(self):
      
      #self.cTrav = CollisionTraverser()
      #self.pusher = CollisionHandlerPusher()
      # Значение шага перемещения клавы
      self.key_step = 0.1
      # Значение шага поворота мыши
      self.mouse_step = 0.2
      # Координаты ценра экрана
      self.x_center = base.win.getXSize()//2
      self.y_center = base.win.getYSize()//2
      # Перемещаем указатель мыши в цетре экрана
      base.win.movePointer(0, self.x_center, self.y_center)
      # Отключаем стандарное управление мышкой
      base.disableMouse()
      # Устанавливает поле зрения обьекта
      base.camLens.setFov(30)
      
      
      # Устанавливает текущее значение ориентациии камеры
      self.heading = 0
      self.pitch = 0
      
      # Запускаем задачу контроля камеры
      taskMgr.doMethodLater(0.05, self.controlCamera, "camera-task")
      
      # Регистрируем на нажатие клавиши "Esc"
      # Событие закрытия приложения
      base.accept("escape", base.userExit)
      
      # Устанавливаем клавиши управления перемещения камеры
      # Словарь хранящий флаги нажатия клавиш
      self.keys = dict()
      
      # Заполняем словарь
      for key in ['a', 'd', 'w', 's', 'e', 'q']:
         # Создаем запись в словаре
         self.keys [key]= 0
         # Регестрируем событие на нажатие клавиш
         base.accept(key, self.setKey, [key, 1])
         # Регестрируем событие на отжатие клавиш
         base.accept(key+'-up', self.setKey, [key, 0])

   # Метод установки состояния клавиш
   def setKey(self, key, value):
      self.keys [key]= value
      
   # Метод управления положением и ориентации камеры
   def controlCamera(self, task):
      # Расчитывем управлением и ориентации камерры
      move_x = self.key_step * (self.keys['d'] - self.keys['a'])
      # Добавьте перемещение камеры вперед, назад, вверх, вниз
      move_y = self.key_step * (self.keys['w'] - self.keys['s'])
      move_z = self.key_step * (self.keys['e'] - self.keys['q'])
         
      # Смещаем позицию камеры относительно предыдущего положения камеры
      base.camera.setPos(base.camera, move_x, move_y, move_z)
      
      # Получаем новое положение курсора мыши
      new_mouse_pos = base.win.getPointer(0)
      new_x = new_mouse_pos.getX()
      new_y = new_mouse_pos.getY()
      # Пробуем установить курсор в цетре экрана
      if base.win.movePointer(0, self.x_center, self.y_center):
         # Расчитайте поворот камеры по горизонтали
         self.heading = self.heading - (new_x - self.x_center) * self.mouse_step
         # Расчитайте поворот камеры по диагонали
         self.pitch = self.pitch - (new_y - self.y_center) * self.mouse_step
         # Устанавливаем новую ориентацию камеры
         base.camera.setHpr(self.heading, self.pitch, 0)
            
      # Сообщаем о необходимости повторного запуска камеры
      return task.again

if __name__ == '__main__':

   
   class App(ShowBase):
      def __init__(self):
         
         super().__init__()
         
         
         self.cTrav = CollisionTraverser()
        
         pusher = CollisionHandlerPusher()
         pusher.setHorizontal(True)
         
         self.env = loader.loadModel("models/world")
         self.env.reparent_to(self.render)
         self.env.setScale(0.25, 0.25, 0.25)
         self.env.setPos(0, 0, -2)
         
         envBounds = self.env.getBounds()
         envCenter = envBounds.getCenter()
         envRad = envBounds.getRadius() * 0.8
         
         

         cNode = CollisionNode("models/world")
         cNode.addSolid(CollisionInvSphere(envCenter, envRad))
         envC = self.render.attachNewNode(cNode)
        
         camBounds = self.camera.getBounds()
         camCenter = camBounds.getCenter()
         camRad = 1
         
         cNode = CollisionNode("camera")
         cNode.addSolid(CollisionSphere(camCenter, camRad))
         camC = self.camera.attachNewNode(cNode)
         camC.show()
        
         self.cTrav.addCollider(camC, pusher)
         pusher.addCollider(camC, self.camera)

         

         self.controller = Controller()

   app=App()
   app.run()
 
serg-kkzДата: Суббота, 05.06.2021, 14:19 | Сообщение # 311
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Однозначно могу сказать ваш код сделан не для этого. Я привел пример с пандой, вам достаточно прицепить камеру к ней.

Пример FPS - http://panda3d.org.ru/forum/5-13-1


ООП  -  
 
fron_de_befДата: Суббота, 19.06.2021, 17:10 | Сообщение # 312
Сержант
Группа: Пользователи
Сообщений: 36
Награды: 0
Репутация: 5
Статус: Offline
У меня тут небольшой баг, некритичный, хотя мой внутренний перфекционист орет как резанный.  В чем суть - я прописал спрайту координаты потом мне нужно получить координаты этого же спрайта и тут ... Как видите я даже специально в одном варианте прописал нули после запятой, причем другую переменную он возвращяет как есть. Есть мысли почему так и как это исправить?

Добавлено (09.08.2021, 17:40)
---------------------------------------------
У меня тут назрел более важный и интересный вопрос - переустановил винду, установил назад пайтон и панду, запустил свой код и..... он работает на половину. Если быть конкретнее, он он отрисовывает окно, gui работает, а вот скрытые модельки на которых я жмякал мышью на кликанье не реагируют.  Сначала подумал может в последней версии я чего неправильно дописал или какой то другой модуль использовал просто забыл, протестил старую версию которая 100% работала - результат тот же. Теперь вот думаю может это связано с каким то драйвером? Или в чем еще может быть причина?
Конкретно эти участки кода не работают

Код

  def mouse_left_click(self):
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            self.mpos_x = mpos[0]
            self.mpos_y = mpos[1]        
            self.pickerRay.setFromLens(base.camNode,mpos.getX(),mpos.getY())
            self.picker.traverse(render)
            print("лево")
            if self.number_click == 1:
                 self.number_click += 1

            if self.pq.getNumEntries() > 0:
                print("1")
                self.pq.sortEntries()
                pickedObj = self.pq.getEntry(0).getIntoNodePath()
                t = pickedObj.getNetTag('slot')
                print(t)



Код

  def collisionSlot(self, pos_x, pos_y, slot, number):
        sprite = self.loader.loadModel("assets/eggs/64_64")
        sprite.reparentTo(render)
        sprite.setScale(11.25, 15, 15)
        sprite.setPos(pos_x, 1, pos_y)
        sprite.setCollideMask(BitMask32.bit(1))
        sprite.setTag(str(slot), str(number))
        return sprite


 
serg-kkzДата: Понедельник, 09.08.2021, 19:02 | Сообщение # 313
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
То что вы описываете, на самом деле не бывает. Проблема может быть в другом, что ранее модели были в кеше, теперь вы их изменили. Может только в этом дело быть, по идее должна была бы быть ошибка. Но я как понял у вас её нет, тут явно что то с вашей моделью.

ООП  -  
 
fron_de_befДата: Понедельник, 09.08.2021, 19:07 | Сообщение # 314
Сержант
Группа: Пользователи
Сообщений: 36
Награды: 0
Репутация: 5
Статус: Offline
а как с ней что то смогло случиться если я ее не менял ну вообще никак? название? нет? геометрию? да нафиг мне это нужно. Я даже весь остальной фон переудалял что бы проверить прорисовываются ли они. Повторюсь я сначала подумал что я добавил какие то изменения в код просто забыл об этом, но потом понял что я следовал вполне понятной и логичной схеме "работает - не трожь"
 
serg-kkzДата: Понедельник, 09.08.2021, 19:43 | Сообщение # 315
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Думаю лучший способ проверить логику. Меня смущает то что вы тег проверяете на узле и предке, а если его нет то будет пустая строка. Возможно где то здесь проблема.

ООП  -  
 
Поиск: