PyGame Simulation Coordinate Bug - python

I want to create a simulation. (not sure where it will head)
I created a Human class and HumanRace class.
The HumanRace class contains every Human class object within an list.
Currently I'm using 2 HumanRaces and 10 Humans per race.
Humans get represented with a circle, the color of it is assigned to the HumanRace. Also there will be a circle representing the spawn area of this race, although the math behind this is a bit sloppy.
Humans spawn within the spawn area of their race. That's where the problem comes in. If I render only 1 race everything is okay, but if I do render the second too, it will redraw those positions with a different color, even tho my the Humans added to the race have different positions. So I guess my render definition is incorrect.
Main.py
import sys, pygame
from HumanRace import *
from random import randint
BLACK = 0, 0, 0
WHITE = 255, 255, 255
GREEN = 124, 252, 0
RED = 255, 0, 0
PURPLE = 255, 23, 240
BLUE = 0, 68, 255
YELLOW = 255, 255, 0
humanRaces = []
def generateHuman(race):
spawnpos = (race.getSpawnX(), race.getSpawnY())
rsize = race.getSize()
rHP = randint(10, 100)
rATK = randint(20, 100)
rAGIL = randint(20, 50)
x = randint(spawnpos[0] - rsize, spawnpos[0] + rsize)
y = randint(spawnpos[1] - rsize, spawnpos[1] + rsize)
print(x, y, rHP)
return Human(x, y, rHP, rATK, rAGIL)
def generateHumans(race, amount):
for i in range(0, amount):
newHuman = generateHuman(race)
race.addHuman(newHuman)
barbaren = HumanRace("Barbar", 300, 320)
barbaren.setColor(GREEN)
barbaren.setSpawnColor(PURPLE)
generateHumans(barbaren, 4)
chinesen = HumanRace("Chinese", 100, 100)
chinesen.setColor(YELLOW)
chinesen.setSpawnColor(BLUE)
generateHumans(chinesen, 4)
humanRaces.append(barbaren)
humanRaces.append(chinesen)
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Fighting Era")
clock = pygame.time.Clock()
def renderHumanRaceSpawn():
raceNumber = len(humanRaces)
for i in range(0, raceNumber):
currRace = humanRaces[i]
scolor = currRace.getSpawnColor()
spawnX = currRace.getSpawnX()
spawnY = currRace.getSpawnY()
radius = currRace.getSize()
pygame.draw.circle(screen, scolor, (spawnX, spawnY), radius * 2, 0)
def renderHumanRace():
for i in range(0, 2):
currRace = humanRaces[i]
color = currRace.getColor()
for x in range(0, currRace.getSize()):
currHuman = currRace.getAt(x)
posX = currHuman.getPosX()
posY = currHuman.getPosY()
pygame.draw.circle(screen, color, (posX, posY), 3, 0)
while 1:
clock.tick(246)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(BLACK)
renderHumanRaceSpawn()
renderHumanRace()
pygame.display.flip()
Human and HumanRace Class
class Human:
def __init__(self, posX, posY, HP, ATK, AGIL):
self.posX = posX
self.posY = posY
self.HP = HP
self.ATK = ATK
self.AGIL = AGIL
def getIndex(self):
return self.index
def getPosX(self):
return self.posX
def getPosY(self):
return self.posY
def setPosX(self, posX):
self.posX = posX
def setPosY(self, posY):
self.posY = posY
from Human import *
class HumanRace:
size = 0
humans = []
spawn = (0, 0)
color = 0, 0, 0
spawnColor = 1, 1, 1
def __init__(self, name, spawnX, spawnY):
self.name = name
self.spawnX = spawnX
self.spawnY = spawnY
def getName(self):
return self.name
def getSpawnX(self):
return self.spawnX
def getColor(self):
return self.color
def setColor(self, color):
self.color = color
def getSpawnColor(self):
return self.spawnColor
def setSpawnColor(self, color):
self.spawnColor = color
def getSpawnY(self):
return self.spawnY
def getSize(self):
return self.size
def addHuman(self, human):
global size
self.humans.append(human)
self.size += 1
def getAt(self, index):
return self.humans[index]
def removeAt(self, index):
global size
self.humans.delete(index)
self.size -= 1
Picture of Window

