问题描述
我有一个2d的pygame水模拟游戏,我遵循了教程进行制作。我还找到了解决该问题的答案,以解决本教程中的问题:Pygame water physics not working as intended
此后,我一直在尝试将此程序转换为使用pyopengl渲染事物。但是,我一直在努力: 答:画水多边形 B:用平铺的纹理对水多边形进行纹理
这是我(相当差劲)试图将这段代码转换为pyopengl的尝试。
import pygame,random
import math as m
from pygame import *
from OpenGL import *
from OpenGL.GLU import *
from OpenGL.GL import *
pygame.init()
WINDOW_SIZE = (854,480)
screen = pygame.display.set_mode(WINDOW_SIZE,32,DOUBLEBUF|OPENGL) # initiate the window
clock = pygame.time.Clock()
def draw_polygon(polygon_points):
glBegin(GL_POLYGON);
for i in polygon_points:
glVertex3fv(i)
#glEnd()
class surface_water_particle():
def __init__(self,x,y):
self.x_pos = x
self.y_pos = y
self.target_y = y
self.velocity = 0
self.k = 0.04
self.d = 0.08
self.time = 1
def update(self):
x = self.y_pos - self.target_y
a = -(self.k * x + self.d * self.velocity)
if self.y_pos > self.target_y:
self.y_pos -= 0.1
if self.y_pos < self.target_y:
self.y_pos += 0.1
self.velocity = round(self.velocity)
self.y_pos += self.velocity
self.velocity += a
self.time += 1
class water_tile():
def __init__(self,x_start,x_end,y_start,y_end,segment_length):
self.springs = []
self.x_start = x_start
self.y_start = y_start
self.x_end = x_end
self.y_end = y_end - 10
for i in range(abs(x_end - x_start) // segment_length):
self.springs.append(surface_water_particle(i * segment_length + x_start,y_end))
def update(self,spread):
passes = 4 # more passes = more splash spreading
for i in range(len(self.springs)):
self.springs[i].update()
leftDeltas = [0] * len(self.springs)
rightDeltas = [0] * len(self.springs)
for p in range(passes):
for i in range(0,len(self.springs)):
if i > 0:
leftDeltas[i] = spread * (self.springs[i].y_pos - self.springs[i - 1].y_pos)
self.springs[i - 1].velocity += leftDeltas[i]
if i < len(self.springs):
rightDeltas[i] = spread * (self.springs[i].y_pos - self.springs[(i + 1)%len(self.springs)].y_pos)
self.springs[(i + 1)%len(self.springs)].velocity += rightDeltas[i]
for i in range(0,len(self.springs)):
if round (leftDeltas[i],12) == 0 or round (rightDeltas[i],12) == 0:
self.springs[i - 1].y_pos = self.y_end+10
if i > 0:
self.springs[i - 1].y_pos += leftDeltas[i] # you were updating velocity here!
if i < len(self.springs):
self.springs[(i + 1)%len(self.springs)].y_pos += rightDeltas[i]
def splash(self,index,speed):
if index >= 0 and index < len(self.springs):
self.springs[index].velocity = speed
def draw(self):
water_surface = pygame.Surface((abs(self.x_end-self.x_start),abs(self.y_start - self.y_end)),depth=8).convert_alpha()
polygon_points = []
polygon_points.append((self.x_start,self.y_start,0))
for spring in range(len(self.springs)):
polygon_points.append((self.springs[spring].x_pos,self.springs[spring].y_pos,0))
polygon_points.append((self.springs[len(self.springs) - 1].x_pos,0))
draw_polygon(polygon_points)
return water_surface
class water_object:
def __init__(self,segment_length,x_pos,y_pos):
self.water = water_tile(x_start,segment_length)
self.image = self.water.draw()
self.rect = self.image.get_rect()
self.rect.x = x_pos
self.rect.y = y_pos
def update(self):
self.water.update(0.1)
self.image = self.water.draw()
water_list = [water_object(0,276+16,64,16,20)]
while True:
screen.fill((0,0))
for water in water_list:
gluPerspective(45,(WINDOW_SIZE[0]/WINDOW_SIZE[1]),0.1,50.0)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
water.update()
#screen.blit(water.image,(water.rect.x,water.rect.y))
#water_test.x_start = water_test.x_start + 1
#if random.randint(0,8) == 1:
#water_test.splash(random.randint(0,len(water_test.springs) - 1),2)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
if event.type == MOUSEBUTTONDOWN:
print (len(water.water.springs))
water.water.splash(random.randint(0,len(water.water.springs) - 1),50)
pygame.display.update()
clock.tick(60)
但是,尽管我做了尝试,但我什么都没显示在屏幕上。如何解决这个问题/如何获得我一直在努力的两件事?
解决方法
您无法将OpenGL primitive绘制到pygame.Surface
。无论如何,没有必要这样做。
为了获得最佳性能,请直接绘制到默认的帧缓冲区(窗口)。
由于要画线,因此必须使用Line primitive
类型。 GL_POLYGON
将绘制一个场凸多边形。使用原始类型GL_LINE_STRIP
:
def draw_polygon(polygon_points):
glBegin(GL_LINE_STRIP)
for pt in polygon_points:
glVertex2f(*pt)
glEnd()
在绘制线条之前,请按glColor
设置当前颜色:
glColor3f(0,1)
draw_polygon(polygon_points)
谎言的顶点坐标在窗口空间中指定。因此,您必须设置Orthographic projection而不是Perspective projection。通过[{glMatrixMode
]指定当前矩阵,并通过glOrtho
设置投影矩阵。由于矩阵运算不会设置矩阵,而是将当前矩阵乘以指定矩阵,因此我建议在(glLoadIdentity
)之前加载单位矩阵:
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0,WINDOW_SIZE[0],WINDOW_SIZE[1],-1,1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
在绘制线条之前,必须先通过glClear
清除帧缓冲区。透明颜色可以通过glClearColor
定义:
glClearColor(1,1,1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
完整示例:
import pygame,random
import math as m
from pygame import *
from OpenGL import *
from OpenGL.GLU import *
from OpenGL.GL import *
pygame.init()
WINDOW_SIZE = (854,480)
screen = pygame.display.set_mode(WINDOW_SIZE,flags=DOUBLEBUF|OPENGL,depth=32,display=0) # initiate the window
clock = pygame.time.Clock()
def draw_polygon(polygon_points):
glBegin(GL_LINE_STRIP)
for pt in polygon_points:
glVertex2f(*pt)
glEnd()
class surface_water_particle():
def __init__(self,x,y):
self.x_pos = x
self.y_pos = y
self.target_y = y
self.velocity = 0
self.k = 0.04
self.d = 0.08
self.time = 1
def update(self):
x = self.y_pos - self.target_y
a = -(self.k * x + self.d * self.velocity)
if self.y_pos > self.target_y:
self.y_pos -= 0.1
if self.y_pos < self.target_y:
self.y_pos += 0.1
self.velocity = round(self.velocity)
self.y_pos += self.velocity
self.velocity += a
self.time += 1
class water():
def __init__(self,x_start,x_end,y_start,y_end,segment_length):
self.springs = []
self.x_start = x_start
self.y_start = y_start
self.x_end = x_end
self.y_end = y_end - 10
for i in range(abs(x_end - x_start) // segment_length):
self.springs.append(surface_water_particle(i * segment_length + x_start,y_end))
def update(self,spread):
passes = 4 # more passes = more splash spreading
for i in range(len(self.springs)):
self.springs[i].update()
leftDeltas = [0] * len(self.springs)
rightDeltas = [0] * len(self.springs)
for p in range(passes):
for i in range(0,len(self.springs) -1 ):
if i > 0:
leftDeltas[i] = spread * (self.springs[i].y_pos - self.springs[i - 1].y_pos)
self.springs[i - 1].velocity += leftDeltas[i]
if i < len(self.springs) - 1:
rightDeltas[i] = spread * (self.springs[i].y_pos - self.springs[i + 1].y_pos)
self.springs[i + 1].velocity += rightDeltas[i]
for i in range(0,len(self.springs) -1):
if i > 0:
self.springs[i - 1].y_pos += leftDeltas[i] # you were updating velocity here!
if i < len(self.springs) - 1:
self.springs[i + 1].y_pos += rightDeltas[i]
def splash(self,index,speed):
if index > 0 and index < len(self.springs) :
self.springs[index].velocity = speed
def draw(self):
water_surface = pygame.Surface((abs(self.x_start - self.x_end),abs(self.y_start - self.y_end))).convert_alpha()
water_surface.fill((0,0))
water_surface.set_colorkey((0,0))
polygon_points = []
polygon_points.append((self.x_start,self.y_start))
for spring in range(len(self.springs)):
polygon_points.append((self.springs[spring].x_pos,self.springs[spring].y_pos))
polygon_points.append((self.springs[len(self.springs) - 1].x_pos,self.y_start))
glColor3f(0,1)
draw_polygon(polygon_points)
water_test = water(0,800,200,3)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0,1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glClearColor(1,1)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
if event.type == MOUSEBUTTONDOWN:
water_test.splash(50,100)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
water_test.update(0.025)
water_test.draw()
pygame.display.flip()
clock.tick(60)