Python - 3D mapping, without 3D engines - python

Does anyone know how to do this?
I want to be able to map a texture to a 3d cube in Python.
here's my code so far,
from pygame import gfxdraw
import pygame, sys, math
def rotate2d(pos,rad): x,y=pos; s,c = math.sin(rad),math.cos(rad); return x*c-y*s,y*c+x*s
class Cam:
def __init__(self,pos=(0,0,0),rot=(0,0)):
self.pos=list(pos)
self.rot=list(rot)
def events(self,event):
if event.type == pygame.MOUSEMOTION:
x,y = event.rel
x/=200;y/=200
self.rot[0]+=y; self.rot[1]+=x
def update(self,dt,key):
s=dt*10
if key[pygame.K_q]: self.pos[1]+=s
if key[pygame.K_e]: self.pos[1]-=s
x,y = s*math.sin(self.rot[1]),s*math.cos(self.rot[1])
if key[pygame.K_w]: self.pos[0]+=x;self.pos[2]+=y
if key[pygame.K_s]: self.pos[0]-=x;self.pos[2]-=y
if key[pygame.K_a]: self.pos[0]-=y;self.pos[2]+=x
if key[pygame.K_d]: self.pos[0]+=y;self.pos[2]-=x
class Cube:
vertices = (-1,-1,-1),(1,-1,-1),(1,1,-1),(-1,1,-1),(-1,-1,1),(1,-1,1),(1,1,1),(-1,1,1)
edges = (0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),(0,4),(1,5),(2,6),(3,7)
faces = (0,1,2,3),(4,5,6,7),(0,1,5,4),(2,3,7,6),(0,3,7,4),(1,2,6,5)
colors = (255,0,0),(0,255,0),(0,0,255),(255,255,0),(255,0,255),(0,255,255)
def __init__(self,pos=(0,0,0)):
x,y,z = pos
self.verts = [(x+X/2,y+Y/2,z+Z/2) for X,Y,Z in self.vertices]
pygame.init()
w,h = 400,400; cx,cy = w//2,h//2; fov = min(w,h)
screen = pygame.display.set_mode((w,h))
clock = pygame.time.Clock()
cam=Cam((0,0,-5))
pygame.event.get(); pygame.mouse.get_rel()
pygame.mouse.set_visible(0); pygame.event.set_grab(1);
i1 = pygame.image.load("Untitled.png")
cubes = [Cube((0,0,0)),Cube((-2,0,0)),Cube((2,0,0))]
while True:
dt = clock.tick()/1000
event = pygame.event.poll()
if event.type == pygame.QUIT: pygame.quit();sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE: pygame.quit();sys.exit()
cam.events(event)
screen.fill((0,0,0))
face_list = []; face_color = []; depth = []
for obj in cubes:
vert_list = []; screen_coords = []
for x,y,z in obj.verts:
x-=cam.pos[0]
y-=cam.pos[1]
z-=cam.pos[2]
x,z = rotate2d((x,z),cam.rot[1])
y,z = rotate2d((y,z),cam.rot[0])
vert_list += [(x,y,z)]
f=fov/z
x,y = x*f,y*f
screen_coords+=[(cx+int(x),cy+int(y))]
for f in range(len(obj.faces)):
face = obj.faces[f]
on_screen = False
for i in face:
x,y = screen_coords[i]
if vert_list[i][2]>0 and x>0 and x<w and y>0 and y<h: on_screen = True; break
if on_screen:
coords = [screen_coords[i] for i in face]
face_list += [coords]
face_color += [obj.colors[f]]
depth += [sum([sum(vert_list[j][i] for j in face)**2 for i in range(3)])]
order = sorted(range(len(face_list)),key=lambda i: depth[i],reverse=1)
for i in order:
try:
x-=cam.pos[0]
y-=cam.pos[1]
z-=cam.pos[2]
x,z = rotate2d((x,z),cam.rot[1])
y,z = rotate2d((y,z),cam.rot[0])
vert_list += [(x,y,z)]
f=fov/z
x,y = x*f,y*f
#x2 = str(x)
#x2 = int(x2.split('.')[0])
#{
# HERE IS THE TEXTURED POLYGON PART!!!!! VVVVVVVV
pygame.gfxdraw.textured_polygon(screen, face_list[i], i1, 0, 0) # !!!
#}
except:
pass
pygame.display.flip()
key=pygame.key.get_pressed()
cam.update(dt/10,key)
So far I'm using gfxdraw.textured_polygon, however, that's meant for 2d. So it looks masked and weird. I've tried using the x,y values instead of the 0,0 in the offsetting part.
I followed this tutorial to do this: https://www.youtube.com/watch?v=g4E9iq0BixA
Any help wanted.
If you need anything else please ask.

