python pygame mouse events not working and not raising errors - python

I'm new to python and I'm trying to make a chess game with pygame, I have the chessboard and the various pieces placed as objects on it. This is the pieces class:
class piece(object):
def __init__(self, x, y, which):
self.x = x
self.y = y
self.which = which
self.square = getsquare(x + PIECE/2, y + PIECE/2)
self.dragging = False
def drag(self, x, y):
limit = 720
if x >= limit:
x = limit
self.x = x - PIECE/2
self.y = y - PIECE/2
def draw(self, win):
win.blit(self.which, (self.x, self.y))
self.square = getsquare(self.x + PIECE/2, self.y + PIECE/2)
where PIECE is the dimension of the spritesheets with the pieces images. I tried to make a drag system for pieces (stored in a 64 element long list) and by using only 1 piece it worked, but when I used the full list it stopped working without rasing any error. This is the drag system:
"""event listeners"""
for event in pygame.event.get():
if event.type == pygame.QUIT: #quit event
run = False
"""mouse release"""
if event.type == pygame.MOUSEBUTTONUP:
clickpos = pygame.mouse.get_pos()
x = clickpos[0]
y = clickpos[1]
sqr = getsquare(x, y)
for i in pieceslist:
if not i == "none":
if i.dragging:
i.dragging = False
try:
i.x = squarepos(i.square[0], i.square[1])[1]
i.y = squarepos(i.square[0], i.square[1])[0]
except:
i.x = squarepos(originalsquare[0], originalsquare[1])[1]
i.y = squarepos(originalsquare[0], originalsquare[1])[0]
"""mouse click"""
if event.type == pygame.MOUSEBUTTONDOWN:
clickpos = pygame.mouse.get_pos()
x = clickpos[0]
y = clickpos[1]
#print("X: " + str(x) + ", Y: " + str(y))
sqr = getsquare(x, y)
for i in pieceslist:
if not i == "none":
if sqr == i.square:
originalsquare = sqr
i.dragging = True
"""mouse drag"""
if event.type == pygame.MOUSEMOTION:
clickpos = pygame.mouse.get_pos()
x = clickpos[0]
y = clickpos[1]
#print("X: " + str(x) + ", Y: " + str(y))
sqr = getsquare(x, y)
for i in pieceslist:
if not i == "none":
if i.dragging:
i.drag(x, y)
since pieceslist is filled with piece objects and "none" strings I made the if checks (I know there surely are better ways to do this but I'm new to python)
So, the problem is that the click event works and it modifies dragging, but when it comes to the drag event the object no longer has dragging == True
EDIT:
squarepos() returns the coordinates where to put the spritesheet, getsquare() returns the coordinates by row-column:
def getsquare(x, y):
if x <= BORDER or y <= BORDER or x >= squarepos(1, 9)[0] or y >= squarepos(9, 1)[1]:
pass #not on the board
else:
x -= BORDER
y -= BORDER
x /= SQUARE
y /= SQUARE
return [int(x) + 1, int(y) + 1]
EDIT:
Full program here for testing and debugging

The dragging algorithm actually works. However, defBoardPieces() is called in every frame. Therefore, the game is reset every frame. And the dragging has no effect.
Remove the defBoardPieces() call from the drawBoardPieces function, but call it once before the application loop:
#renders board pieces
def drawBoardPieces(win):
# defBoardPieces() <--- DELETE
for i in pieceslist:
if not i == "none":
i.draw(win)
pieceslist = []
startsquare = []
defBoardPieces() # <--- INSERT
run = True
while run:
# [...]
Call defBoardPieces() also in reset:
def reset():
global position
position = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"
defBoardPieces()

Use mouse.get_pressed()[0] to drag. 0 is left button.
if event.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pressed()[0]:
... drag code here

Related

Pygame how to detect clicks from a list of images

For my levels screen I use images for each level button, there are 15 on a page. I was able to blit them all to the screen in a nice layout using some iteration and math, I have been trying to figure out a way to do this with the click detection aswell. But I do not want to type "var = get_rect" 15 times a page.
All of the images are in a list for iteration,
self.levels_p1 = [self.l1, self.l2, self.l3, self.l4, self.l5,
self.l6, self.l7, self.l8, self.l9, self.l10,
self.l11, self.l12, self.l13, self.l14, self.l15,]
and are added to the screen in a 5 x 3 like this,
for i, lvl in enumerate(self.levels_p1, start=1):
x = ((WIDTH - 100) * (i % 5) // 6) + 17
y = HEIGHT // 10 + ((i // 5) * 125)
if i % 5 == 0:
x = ((WIDTH - 100) * 5 // 6) + 17
y = HEIGHT // 10 + (((i // 5) - 1) * 125)
self.screen.blit(lvl, (x, y))
if self.level_unlocked < i:
self.screen.blit(self.level_shade, (x, y))
And I have been detecting clicks like this,
mousepos = pg.mouse.get_pos()
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
if event.type == pg.MOUSEBUTTONDOWN:
#to menu
if self.back_rect.collidepoint(*mousepos):
on_levels = False
self.swipe.play()
self.start()
#to levels2 page
if self.arrow_rect.collidepoint(*mousepos):
on_levels = False
self.swipe.play()
self.levels_page2()
#to level 1
if self.l1_rect.collidepoint(*mousepos):
on_levels = False
self.swipe.play()
self.load_level(1)
But that will only work for all the levels if I manually define a rect for all of the buttons, which is what I am trying to avoid.
I was wondering if there is a good way to detect the clicks on each and every one of these buttons? Similarly to how I displayed them in the 2nd code bit.
Much appreciated.
pygame.Surface.blit returns a rectangle with the area of the affected pixels:
self.rect = self.screen.blit(self.level_shade, (x, y))
Alternatively you can get the bounding rectangle of a pygame.Surface by get_rect(). The location of this rectangle is (0, 0). Hence, you have to set the position by a keyword argument:
self.rect = self.level_shade.get_rect(topleft = (x, y))
if self.arrow_rect.collidepoint(*mousepos)
I don't know what you're packing on the line above. If you want to detect clicks, I think you should get mouse position first. I'll do something like this:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
if event.type == pg.MOUSEBUTTONDOWN:
#to menu
mousepos = pg.mouse.get_pos() #Here lies the magic and no need to unpack
if self.back_rect.collidepoint(mousepos):
on_levels = False
self.swipe.play()
self.start()
#to levels2 page
if self.arrow_rect.collidepoint(mousepos):
on_levels = False
self.swipe.play()
self.levels_page2()
#to level 1
if self.l1_rect.collidepoint(mousepos):
on_levels = False
self.swipe.play()
self.load_level(1)
If that solves your problem please let me know and of it doesn't still let me know!
Edit: Try if/elif block instead of just if.
mousepos = pg.mouse.get_pos()
lvls = []
for i, lvl in enumerate(self.levels_p1):
#x, y topleft for 5x3 grid with easement and centered
x = ((WIDTH - 100) * (i % 5) // 5) + 110
y = HEIGHT // 10 + ((i // 5) * 125)
#add to screen
temp = self.screen.blit(lvl, (x, y))
#if not unlocked
if self.level_unlocked < i:
#darken
self.screen.blit(self.level_shade, (x, y))
#if unlocked
else:
#enlarged version if hovering over and unlocked
if temp.collidepoint(*mousepos):
self.screen.blit(self.levels_1l[i], (x-6, y-6))
#rect list for click detection
lvls.append(temp)
#back button interactive
if self.back_rect.collidepoint(*mousepos):
self.screen.blit(self.t_back2, self.back_rect2) # bigger
else:
self.screen.blit(self.t_back, self.back_rect) # normal
#arrow button interactive
if self.arrow_rect.collidepoint(*mousepos):
self.screen.blit(self.arrowr2, self.arrow_rect2) # bigger
else:
self.screen.blit(self.arrowr, self.arrow_rect) # normal
pg.display.flip()
#all button presses
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
if event.type == pg.MOUSEBUTTONDOWN:
#to menu
if self.back_rect.collidepoint(*mousepos):
on_levels = False
self.swipe.play()
self.start()
#to levels2 page
if self.arrow_rect.collidepoint(*mousepos):
on_levels = False
self.swipe.play()
self.levels_page2()
#to level
for i, val in enumerate(lvls):
#if clicked pos = level pos
if lvls[i].collidepoint(*mousepos):
on_levels = False
self.swipe.play()
#level to load
self.load_level(i+1)

Can you help me fix this bug in my pygame physics simulation?

I wrote this physics simulation in pygame and the collision mechanism is not working properly. It seems to work when I collide the player character with the wall from above the wall or from the left and not work for collisions from the bottom or from the right
I have been trying to find this bug for some time but I just have no clue as to what might cause this. I am using python 3.7.3 and pygame 1.9.5 (latest versions as of date)
I am sorry for pasting an entire file but I just have no Idea where the problem is
import pygame # import the pygame library to have access to game building tools
import math
# these variables will be used to hold game objects and draw them
rigid_bodies = []
g = 100
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
PURPLE = (127, 0, 255)
RED = (200, 0, 0)
GREEN = (0, 200, 0)
BLUE = (0, 0, 200)
class RigidBody(pygame.Rect):
"""
represents a rectangular object that acts according to newton's laws of motion
"""
def __init__(self, canvas, color, m, u, x, y, w, h):
"""
called automatically when a new object is created to initialize the object
:param canvas: the canvas on which to draw the object
:param color: the color of the object
:param m: the mass of the object
:param u: Coefficient of friction
:param x: the starting position of the object on the x axis
:param y: the starting position of the object on the y axis
:param w: the width of the object
:param h: the height of the object
"""
super().__init__(x, y, w, h) # initialize the parent Rect object
self.canvas = canvas
self.color = color
self.m = m
self.u = u
self.x_speed = 0 # the speed of the object on the x axis
self.y_speed = 0 # the speed of the object on the y axis
def apply_force(self, axis, F, initiator=None):
"""
used to apply force on the object
:param axis: the axis of the force
:param F: the amount of force to apply
:param initiator: the object that is applying the force
"""
a = F / self.m # calculate the acceleration the object should have
if axis == 'y':
self.y_speed += a
elif axis == 'x':
self.x_speed += a
if initiator:
initiator.apply_force(axis, -1 * F) # apply normal force
print('colliding')
def inertia(self):
"""
shall be run every frame to make the object move according to its speed
if possible and take the necessary steps if not
"""
# go:
self.x += self.x_speed
self.y += self.y_speed
for body in rigid_bodies:
if self.colliderect(body): # if collide with another object:
self.x -= self.x_speed # go back
self.y -= self.y_speed
body.apply_force('x', self.m * self.x_speed, self) # and apply force on that object
body.apply_force('y', self.m * self.y_speed, self)
break
def draw(self):
"""
shall be run every frame to draw the object on the canvas
"""
pygame.draw.rect(self.canvas, self.color, (self.x, self.y, self.w, self.h))
class Controller:
def __init__(self, character, F):
"""
initialize the controller object
:param character: the character to control
:param F: the force to apply to the character for every frame a button is being pressed
"""
self.character = character
self.up = 0 # whether to move up or not
self.down = 0 # whether to move down or not
self.left = 0 # whether to move left or not
self.right = 0 # whether to move right or not
self.F = F
def stop(self):
"""
stops applying force on the object
"""
self.up = 0
self.down = 0
self.left = 0
self.right = 0
def run(self):
"""
shall be run every frame to apply force on the character according to user input
"""
self.character.apply_force('y', -self.F * self.up)
self.character.apply_force('y', self.F * self.down)
self.character.apply_force('x', -self.F * self.left)
self.character.apply_force('x', self.F * self.right)
def main():
"""
the main function contains the main loop
that runs repeatedly while the game is running
"""
crashed = False # tells if the program crashed or if the window was closed
pygame.init() # required to use pygame
canvas = pygame.display.set_mode((1000, 700)) # define the canvas
clock = pygame.time.Clock() # will be used to limit the number of times a loop runs per second
pygame.display.set_caption('the dot game V2')
character = RigidBody(canvas, WHITE, 1000, 0.3, 500, 500, 20, 50) # initialize the character
player = Controller(character, 500) # initialize the controller
rigid_bodies.append(RigidBody(canvas, WHITE, math.inf, 0, 300, 300, 300, 20)) # initialize the wall
while not crashed:
# handle inputs:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
elif event.type == pygame.MOUSEBUTTONUP:
pass
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
player.up = 1
elif event.key == pygame.K_DOWN:
player.down = 1
elif event.key == pygame.K_LEFT:
player.left = 1
elif event.key == pygame.K_RIGHT:
player.right = 1
elif event.type == pygame.KEYUP:
player.stop()
player.run()
character.inertia()
canvas.fill(BLACK)
character.draw()
for body in rigid_bodies:
body.draw()
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
main()
I suspect that the problem is with either the "inertia" or the "apply_force" functions but I just cant figure out WHAT is the problem with those functions
The character should stop moving every time it hits the wall, but when it hits the wall from below or from the right it gets stuck and can only move up or to the left
The issue is caused by casting a floating point value to int and can be solved by:
stored_pos = (self.x, self.y)
self.x += self.x_speed
self.y += self.y_speed
for body in rigid_bodies:
if self.colliderect(body): # if collide with another object:
self.x, self.y = stored_pos
Note, that
self.x -= self.x_speed
self.y -= self.y_speed
is not the inverse operation of
self.x += self.x_speed
self.y += self.y_speed
e.g: a = 2 and b = 0.5
int(a + b) == int(2 + 0.5) == 2
int(a - b) == int(2 - 0.5) == 1
The solution is to store the original values of self.x and self.y
stored_pos = (self.x, self.y)
and to restore it in the case of a collision:
self.x, self.y = stored_pos

How do I find the distance from the goal node named target, when I have the below mentioned start node named seeker?

I am trying to find the distance from the start node named seeker to the goal node named target. I have already done most of the implementation of the algorithm and each of the nodes have a coordinate or box on a grid. My python code is lacking and I cannot find the coordinates and distance.
I have tried using the vector in the math class which gave me logical errors.
I also tried sending the actual objects hoping I could use those to reference the coordinates as I'd done in the code but got a TypeError: expected sequence object with len >= 0 or a single integer.
import numpy as np
import pygame as pg
import sys
from Settings import *
from Sprites import *
vec = pg.math.Vector2
class Game:
# initialise game window, etc
def __init__(self):
self.playing = True
pg.init()
self.mover = 'target'
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption(Title)
self.clock = pg.time.Clock()
pg.key.set_repeat(500, 100)
self.load_data()
# pg.mouse.set_pos(0, 0)
self.walls = []
def load_data(self):
pass
# start a new game
def new(self):
self.all_sprites = pg.sprite.Group()
self.player = Player(self, 10, 10)
self.target = Target(self, 5, 5)
def load_data(self):
pass
# game loop
def run(self):
while self.playing:
self.dt = self.clock.tick(FPS) / 10000
self.events()
self.update()
self.draw()
def draw_grid(self):
for x in range(0, WIDTH, TILESIZE):
pg.draw.line(self.screen, LIGHTGREY, (x, 0), (x, HEIGHT))
for y in range(0, HEIGHT, TILESIZE):
pg.draw.line(self.screen, LIGHTGREY, (0, y), (WIDTH, y))
def quit(self):
pg.quit()
sys.exit()
def update(self):
# game loop update
self.all_sprites.update()
def events(self):
# game loop events
for event in pg.event.get():
if event.type == pg.QUIT:
self.quit()
if event.type == pg.MOUSEBUTTONDOWN:
mpos = vec(pg.mouse.get_pos()) // TILESIZE
if event.button == 1:
if mpos in g.walls:
g.walls.remove(mpos)
else:
g.walls.append(mpos)
if event.type == pg.KEYDOWN:
if event.key == pg.K_b:
# start breadth first
breadthfirst(self.target, self.player, self.walls, self.screen)
if event.key == pg.K_d:
# start depth first
depthfirst(self.target, self.player, self.walls, self.screen)
if event.key == pg.K_a:
# start A* search
astarsearch(self.target, self.player, self.walls, self.screen)
if event.key == pg.K_ESCAPE:
self.quit()
if event.key == pg.K_t:
self.mover = 'target'
if event.key == pg.K_s:
self.mover = 'seeker'
if self.mover == 'target':
if event.key == pg.K_LEFT:
self.target.move(dx=-1)
if event.key == pg.K_RIGHT:
self.target.move(dx=1)
if event.key == pg.K_UP:
self.target.move(dy=-1)
if event.key == pg.K_DOWN:
self.target.move(dy=1)
else:
if event.key == pg.K_LEFT:
self.player.move(dx=-1)
if event.key == pg.K_RIGHT:
self.player.move(dx=1)
if event.key == pg.K_UP:
self.player.move(dy=-1)
if event.key == pg.K_DOWN:
self.player.move(dy=1)
def draw(self):
# game loop - draw
self.screen.fill(BGCOLOR)
self.draw_grid()
self.all_sprites.draw(self.screen)
for wall in self.walls:
rect = pg.Rect(wall * TILESIZE, (TILESIZE, TILESIZE))
pg.draw.rect(self.screen, GREEN, rect)
# always do the flip after drawing everything
pg.display.flip()
def show_start_screen(self):
# game splash/start screen
pass
def show_go_screen(self):
# game over/continue screen
pass
def breadthfirst(target, seeker, walls, maingrid):
pass
def depthfirst(target, seeker, wall, maingrid):
pass
def astarsearch(target, seeker, wall, maingrid):
# array to store path locations
direct_graph = {}
# target location, returns a tuple
target = np.where(target.pos) # problem area
# seeker location, returns locations
start = np.where(seeker.pos) # problem area
# array of cost to travel so far
g_cost_array = np.zeros(seeker) # problem area
g_cost_array[start] = 0
total_g_cost = 0
# array for heuristic cost
h_cost_array = np.zeros(seeker) # problem area
# need to use a loop unfortunately...
t = 0
# possible steps
steps = ((-1, 0), (+1, 0), (0, -1), (0, +1))
for rows in h_cost_array:
s = 0
for cols in rows:
# check if it's a wall! if not - get the distance to target
loc = (t, s)
if (maingrid[loc]):
pass
else:
dist = abs(target[0] - s) + abs(target[1] - t)
h_cost_array[t, s] = dist
s += 1
t += 1
# total cost = h + g
f_cost_array = g_cost_array + h_cost_array
# closed and open sets
open_set = []
open_set.append(start)
closed_set = []
# actual path
path = []
path.append([tuple(target[0]), tuple(target[1])])
solution_found = False
while (open_set):
open_f_cost = []
# get the heuristic cost for the candidates in the open set
for vals in open_set:
open_f_cost.append(f_cost_array[vals])
# the shortest heuristic now
# the index of the candidate with the lowest distance/heuristic
best_dist_now = open_f_cost.index(min(open_f_cost))
# the current best position
best_pos_now = open_set[best_dist_now]
# if the destination is reached, finish!
if (tuple(best_pos_now) == target):
solution_found = True
break
else:
# remove the best guy from the open_set and add it to the closed set
closed_set.append(open_set.pop(best_dist_now))
# analyze the steps from the current best
for step in steps:
cand = (best_pos_now[0] + step[0], best_pos_now[1] + step[1])
# check if there's a wall or beyond the screen
if cand[0] < 0 or cand[1] < 0 or cand[0] > 39 or cand[1] > 23:
pass
# skip this candidate because it's a wall!
elif maingrid[cand]:
pass
# need an else clause here to weed out the off-screen locations
else:
# check if the candidate is in the closed set
already_seen = False
for dead in closed_set:
if np.all(dead == cand):
already_seen = True
break
# if the cell is in the closed set, skip it
if already_seen:
pass
else:
approx_g_score = g_cost_array[best_pos_now] + 1
# check if it's in the open list:
new = True
for others in open_set:
if np.all(others == cand):
new = False
break
# if a new cell or improved
if (new or approx_g_score < g_cost_array[cand]):
direct_graph[tuple(cand[0]), tuple(cand[1])] = (
tuple(best_pos_now[0]), tuple(best_pos_now[1]))
g_cost_array[cand] = approx_g_score
f_cost_array[cand] = g_cost_array[cand] + h_cost_array[cand]
if new:
open_set.append(cand)
if not solution_found:
return None
else:
recurrentPath(path, direct_graph, target, start)
return path
# takes a dictionary as input
def recurrentPath(final_path, raw_path, dest, origin):
a = raw_path[tuple(dest[0]), tuple(dest[1])]
final_path.append(a)
if (a != origin):
recurrentPath(final_path, raw_path, a, origin)
else:
return final_path
g = Game()
g.show_start_screen()
while True:
g.new()
g.run()
g.show_go_screen()
pg.QUIT
the expected results is to return the correct path to the target object from the seeker object after you press the keyboard character a. Note that with a left click, a wall can be constructed to add a hindrance to the seeking of the goal.

Mandelbrot set displays incorrectly

This is my attempt to program the Mandelbrot set in Python 3.5 using the Pygame module.
import math, pygame
pygame.init()
def mapMandelbrot(c,r,dim,xRange,yRange):
x = (dim-c)/dim
y = (dim-r)/dim
#print([x,y])
x = x*(xRange[1]-xRange[0])
y = y*(yRange[1]-yRange[0])
x = xRange[0] + x
y = yRange[0] + y
return [x,y]
def checkDrawBox(surface):
for i in pygame.event.get():
if i.type == pygame.QUIT:
pygame.quit()
elif i.type == pygame.MOUSEBUTTONDOWN:
startXY = pygame.mouse.get_pos()
boxExit = False
while boxExit == False:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONUP:
boxExit = True
if boxExit == True:
return [startXY,pygame.mouse.get_pos()]
pygame.draw.rect(surface,[255,0,0],[startXY,[pygame.mouse.get_pos()[0]-startXY[0],pygame.mouse.get_pos()[1]-startXY[1]]],1)
pygame.display.update()
def setup():
dimensions = 500
white = [255,255,255]
black = [0,0,0]
checkIterations = 100
canvas = pygame.display.set_mode([dimensions,dimensions])
canvas.fill(black)
xRange = [-2,2]
yRange = [-2,2]
xRangePrev = [0,0]
yRangePrev = [0,0]
newxRange = [0,0]
newyRange = [0,0]
while True:
if not ([xRange,yRange] == [xRangePrev,yRangePrev]):
draw(dimensions, canvas, xRange, yRange, checkIterations)
pygame.display.update()
xRangePrev = xRange
yRangePrev = yRange
box = checkDrawBox(canvas)
if box != None:
maxX = max([box[0][0],box[1][0]])
maxY = max([box[0][1],box[1][1]])
newxRange[0] = mapMandelbrot(box[0][0],0,dimensions,xRange,yRange)[0]
newxRange[1] = mapMandelbrot(box[1][0],0,dimensions,xRange,yRange)[0]
newyRange[0] = mapMandelbrot(0,box[0][1],dimensions,xRange,yRange)[1]
newyRange[1] = mapMandelbrot(0,box[1][1],dimensions,xRange,yRange)[1]
xRange = newxRange
yRange = newyRange
def draw(dim, surface, xRange, yRange, checkIterations):
for column in range(dim):
for row in range(dim):
greyVal = iteration(0,0,mapMandelbrot(column,row,dim,xRange,yRange),checkIterations,checkIterations)
surface.set_at([dim-column,row],greyVal)
def iteration(a, b, c, iterCount, maxIter):
a = (a*a) - (b*b) + c[0]
b = (2*a*b) + c[1]
iterCount = iterCount - 1
if iterCount == 0:
return [0,0,0]
elif abs(a+b) > 17:
b = (iterCount/maxIter)*255
return [b,b,b]
else:
return iteration(a,b,c,iterCount,maxIter)
setup()
I believe that the iteration algorithm is correct, but the output doesn't look right:
Wondering what might be the problem? Sorry for the code dump, just not sure which part may cause it to look like that.
Fascinating bug -- it literally looks like a squashed bug :)
The problem lies in the two lines:
a = (a*a) - (b*b) + c[0]
b = (2*a*b) + c[1]
You are changing the meaning of a in the first line, hence using the wrong a in the second.
The fix is as simple as:
a, b = (a*a) - (b*b) + c[0], (2*a*b) + c[1]
which will cause the same value of a to be used in calculating the right hand side.
It would be interesting to work out just what your bug has produced. Even though it isn't the Mandelbrot set, it seems to be an interesting fractal in its own right. In that sense, you had a very lucky bug. 99% percent of the times, bugs lead to garbage, but every now and then they produce something quite interesting, but simply unintended.
On Edit:
The Mandelbrot set is based on iterating the complex polynomial:
f(z) = z^2 + c
The pseudo-Mandelbrot set which this bug has produced is based on iterating the function
f(z) = Re(z^2 + c) + i*[2*Re(z^2 + c)*Im(z) + Im(c)]
where Re() and Im() are the operators which extract the real and imaginary parts of a complex number. This isn't a polynomial in z, though it is easy to see that it is a polynomial in z,z* (where z* is the complex conjugate of z). Since it is a fairly natural bug, it is almost certain that this has appeared somewhere in the literature on the Mandelbrot set, though I don't remember ever seeing it.
I decided to learn about the mandelbrot set and wrote my own version! I used python's complex data type, which should make the mandelbrot calculation for each pixel a bit clearer. Here is a screenshot of the result:
And here is the source code/code dump:
import pygame
import sys
def calc_complex_coord(x, y):
real = min_corner.real + x * (max_corner.real - min_corner.real) / (width - 1.0)
imag = min_corner.imag + y * (max_corner.imag - min_corner.imag) / (height - 1.0)
return complex(real, imag)
def calc_mandelbrot(c):
z = c
for i in range(1, max_iterations+1):
if abs(z) > 2:
return i
z = z*z + c
return i
def calc_color_score(i):
if i == max_iterations:
return black
frac = 255.0 - (255.0 * i / max_iterations)
return (frac, frac, frac)
def update_mandelbrot():
for y in range(height):
for x in range(width):
c = calc_complex_coord(x, y)
mandel_score = calc_mandelbrot(c)
color = calc_color_score(mandel_score)
mandel_surface.set_at((x, y), color)
if __name__ == "__main__":
pygame.init()
(width, height) = (500, 500)
display = pygame.display.set_mode((width, height))
pygame.display.set_caption("Mandelbrot Magic")
clock = pygame.time.Clock()
mandel_surface = pygame.Surface((width, height))
black = (0, 0, 0)
red = (255, 0, 0)
max_iterations = 50
min_corner = complex(-2, -2)
max_corner = complex(2, 2)
box = pygame.Rect(0, 0, width, height)
update_mandel = True
draw_box = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
x, y = event.pos
box = pygame.Rect(x, y, 0, 0)
draw_box = True
elif event.type == pygame.MOUSEMOTION:
x, y = event.pos
if draw_box:
box = pygame.Rect(box.left, box.top, x - box.left, y - box.top)
elif event.type == pygame.MOUSEBUTTONUP:
x, y = event.pos
update_mandel = True
display.blit(mandel_surface, (0, 0))
if draw_box:
pygame.draw.rect(display, red, box, 1)
if update_mandel:
box.normalize()
new_min_corner = calc_complex_coord(box.left, box.top)
new_max_corner = calc_complex_coord(box.right, box.bottom)
min_corner, max_corner = new_min_corner, new_max_corner
update_mandelbrot()
update_mandel = False
draw_box = False
pygame.display.update()
clock.tick(60)
The two issues with this code are that one, it is quite slow in updating the mandelbrot set, and two, the aspect ratios get distorted if you work with non-square windows or box-selections. Let me know if any of the code is unclear!

I get an incorrect position from .get_rect()?

I'm currently working on a school project where I'm making a "hexcells" similar game in pygame and now I'm trying to blit an a new image if the user has clicked a current image. It will blit an image in the top left area, if clicked in the top left area, but not if I click any of the existing images. I told the program to print the coordinates from the images with help of the .get_rect() function, but it remains the same whereever I click and the coordinates aren't even where a image is. Can someone help me understand how this works and help me blit the new images on top of the existing images? Code below is not the entire document, however there is so much garbage/trash/unused code so I'd thought I spare you the time of looking at irrelevant code. Also sorry if the formatting is wrong or the information isn't enough, I tried my best.
import pygame, sys
from pygame.locals import *
#Magic numbers
fps = 30
winW = 640
winH = 480
boxSize = 40
gapSize = 75
boardW = 3
boardH = 3
xMargin = int((winW - (boardW * (boxSize + gapSize))) / 2)
yMargin = int((winW - (boardW * (boxSize + gapSize))) / 2)
#Lil bit o' color R G B
NAVYBLUE = ( 60, 60, 100)
correctCords = [[175,275,375],[375,275,175]]
bgColor = NAVYBLUE
unC = pygame.image.load("unC.png")
cor = pygame.image.load("correct.png")
inc = pygame.image.load("wrong.png")
correct = "Correct"
inCorrect = "Incorrect"
def main():
global FPSCLOCK, DISPLAYSURF
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((winW, winH))
mousex = 0 #stores x-coordinate of mouse event
mousey = 0 #stores y-coordinate of mouse event
pygame.display.set_caption("Branches")
DISPLAYSURF.fill(bgColor)
gridGame(inCorrect, correct,gapSize,xMargin,yMargin,boxSize)
while True:
mouseClicked = False
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
mousex,mousey = event.pos
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
pos = pygame.mouse.get_pos()
mouseClicked = True
unCa = unC.get_rect()
corA = cor.get_rect()
print unCa
print corA
print pos
if unCa.collidepoint(pos):
DISPLAYSURF.blit(cor,(mousey,mousex))
"""lada = unC.get_rect()
lada =
if mousex and mousey == lada:
for x in correctCords:
for y in x:
for z in x:
if mousey and mousex == z and y:
DISPLAYSURF.blit(cor,(mousey,mousex))
print lada"""
pygame.display.update()
FPSCLOCK.tick(fps)
def gridGame(inCorrect, correct,gapSize,xMargin,yMargin,boxSize):
grid = []
cordX = []
cordY = []
correctRecs = []
#cordinates = []
#cordinates.append([])
#cordinates.append([])
#cordinates.append([])
#this is basically getBoard() all over again
#This part will arrange the actual backend grid
for row in range(3):
grid.append([])
#cordinates[0].append(gapSize+(row+1)*100)
#cordinates[1].append(gapSize+(row+1)*100)
#cordinates[2].append(gapSize+(row+1)*100)
for column in range(3):
grid[row].append(inCorrect)
for row in range(3):
cordX.append([])
for column in range(3):
cordX[row].append(gapSize+(row+1)*100)
for row in range(3):
cordY.append([])
for column in range(3):
cordY[row].append(gapSize+(column+1)*100)
#print cordX[0][0], cordY[0][0]
grid[0][2] = correct
grid[1][1] = correct
grid[2][0] = correct
#Y-AXEL SKRIVS FoRST ([Y][X])
#print cordinates[2][1]
DISPLAYSURF.blit(cor,(100,100))
#Let's draw it as well
for row in range(3):
for column in range(3):
DISPLAYSURF.blit(unC,(gapSize+(row+1)*100,gapSize+(column+1)*100))
main()
Also real sorry about the horrible variable naming and occasional swedish comments.
unCa = unC.get_rect() gives you only image size - so use it only once at start (before while True) - and later use the same unCa all the time to keep image position and change it.
btw: better use more readable names - like unC_rect
ie.
# move 10 pixel to the right
unC_rect.x += 10
# set new position
unC_rect.x = 10
unC_rect.right = 100
unC_rect.topleft = (10, 200)
unC_rect.center = (10, 200)
# center on screen
unC_rect.center = DISPLAYSURF.get_rect().center
etc.
And then use this rect to blit image
blit(unC, unC_rect)
and check collision with other rect
if unC_rect.colliderect(other_rect):
or with point - like mouse position
elif event.type == MOUSEMOTION:
if unC_rect.collidepoint(pygame.mouse.get_pos()):
hover = True
# shorter
elif event.type == MOUSEMOTION:
hover = unC_rect.collidepoint(pygame.mouse.get_pos()):

Categories

Resources