当我在地形中创建一个火山口时,似乎偶尔会弹出奇怪的矩形,尤其是在窗口的边缘创建一个火山口时,会造成巨大的破坏。我怀疑它与nodeIntersects函数有关,该函数检查矩形是否在鼠标的范围内,但我找不到错误
# --------QuadTree Destructable Terrain
# ----Imports
from PIL import Image
import pyglet
from pyglet.window import mouse
from pyglet.window import key
import sys
import math
# ----Variables
terrain = Image.open("terrain.png")
width, height = terrain.size
window = pyglet.window.Window(width=width, height=height)
outline = 1
explosionPower = 50
blackNodes = []
whiteNodes = []
blackNodesCopy=[]
# ----Classes
#-Node: A rectangle that splits into multiple parts
class node:
def __init__(self, min, width, height, parent):
self.min = min
self.width = width
self.height = height
self.children = []
self.parent = parent
self.black = False
def subDivide(self):
if self.height == 1:
newWidth = math.floor(self.width/2)
newWidth2 = math.ceil(self.width/2)
self.children.append(node(self.min, newWidth, 1, self))
self.children.append(node((self.min[0]+newWidth,self.min[1]), newWidth2, 1, self))
return self.children
elif self.width == 1:
newHeight = math.floor(self.height/2)
newHeight2 = math.ceil(self.height/2)
self.children.append(node(self.min, 1, newHeight, self))
self.children.append(node((self.min[0],self.min[1]+newHeight), 1, newHeight2, self))
return self.children
else:
newHeight = math.floor(self.height/2)
newWidth = math.floor(self.width/2)
newHeight2 = math.ceil(self.height/2)
newWidth2 = math.ceil(self.width/2)
self.children.append(node(self.min, newWidth, newHeight, self))
self.children.append(
node((self.min[0]+newWidth, self.min[1]), newWidth2, newHeight, self))
self.children.append(
node((self.min[0]+newWidth, self.min[1]+newHeight), newWidth2, newHeight2, self))
self.children.append(
node((self.min[0], self.min[1]+newHeight), newWidth, newHeight2, self))
return self.children
def allSameColor(self, image):
getColors = []
pixels = image.load()
global height
if (self.height * self.width) == 1:
return True
for x in range(self.min[0], self.min[0]+self.width):
for y in range(abs(self.min[1]+self.height - height), abs(self.min[1]-height)):
if pixels[x, y] not in getColors and (pixels[x, y] == (0,0,0,255) or pixels[x,y] == (255,255,255,255)):
getColors.append(pixels[x, y])
return len(getColors) == 1
def recursionDivision(self, image):
if not self.allSameColor(image):
childs = self.subDivide()
for x in childs:
x.recursionDivision(image)
else:
pixels = image.load()
global height
if pixels[self.min[0], abs(self.min[1]-height) - 1] == (0, 0, 0, 255):
self.black = True
else:
self.black = False
def getAllNodes(self):
if len(self.children) == 0:
global blackNodes
global whiteNodes
if(self.black):
blackNodes.append(self)
else:
whiteNodes.append(self)
else:
for x in self.children:
x.getAllNodes()
def __str__(self):
return str(self.min[0]) + " " + str(self.min[1]) + " " + str(self.width) + " " + str(self.height)
#-QuadtreeFromImage: Sets into motion the Node chain reaction
class QuadtreeFromImage:
def __init__(self, image):
width, height = image.size
self.coreNode = node((0, 0), width, height, None)
self.coreNode.recursionDivision(image)
#-------------------------------------------------Decorated Functions
#-Registers all Mouse Presses and creates Craters
@window.event
def on_mouse_press(x, y, button, modifiers):
if button == mouse.LEFT:
#-Check all boxes within the mouse's range
boxesForUpdate = []
global blackNodes
for z in blackNodes:
if nodeIntersects(z,x,y):
boxesForUpdate.append(z)
#-Get all the boxes that stay after the explosion
newBoxes = []
for z in boxesForUpdate:
global explosionPower
if not (distBetweenPoints(z.min[0],z.min[1],x,y)+distBetweenPoints(z.min[0],z.min[1]+z.height,x,y)+distBetweenPoints(z.min[0]+z.width,z.min[1]+z.height,x,y)+distBetweenPoints(z.min[0]+z.width,z.min[1],x,y) <= explosionPower*4):
list = explosionRecursion(z,x,y).copy()
for b in list:
newBoxes.append(b)
#-Create Appropriate changes to the NodeList
for b in newBoxes:
blackNodes.append(b)
for b in boxesForUpdate:
blackNodes.remove(b)
#-Take in key presses and change Settings
@window.event
def on_key_press(symbol, modifiers):
#-Turn On Outline
if symbol == key.O:
global outline
outline += 1
if outline == 2:
outline = 0
#-Change ExplosionPower from 10-70
if symbol == key.E:
global explosionPower
explosionPower += 10
if explosionPower == 80:
explosionPower = 10
#-Respawn Terrain
if symbol == key.R:
global blackNodes
global blackNodesCopy
blackNodes = blackNodesCopy.copy()
#-----------------------------------------------------Normal Functions
def closestPointToRay(X1, Y1, X2, Y2, X0, Y0):
result = closestPointToLine(X1, Y1, X2, Y2, X0, Y0)
biggerx = 0
biggery = 0
smallerx = 0
smallery = 0
if(X1 > X2):
biggerx = X1
biggery = Y1
smallerx = X2
smallery = Y2
elif(X2 > X1):
biggerx = X2
biggery = Y2
smallerx = X1
biggerx = X2
else:
if(Y1 > Y2):
biggery = Y1
biggerx = X1
smallery = Y2
smallerx = X2
else:
biggery = Y2
biggerx = X2
smallery = Y1
smallerx = X1
if(result[1] < smallery):
return(smallerx, smallery)
elif(result[1] > biggery):
return(biggerx, biggery)
return result
if(result[0] < smallerx):
return(smallerx, smallery)
elif(result[0] > biggerx):
return(biggerx, biggery)
return result
def closestPointToLine(X1, Y1, X2, Y2, X0, Y0):
if(X1-X2 == 0):
return (X1, Y0)
m1 = (Y1-Y2)/(X1-X2)
if(m1 == 0):
return (X0, Y1)
m2 = (m1**-1) * -1
b1 = -(X1 * m1) + Y1
b2 = -(X0 * m2) + Y0
X = (b2-b1)/(m1-m2)
Y = X * m1 + b1
return (X, Y)
def distBetweenPoints(x1, y1, x2, y2):
return math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
def nodeIntersects(z,x,y):
if(x>= z.min[0] and x<= z.min[0]+z.width and y>=z.min[1] and y<=z.min[1]+z.height):
return True
global explosionPower
closestPoint = closestPointToRay(z.min[0],z.min[1],z.min[0],z.min[1]+z.height,x,y)
if distBetweenPoints(closestPoint[0],closestPoint[1],x,y) <= explosionPower:
return True
closestPoint = closestPointToRay(z.min[0],z.min[1],z.min[0]+z.width,z.min[1],x,y)
if distBetweenPoints(closestPoint[0],closestPoint[1],x,y) <= explosionPower:
return True
closestPoint = closestPointToRay(z.min[0],z.min[1]+z.height,z.min[0]+z.width,z.min[1]+z.height,x,y)
if distBetweenPoints(closestPoint[0],closestPoint[1],x,y) <= explosionPower:
return True
closestPoint = closestPointToRay(z.min[0]+z.width,z.min[1]+z.height,z.min[0]+z.width,z.min[1],x,y)
if distBetweenPoints(closestPoint[0],closestPoint[1],x,y) <= explosionPower:
return True
return False
def explosionRecursion(z,x,y):
nodeList = []
for a in z.subDivide():
if nodeIntersects(a,x,y):
if(a.width != 1 or a.height != 1) and not (a.width * a.height == 0):
list = explosionRecursion(a,x,y)
for b in list:
nodeList.append(b)
else:
nodeList.append(a)
return nodeList
#------------------------------------------------------Running
def update(dt):
global blackNodes
global whiteNodes
window.clear()
for x in blackNodes:
global height
global outline
pyglet.graphics.draw(4, pyglet.gl.GL_QUADS, ('v2f', (x.min[0], x.min[1],
x.min[0] + x.width - outline, x.min[1],
x.min[0] + x.width - outline, x.min[1] + x.height - outline,
x.min[0], x.min[1] + x.height - outline )), ('c3B', (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) )
newQuadTree = QuadtreeFromImage(terrain)
newQuadTree.coreNode.getAllNodes()
blackNodesCopy = blackNodes.copy()
pyglet.gl.glClearColor(1,1,1,1)
pyglet.clock.schedule_interval(update, 1/60)
pyglet.app.run()
代码中使用了以下图像,应称为terrain.png: terrain.png
目前没有回答
相关问题 更多 >
编程相关推荐