Related

Pygame: Sprites spawn close to each other [duplicate]

Right now, my game blits all the images in random positions correctly and also gets the rect of the images correctly, but I can´t figure out how to use colliderect to make sure the images don´t overlap. How could it work for my code?
Also I´m trying to make the first text fade out and I don´t know why it doesn´t work for me.
Here is the code:
class GAME1:
def __init__(self, next_scene):
self.background = pygame.Surface(size)
# Create an array of images with their rect
self.images = []
self.rects = []
self.imagenes1_array = ['autobus.png','coche.png','barco.png','autobus2.png','grua.png','bici.png']
for i in self.imagenes1_array:
# We divide in variables so we can then get the rect of the whole Img (i2)
i2 = pygame.image.load(i)
self.images.append(i2)
s = pygame.Surface(i2.get_size())
r = s.get_rect()
# Trying to use colliderect so it doesnt overlap
if pygame.Rect.colliderect(r,r) == True:
x = random.randint(300,1000)
y = random.randint(200,700)
self.rects.append(r)
def start(self, gamestate):
self.gamestate = gamestate
for rect in self.rects:
# Give random coordinates (we limit the dimensions (x,y))
x = random.randint(300,1000)
y = random.randint(200,700)
rect.x = x
rect.y = y
def draw(self,screen):
self.background = pygame.Surface(size)
font = pygame.font.SysFont("comicsansms",70)
# First half (Show image to remember)
text1 = font.render('¡A recordar!',True, PURPLE)
text1_1 = text1.copy()
# This surface is used to adjust the alpha of the txt_surf.
alpha_surf = pygame.Surface(text1_1.get_size(), pygame.SRCALPHA)
alpha = 255 # The current alpha value of the surface.
if alpha > 0:
alpha = max(alpha-4, 0)
text1_1 = text1.copy()
alpha_surf.fill((255, 255, 255, alpha))
text1_1.blit(alpha_surf, (0,0), special_flags = pygame.BLEND_RGBA_MULT)
screen.blit(text1_1, (600,50))
# Second half (Show all similar images)
text2 = font.render('¿Cuál era el dibujo?',True, PURPLE)
#screen.blit(text2, (500,50))
for i in range(len(self.images)):
#colliding = pygame.Rect.collidelistall(self.rects)
screen.blit(self.images[i], (self.rects[i].x, self.rects[i].y))
def update(self, events, dt):
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
for rect in self.rects:
if rect.collidepoint(event.pos):
print('works!')
Use collidelist() to test test if one rectangle in a list intersects:
for i in self.imagenes1_array:
s = pygame.image.load(i)
self.images.append(s)
r = s.get_rect()
position_set = False
while not position_set:
r.x = random.randint(300,1000)
r.y = random.randint(200,700)
margin = 10
rl = [rect.inflate(margin*2, margin*2) for rect in self.rects]
if len(self.rects) == 0 or r.collidelist(rl) < 0:
self.rects.append(r)
position_set = True
See the minimal example, that uses the algorithm to generate random not overlapping rectangles:
import pygame
import random
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
def new_recs(rects):
rects.clear()
for _ in range(10):
r = pygame.Rect(0, 0, random.randint(30, 40), random.randint(30, 50))
position_set = False
while not position_set:
r.x = random.randint(10, 340)
r.y = random.randint(10, 340)
margin = 10
rl = [rect.inflate(margin*2, margin*2) for rect in rects]
if len(rects) == 0 or r.collidelist(rl) < 0:
rects.append(r)
position_set = True
rects = []
new_recs(rects)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
new_recs(rects)
window.fill(0)
for r in rects:
pygame.draw.rect(window, (255, 0, 0), r)
pygame.display.flip()
pygame.quit()
exit()