Your humans list inside the HumanRace class is a class variable. All instances of HumanRace will share the same humans list. You should change it to an instance variable by putting inside the __init__ function.
Something like this:
class HumanRace:
def __init__(self, name, spawnX, spawnY):
self.name = name
self.spawn = (spawnX, spawnY)
self.size = 0 # dont really need this, you can just len(humans)
self.humans = []
self.color = 0, 0, 0
self.spawnColor = 1, 1, 1

Related

Snake with pygame method - pixel overlap problem

I started playing a little with pygame and so far I'm not doing badly. I encountered a problem and managed to solve it. The solution is possible. It is not 100% correct. I want to implement an eat method when the head of the subject meets the food.
It is probably a relatively simple method when the rest of the value of X and Y are equal to the head of the snake being eaten.
For some reason I was not able to fully understand the overlap of pixels and I am not really correct in the method.
The problem at the moment is that there is no overlap between the pixels and "eating is not done".
BACKGROUND = pygame.image.load("background.jpg")
WIDTH, HEIGHT = BACKGROUND.get_width(), BACKGROUND.get_height()
pygame.font.init()
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
def checkForEat(self):
head = self.body[-1]
x = self.food.getPos()[0]
y= self.food.getPos()[1]
# if abs(head[0] - x ) < 9 and abs(head[1] - y ) < 9: -- This is my temporary solution
if head[0] == x and head[1] == y:
self.food = Food()
self.eat()
I try not to add too much unnecessary code.
class Food:
def __init__(self):
self.color = (5, 5, 255)
self.pos = (random.randint(10,WIDTH-50),random.randint(10,HEIGHT-50))
def draw(self,win):
pygame.draw.circle(win,self.color, self.pos, 5)
def getPos(self):
return self.pos
class Snake:
START_POS = (85, 85)
def __init__(self):
self.food = Food()
self.block_size = 11
self.x , self.y = self.START_POS
self.body = self.create_body()
def create_body(self):
body = []
for i in range(self.length):
body.append((85,85+i*self.block_size))
return body
def draw(self,win):
WIN.blit(BACKGROUND, (0, 0))
self.food.draw(win)
for i in range(self.length):
pygame.draw.circle(win, (255, 0, 0), self.body[i], 5)
I'm not adding the rest of the program.
Just saying that apart from the problem I wrote above everything works fine.
Use pygame.Rect/pygame.Rect.colliderect to check if the bounding rectangle of the food overlaps with the head of the snake:
class Food:
def __init__(self):
self.color = (5, 5, 255)
self.pos = (random.randint(10,WIDTH-50),random.randint(10,HEIGHT-50))
def draw(self,win):
pygame.draw.circle(win,self.color, self.pos, 5)
def getPos(self):
return self.pos
def getRect(self):
return pygame.Rect(self.pos[0]-5, self.pos[1]-5, 10, 10)
class Snake:
START_POS = (85, 85)
def __init__(self):
self.food = Food()
self.block_size = 11
self.x , self.y = self.START_POS
self.body = self.create_body()
# [...]
def checkForEat(self):
head = self.body[-1]
head_rect = pygame.Rect(head[0]-5, head[1]-5, self.block_size, self.block_size)
food_rect = self.food.getRect()
if food_rect.colliderect(head_rect):
self.food = Food()
self.eat()
Also see How do I detect collision in pygame?.
Alternatively you can compute the Euclidean distance between the circle center of the circles and compare the distance to the sum of the radii:
class Snake:
# [...]
def checkForEat(self):
dx = self.food.getPos()[0] - self.body[-1][0]
dy = self.food.getPos()[1] - self.body[-1][1]
dist_center = math.hypot(dx, dy)
if dist_center <= 20:
self.food = Food()
self.eat()

Pygame line appearing broken

