[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Реализация двери
serg-kkzДата: Среда, 25.01.2012, 15:58 | Сообщение # 1
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Мой пример реализации дверей и зон, которые являются тригерами. В данном примере реализованно: возможность визуально
настроить зону, ось открытия двери и скорость.

В архиве все нужные ресурсы для демонстрации.

Главные файлы.

primer.py
Code
# -*- coding: utf-8 -*-
import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.showbase import DirectObject
from direct.interval.IntervalGlobal import *      

class Game(object, DirectObject.DirectObject):
         def __init__(self):
             # Импорт класса двери
             from class_door import door_vert
                  
             base.cTrav = CollisionTraverser()
             base.pusher = CollisionHandlerPusher()
                  
             self.level = loader.loadModel('level.egg')
             self.level.reparentTo(render)
             self.level.setTwoSided(True)
                  
             self.igrok = Player()

             # Вызываем класс двери и передаем ссылку на объект который будет открывать дверь если окажется в зоне.
             door_vert(self.igrok)

class Player(object):

         STOP = Vec3(0)
         walk = STOP
         strafe = STOP
              
         def __init__(self):
             self.node = NodePath('player')
             self.node.reparentTo(render)
             self.node.setPos(0,0,0)
             self.node.setScale(.05)

             colnode = CollisionNode('player')
             colnode.addSolid(CollisionSphere(0,0,0,3))
             solid1 = self.node.attachNewNode(colnode)
             solid1.show()
                  
             base.cTrav.addCollider(solid1, base.pusher)
             base.pusher.addCollider(solid1, self.node)
                  
             base.accept( "w" , self.__setattr__,["walk",Vec3(0,1,0)])
             base.accept( "w-up" , self.__setattr__,["walk",Vec3(0)] )
             base.accept( "s" , self.__setattr__,["walk",Vec3(0,-1,0)] )
             base.accept( "s-up" , self.__setattr__,["walk",Vec3(0)] )
             base.accept( "a" , self.__setattr__,["strafe",Vec3(-1,0,0)])
             base.accept( "a-up" , self.__setattr__,["strafe",Vec3(0)] )
             base.accept( "d" , self.__setattr__,["strafe",Vec3(1,0,0)] )
             base.accept( "d-up" , self.__setattr__,["strafe",Vec3(0)] )
             base.accept( "z" , self.__setattr__,["strafe",Vec3(0,0,1)] )
             base.accept( "z-up" , self.__setattr__,["strafe",Vec3(0)] )
             base.accept( "x" , self.__setattr__,["strafe",Vec3(0,0,-1)] )
             base.accept( "x-up" , self.__setattr__,["strafe",Vec3(0)] )
                  
             taskMgr.add(self.moveUpdate, 'move-task')

         def moveUpdate(self,task):      
             self.node.setPos(self.node,self.walk*globalClock.getDt()*17)
             self.node.setPos(self.node,self.strafe*globalClock.getDt()*17)
             return task.cont

Game()
run()


И модуль который реализует дверь.

class_door.py
Code
# -*- coding: utf-8 -*-
from direct.directtools.DirectGeometry import LineNodePath
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *

class door_vert():
      def __init__(self, obekt):
        
          self.igrok = obekt #  Передаем ссылку на объект который будет открывать дверь если окажется в зоне.
          linescreate = 1 # Включаем отображение зоны, чтоб выключить установите 0
          self.statys_door = 0 # Статус двери, 0 - закрыта, 1-открыта.

          self.door = loader.loadModel('door.egg') # Загрузка модели двери.
          self.door.reparentTo(render) # Добавляем в рендер.
            
          # Позиция двери
          self.posdoor = (0, 1.5, 0) # Задаем координаты двери
          self.door.setPos(self.posdoor) # Устанавливаем эту позицию для модели двери.
            
          # Настройка зоны двери, считается от центра двери.

          xlevo = 0.5   # Прибавление зоны в левую сторону.
          xpravo = 0.5  # Прибавление зоны в правую сторону.
          yvpered = 0.8 # Прибавление зоны в перед.
          ynazad = 0.8  # Прибавление зоны на зад.
          zverx = 0.4   # Прибавление зоны вверх.
          zniz = 0.4    # Прибавление зоны вниз.
            
          # Выбираем по какой оси открыть дверь и насколько.
          self.x = 0   
          self.y = 0
          self.z = 1 # Открываем вверх, а если с минусом, то наоборот.
            
          self.timemove = 0.6 # Время открытия и закрытия двери.
            
          # Блок кода для расчета точек, по которым строятся линии зоны и собственно сама зона.
          self.t1, self.t2, self.t3 = self.door.getX()-xlevo, self.door.getY()+yvpered, self.door.getZ()-zniz
          self.t4, self.t5, self.t6 = self.door.getX()+xpravo, self.door.getY()+yvpered, self.door.getZ()-zniz
          self.t7, self.t8, self.t9 = self.door.getX()-xlevo, self.door.getY()-ynazad, self.door.getZ()-zniz
          self.t10, self.t11, self.t12 = self.door.getX()+xpravo, self.door.getY()-ynazad, self.door.getZ()-zniz
          self.t13, self.t14, self.t15 = self.door.getX()-xlevo, self.door.getY()+yvpered, self.door.getZ()+zverx
          self.t16, self.t17, self.t18 = self.door.getX()+xpravo, self.door.getY()+yvpered, self.door.getZ()+zverx
          self.t19, self.t20, self.t21 = self.door.getX()-xlevo, self.door.getY()-ynazad, self.door.getZ()+zverx
          self.t22, self.t23, self.t24 = self.door.getX()+xpravo, self.door.getY()-ynazad, self.door.getZ()+zverx

          # Проверяем включено ли отображение зоны.
          if (linescreate == 1):
          # Строим зону из линий.
              lines = LineNodePath(render, colorVec = Vec4(1, 0, 0, 1))
              lines.drawLines([((self.t1, self.t2, self.t3),(self.t4, self.t5, self.t6)),   
                    ((self.t7, self.t8, self.t9),(self.t10, self.t11, self.t12)),
                    ((self.t4, self.t5, self.t6), (self.t10, self.t11, self.t12)),
                    ((self.t1, self.t2, self.t3), (self.t7, self.t8, self.t9)),
                    ((self.t13, self.t14, self.t15), (self.t16, self.t17, self.t18)),
                    ((self.t19, self.t20, self.t21), (self.t22, self.t23, self.t24)),
                    ((self.t16, self.t17, self.t18), (self.t22, self.t23, self.t24)),
                    ((self.t13, self.t14, self.t15), (self.t19, self.t20, self.t21)),
                    ((self.t1, self.t2, self.t3), (self.t13, self.t14, self.t15)),
                    ((self.t4, self.t5, self.t6), (self.t16, self.t17, self.t18)),
                    ((self.t7, self.t8, self.t9), (self.t19, self.t20, self.t21)),
                    ((self.t10, self.t11, self.t12), (self.t22, self.t23, self.t24))])
              lines.create()

          taskMgr.add(self.posget, 'move')

      # Проверка находится ли игрок или нужный объект в зоне двери.
      def posget(self,task):
          if (self.igrok.node.getX() > self.t1) and (self.igrok.node.getX() < self.t4):
              if (self.igrok.node.getY() < self.t5) and (self.igrok.node.getY() > self.t8):
                  if (self.igrok.node.getZ() > self.t9) and (self.igrok.node.getZ() < self.t15):
                      self.opendoor() # Если да, то запускаем функцию открытия двери.
                  else:
                      self.closedoor() # Если нет, то закрытия.
              else:
                  self.closedoor() # Если нет, то закрытия.
          else:
              self.closedoor() # Если нет, то закрытия.

          return task.cont

      # Функция открытия двери.
      def opendoor(self):
          # Проверям статус двери, если закрыта, то открываем.
          if (self.statys_door == 0):
              if (self.door.getPos() == Point3(self.posdoor)):# Проверка закрылась ли дверь.
                  open = self.door.posInterval(self.timemove,Point3(self.door.getPos())+(self.x, self.y, self.z), startPos=Point3(self.posdoor))
                  move = Sequence(open)
                  move.start()
                  self.statys_door = 1 # Меняем статус.
                    
      def closedoor(self):
          # Проверям статус двери, если открыта, то закрываем.
          if (self.statys_door == 1):
              if (self.door.getPos() == Point3(self.posdoor)+(self.x, self.y, self.z)):# Проверка открылась ли дверь.
                  close = self.door.posInterval(self.timemove,Point3(self.posdoor), startPos=Point3(self.door.getPos()))
                  move = Sequence(close)
                  move.start()
                  self.statys_door = 0 # Меняем статус.


Управление W, S, A, D и Z, X
Прикрепления: 3716376.rar (132.7 Kb)


ООП  -  

Сообщение отредактировал serg-kkz - Среда, 25.01.2012, 17:30
 
serg-kkzДата: Среда, 25.01.2012, 17:22 | Сообщение # 2
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Поправил код, теперь дверь не закрывается пока полностью не откроется и наоборот.

ООП  -  
 
ZegyДата: Четверг, 26.01.2012, 13:33 | Сообщение # 3
Сержант
Группа: Пользователи
Сообщений: 24
Награды: 0
Репутация: 0
Статус: Offline
для каждой двери нужно индивидуально всё прописывать?
 
serg-kkzДата: Четверг, 26.01.2012, 18:30 | Сообщение # 4
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Не понял что именно, согласен что например, координаты расположения двери нужно задавать разные. Но что этому мешает?

Допишем в классе двери:
Code
def __init__(self, obekt, pos):


Ну и, еще:
Code
self.posdoor = pos # Задаем координаты двери


Теперь пишем, при вызове класса двери, это в файле primer.py
Code
# Вызываем класс двери и передаем ссылку на объект который будет открывать дверь если окажется в зоне.
# А также координаты расположения двери
door_vert(self.igrok, pos = (0, 2, 1)) # №1
door_vert(self.igrok, pos = (0, 1, 0)) # №2


Таким образом можно и модель для двери задать и все остальное... ОПП'же smile


ООП  -  
 
ZegyДата: Пятница, 27.01.2012, 18:30 | Сообщение # 5
Сержант
Группа: Пользователи
Сообщений: 24
Награды: 0
Репутация: 0
Статус: Offline
А как определить координаты , чтобы точно установить дверь? или можно не через лоадер панды, а в самой модельке установить двери?
 
serg-kkzДата: Пятница, 27.01.2012, 19:53 | Сообщение # 6
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Quote (Zegy)
А как определить координаты , чтобы точно установить дверь? или можно не через лоадер панды, а в самой модельке установить двери?

Ну это к задаче выложенного примера не относится, здесь можно написать редактор уровней или в 3D редакторе устанавливать и смотреть координаты. Можно теги вешать в моделях уровня или пустышки, на место которых ставить через специально созданный загрузчик. Можно еще загружать модель двери с управлением от кнопок. И после того как ты её примостишь, смотришь её координаты. Методом getPos(), для этого можно сделать кнопку, по нажатию который они будут записываться в файл или выводятся на экран. Кстати в этом примере не реализовано поворот зоны, об этом не надо забывать.


ООП  -  

Сообщение отредактировал serg-kkz - Пятница, 27.01.2012, 19:55
 
serg-kkzДата: Воскресенье, 29.01.2012, 21:56 | Сообщение # 7
Генерал-полковник
Группа: Модераторы
Сообщений: 803
Награды: 3
Репутация: 18
Статус: Offline
Написал другую версию двери, как мне кажется более правильную. Здесь дверь открывается от расстояния. И главное её можно поворачивать на нужный угол.

Все нужное в архиве.

Сам код класса, который в модуле door.py

Code
# -*- coding: utf-8 -*-
from direct.directtools.DirectGeometry import LineNodePath
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import Sequence
import math

class Door():
     def __init__(self, obekt, pos, rot):
         self.dist=0.5 # Задаем дистанцию до двери, при которой она открывается.
         self.timemove = 0.4 # Время движения двери
         self.igrok = obekt #  Передаем ссылку на объект который будет открывать дверь если окажется в зоне.
         self.posdoor = pos # Задаем координаты зоны двери.
         self.statys_door = 0 # Статус двери, 0 - закрыта, 1-открыта.
         zonaview = 1 # Включаем отображение зоны, чтоб выключить установите 0
         self.door = loader.loadModel('Objects/door.egg') # Загрузка модели двери.
         self.door.setPos(self.posdoor) # Устанавливаем позицию для модели двери.
         self.door.setHpr(rot) # Задаем поворот двери
         self.door.reparentTo(render) # Добавляем в рендер.
         # Создаем пустышку, для расчета конечной точки двери.
         self.emty = NodePath('pointend') # Собственно создаем.
         self.emty.setPos(self.door, 0,0,1) # Устанавливаем конечную позицию и ось, а также расстояние.
          
         # Проверяем включено ли отображение зоны. Данный код можно удалить с 25 стр по 41 и "zonaview = 1" на 14 стр.
         if (zonaview == 1): # Если да(т.е. 1), то строим зону.
             seg = LineSegs()
             seg.setColor(1, 0, 0, 1)
             seg.moveTo(self.dist,0,0)
             for angle in range(0,360,10):
                 x = self.dist*math.cos(math.radians(angle))
                 y = self.dist*math.sin(math.radians(angle))
                 seg.drawTo(x,y,0)
             seg.drawTo(self.dist,0,0)
              
             axis1 = render.attachNewNode(seg.create())
             axis1.setPos(pos)
             axis2 = axis1.copyTo(render)
             axis2.setR(90)
             axis2.setH(self.door.getH())
             axis3 = axis2.copyTo(render)
             axis3.setH(self.door.getH()+90)
              
         taskMgr.add(self.movedoor, 'move')

     def movedoor(self, task):
         if ((self.igrok.node.getPos(render) - self.posdoor).length() < self.dist): # Проверка на каком растоянии находится игрок.
             if (self.statys_door == 0):
                 if (self.door.getPos() == Point3(self.posdoor)):# Проверка закрылась ли дверь полностью.
                     open = self.door.posInterval(self.timemove, self.emty.getPos(), startPos=self.posdoor)
                     move = Sequence(open)
                     move.start()
                     self.statys_door = 1 # Меняем статус.
         else:
             if (self.statys_door == 1):# Проверяем статус двери, если открыта, то закрываем.
                 if (self.door.getPos() == self.emty.getPos()):# Проверка открылась ли дверь полностью.
                     close = self.door.posInterval(self.timemove,self.posdoor, startPos=self.door.getPos())
                     move = Sequence(close)
                     move.start()
                     self.statys_door = 0 # Меняем статус.
         return task.cont
Прикрепления: demo.rar (136.3 Kb)


ООП  -  
 
  • Страница 1 из 1
  • 1
Поиск: