无法使用 gluSphere() 绘制到同一位置?
Cannot draw to the same position using gluSphere()?
我正在使用 PyOpenGL 制作游戏。我想每 4 秒从一个地方发射子弹,但是当我使用 gluSphere()
绘制子弹时,它并没有出现在我排除的地方(除了第一次绘制球体)。我该如何解决?
相关代码:
import threading
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
class Object:
def __init__(self):
self.bullet = []
def draw_bullet(pos):
glTranslated(pos[0], pos[1], pos[2]) #Move to the place
glColor4f(1, 1, 1, 1) #Put color
gluSphere(sphere, 0.5, 32, 16) #Draw sphere
def shoot(obj):
global shoottimer
shoottimer = None
obj.bullet.append(pos)
object = Object()
shoottimer = None
pos = [0,0,0]
while True:
if shoottimer == None:
shoottimer = threading.Timer(4,shoot,args = [object])
shoottimer.start()
for bullet in person.bullet:
person.draw_bullet(bullet)
完整代码:
#!/usr/local/bin/python3
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import math,sys,numpy,random,ctypes,threading,os
pygame.init()
display = (1440, 900)
screen = pygame.display.set_mode(display, DOUBLEBUF | OPENGL | RESIZABLE)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glShadeModel(GL_SMOOTH)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_BLEND)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
glEnable(GL_LIGHT0)
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5, 1])
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1])
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glMatrixMode(GL_MODELVIEW)
gluLookAt(0, -8, 0, 0, 0, 0, 0, 0, 1)
glTranslatef(0,-8,0)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
glLoadIdentity()
# init mouse movement and center mouse on screen
displayCenter = [screen.get_size()[i] // 2 for i in range(2)]
mouseMove = [0, 0]
pygame.mouse.set_pos(displayCenter)
cmddown = False
light = 0
mouseclick = False
cam_attack = False
cam_damage = random.randint(20,30)
max_health = 100
health = max_health
knockback = False
knocktimer = None
shoottimer = None
sphere = gluNewQuadric()
dist = None
dist_list = []
person_count = 1
up_down_angle = 0.0
camera_pos = (0,0,0)
paused = False
run = True
#xzy = xyz
#Functions & Classes
def InverseMat44(mat):
m = [mat[i][j] for i in range(4) for j in range(4)]
inv = [0]*16
inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]
inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]
inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]
inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9]
inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]
inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]
inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9]
inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]
inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]
inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6]
inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]
inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5]
inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6]
inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]
inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5]
inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5]
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]
for i in range(16):
inv[i] /= det
return inv
def clicked(tar_x,tar_y,tarimg):
if tar_x < cursor_x < tar_x + tarimg.get_width() and tar_y < cursor_y < tar_y + tarimg.get_height():
return True
return False
def follower(x,y,z,x1,y1,z1,speed):
dir_x, dir_y = (x1-x, y1-y)
distance = math.hypot(dir_x, dir_y)
dir_x, dir_y = (dir_x/distance, dir_y/distance)
angle = math.degrees(math.atan2(dir_y, dir_x)) + 90
return (dir_x*speed, dir_y*speed, 0, angle)
def random_pos(max_distance):
x_value_change = random.randrange(-max_distance + 2,max_distance + 2)
y_value_change = random.randrange(-max_distance + 20,max_distance + 3)
z_value_change = 0
return (x_value_change, y_value_change, z_value_change)
def blit_text(x,y,font,text,r,g,b):
glColor3f(r,g,b)
glWindowPos2f(x,y)
for ch in text:
glutBitmapCharacter(font,ctypes.c_int(ord(ch)))
def stopknock() :
global knockback,knocktimer,health
knockback = False
knocktimer = None
health -= random.randint(20,40)
def shoot(obj):
global shoottimer
shoottimer = None
obj.bullet.append(obj.pos)
def subtract(v0, v1):
return [v0[0]-v1[0], v0[1]-v1[1], v0[2]-v1[2]]
def dot(v0, v1):
return v0[0]*v1[0]+v0[1]*v1[1]+v0[2]*v1[2]
def length(v):
return math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2])
def mults(v, s):
return [v[0]*s, v[1]*s, v[2]*s]
def add(v0, v1):
return [v0[0]+v1[0], v0[1]+v1[1], v0[2]+v1[2]]
def cross(v0, v1):
return [
v0[1]*v1[2]-v1[1]*v0[2],
v0[2]*v1[0]-v1[2]*v0[0],
v0[0]*v1[1]-v1[0]*v0[1]]
def normalize(v):
l = length(v)
return [v[0]/l, v[1]/l, v[2]/l]
def PointInOrOn( P1, P2, A, B ):
CP1 = cross(subtract(B, A), subtract(P1, A))
CP2 = cross(subtract(B, A), subtract(P2, A))
return dot( CP1, CP2 ) >= 0
def PointInOrOnTriangle( P, A, B, C ):
return PointInOrOn(P, A, B, C) and PointInOrOn(P, B, C, A) and PointInOrOn(P, C, A, B)
def isectPlane(p0, p1, PA, PB, PC):
R0 = p0 # origin
D = normalize(subtract(p1, p0))
P0 = PA
NV = normalize(cross(subtract(PB, PA), subtract(PC, PA)))
dist_isect = dot(subtract(P0, R0), NV) / dot(D, NV)
P_isect = add(R0, mults(D, dist_isect))
return P_isect, dist_isect
def isectQuad(p0, p1, PA, PB, PC, PD):
P, t = isectPlane(p0, p1, PA, PB, PC)
if t >= 0 and (PointInOrOnTriangle(P, PA, PB,
PC) or PointInOrOnTriangle(P, PA, PC, PD)):
return t
return None
def isectCuboid(p0, p1, pMin, pMax):
t = None
try:
pl = [ [pMin[0], pMin[1], pMin[2]], [pMax[0], pMin[1], pMin[2]], [pMax[0], pMax[1], pMin[2]], [pMin[0], pMax[1], pMin[2]],
[pMin[0], pMin[1], pMax[2]], [pMax[0], pMin[1], pMax[2]], [pMax[0], pMax[1], pMax[2]], [pMin[0], pMax[1], pMax[2]] ]
il = [[0, 1, 2, 3], [4, 5, 6, 7], [4, 0, 3, 7], [1, 5, 6, 2], [4, 3, 1, 0], [3, 2, 6, 7]]
for qi in il:
ts = isectQuad(p0, p1, pl[qi[0]], pl[qi[1]], pl[qi[2]], pl[qi[3]])
if ts != None and ts >= 0 and (t == None or ts < t):
t = ts
except:
t = None
return t
class Ground:
def __init__(self,mul=1):
self.vertices = [
[-20,20,-1],
[20,20,-1],
[-20,-300,-1],
[20,-300,-1]
]
def draw(self):
glBegin(GL_QUADS) #Begin fill
for vertex in self.vertices:
glColor3f(0,0.5,0.5)
glVertex3fv(vertex)
glEnd()
class Person:
def __init__(self):
self.vertices = [
[-1,0,1],
[-1,0,-1],
[1,0,-1],
[1,0,1],
[-1,1,1],
[-1,1,-1],
[1,1,-1],
[1,1,1]
]
self.vertices = list(numpy.multiply(numpy.array(self.vertices),1))
self.edges = (
(0,1),
(0,3),
(0,4),
(1,2),
(1,5),
(2,3),
(2,6),
(3,7),
(4,5),
(4,7),
(5,6),
(6,7)
)
self.surfaces = (
(0,1,2,3),
(0,1,5,4),
(4,5,6,7),
(1,2,6,5),
(0,3,7,4),
(2,3,7,6)
)
self.x = self.vertices[1][0]
self.y = self.vertices[1][2]
self.z = self.vertices[1][1]
self.pos = (self.x,self.y,self.z)
self.rot = 0
self.health = 100
self.damage = random.randint(20,40)
self.bullet = []
def draw(self):
glTranslated(self.pos[0], self.pos[1], self.pos[2])
glRotated(self.rot,0,0,1)
#Get current view matrix, projection matrix and viewport rectangle
mv_matrix = glGetDoublev(GL_MODELVIEW_MATRIX)
proj_matrix = glGetDoublev(GL_PROJECTION_MATRIX)
vp_rect = glGetIntegerv(GL_VIEWPORT)
#Calculate "near" and "far" point
pt_near = gluUnProject(displayCenter[0], displayCenter[1], 0, mv_matrix, proj_matrix, vp_rect)
pt_far = gluUnProject(displayCenter[0], displayCenter[1], 1, mv_matrix, proj_matrix, vp_rect)
dist = isectCuboid(pt_near, pt_far, [-1, 0, -1], [1, 1, 1])
glBegin(GL_QUADS) #Begin fill
for surface in self.surfaces:
for vertex in surface:
glColor3f(0,1,0)
glVertex3fv(self.vertices[vertex])
glEnd()
glLineWidth(5) #Set width of the line
glBegin(GL_LINES) #Begin outline
for edge in self.edges:
for vertex in edge:
glColor3f(1,1,0)
glVertex3fv(self.vertices[vertex])
glEnd()
return dist
def draw_bullet(self,pos): #This is the part where I got stuck
glLoadIdentity()
glTranslated(pos[0], pos[1], pos[2]) #Move to the place
glColor4f(1, 1, 1, 1) #Put color
gluSphere(sphere, 0.5, 32, 16) #Draw sphere
def move(self,x,y,z):
self.pos = (self.pos[0]+x,self.pos[1]+y,self.pos[2]+z)
glutInit()
persons = [Person() for person in range(person_count)]
ground = Ground()
for person in persons:
person.pos = random_pos(12)
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LMETA:
cmddown = True
if event.key == pygame.K_ESCAPE:
paused = not paused
if event.key == pygame.K_q:
if cmddown:
run = False
if not paused:
if event.type == pygame.MOUSEMOTION:
mouseMove = [event.pos[i] - displayCenter[i] for i in range(2)]
pygame.mouse.set_pos(displayCenter)
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
cam_attack = True
else:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
mouseclick = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LMETA:
cmddown = False
pygame.mouse.set_visible(False)
if not paused:
pygame.mouse.set_pos(displayCenter)
#Get keys
keypress = pygame.key.get_pressed()
#Init model view matrix
glLoadIdentity()
#------------------------View------------------------
#Apply the look up and down (with 90° angle limit)
if up_down_angle < -90:
if mouseMove[1] > 0:
up_down_angle += mouseMove[1]*0.1
elif up_down_angle > 90:
if mouseMove[1] < 0:
up_down_angle += mouseMove[1]*0.1
else:
up_down_angle += mouseMove[1]*0.1
glRotatef(up_down_angle, 1.0, 0.0, 0.0)
#Init the view matrix
glPushMatrix()
glLoadIdentity()
#Apply the movement
if keypress[pygame.K_w]:
glTranslatef(0,0,0.1)
if keypress[pygame.K_s]:
glTranslatef(0,0,-0.1)
if keypress[pygame.K_d]:
glTranslatef(-0.1,0,0)
if keypress[pygame.K_a]:
glTranslatef(0.1,0,0)
#Apply the look left and right
glRotatef(mouseMove[0]*0.1, 0.0, 1.0, 0.0)
#------------------------View------------------------
#Multiply the current matrix by the new view matrix and store the final view matrix
glMultMatrixf(viewMatrix)
#Knockback
if knockback:
if knocktimer == None:
knockback_dist = 0.4
knockback_dir = normalize(subtract(knockback, camera_pos))
glTranslatef(knockback_dir[0]*knockback_dist, knockback_dir[1]*knockback_dist, 0)
if knocktimer == None:
knocktimer = threading.Timer(0.2,stopknock)
knocktimer.start()
#Bullet
for person in persons:
if shoottimer == None:
shoottimer = threading.Timer(4,shoot,args = [person])
shoottimer.start()
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
invVM = InverseMat44(viewMatrix)
camera_pos = (invVM[12],invVM[13],invVM[14])
#Apply view matrix
glPopMatrix()
glMultMatrixf(viewMatrix)
glLightfv(GL_LIGHT0, GL_POSITION, [1, -1, 1, 0])
#Follow, attack
crosshair_color = (1,1,1)
attacklist = []
for counter,person in enumerate(persons):
freturn = follower(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2],0.02)
xchange,ychange,zchange = freturn[0],freturn[1],freturn[2]
person.rot = freturn[3]
if (touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])) < 3:
xchange,ychange,zchange = 0,0,0
knockback = person.pos
person.move(xchange,ychange,zchange)
if (touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])) < 5 and distlist[counter] != None:
crosshair_color = (1,0,0)
if len(attacklist) >= 2:
bigger = attacklist[1] > touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])
if bigger == True:
attacklist = [person,touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])]
else:
attacklist = [person,touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])]
distlist = []
if attacklist:
if cam_attack == True:
attacklist[0].health -= cam_damage
glClearColor(0.53 + light, 0.63 + light, 0.98 + light, 1) #Change background colour (sky blue)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
blit_text(displayCenter[0] - 700,displayCenter[1] + 410,GLUT_BITMAP_TIMES_ROMAN_24,"Health: " + str(health) + "/" + str(max_health),0,0,0)
#Draw crosshair, health
if health > 0:
blit_text(displayCenter[0] - 5,displayCenter[1] - 5,GLUT_BITMAP_TIMES_ROMAN_24,"+",crosshair_color[0],crosshair_color[1],crosshair_color[2])
glPushMatrix()
glColor4f(0.2, 0.2, 0.5, 1)
for person in persons:
glPushMatrix()
distlist.append(person.draw())
for bullet in person.bullet:
person.draw_bullet(bullet)
glPopMatrix()
ground.draw()
glPopMatrix()
for person in persons:
if person.health <= 0:
persons.remove(person)
if not persons and health > 0:
pass #Show victory
if health <= 0:
light -= 0.04
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5 + light, 0.5 + light, 0.5 + light, 1])
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0 + light, 1.0 + light, 1.0 + light, 1])
cam_attack = False
else:
cursor_x,cursor_y = pygame.mouse.get_pos()
pygame.mouse.set_visible(True)
glClearColor(0.53 + light, 0.63 + light, 0.98 + light, 1) #Change background colour (sky blue)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
mouseclick = False
for person in persons:
glPushMatrix()
distlist.append(person.draw())
for bullet_shot in person.bullet:
person.draw_bullet(bullet_shot)
glPopMatrix()
ground.draw()
pygame.display.flip()
pygame.time.wait(10)
pygame.quit()
我原以为它会绘制球体,但它却关闭了灯光并且什么也没做(可能在其他地方绘制)。
glTranslated
向当前矩阵堆栈添加一个新的翻译。如果你想指定一个新的位置,你必须先撤销之前的翻译。
您应该可以通过在 draw_bullet 方法的开头调用 glLoadIdentity()
来解决您的问题。
现在看到你的整个代码后,更好的解决方案是将 draw_bullet
方法包装在 push/pop 块中:
def draw_bullet(self,pos): #This is the part where I got stuck
glPushMatrix()
glLoadIdentity()
glTranslated(pos[0], pos[1], pos[2]) #Move to the place
glColor4f(1, 1, 1, 1) #Put color
gluSphere(sphere, 0.5, 32, 16) #Draw sphere
glPopMatrix()
备案:您使用的 OpenGL 方法(fixed-function 管道)已经过时十多年了。人们真的应该尽量避免使用它们并使用 OpenGL 3.3 + Core Profile。
每个对象都有它的模型矩阵。模型矩阵应用glTranslate
respctively glRotate
.
调用此函数会更改当前矩阵。为确保模型转换仅应用于 1 个模型而不应用于之后绘制的所有模型,在更改当前矩阵之前,当前矩阵必须为 "saved" 乘以 glPushMatrix
,并且必须为
"restored" 由 glPopMatrix
绘制模型后。
绘制 Person
对象时执行此操作:
class Person:
# [...]
def draw(self):
glPushMatrix() # <--- save
glTranslated(self.pos[0], self.pos[1], self.pos[2])
glRotated(self.rot,0,0,1)
# [...]
glPopMatrix() # <--- restore
return dist
当你绘制子弹时:
class Person:
# [...]
def draw_bullet(self,pos): #This is the part where I got stuck
glPushMatrix() # <--- save
glTranslated(pos[0], pos[1], pos[2]) #Move to the place
glColor4f(1, 1, 1, 1) #Put color
gluSphere(sphere, 0.5, 32, 16) #Draw sphere
glPopMatrix() # <--- restore
注意,视图矩阵设置在模型矩阵之前。 glTranslate
定义的矩阵乘以当前矩阵。这就是你想要的:
mdelview = view * model
所以你必须在设置模型之前跳过设置单位矩阵:
def draw_bullet(self,pos): #This is the part where I got stuck
glPushMatrix()
# glLoadIdentity() <--- delete
glTranslated(pos[0], pos[1], pos[2]) #Move to the place
glColor4f(1, 1, 1, 1) #Put color
gluSphere(sphere, 0.5, 32, 16) #Draw sphere
glPopMatrix()
此外,我建议在新子弹产生时复制位置:
def shoot(obj):
global shoottimer
shoottimer = None
# obj.bullet.append(obj.pos)
obj.bullet.append(obj.pos[:])
我正在使用 PyOpenGL 制作游戏。我想每 4 秒从一个地方发射子弹,但是当我使用 gluSphere()
绘制子弹时,它并没有出现在我排除的地方(除了第一次绘制球体)。我该如何解决?
相关代码:
import threading
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
class Object:
def __init__(self):
self.bullet = []
def draw_bullet(pos):
glTranslated(pos[0], pos[1], pos[2]) #Move to the place
glColor4f(1, 1, 1, 1) #Put color
gluSphere(sphere, 0.5, 32, 16) #Draw sphere
def shoot(obj):
global shoottimer
shoottimer = None
obj.bullet.append(pos)
object = Object()
shoottimer = None
pos = [0,0,0]
while True:
if shoottimer == None:
shoottimer = threading.Timer(4,shoot,args = [object])
shoottimer.start()
for bullet in person.bullet:
person.draw_bullet(bullet)
完整代码:
#!/usr/local/bin/python3
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import math,sys,numpy,random,ctypes,threading,os
pygame.init()
display = (1440, 900)
screen = pygame.display.set_mode(display, DOUBLEBUF | OPENGL | RESIZABLE)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glShadeModel(GL_SMOOTH)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_BLEND)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
glEnable(GL_LIGHT0)
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5, 1])
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1])
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glMatrixMode(GL_MODELVIEW)
gluLookAt(0, -8, 0, 0, 0, 0, 0, 0, 1)
glTranslatef(0,-8,0)
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
glLoadIdentity()
# init mouse movement and center mouse on screen
displayCenter = [screen.get_size()[i] // 2 for i in range(2)]
mouseMove = [0, 0]
pygame.mouse.set_pos(displayCenter)
cmddown = False
light = 0
mouseclick = False
cam_attack = False
cam_damage = random.randint(20,30)
max_health = 100
health = max_health
knockback = False
knocktimer = None
shoottimer = None
sphere = gluNewQuadric()
dist = None
dist_list = []
person_count = 1
up_down_angle = 0.0
camera_pos = (0,0,0)
paused = False
run = True
#xzy = xyz
#Functions & Classes
def InverseMat44(mat):
m = [mat[i][j] for i in range(4) for j in range(4)]
inv = [0]*16
inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]
inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]
inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]
inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9]
inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]
inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]
inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9]
inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]
inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]
inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6]
inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]
inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5]
inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6]
inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]
inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5]
inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5]
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]
for i in range(16):
inv[i] /= det
return inv
def clicked(tar_x,tar_y,tarimg):
if tar_x < cursor_x < tar_x + tarimg.get_width() and tar_y < cursor_y < tar_y + tarimg.get_height():
return True
return False
def follower(x,y,z,x1,y1,z1,speed):
dir_x, dir_y = (x1-x, y1-y)
distance = math.hypot(dir_x, dir_y)
dir_x, dir_y = (dir_x/distance, dir_y/distance)
angle = math.degrees(math.atan2(dir_y, dir_x)) + 90
return (dir_x*speed, dir_y*speed, 0, angle)
def random_pos(max_distance):
x_value_change = random.randrange(-max_distance + 2,max_distance + 2)
y_value_change = random.randrange(-max_distance + 20,max_distance + 3)
z_value_change = 0
return (x_value_change, y_value_change, z_value_change)
def blit_text(x,y,font,text,r,g,b):
glColor3f(r,g,b)
glWindowPos2f(x,y)
for ch in text:
glutBitmapCharacter(font,ctypes.c_int(ord(ch)))
def stopknock() :
global knockback,knocktimer,health
knockback = False
knocktimer = None
health -= random.randint(20,40)
def shoot(obj):
global shoottimer
shoottimer = None
obj.bullet.append(obj.pos)
def subtract(v0, v1):
return [v0[0]-v1[0], v0[1]-v1[1], v0[2]-v1[2]]
def dot(v0, v1):
return v0[0]*v1[0]+v0[1]*v1[1]+v0[2]*v1[2]
def length(v):
return math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2])
def mults(v, s):
return [v[0]*s, v[1]*s, v[2]*s]
def add(v0, v1):
return [v0[0]+v1[0], v0[1]+v1[1], v0[2]+v1[2]]
def cross(v0, v1):
return [
v0[1]*v1[2]-v1[1]*v0[2],
v0[2]*v1[0]-v1[2]*v0[0],
v0[0]*v1[1]-v1[0]*v0[1]]
def normalize(v):
l = length(v)
return [v[0]/l, v[1]/l, v[2]/l]
def PointInOrOn( P1, P2, A, B ):
CP1 = cross(subtract(B, A), subtract(P1, A))
CP2 = cross(subtract(B, A), subtract(P2, A))
return dot( CP1, CP2 ) >= 0
def PointInOrOnTriangle( P, A, B, C ):
return PointInOrOn(P, A, B, C) and PointInOrOn(P, B, C, A) and PointInOrOn(P, C, A, B)
def isectPlane(p0, p1, PA, PB, PC):
R0 = p0 # origin
D = normalize(subtract(p1, p0))
P0 = PA
NV = normalize(cross(subtract(PB, PA), subtract(PC, PA)))
dist_isect = dot(subtract(P0, R0), NV) / dot(D, NV)
P_isect = add(R0, mults(D, dist_isect))
return P_isect, dist_isect
def isectQuad(p0, p1, PA, PB, PC, PD):
P, t = isectPlane(p0, p1, PA, PB, PC)
if t >= 0 and (PointInOrOnTriangle(P, PA, PB,
PC) or PointInOrOnTriangle(P, PA, PC, PD)):
return t
return None
def isectCuboid(p0, p1, pMin, pMax):
t = None
try:
pl = [ [pMin[0], pMin[1], pMin[2]], [pMax[0], pMin[1], pMin[2]], [pMax[0], pMax[1], pMin[2]], [pMin[0], pMax[1], pMin[2]],
[pMin[0], pMin[1], pMax[2]], [pMax[0], pMin[1], pMax[2]], [pMax[0], pMax[1], pMax[2]], [pMin[0], pMax[1], pMax[2]] ]
il = [[0, 1, 2, 3], [4, 5, 6, 7], [4, 0, 3, 7], [1, 5, 6, 2], [4, 3, 1, 0], [3, 2, 6, 7]]
for qi in il:
ts = isectQuad(p0, p1, pl[qi[0]], pl[qi[1]], pl[qi[2]], pl[qi[3]])
if ts != None and ts >= 0 and (t == None or ts < t):
t = ts
except:
t = None
return t
class Ground:
def __init__(self,mul=1):
self.vertices = [
[-20,20,-1],
[20,20,-1],
[-20,-300,-1],
[20,-300,-1]
]
def draw(self):
glBegin(GL_QUADS) #Begin fill
for vertex in self.vertices:
glColor3f(0,0.5,0.5)
glVertex3fv(vertex)
glEnd()
class Person:
def __init__(self):
self.vertices = [
[-1,0,1],
[-1,0,-1],
[1,0,-1],
[1,0,1],
[-1,1,1],
[-1,1,-1],
[1,1,-1],
[1,1,1]
]
self.vertices = list(numpy.multiply(numpy.array(self.vertices),1))
self.edges = (
(0,1),
(0,3),
(0,4),
(1,2),
(1,5),
(2,3),
(2,6),
(3,7),
(4,5),
(4,7),
(5,6),
(6,7)
)
self.surfaces = (
(0,1,2,3),
(0,1,5,4),
(4,5,6,7),
(1,2,6,5),
(0,3,7,4),
(2,3,7,6)
)
self.x = self.vertices[1][0]
self.y = self.vertices[1][2]
self.z = self.vertices[1][1]
self.pos = (self.x,self.y,self.z)
self.rot = 0
self.health = 100
self.damage = random.randint(20,40)
self.bullet = []
def draw(self):
glTranslated(self.pos[0], self.pos[1], self.pos[2])
glRotated(self.rot,0,0,1)
#Get current view matrix, projection matrix and viewport rectangle
mv_matrix = glGetDoublev(GL_MODELVIEW_MATRIX)
proj_matrix = glGetDoublev(GL_PROJECTION_MATRIX)
vp_rect = glGetIntegerv(GL_VIEWPORT)
#Calculate "near" and "far" point
pt_near = gluUnProject(displayCenter[0], displayCenter[1], 0, mv_matrix, proj_matrix, vp_rect)
pt_far = gluUnProject(displayCenter[0], displayCenter[1], 1, mv_matrix, proj_matrix, vp_rect)
dist = isectCuboid(pt_near, pt_far, [-1, 0, -1], [1, 1, 1])
glBegin(GL_QUADS) #Begin fill
for surface in self.surfaces:
for vertex in surface:
glColor3f(0,1,0)
glVertex3fv(self.vertices[vertex])
glEnd()
glLineWidth(5) #Set width of the line
glBegin(GL_LINES) #Begin outline
for edge in self.edges:
for vertex in edge:
glColor3f(1,1,0)
glVertex3fv(self.vertices[vertex])
glEnd()
return dist
def draw_bullet(self,pos): #This is the part where I got stuck
glLoadIdentity()
glTranslated(pos[0], pos[1], pos[2]) #Move to the place
glColor4f(1, 1, 1, 1) #Put color
gluSphere(sphere, 0.5, 32, 16) #Draw sphere
def move(self,x,y,z):
self.pos = (self.pos[0]+x,self.pos[1]+y,self.pos[2]+z)
glutInit()
persons = [Person() for person in range(person_count)]
ground = Ground()
for person in persons:
person.pos = random_pos(12)
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LMETA:
cmddown = True
if event.key == pygame.K_ESCAPE:
paused = not paused
if event.key == pygame.K_q:
if cmddown:
run = False
if not paused:
if event.type == pygame.MOUSEMOTION:
mouseMove = [event.pos[i] - displayCenter[i] for i in range(2)]
pygame.mouse.set_pos(displayCenter)
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
cam_attack = True
else:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
mouseclick = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LMETA:
cmddown = False
pygame.mouse.set_visible(False)
if not paused:
pygame.mouse.set_pos(displayCenter)
#Get keys
keypress = pygame.key.get_pressed()
#Init model view matrix
glLoadIdentity()
#------------------------View------------------------
#Apply the look up and down (with 90° angle limit)
if up_down_angle < -90:
if mouseMove[1] > 0:
up_down_angle += mouseMove[1]*0.1
elif up_down_angle > 90:
if mouseMove[1] < 0:
up_down_angle += mouseMove[1]*0.1
else:
up_down_angle += mouseMove[1]*0.1
glRotatef(up_down_angle, 1.0, 0.0, 0.0)
#Init the view matrix
glPushMatrix()
glLoadIdentity()
#Apply the movement
if keypress[pygame.K_w]:
glTranslatef(0,0,0.1)
if keypress[pygame.K_s]:
glTranslatef(0,0,-0.1)
if keypress[pygame.K_d]:
glTranslatef(-0.1,0,0)
if keypress[pygame.K_a]:
glTranslatef(0.1,0,0)
#Apply the look left and right
glRotatef(mouseMove[0]*0.1, 0.0, 1.0, 0.0)
#------------------------View------------------------
#Multiply the current matrix by the new view matrix and store the final view matrix
glMultMatrixf(viewMatrix)
#Knockback
if knockback:
if knocktimer == None:
knockback_dist = 0.4
knockback_dir = normalize(subtract(knockback, camera_pos))
glTranslatef(knockback_dir[0]*knockback_dist, knockback_dir[1]*knockback_dist, 0)
if knocktimer == None:
knocktimer = threading.Timer(0.2,stopknock)
knocktimer.start()
#Bullet
for person in persons:
if shoottimer == None:
shoottimer = threading.Timer(4,shoot,args = [person])
shoottimer.start()
viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
invVM = InverseMat44(viewMatrix)
camera_pos = (invVM[12],invVM[13],invVM[14])
#Apply view matrix
glPopMatrix()
glMultMatrixf(viewMatrix)
glLightfv(GL_LIGHT0, GL_POSITION, [1, -1, 1, 0])
#Follow, attack
crosshair_color = (1,1,1)
attacklist = []
for counter,person in enumerate(persons):
freturn = follower(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2],0.02)
xchange,ychange,zchange = freturn[0],freturn[1],freturn[2]
person.rot = freturn[3]
if (touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])) < 3:
xchange,ychange,zchange = 0,0,0
knockback = person.pos
person.move(xchange,ychange,zchange)
if (touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])) < 5 and distlist[counter] != None:
crosshair_color = (1,0,0)
if len(attacklist) >= 2:
bigger = attacklist[1] > touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])
if bigger == True:
attacklist = [person,touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])]
else:
attacklist = [person,touched(person.pos[0],person.pos[1],person.pos[2],camera_pos[0],camera_pos[1],camera_pos[2])]
distlist = []
if attacklist:
if cam_attack == True:
attacklist[0].health -= cam_damage
glClearColor(0.53 + light, 0.63 + light, 0.98 + light, 1) #Change background colour (sky blue)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
blit_text(displayCenter[0] - 700,displayCenter[1] + 410,GLUT_BITMAP_TIMES_ROMAN_24,"Health: " + str(health) + "/" + str(max_health),0,0,0)
#Draw crosshair, health
if health > 0:
blit_text(displayCenter[0] - 5,displayCenter[1] - 5,GLUT_BITMAP_TIMES_ROMAN_24,"+",crosshair_color[0],crosshair_color[1],crosshair_color[2])
glPushMatrix()
glColor4f(0.2, 0.2, 0.5, 1)
for person in persons:
glPushMatrix()
distlist.append(person.draw())
for bullet in person.bullet:
person.draw_bullet(bullet)
glPopMatrix()
ground.draw()
glPopMatrix()
for person in persons:
if person.health <= 0:
persons.remove(person)
if not persons and health > 0:
pass #Show victory
if health <= 0:
light -= 0.04
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5 + light, 0.5 + light, 0.5 + light, 1])
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0 + light, 1.0 + light, 1.0 + light, 1])
cam_attack = False
else:
cursor_x,cursor_y = pygame.mouse.get_pos()
pygame.mouse.set_visible(True)
glClearColor(0.53 + light, 0.63 + light, 0.98 + light, 1) #Change background colour (sky blue)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
mouseclick = False
for person in persons:
glPushMatrix()
distlist.append(person.draw())
for bullet_shot in person.bullet:
person.draw_bullet(bullet_shot)
glPopMatrix()
ground.draw()
pygame.display.flip()
pygame.time.wait(10)
pygame.quit()
我原以为它会绘制球体,但它却关闭了灯光并且什么也没做(可能在其他地方绘制)。
glTranslated
向当前矩阵堆栈添加一个新的翻译。如果你想指定一个新的位置,你必须先撤销之前的翻译。
您应该可以通过在 draw_bullet 方法的开头调用 glLoadIdentity()
来解决您的问题。
现在看到你的整个代码后,更好的解决方案是将 draw_bullet
方法包装在 push/pop 块中:
def draw_bullet(self,pos): #This is the part where I got stuck
glPushMatrix()
glLoadIdentity()
glTranslated(pos[0], pos[1], pos[2]) #Move to the place
glColor4f(1, 1, 1, 1) #Put color
gluSphere(sphere, 0.5, 32, 16) #Draw sphere
glPopMatrix()
备案:您使用的 OpenGL 方法(fixed-function 管道)已经过时十多年了。人们真的应该尽量避免使用它们并使用 OpenGL 3.3 + Core Profile。
每个对象都有它的模型矩阵。模型矩阵应用glTranslate
respctively glRotate
.
调用此函数会更改当前矩阵。为确保模型转换仅应用于 1 个模型而不应用于之后绘制的所有模型,在更改当前矩阵之前,当前矩阵必须为 "saved" 乘以 glPushMatrix
,并且必须为
"restored" 由 glPopMatrix
绘制模型后。
绘制 Person
对象时执行此操作:
class Person:
# [...]
def draw(self):
glPushMatrix() # <--- save
glTranslated(self.pos[0], self.pos[1], self.pos[2])
glRotated(self.rot,0,0,1)
# [...]
glPopMatrix() # <--- restore
return dist
当你绘制子弹时:
class Person:
# [...]
def draw_bullet(self,pos): #This is the part where I got stuck
glPushMatrix() # <--- save
glTranslated(pos[0], pos[1], pos[2]) #Move to the place
glColor4f(1, 1, 1, 1) #Put color
gluSphere(sphere, 0.5, 32, 16) #Draw sphere
glPopMatrix() # <--- restore
注意,视图矩阵设置在模型矩阵之前。 glTranslate
定义的矩阵乘以当前矩阵。这就是你想要的:
mdelview = view * model
所以你必须在设置模型之前跳过设置单位矩阵:
def draw_bullet(self,pos): #This is the part where I got stuck
glPushMatrix()
# glLoadIdentity() <--- delete
glTranslated(pos[0], pos[1], pos[2]) #Move to the place
glColor4f(1, 1, 1, 1) #Put color
gluSphere(sphere, 0.5, 32, 16) #Draw sphere
glPopMatrix()
此外,我建议在新子弹产生时复制位置:
def shoot(obj):
global shoottimer
shoottimer = None
# obj.bullet.append(obj.pos)
obj.bullet.append(obj.pos[:])