Creating a surface with pygame but when I run program, nothing showing

I am making a menu for a chess game. Since I cannot create multiple pygame windows, I am attempting to create a surface on top of my game. However, when I click my trigger key to show the menu, nothing happens.
Here is the main file of my code:
import pygame as p
import ChessEngine
import os
from tkinter import *
import time
WIDTH = HEIGHT = 512
DIMENSION = 8
SQ_SIZE = HEIGHT//DIMENSION
MAX_FPS = 15
IMAGES = {}
def loadImages():
pieces = ['wp', 'wR', 'wN', 'wB', 'wK',
'wQ', 'bp', 'bR', 'bN', 'bB', 'bK', 'bQ']
for piece in pieces:
IMAGES[piece] = p.transform.scale(
p.image.load('Chess/Images/' + piece + '.png'), (SQ_SIZE, SQ_SIZE))
def main():
p.init()
screen = p.display.set_mode((WIDTH, HEIGHT))
clock = p.time.Clock()
screen.fill(p.Color("white"))
gs = ChessEngine.GameState()
validMoves = gs.getValidMoves()
moveMade = False
animate = False
loadImages()
running = True
sqSelected = ()
playerClicks = []
gameOver = False
CheckV = False
sidebar = False
while running:
for e in p.event.get():
if e.type == p.QUIT:
running = False
elif e.type == p.MOUSEBUTTONDOWN:
if not gameOver:
location = p.mouse.get_pos()
col = location[0]//SQ_SIZE
row = location[1]//SQ_SIZE
if sqSelected == (row, col):
sqSelected = ()
playerClicks = []
else:
sqSelected = (row, col)
playerClicks.append(sqSelected)
if len(playerClicks) == 2:
move = ChessEngine.Move(
playerClicks[0], playerClicks[1], gs.board)
for i in range(len(validMoves)):
if move == validMoves[i]:
gs.makeMove(validMoves[i])
moveMade = True
animate = True
sqSelected = ()
playerClicks = []
if not moveMade:
playerClicks = [sqSelected]
elif e.type == p.KEYDOWN:
if e.key == p.K_z:
gs.undoMove()
moveMade = True
animate = False
checkMate = False
staleMate = False
gameOver = False
if e.key == p.K_r:
gs = ChessEngine.GameState()
validMoves = gs.getValidMoves()
sqSelected = ()
playerClicks = []
moveMade = False
animate = False
checkMate = False
staleMate = False
gameOver = False
if e.key == p.K_s and sidebar == False: # show sidebar
print('show sidebar')
b = p.Surface((SQ_SIZE, SQ_SIZE))
b.set_alpha(255)
b.fill(p.Color('blue'))
screen.blit(b, (HEIGHT, WIDTH))
sidebar = True
elif e.key == p.K_s and sidebar == True: # show board
`print('hide sidebar')`
sidebar = False
if moveMade:
if animate:
animateMove(gs.moveLog[-1], screen, gs.board, clock)
validMoves = gs.getValidMoves()
if gs.inCheck():
CheckV = True
if CheckV == True:
CheckV = False
os.system("say 'check'")
moveMade = False
animate = False
drawGameState(screen, gs, validMoves, sqSelected)
if gs.checkMate:
gameOver = True
if gs.whitetoMove:
drawText(screen, ' Black wins by Checkmate')
else:
drawText(screen, ' White wins by Checkmate')
elif gs.staleMate:
gameOver = True
drawText(screen, 'Stalemate')
clock.tick(MAX_FPS)
p.display.flip()
def highlightSquares(screen, gs, validMoves, sqSelected):
if sqSelected != ():
r, c = sqSelected
if gs.board[r][c][0] == ('w' if gs.whitetoMove else 'b'):
s = p.Surface((SQ_SIZE, SQ_SIZE))
s.set_alpha(100)
s.fill(p.Color('blue'))
screen.blit(s, (c*SQ_SIZE, r*SQ_SIZE))
s.fill(p.Color('yellow'))
for move in validMoves:
if move.startRow == r and move.startCol == c:
screen.blit(s, (SQ_SIZE*move.endCol, SQ_SIZE*move.endRow))
def drawGameState(screen, gs, validMoves, sqSelected):
drawBoard(screen)
highlightSquares(screen, gs, validMoves, sqSelected)
drawPieces(screen, gs.board)
def drawBoard(screen):
global colors
colors = [p.Color("white"), p.Color("gray")]
for r in range(DIMENSION):
for c in range(DIMENSION):
color = colors[((r+c) % 2)]
p.draw.rect(screen, color, p.Rect(
c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE))
def drawPieces(screen, board):
for r in range(DIMENSION):
for c in range(DIMENSION):
piece = board[r][c]
if piece != "--":
screen.blit(IMAGES[piece], p.Rect(
c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE))
def animateMove(move, screen, board, clock):
global colors
dR = move.endRow - move.startRow
dC = move.endCol - move.startCol
framesPerSquare = 10
frameCount = (abs(dR) + abs(dC)) * framesPerSquare
for frame in range(frameCount + 1):
p.event.pump()
r, c = (move.startRow + dR * frame / frameCount,
move.startCol + dC*frame / frameCount)
drawBoard(screen)
drawPieces(screen, board)
color = colors[(move.endRow + move.endCol) % 2]
endSquare = p.Rect(move.endCol*SQ_SIZE,
move.endRow*SQ_SIZE, SQ_SIZE, SQ_SIZE)
p.draw.rect(screen, color, endSquare)
if move.pieceCaptured != '--':
screen.blit(IMAGES[move.pieceCaptured], endSquare)
screen.blit(IMAGES[move.pieceMoved], p.Rect(
c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE))
p.display.flip()
clock.tick(60)
def drawText(screen, text):
font = p.font.SysFont("Helvetica", 32, True, False)
textObject = font.render(text, 0, p.Color('Gray'))
textLocation = p.Rect(0, 0, WIDTH, HEIGHT).move(
WIDTH/2 - textObject.get_width()/2, HEIGHT/2 - textObject.get_height()/2)
screen.blit(textObject, textLocation)
textObject = font.render(text, 0, p.Color("Black"))
screen.blit(textObject, textLocation.move(2, 2))
if __name__ == '__main__':
main()
The menu portion is this bit:
if e.key == p.K_s and sidebar == False: # show sidebar
print('show sidebar')
b = p.Surface((SQ_SIZE, SQ_SIZE))
b.set_alpha(255)
b.fill(p.Color('blue'))
screen.blit(b, (HEIGHT, WIDTH))
sidebar = True
elif e.key == p.K_s and sidebar == True: # show board
`print('hide sidebar')`
sidebar = False
What am I doing wrong? Please help. Thanks.
screen.blit(b, (HEIGHT, WIDTH))
This bit of code places the top left corner of Surface "b" on the screen at the coordinates of the lower right corner of the screen. This means that the Surface is placed, but it isn't visible because it is entirely "offscreen."
Also!
b.set_alpha(255)
Is unnecessary, since fully opaque is the default for a Surface. No need to manually set it.

