Panda3D 鼠标控制摄像机围绕目标点旋转并避免碰撞
from direct.showbase.ShowBase import ShowBase # 导入ShowBase类
from panda3d.core import WindowProperties # 导入WindowProperties类
from panda3d.core import Vec3 # 导入Vec3类
from direct.task import Task # 导入Task类
from direct.actor.Actor import Actor # 导入Actor类
from panda3d.core import DirectionalLight # 导入DirectionalLight类
from panda3d.core import Point3 # 导入Point3类
from panda3d.core import WindowProperties # 导入WindowProperties类
from win32api import GetSystemMetrics
import pyautogui
import math
# 创建一个继承自ShowBase的类
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
# 加载场景模型(场景树)
self.scene = self.loader.loadModel('models/environment') # 加载名为'models/environment'的模型
# 将render设为场景模型的父节点
self.scene.reparentTo(self.render) # 将场景模型的父节点设置为render
# 改变场景大小,并设置镜头初始位置
self.scene.setScale(0.25, 0.25, 0.25) # 缩小场景模型
self.scene.setPos(-8, 42, 0) # 设置场景模型的位置
# 设置相机
self.disableMouse() # 禁用鼠标
self.camera.setPos(0, -10, 0) # 设置相机的位置
self.camera.lookAt(0, 0, 0) # 设置相机的朝向
# 加载目标点模型
self.target = self.loader.loadModel('models/misc/smiley')
# 将目标点模型隐藏
self.target.hide()
# 将目标点模型设置为父节点
self.target.reparentTo(self.render)
self.distance = 50 # 初始化distance为10
self.angleH = 0 # 初始化angleH为0
self.angleP = 0 # 初始化angleP为0
self.speedH = 0 # 初始化speedH为0
self.speedP = 0 # 初始化speedP为0
self.accept('mouse1', self.startDrag) # 监听鼠标左键按下事件
self.accept('mouse3', self.stopDrag) # 监听鼠标右键按下事件
self.isDragging = False # 初始化isDragging为False
self.lastPosition = None # 初始化lastPosition为None
self.taskMgr.add(self.rotateCameraTask, 'rotateCameraTask') # 添加rotateCameraTask任务
self.lastPosition = self.win.getPointer(0) # 获取鼠标指针的位置
pyautogui.mouseUp(button='middle')
pyautogui.mouseUp(button='left')
pyautogui.mouseUp(button='right')
def startDrag(self):
self.isDragging = True # 将isDragging设置为True
self.lastPosition = self.win.getPointer(0) # 获取鼠标指针的位置
wp = WindowProperties() # 创建WindowProperties对象
wp.setCursorHidden(True) # 隐藏鼠标光标
self.win.requestProperties(wp) # 设置窗口属性
pyautogui.mouseDown(button='middle')
def stopDrag(self):
if self.isDragging == True:
try:
pyautogui.mouseUp(button='middle')
except:
pass
self.isDragging = False # 将isDragging设置为False
wp = WindowProperties() # 创建WindowProperties对象
wp.setCursorHidden(False) # 显示鼠标光标
self.win.requestProperties(wp) # 设置窗口属性
self.win.movePointer(0, self.win.getXSize() // 2, self.win.getYSize() // 2) # 将鼠标指针移动到窗口中心
else:
self.startDrag()
def rotateCameraTask(self, task):
if self.isDragging:
currentPosition = self.win.getPointer(0) # 获取鼠标指针的位置
#print(self.camera.getHpr())
if currentPosition.getX() >= self.win.getXSize() - 2 or currentPosition.getX() <= 2:
print('碰到了窗口左或右边缘,,已将鼠标重新设置为窗口中心')
self.edge = True
elif currentPosition.getY() >= self.win.getYSize() - 2 or currentPosition.getY() <= 2:
print('碰到了窗口上或下边缘,已将鼠标重新设置为窗口中心')
self.edge = True
else:
self.edge=False
if self.edge:
self.win.movePointer(0, self.win.getXSize() // 2, self.win.getYSize() // 2)
self.lastPosition = self.win.getPointer(0) # 获取鼠标指针的位置
else:
currentPosition = self.win.getPointer(0) # 获取鼠标指针的位置
deltaX = self.lastPosition.getX() - currentPosition.getX() # 计算鼠标指针在x轴上的移动距离
deltaY = self.lastPosition.getY() - currentPosition.getY() # 计算鼠标指针在y轴上的移动距离
print(self.camera.getHpr()[1])
if self.camera.getHpr()[1]<=-80:
if deltaY>0:
deltaY=0
if self.camera.getHpr()[1]>=80:
if deltaY<0:
deltaY=0
self.speedH = deltaX * 0.1 # 根据鼠标指针在x轴上的移动距离设置水平旋转速度
self.speedP = deltaY * 0.1 # 根据鼠标指针在y轴上的移动距离设置垂直旋转速度
self.angleH += self.speedH # 根据水平旋转速度更新水平旋转角度
self.angleP += self.speedP # 根据垂直旋转速度更新垂直旋转角度
# 获取摄像机到目标点的向量
vec = self.camera.getPos() - self.target.getPos()
# 获取摄像机到目标点的距离
dist = vec.length()
# 计算摄像机与其他模型之间的最小距离
min_dist = 5
for model in self.render.getChildren():
if model != self.target and model.getTag('collider') == 'True':
# 获取摄像机到模型的向量
vec = self.camera.getPos() - model.getPos()
# 获取摄像机到模型的距离
dist = vec.length()
# 如果摄像机与模型之间的距离小于min_dist,则减小self.distance的值
if dist < min_dist:
self.distance -= 0.1
break
self.camera.setPos(self.target + Vec3(self.distance * math.sin(math.radians(self.angleH)) * math.cos(math.radians(self.angleP)),
self.distance * math.cos(math.radians(self.angleH)) * math.cos(math.radians(self.angleP)),
self.distance * math.sin(math.radians(self.angleP)))) # 设置相机的位置
self.camera.lookAt(self.target) # 设置相机的朝向
self.lastPosition = currentPosition # 更新lastPosition的值
return task.cont # 返回task.cont
# 创建MyApp类的实例并运行应用程序
app = MyApp() # 创建MyApp类的实例
app.run() # 运行应用程序
模型碰撞检测设置:
在模型的egg文件中添加一个tag,代码如下:
<Cube> {
<Collide> { Polyset keep descend }
<Tag> collider { 'True' }
}
原文地址: https://www.cveoy.top/t/topic/oiSw 著作权归作者所有。请勿转载和采集!