So I was making a turtle like object in python and I had a issue which got resolved.
Now I am noticing a intersting or rather annoying thing that when I attempt to a make a square with lt(90) or rt(270), one of the line appears broken.
Here is my code:
import pygame
from pygame.locals import *
from pygame.math import Vector2
from math import sin, cos, radians
class Turtle:
def __init__(self):
self.vector = Vector2(0, 0)
self.angle = 0
self.pen_width = 25
self.pen_color = (255, 255, 255)
self.pen_visible = True
def forward(self, win, distance):
start = self.vector
offset = Vector2(sin(radians(self.angle)), cos(radians(self.angle)))
offset *= distance
end = start + offset
if self.is_down():
pygame.draw.line(win, self.pen_color, start, end, self.pen_width)
self.vector = end
fd = forward
def backward(self, win, distance):
self.forward(win, -distance)
bk = back = backward
def left(self, angle):
self.angle = (self.angle + angle) % 360
self.angle
lt = left
def right(self, angle):
self.left(-angle)
rt = right
def goto(self, win, pos):
if self.is_down():
pygame.draw.line(win, self.pen_color, self.vector, pos, self.pen_width)
self.vector = Vector2(pos)
setposition = setpos = goto
def set_angle(self, angle= None):
if not angle:
return self.angle
self.angle = angle
def position(self):
return self.vector.xy
pos = position
def sety(self, y):
self.vector.y = y
def setx(self, x):
self.vector.x = x
def xcor(self):
return self.vector.x
def ycor(self):
return self.vector.y
def penup(self):
self.pen_visible = False
pu = up = penup
def pendown(self):
self.pen_visible = True
pd = down = pendown
def is_down(self):
return self.pen_visible
def write(self, win, font_label):
win.blit(font_label, self.vector)
def test():
pygame.init()
pygame.font.init()
WIDTH, HEIGHT = 500, 500
CAPTION = 'Caption'
win = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(CAPTION)
FPS = 60
clock = pygame.time.Clock()
mytut = Turtle()
mytut.pen_width = 5
mytut.goto(win, (250, 250))
mytut.pen_color = '#00FF00'
for _ in range(4):
mytut.fd(win, 100)
mytut.rt(270)
while True:
clock.tick(FPS)
pygame.display.flip()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
quit()
if __name__ == '__main__':
test()
Screenshot -
Moreover this issue does not occur when I use lt(270) or rt(90).
I dont know why this happens in pygame. I feel it may related to some floating point numbers being a bit off but dont know exactly why?
I need help to fix this!
The problem is caused by a floating point inaccuracy. round the coordinates to solve the issue. You can further improve the representation, by drawing a small circle at the end of the line:
class Turtle:
# [...]
def forward(self, win, distance):
start = self.vector
offset = Vector2(sin(radians(self.angle)), cos(radians(self.angle)))
offset *= distance
end = start + offset
if self.is_down():
s = round(start.x), round(start.y)
e = round(end.x), round(end.y)
pygame.draw.line(win, self.pen_color, s, e, self.pen_width)
pygame.draw.circle(win, self.pen_color, e, self.pen_width // 2)
self.vector = end

Need to pass tuples to subclass to draw triangle

I want to draw a triangle from a class, so I call the function
pygame.draw.polygon()
Now, the problem is that I need to pass the points in a manner that will allow me to calculate the centre of the triangle.
I was trying to pass the tuples one by one in this way
self.first_point = (int, int)
self.second_point = (int, int)
self.third_point = (int, int)
so that I can then access the single tuple values.
Then pass the three points like this
self.position = [self.first_point, self.second_point, self.third_point]
But for some reason, it doesn't work.
This is the error I get
File "C:/Users/oricc/PycharmProjects/designAChessboardChallange/display.py", line 178, in <module>
white_archer_3 = Archer(white, [(100, 100), (200, 200), (300, 300)])
[(100, 100), (200, 200), (300, 300)]
File "C:/Users/oricc/PycharmProjects/designAChessboardChallange/display.py", line 132, in __init__
self.triangle = pygame.draw.polygon(game_window, colour, self.position)
TypeError: points must be number pairs
By number of pairs, the Pygame documentation gives as an example
e.g. [(x1, y1), (x2, y2), (x3, y3)]
In fact, when I print the position I pass I get, as you can see from the error above
[(100, 100), (200, 200), (300, 300)]
Anyone can help with this?
Is there another manner to calculate the centre without accessing the xs and ys like that?
Full code here
import pygame
import sys
from coordinator import coordinator
# set up the display
pygame.init()
window_size = (800, 800)
game_window = pygame.display.set_mode(size=window_size)
pygame.display.set_caption('My Game')
# defines classes and related methods
class WhiteSquare:
def __init__(self):
self.height = int(window_size[0] / 8)
self.width = int(window_size[1] / 8)
self.white_square = pygame.Surface((self.height, self.width))
self.white_square.fill((255, 255, 255))
class BlackSquare:
def __init__(self):
self.height = int(window_size[0] / 8)
self.width = int(window_size[1] / 8)
self.black_square = pygame.Surface((self.height, self.width))
self.black_square.fill((0, 0, 0))
class ChessBoard:
def __init__(self):
self.ws = ws
self.bs = bs
self.white_columns = white_columns
self.black_columns = black_columns
def draw(self):
for w_columns in self.white_columns:
game_window.blit(self.ws.white_square, w_columns)
for b_columns in self.black_columns:
game_window.blit(self.bs.black_square, b_columns)
# declare letters and numbers
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
numbers = ['1', '2', '3', '4', '5', '6', '7', '8']
# create coordinates
coordinates = []
for item_letter in letters:
letter = item_letter
for item_number in numbers:
number = item_number
coordinates.append(letter + number)
# create coordinates values components
x_values = []
for number in range(0, 800, 100):
x = number
x_values.append(x)
y_values = []
for number in range(0, 800, 100):
y = number
y_values.append(y)
# create coordinate values
coordinate_values = []
for x in x_values:
for y in y_values:
coordinate_values.append((x, y))
# assign values to coordinates
squares_coordinates = dict(zip(coordinates, coordinate_values))
# Background for units
class CircleSurface:
def __init__(self):
self.circle_surface = pygame.Surface((100, 100), flags=pygame.SRCALPHA)
pygame.draw.circle(self.circle_surface, (255, 0, 0), (50, 50), 45)
# define colours
black = (0, 0, 0)
white = (255, 255, 255)
gold = (153, 153, 0)
class Unit:
def __init__(self, colour, position):
# define Unit colour
self.colour = colour
# define Unit position
self.position = position
class Knight(Unit):
def __init__(self, colour, position):
# draw circle, inline, and outline
super().__init__(colour, position)
self.center_x = position[0]
self.center_y = position[1]
self.colour = colour
self.position = position
circle_radius = 40
self.circle = pygame.draw.circle(game_window, colour, self.position, circle_radius)
self.circle_outline = pygame.draw.circle(game_window, gold, self.position, circle_radius, 5)
self.circle_inline = pygame.draw.circle(game_window, gold, self.position, (circle_radius - 10), 5)
# draw letter
pygame.font.init()
my_font_size = 50
my_font = pygame.font.SysFont('Time New Roman', my_font_size)
text_surface = my_font.render('K', 1, gold)
center_text = text_surface.get_rect(center=(self.center_x, self.center_y))
game_window.blit(text_surface, center_text)
class Archer(Unit):
def __init__(self, colour, position):
super().__init__(colour, position)
self.first_point = (int, int)
self.second_point = (int, int)
self.third_point = (int, int)
self.position = [self.first_point, self.second_point, self.third_point]
print(position)
self.triangle = pygame.draw.polygon(game_window, colour, self.position)
self.triangle_outline = pygame.draw.polygon(game_window, gold, self.position, 5)
self.triangle_inline = pygame.draw.polygon(game_window, gold, self.position, 5)
# draw letter
# pygame.font.init()
# my_font_size = 50
# my_font = pygame.font.SysFont('Time New Roman', my_font_size)
# text_surface = my_font.render('A', 1, gold)
# center_text = text_surface.get_rect(center=(self.center_x, self.center_y))
# game_window.blit(text_surface, center_text)
# Sets and gets the coordinates for black and white squares
coordinator = coordinator()
black_columns = coordinator[2] + coordinator[3]
white_columns = coordinator[0] + coordinator[1]
# Creates needed objects
ws = WhiteSquare()
bs = BlackSquare()
cb = ChessBoard()
cs = CircleSurface()
# Event loop (outer)
while 1:
# Event loop (inner)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Draws the chessboard
cb.draw()
# Draws white pieces in their initial position
white_knight_1 = Knight(white, (150, 650))
white_knight_2 = Knight(white, (650, 650))
white_archer_3 = Archer(white, [(100, 100), (200, 200), (300, 300)])
pygame.display.update()
Thank you
OK, I managed to make it work.
You guys are both right, I should know by now that I can't pass placeholders, so I figured out the solution to my problem as follow:
class Archer(Unit):
def __init__(self, colour, first_point, second_point, third_point):
self.first_point = first_point
self.second_point = second_point
self.third_point = third_point
position = [self.first_point, self.second_point, self.third_point]
super().__init__(colour, position)
print(self.position)
self.triangle = pygame.draw.polygon(game_window, colour, self.position)
self.triangle_outline = pygame.draw.polygon(game_window, gold, self.position, 5)
self.triangle_inline = pygame.draw.polygon(game_window, gold, self.position, 5)
Basically I have to declare the three points self variables, as well as position before the super function so that I can then pass them as 'position' to the parent class initializer. This has been really useful!!
Thanks both
you could also do this: self.first_point = (int(0), int(0)) as int is not a placeholder but to declare that a variable is an integer str('0') will print '0' you could also input this
zero = 0
str(zero) #'0'
int(zero) #0
and you dont need to put rgb tupels because you can store them in a variable like this
black = (0, 0, 0)
Display = pygame.display.set_mode((800, 600))
Display.fill(black)

Putting the scrolling camera in a mini-window in pygame

I'm trying to create a game where the action is shown in a little box within the main screen object, freeing up the surrounding space for text and menus and what-not. Since the map is larger than the allotted window, I coded a basic "camera" that follows the player around. It mostly works, but I'm having trouble "trimming off" the area outside of this window.
Here's the relevant bits of code (EDITED to provide Working Example):
import pygame, os, sys
from pygame.locals import *
pygame.init()
RIGHT = 'RIGHT'
LEFT = 'LEFT'
UP = 'UP'
DOWN = 'DOWN'
class Camera():
def __init__(self, screen, x_ratio = 1, y_ratio = 1, x_offset = 0, y_offset = 0):
self.screen = screen.copy()
self.rec = self.screen.get_rect()
self.rec.width *= x_ratio
self.rec.height *= y_ratio
self.x_offset = x_offset
self.y_offset = y_offset
def get_pos(self):
return (self.x_offset - self.rec.x, self.y_offset - self.rec.y)
def get_window(self):
w = pygame.Rect(self.rec)
w.topleft = (0 - self.rec.x, 0 - self.rec.y)
return w
def move(self, x, y):
"""Move camera into new position"""
self.rec.x = x
self.rec.y = y
def track(self, obj):
while obj.rec.left < self.rec.left:
self.rec.x -= 1
while obj.rec.right > self.rec.right:
self.rec.x += 1
while obj.rec.top < self.rec.top:
self.rec.y -= 1
while obj.rec.bottom > self.rec.bottom:
self.rec.y += 1
class Map:
def __init__(self, width, height):
self.width = width
self.height = height
self.rec = pygame.Rect(0,0,self.width,self.height)
def draw(self, screen):
pygame.draw.rect(screen, (200,200,200), self.rec)
class Obj:
def __init__(self, char, x = 0, y = 0, width = 0, height = 0):
self.width = width
self.height = height
self.rec = pygame.Rect(x, y, width, height)
self.cur_map = None
self.timers = {}
#Dummying in chars for sprites
self.char = char
self.x_dir = 1
self.y_dir = 1
self.speed = 1
self.moving = False
def move(self):
if self.x_dir != 0 or self.y_dir != 0:
new_x = self.rec.x + (self.x_dir*self.speed)
new_y = self.rec.y + (self.y_dir*self.speed)
new_rec = pygame.Rect(new_x, new_y, self.width, self.height)
#Keep movement within bounds of map
while new_rec.left < self.cur_map.rec.left:
new_rec.x += 1
while new_rec.right > self.cur_map.rec.right:
new_rec.x -= 1
while new_rec.top < self.cur_map.rec.top:
new_rec.y += 1
while new_rec.bottom > self.cur_map.rec.bottom:
new_rec.y -= 1
self.rec = new_rec
def set_dir(self, d):
self.x_dir = 0
self.y_dir = 0
if d == LEFT:
self.x_dir = -1
elif d == RIGHT:
self.x_dir = 1
elif d == UP:
self.y_dir = -1
elif d == DOWN:
self.y_dir = 1
def set_moving(self, val = True):
self.moving = val
class Game:
def __init__(self):
self.screen_size = (800, 600)
self.screen = pygame.display.set_mode(self.screen_size)
self.map_screen = self.screen.copy()
self.title = 'RPG'
pygame.display.set_caption(self.title)
self.camera = Camera(self.screen, 0.75, 0.75)#, 10, 75)
self.fps = 80
self.clock = pygame.time.Clock()
self.debug = False
self.bg_color = (255,255,255)
self.text_size = 18
self.text_font = 'Arial'
self.text_style = pygame.font.SysFont(self.text_font, self.text_size)
self.key_binds = {LEFT : [K_LEFT, K_a], RIGHT : [K_RIGHT, K_d], UP : [K_UP, K_w], DOWN : [K_DOWN, K_s],
'interact' : [K_RETURN, K_z], 'inventory' : [K_i, K_SPACE], 'quit' : [K_ESCAPE]}
self.player = Obj('p', 0, 0, 10, self.text_size)
def draw(self, obj):
char = obj.char
self.draw_text(char, obj.rec.x, obj.rec.y, screen = self.map_screen)
def draw_text(self, text, x, y, color = (0,0,0), screen = None):
textobj = self.text_style.render(text, 1, color)
textrect = textobj.get_rect()
textrect.x = x
textrect.y = y
if screen == None:
"""Use default screen"""
self.screen.blit(textobj, textrect)
else:
screen.blit(textobj, textrect)
def play(self):
done = False
cur_map = Map(800, 800)
self.map_screen = pygame.Surface((cur_map.width, cur_map.height))
self.map_screen.fill(self.bg_color)
bg = pygame.Surface((cur_map.width, cur_map.height))
cur_map.draw(bg)
self.player.cur_map = cur_map
while not done:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key in self.key_binds[LEFT]:
self.player.set_dir(LEFT)
self.player.set_moving()
elif event.key in self.key_binds[RIGHT]:
self.player.set_dir(RIGHT)
self.player.set_moving()
elif event.key in self.key_binds[UP]:
self.player.set_dir(UP)
self.player.set_moving()
elif event.key in self.key_binds[DOWN]:
self.player.set_dir(DOWN)
self.player.set_moving()
elif event.type == KEYUP:
self.player.set_moving(False)
if self.player.moving:
self.player.move()
self.camera.track(self.player)
self.clock.tick()
self.screen.fill(self.bg_color)
self.map_screen.blit(bg, (0,0))
self.draw(self.player)
pygame.draw.rect(self.map_screen, (0,0,0), self.camera.rec, 1)
#self.screen.blit(self.map_screen, (0,0), [0 - self.camera.rec.x, 0 - self.camera.rec.y, self.camera.rec.width, self.camera.rec.height])
self.screen.blit(self.map_screen, self.camera.get_pos(), self.camera.get_window())
pygame.display.flip()
game = Game()
game.play()
Moving the player past past the bounds of the camera's window causes the window to roll up completely and disappear. I tried adjusting the blitting coordinates, as advised earlier, but it seems to only change the direction in which the window rolls up.
From your updated code, the blitting coordinates for self.screen.blit(...) are still changing: self.camera.get_window() changes value because rec.x and rec.y are values referring to the player position within the map. Hence you should define a constant minimap coordinate, this should be the same as the camera offset.
self.screen.blit(self.map_screen, (self.camera.x_offset,self.camera.y_offset), (*self.camera.get_pos(), self.camera.rec.width, self.camera.rec.height))
Change the Camera().get_pos() to:
def get_pos(self):
return (self.rec.x, self.rec.y)
I believe I only changed the self.screen.blit(...) and stopped using or rewrote your Camera functions as you're confusing yourself with all the rec variables.
To illustrate it working amend the Map().draw(screen) to:
def draw(self, screen):
pygame.draw.rect(screen, (200,200,200), self.rec)
pygame.draw.circle(screen, (255, 255, 255), (50, 50), 20, 2)
One tip as well don't draw the entire map at each loop, just the part that will be visible.

Pygame draw.rect 2d object array black screen

I have a problem with a program. I'm trying to code a battleship game and the problem is over here:
class Battleship(object):
def __init__(self):
pygame.init()
pygame.display.set_caption('battleship')
self.gameDisplay = pygame.display.set_mode((DISPLAYWIDTH, DISPLAYHEIGHT))
self.clock = pygame.time.Clock()
class Tile(object):
def __init__(self):
self.occupied = False
self.shipID = 0
self.playerID = 0
def setOccupied(self, occupied):
self.occupied = occupied
def setShipID(self, shipID):
self.shipID = shipID
def setPlayerID(self, pID):
self.playerID = pID
class Board:
shipSizes = [1, 2, 3]
sizeX = 25
sizeY = 25
def __init__(self, playerID):
self.playerID = playerID
self.playerShips = []
for i in range(0, len(self.shipSizes)):
self.playerShips.append(Ship(i, self.shipSizes[i]))
self.tiles = [[Tile() for i in range(self.sizeX)] for j in range(self.sizeY)]
def drawBoard(self):
x = 0
y = 0
for row in self.visual:
for col in row:
pygame.draw.rect(Battleship().gameDisplay, black, (x, y, CASILLA, CASILLA), LINEWIDTH)
x = x + CASILLA
y = y + CASILLA
x=0
I don't get any errors, but the function does not work properly and only shows a black screen, checked everything else and the problem definitely lies in that part.
Edit, i added the clas Battleship
I've written this minimal example to show you what I described in the comments. The board instance is an attribute of the Battleship now and you can just call its draw method in the draw method of the battleship.
import pygame as pg
GRAY = pg.Color('gray20')
BLUE = pg.Color('dodgerblue1')
class Battleship(object):
def __init__(self):
pg.init()
pg.display.set_caption('battleship')
self.display = pg.display.set_mode((800, 600))
self.clock = pg.time.Clock()
self.fps = 30
self.done = False
# Is an attribute of the Battleship now.
self.board = Board()
def run(self):
while not self.done:
self.handle_events()
self.run_logic()
self.draw()
self.clock.tick(self.fps)
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
def run_logic(self):
pass
def draw(self):
self.display.fill(GRAY)
# Call the board's draw method and pass the display.
self.board.draw(self.display)
pg.display.flip()
class Board:
shipSizes = [1, 2, 3]
sizeX = 25
sizeY = 25
def __init__(self):
self.tiles = [['-' for i in range(self.sizeX)] for j in range(self.sizeY)]
def draw(self, display):
for y, row in enumerate(self.tiles):
for x, col in enumerate(row):
pg.draw.rect(
display, BLUE,
(x*self.sizeX, y*self.sizeY, self.sizeX, self.sizeY),
2)
battleship = Battleship()
battleship.run()

Categories