Depth issue with 3D graphics

I copied a code off YouTube recently, about 3d graphics in Python without the use of 3D modules, like OpenGL. The video worked with only cubes, so I tried adding a tetrahedron to the shapes, and things started popping up where they weren't supposed to. The code is as follows:
import pygame, sys, math, random
def rotate2d(pos, rad): x,y=pos; s,c = math.sin(rad),math.cos(rad); return x*c-y*s,y*c+x*s
class Cam:
def __init__(self, pos=(0,0,0),rot=(0,0)):
self.pos = list(pos)
self.rot = list(rot)
def events(self, event):
if event.type == pygame.MOUSEMOTION:
x, y = event.rel; x/=200; y/=200
self.rot[0]+=y; self.rot[1]+=x
def update(self, dt, key):
s = dt*10
if key[pygame.K_q]: self.pos[1]+=s
if key[pygame.K_e]: self.pos[1]-=s
x,y = s*math.sin(self.rot[1]),s*math.cos(self.rot[1])
if key[pygame.K_w]: self.pos[0]+=x; self.pos[2]+=y
if key[pygame.K_s]: self.pos[0]-=x; self.pos[2]-=y
if key[pygame.K_a]: self.pos[0]-=y; self.pos[2]+=x
if key[pygame.K_d]: self.pos[0]+=y; self.pos[2]-=x
if key[pygame.K_r]: self.pos[0]=0; self.pos[1]=0;\
self.pos[2]=-5; self.rot[0]=0; self.rot[1]=0
class Cube:
faces = (0,1,2,3),(4,5,6,7),(0,1,5,4),(2,3,7,6),(0,3,7,4),(1,2,6,5)
colors = (255,0,0),(255,128,0),(255,255,0),(255,255,255),(0,0,255),(0,255,0)
def __init__(self,pos=(0,0,0),v0=(-1,-1,-1),v1=(1,-1,-1),v2=(1,1,-1),v3=(-1,1,-1),v4=(-1,-1,1),v5=(1,-1,1),v6=(1,1,1),v7=(-1,1,1)):
self.vertices = (v0,v1,v2,v3,v4,v5,v6,v7)
x,y,z = pos
self.verts = [(x+X/2,y+Y/2,z+Z/2) for X,Y,Z in self.vertices]
class Tetrahedron:
faces = (1,2,3),(0,1,2),(0,1,3),(0,2,3)
colors = (255,0,0),(255,128,0),(255,255,0),(255,255,255)
def __init__(self,pos=(0,0,0),v0=(0,0,.866),v1=(-.866,-1,-1),v2=(-.866,1,-1),v3=(.866,0,-1)):
self.vertices = (v0,v1,v2,v3)
x,y,z = pos
self.verts = [(x+X/2,y+Y/2,z+Z/2) for X,Y,Z in self.vertices]
pygame.init()
w,h = 400,400; cx,cy = w//2, h//2
screen = pygame.display.set_mode((w,h))
clock = pygame.time.Clock()
cam = Cam((0,0,-5))
pygame.event.get(); pygame.mouse.get_rel()
pygame.mouse.set_visible(0); pygame.event.set_grab(1)
objects = [Cube((0,0,0)),Cube((0,0,2)),Tetrahedron((0,0,1))]
while True:
dt = clock.tick()/1000
for event in pygame.event.get():
if event.type == pygame.QUIT: pygame.quit(); sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE: pygame.quit(); sys.exit()
cam.events(event)
screen.fill((0,0,0))
face_list = []; face_color = []; depth = []
for obj in objects:
vert_list = []; screen_coords = []
for x,y,z in obj.verts:
x-=cam.pos[0]; y-=cam.pos[1];z-=cam.pos[2]
x,z=rotate2d((x,z),cam.rot[1])
y,z = rotate2d((y,z),cam.rot[0])
vert_list += [(x,y,z)]
f = 200/z
x,y = x*f,y*f
screen_coords+=[(cx+int(x),cy+int(y))]
for f in range(len(obj.faces)):
face = obj.faces[f]
on_screen = False
for i in face:
x,y = screen_coords[i]
if vert_list[i][2]>0 and x>0 and x<w and y>0 and y<h: on_screen = True; break
if on_screen:
coords = [screen_coords[i] for i in face]
face_list += [coords]
face_color += [obj.colors[f]]
depth += [sum(sum(vert_list[j][i] for j in face)**2 for i in range(3))]
order = sorted(range(len(face_list)),key=lambda i:depth[i],reverse=1)
for i in order:
try: pygame.draw.polygon(screen,face_color[i],face_list[i])
except: pass
key = pygame.key.get_pressed()
pygame.display.flip()
cam.update(dt,key)
My problem is that the tetrahedron part is showing up through the cubes on either side, when the cam.pos is at least 7.5 away from the object:
As you can see, the tetrahedron is supposed to be buried under the cube, but it's still showing up. Can someone please suggest an edit to the code which will stop the tetrahedron from showing up through any objects?
What you actually try to do is to sort the faces by the square of the Euclidean distance to the vertices of the face.
But sum(vert_list[j][i] for j in face)**2 does not compute the square of the euclidean distance. It computes the square of the sum of the components of a coordinate. The square of the euclidean distance is
vert_list[j][0]**2 + vert_list[j][1]**2 + vert_list[j][2]**2
That is not the same as
(vert_list[j][0] + vert_list[j][1] + vert_list[j][2])**2
Furthermore you do not take into account the number of vertices of a face, because the squared distances are summed.
Note, the faces of the cube are quads and have 4 vertices, but the faces of the tetrahedron are triangles and have 3 vertices.
Correct the computation of the squared distance and divide by the number of vertices, to solve the issue:
depth += [sum(sum(vert_list[j][i] for j in face)**2 for i in range(3))]
depth += [sum(sum(vert_list[j][i]**2 for i in range(3)) for j in face) / len(face)]
But note, if faces are close to another there still may occur an issue (e.g. covering faces in the same plane). That is not an exact algorithm. It is not designed for "touching" objects.

Python: pygame.gfxdraw.texturedpolygon

So, I've been coding in Python for a few weeks and I felt like trying to make a game. I've gotten to a point where I have no clue what is wrong with my code except for the fact that when I try to draw a textured polygon the texture stretches across the display and only reveals on the cubes. It creates a really cool effect but it isn't what I'm looking for. The goal is to render the texture onto the face of the cube like in Minecraft.
import pygame, sys, os, math
from pygame import gfxdraw
def rotate2d(pos,rad) : x,y=pos; s,c = math.sin(rad), math.cos(rad); return x*c-y*s, y*c+x*s
class Cam:
def __init__(self,pos=(0,0,0), rot=(0,0)):
self.pos = list(pos)
self.rot = list(rot)
def events (self, event):
if event.type == pygame.MOUSEMOTION:
x,y = event.rel; x/=200; y/=200
self.rot[0]+=y; self.rot[1]+=x
def update(self,dt,key):
s = dt*10
if key[pygame.K_c]: self.pos[1]+=s
if key[pygame.K_SPACE]: self.pos[1]-=s
x,y = s*math.sin(self.rot[1]),s*math.cos(self.rot[1])
if self.rot[0] <= -1.58:
self.rot[0] = -1.58
if self.rot[0] >= 1.58:
self.rot[0] = 1.58
if key[pygame.K_w]: self.pos[0]+=x; self.pos[2]+=y
if key[pygame.K_s]: self.pos[0]-=x; self.pos[2]-=y
if key[pygame.K_a]: self.pos[0]-=y; self.pos[2]+=x
if key[pygame.K_d]: self.pos[0]+=y; self.pos[2]-=x
if key[pygame.K_ESCAPE]: pygame.quit(); sys.exit() #Quits Game#
pygame.init()
w,h = 800,600; cx,cy = w//2, h//2; fov = min(w,h)
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.display.set_caption('PyCraft')
screen = pygame.display.set_mode((w,h))
clock = pygame.time.Clock()
## Textures ##
dirt_texture = pygame.image.load("textures/dirt.png").convert()
stone_texture = pygame.image.load("textures/stone.png").convert()
bedrock_texture = pygame.image.load("textures/bedrock.png").convert()
class Dirt:
vertices = (-1,-1,-1),(1,-1,-1),(1,1,-1),(-1,1,-1),(-1,-1,1),(1,-1,1),(1,1,1),(-1,1,1)
edges = (0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),(0,4),(1,5),(2,6),(3,7)
faces = (0,1,2,3),(4,5,6,7),(0,1,5,4),(2,3,7,6),(0,3,7,4),(1,2,6,5)
colours = (225,10,0),(255,128,0),(10,250,250),(128,128,128),(0,0,255),(0,255,0)
texture = dirt_texture
def __init__(self,pos=(0,0,0)):
x,y,z = pos
self.verts = [(x+X/2,y+Y/2,z+Z/2) for X,Y,Z in self.vertices]
class Stone:
vertices = (-1,-1,-1),(1,-1,-1),(1,1,-1),(-1,1,-1),(-1,-1,1),(1,-1,1),(1,1,1),(-1,1,1)
edges = (0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),(0,4),(1,5),(2,6),(3,7)
faces = (0,1,2,3),(4,5,6,7),(0,1,5,4),(2,3,7,6),(0,3,7,4),(1,2,6,5)
colours = (0,255,0),(255,128,0),(0,0,250),(128,133,128),(0,0,200),(200,0,255)
texture = stone_texture
def __init__(self,pos=(0,0,0)):
x,y,z = pos
self.verts = [(x+X/2,y+Y/2,z+Z/2) for X,Y,Z in self.vertices]
def TextUI(msg,colour,pos):
screen_text = font.render(msg, True, colour)
screen.blit(screen_text, (pos))
def Draw_Crosshair(colour, width):
pygame.draw.line(screen, colour, (cursorpos1, cursorpos2), (cursorpos3,cursorpos4), width)
pygame.draw.line(screen, colour, (cursorpos5, cursorpos6), (cursorpos7,cursorpos8), width)
cam = Cam((0,0,-5))
pygame.event.get(); pygame.mouse.get_rel()
pygame.mouse.set_visible(0); pygame.event.set_grab(1)
font = pygame.font.SysFont("calibri", 25)
cursorpos1, cursorpos2, cursorpos3, cursorpos4 = w/2, h/2+10, w/2, h/2-10
cursorpos5, cursorpos6, cursorpos7, cursorpos8 = w/2+10, h/2, w/2-10, h/2
cubes = [Dirt((0,0,0)),Stone((2,0,0)),Stone((-2,0,0)),Dirt((0,2,0)),Stone((2,2,0)),Dirt((-2,2,0))]
##cubes = [Dirt((1,0,0)), Dirt((2,0,0)),Dirt((3,0,0)),Dirt((4,0,0)),Dirt((5,0,0)),Dirt((5,1,0)),Dirt((6,1,0)),]
while True:
dt = clock.tick()/1000
for event in pygame.event.get():
if event.type == pygame.QUIT: pygame.quit(); sys.exit()
cam.events(event)
screen.fill((100,100,100))
face_list = []; face_colour = []; depth = [];
for obj in cubes:
vert_list = []; screen_coords = []
for x,y,z in obj.verts:
x-=cam.pos[0]; y-=cam.pos[1]; z-=cam.pos[2]
x,z = rotate2d((x,z), cam.rot[1])
y,z = rotate2d((y,z), cam.rot[0])
vert_list += [(x,y,z)]
f = fov/z
x,y = x*f,y*f
screen_coords+=[(cx+int(x),cy+int(y))]
for f in range (len(obj.faces)):
face = obj.faces[f]
on_screen = False
for i in face:
x,y = screen_coords[i]
if vert_list[i][2]>0 and x>0 and x<w and y>0 and y<h: on_screen = True ; break
if on_screen:
coords = [screen_coords[i] for i in face]
face_list += [coords]
face_colour += [obj.colours[f]]
depth += [sum(sum(vert_list[j][i] for j in face) **2 for i in range (3))]
order = sorted(range(len(face_list)), key=lambda i:depth[i], reverse=1)
for i in order:
try: pygame.gfxdraw.textured_polygon(screen, face_list[i], obj.texture, 0, 0); pygame.gfxdraw.aapolygon(screen, face_list[i], (0,0,0))
except: pass
## OLD CODE - pygame.draw.polygon(screen, face_colour[i], face_list[i]) ##
## NEW CODE - pygame.gfxdraw.textured_polygon(screen, face_list[i], obj.texture, 0, 0) ##
## TEST CODE - pygame.gfxdraw.filled_polygon(screen, face_list[i], face_colour[i]) ##
Draw_Crosshair((255,255,255),2)
TextUI("Press ESCAPE to exit", (255,255,255), (20,20))
TextUI("Movement Controls: W, A, S, D, SPACE and C", (255,255,255), (20,60))
pygame.display.update()
key = pygame.key.get_pressed()
cam.update(dt, key)
That is beautiful code which works exactly as expected, the 2-dimensional polygon is filled with flat texture. To move beyond 2-dimensions to render solid objects, still from pygame, you need to move to OpenGL.

Conway's game of life list index error

So I'm trying to make Conway's game of life in Python/pygame, and the first iteration of making the new grid works, but the second wont because of a list index out of range error. I have been trying to figure out what's wrong, but the list index shouldn't be out of range. This is my code, the mistake is supposedly in changevalue() but i suspect it isn't, since the first iteration works:
import pygame
import random
width = 400
height = 400
blocksize = 10
white = (255, 255, 255)
black = (0, 0, 0)
visual = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
IsOn = True
grid = []
templist = []
tempgrid = []
class square(object):
def __init__(self, x, y, alive):
self.x = x
self.y = y
self.alive = alive
for y in range(height/blocksize):
templist = []
for x in range(width/blocksize):
templist.append(square(x, y, random.choice([True, False, False, False])))
grid.append(templist)
def changevalue(cx, cy, cgrid):
neighbours = []
for dy in range(3):
ddy = dy - 1
for dx in range(3):
ddx = dx - 1
if not (dx - 1 == 0 and dy - 1 == 0):
#print cgrid[(cy + ddy)%len(cgrid)][(cx + ddx)%len(cgrid[y])].alive
#NO ERRORS
#print len(cgrid) > (cy + ddy)%len(cgrid), len(cgrid[y]) > (cx + ddx)%len(cgrid[cy])
#NO ERRORS
neighbours.append(cgrid[(cy + ddy)%len(cgrid)][(cx + ddx)%len(cgrid[cy])].alive)
return len(filter(lambda p: p == True, neighbours))
while IsOn:
for event in pygame.event.get():
if event.type == pygame.QUIT:
IsOn = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
proceed = True
tempgrid = []
for times in range(len(grid)):
tempgrid.append([])
for ty in range(len(grid)):
for tx in range(len(grid[ty])):
if changevalue(tx, ty, grid) < 2 and grid[ty][tx].alive == True:
tempgrid[ty].append(square(tx, ty, False))
elif changevalue(tx, ty, grid) > 3 and grid[ty][tx].alive == True:
tempgrid[ty].append(square(tx, ty, False))
elif changevalue(tx, ty, grid) == 3 and grid[ty][tx].alive == False:
tempgrid[ty].append(square(tx, ty, True))
grid = list(tempgrid)
visual.fill(white)
for y in range(len(grid)):
for x in range(len(grid[y])):
if grid[y][x].alive == True:
pygame.draw.rect(visual, black, (grid[y][x].x*blocksize, grid[y][x].y*blocksize, blocksize, blocksize))
pygame.display.update()
clock.tick(2)
pygame.quit()
quit()
Thanks for your help!
You don't copy square which doesn't change value - so new rows have different length - and later you have problem with index
You need something like this
if changevalue ...:
...
elif changevalue ...:
...
elif changevalue ...:
...
else:
# copy other elements
tempgrid[ty].append(grid[ty][tx])

Categories