I'll try to explain this to my best ability. Short story short, making a tic tac toe game for a school project. I have all the code necessary i think, but when i run my code, tkinter window opens no problem, but when i am to click in one of the squares where i can place a "x" or a "o" my image wont load into the grid.
When i click, this is one the errors that pops up:
line 2776, in _create
return self.tk.getint(self.tk.call(
_tkinter.TclError: unknown option "562.5"
If i was to guess, the error must be in both "def draw_o" and "def draw_x"
If you want to try the code here is the images to download: https://imgur.com/a/kKJPIop
If relevant image of assignment: https://imgur.com/a/3iu4MJy
from math import log
from tkinter import *
import numpy as np
size = 600
symbol_size = (size / 3 - size / 8) /2
symbol_thick = 50
symbol_x_color = '#EE4035'
symbol_o_color = '#0492CF'
green = '#7BC043'
class cell:
def __init__(self):
self.window = Tk()
self.window.title("Bondesjakk/Tic Tac Toe")
self.canvas = Canvas(self.window, width = size, height = size)
self.canvas.pack()
self.window.bind("<Button-1>", self.click)
self.initialize_board()
self.player_x_turns = True
self.board_status = np.zeros(shape=(3, 3) )
self.player_x_starts = True
self.reset_board = False
self.gameover = False
self.tie = False
self.x_wins = False
self.o_wins = False
self.x_score = False
self.o_score = False
self.tie_score = False
def mainloop(self):
self.window.mainloop()
def initialize_board(self):
for i in range(2):
self.canvas.create_line( (i + 1) * size / 3, 0, (i + 1) * size / 3, size)
for i in range(2):
self.canvas.create_line(0, (i + 1) * size / 3, size, (i + 1) * size / 3)
def play_again(self):
self.initialize_board()
self.player_x_starts = not self.player_x_starts
self.player_x_turns = self.player_x_starts
self.board_status = np.zeros(shape =(3, 3) )
def draw_o(self, logical_pos):
o_image = PhotoImage('book/pybook/image/o.gif')
logical_pos = np.array(logical_pos)
grid_pos = self.convert_logical_to_grid_pos(logical_pos)
self.canvas.create_image(grid_pos[0] - symbol_size, grid_pos[1] - symbol_size,
grid_pos[0] + symbol_size, grid_pos[1] + symbol_size, width = symbol_thick,
image = o_image)
def draw_x(self, logical_pos):
x_image = PhotoImage('book/pybook/image/x.gif')
grid_pos = self.convert_logical_to_grid_pos(logical_pos)
self.canvas.create_image(grid_pos[0] - symbol_size, grid_pos[1] - symbol_size,
grid_pos[0] + symbol_size, grid_pos[1] + symbol_size, width = symbol_thick,
image = x_image)
def display_gameover(self):
if self.x_wins:
self.x_score += 1
text = "Winner: Player 1(x)"
color = symbol_x_color
elif self.o_wins:
self.o_score += 1
text = "Winner: Player 2(o)"
color = symbol_o_color
else:
self.tie_score += 1
text = "It's a tie"
color = "gray"
self.canvas.delete("all")
self.canvas.create_text(size / 2, size / 3, font = "cmr 60 bold", fill = color, text = text)
score_text = 'Scores \n'
self.canvas.create_text(size / 2, 5 * size / 8, font = "cmr 40 bold", fill = green, text = score_text)
score_text = 'Player 1 (x) : ' + str(self.x_score) + '\n'
score_text = 'Player 2 (o) : ' + str(self.o_score) + '\n'
score_text = 'Tie : ' + str(self.tie_score) + '\n'
self.canvas.create_text(size / 2, 3 * size / 4, font = "cmr 30 bold", fill = green, text = score_text)
self.reset_board = True
score_text = "Click to play again \n"
self.canvas.create_text(size / 2, 15* size / 16, font = "cmr 20 bold", fill = "gray", text = score_text)
def convert_logical_to_grid_pos(self, logical_pos):
logical_pos = np.array(logical_pos, dtype = int)
return (size / 3) * logical_pos + size / 6
def convert_grid_to_logical_pos(self, grid_pos):
grid_pos = np.array(grid_pos)
return np.array(grid_pos // (size / 3), dtype = int)
def is_grid_occupied(self, logical_pos):
if self.board_status[logical_pos[0] ][logical_pos[1] ] == 0:
return False
else:
return True
def is_winner(self, player):
player = -1 if player == "x" else 1
#Three in a row
for i in range(3):
if self.board_status[i][1] == self.board_status[i][2] == player:
return True
if self.board_status[0][1] == self.board_status[2][i] == player:
return True
#Diagonals
if self.board_status[0][0] == self.board_status[1][1] == self.board_status[2][2] == player:
return True
if self.board_status[2][0] == self.board_status[1][1] == self.board_status[0][2] == player:
return True
return False
def is_tie(self):
r, c = np.where(self.board_status == 0)
tie = False
if len(r) == 0:
tie = True
return tie
def is_gameover(self):
self.x_wins = self.is_winner("x")
if not self.x_wins:
self.o_wins = self.is_winner("o")
if not self.o_wins:
self.tie = self.is_tie()
gameover = self.x.wins or self.o.wins or self.tie
if self.x_wins:
print("x wins!")
if self.o_wins:
print("o wins!")
if self.tie:
print("It's a tie!")
return gameover
def click(self, event):
grid_pos = [event.x, event.y]
logical_pos = self.convert_grid_to_logical_pos(grid_pos)
if not self.reset_board:
if self.player_x_turns:
if not self.is_grid_occupied(logical_pos):
self.draw_x(logical_pos)
self.board_status[logical_pos[0] ][logical_pos[1] ] = -1
self.player_x_turns = not self.player_x_turns
else:
if not self.is_grid_occupied(logical_pos):
self.draw_o(logical_pos)
self.board_status[logical_pos[0] ][logical_pos[1] ] = 1
self.player_x_turns = not self.player_x_turns
if self.gameover():
self.display_gameover()
else:
self.canvas.delete("all")
self.play_again()
self.reset_board = False
game_instance = cell()
game_instance.mainloop()
In create_image() you use x1, y1, x2, y2, width=... but it expects only position (x1,y1) as tuple (without x2,y2) and without width=...
x = grid_pos[0] - symbol_size
y = grid_pos[1] - symbol_size
self.canvas.create_image( (x, y), image=x_image)
EDIT:
You have other mistakes
In line if self.gameover() you have to remove ()
--
If you use PhotoImage('book/pybook/image/o.gif') then it treats it as string with image's data, not as path to file. You have to use file=
o_image = PhotoImage(file='book/pybook/image/o.gif')
--
But there is another problem. There is bug in PhotoImage which removes image from memory when it is assigned to local variable in function. You should assign to class variable using self.
self.o_image = PhotoImage(file='book/pybook/image/o.gif')
--
And here another problem. You load the same image again and again and you assign it to the same variable - so bug removes previous image from memory and it removes it from canvas.
You could load it only once in __init__ and later use all time the same self.o_image, self.x_image
def __init___(...):
self.o_image = PhotoImage(file='book/pybook/image/o.gif')
self.x_image = PhotoImage(file='book/pybook/image/x.gif')
Doc (effbot.org in archive.org): PhotoImage, Canvas
Related
I am trying to make a racing game for my final project(High School). but I am having problems rotating the car. It loads and draws the image properly but I haven't been able to rotate the image.The program is much longer but here is the parts that are involved:
from tkinter import *
from time import *
from math import *
from random import *
from PIL import *
global screenWidth, screenHeight
screenWidth = 1200
screenHeight = 800
root = Tk()
s = Canvas(root, width=screenWidth, height=screenHeight, background= "gray")
def setGameStartingValues():
carLength = 60
carWidth = 28
carAngle = 0
lapCount = 0
speed = 0
speedX = 0
speedY = 0
directionX = ""
directionY = ""
imageCar = PhotoImage(file = "C:\\Users\\Antonio\\Desktop\\Python Programs\\GameFinal\\car.png")
colisionX = False
colisionY = False
carRadius = sqrt((carLength/2)**2 + (carWidth/2)**2)
carAngleFixed = asin((carWidth/2)/carRadius)
barriers, finishLine = createCirquit()
drawnBarriers = []
for i in range(len(barriers)):
drawnBarriers.append(None)
return carAngle, carRadius, carAngleFixed, barriers, speed, drawnBarriers, speedY, speedX, lapCount, finishLine, colisionX, colisionY, imageCar, directionX, directionY
def drawCar(carAngle, carRadius, carAngleFixed):
global screenWidth, screenHeight, correctCarImage
backLeftAngle = ((2*pi-carAngleFixed+carAngle)%(2*pi))
backRightAngle = ((carAngle+carAngleFixed)%(2*pi))
frontRightAngle = ((pi-carAngleFixed+carAngle)%(2*pi))
frontLeftAngle = ((pi+carAngle+carAngleFixed)%(2*pi))
frontRightX = carRadius*cos(frontRightAngle) + screenWidth/2
frontRightY = carRadius*sin(frontRightAngle) + screenHeight/2
frontLeftX = carRadius*cos(frontLeftAngle) + screenWidth/2
frontLeftY = carRadius*sin(frontLeftAngle) + screenHeight/2
backRightX = carRadius*cos(backRightAngle) + screenWidth/2
backRightY = carRadius*sin(backRightAngle) + screenHeight/2
backLeftX= carRadius*cos(backLeftAngle) + screenWidth/2
backLeftY = carRadius*sin(backLeftAngle) + screenHeight/2
car = s.create_image(600, 400, anchor = NW, image = correctCarImage)
return car, frontRightX, frontRightY, frontLeftX, frontLeftY, backRightX, backRightY, backLeftX, backLeftY
def sKeyPressed(event):
global speed, screenUsed
if screenUsed == "Game Screen":
if speed > -6:
speed = speed - 2
def wKeyPressed(event):
global speed, screenUsed
if screenUsed == "Game Screen":
if speed < 30:
speed = speed + 2
def aKeyPressed(event):
global carAngle, screenUsed, imageCar, correctCarImage
if screenUsed == "Game Screen":
carAngle = carAngle - radians(15)
correctCarImage = imageCar.rotate(degrees(carAngle))
def dKeyPressed(event):
global carAngle, screenUsed, correctCarImage, imageCar
if screenUsed == "Game Screen":
carAngle = carAngle + radians(15)
correctCarImage = imageCar.rotate(degrees(carAngle))
The full code doesn't fit in the question
I'm making a game with pygame and pymunk as a physics engine. I'm trying to kill a bullet whenever it hits a player or goes past its lifetime.
When I tried to space.remove(self.shape) and the second bullet hits the player, it gives me an "AssertionError: shape not in space, already removed. I simply changed it to teleport the bullets away, and then learned of the real error.
When I have more than one bullet in the space and a bullet hits the enemy player, all the current bullets teleport away, which means that when I tried to remove one bullet, it called the remove on all the bullets and thats why I had the initial error.
However the problem still remains that one bullet is being treated as every bullet.
Why is something that should be a non-static variable being called as a static variable?
I even tried to use deepcopy to see if that fixed it, but to no avail
This is my chunk of code, apologies since I don't know what is needed to understand it.
The key parts are most likely the Bullet class, the shoot() function in the Player class, and the drawBulletCollision() function
# PyGame template.
# Import modules.
import sys, random, math, time, copy
from typing import List
import pygame
from pygame.locals import *
from pygame import mixer
import pymunk
import pymunk.pygame_util
from pymunk.shapes import Segment
from pymunk.vec2d import Vec2d
pygame.mixer.pre_init(44110, -16, 2, 512)
mixer.init()
# Set up the window.
width, height = 1440, 640
screen = pygame.display.set_mode((width, height))
bg = pygame.image.load("space.png")
def draw_bg():
screen.blit(bg, (0, 0))
#load sounds
#death_fx = pygame.mixer.Sound("")
#death_fx.set_volume(0.25)
shoot_fx = mixer.Sound("shot.wav")
shoot_fx.set_volume(0.25)
#mixer.music.load("video.mp3")
#mixer.music.play()
#time.sleep(2)
#mixer.music.stop()
#gun_mode_fx = pygame.mixer.Sound("")
#gun_mode_fx.set_volume(0.25)
#thrust_mode_fx = pygame.mixer.Sound("")
#thrust_mode_fx.set_volume(0.25)
collision_fx = mixer.Sound("thump.wav")
collision_fx.set_volume(0.25)
ship_group = pygame.sprite.Group()
space = pymunk.Space()
space.gravity = 0, 0
space.damping = 0.6
draw_options = pymunk.pygame_util.DrawOptions(screen)
bulletList = []
playerList = []
environmentList = []
arbiterList = []
b0 = space.static_body
segmentBot = pymunk.Segment(b0, (0,height), (width, height), 4)
segmentTop = pymunk.Segment(b0, (0,0), (width, 0), 4)
segmentLef = pymunk.Segment(b0, (width,0), (width, height), 4)
segmentRit = pymunk.Segment(b0, (0,0), (0, height), 4)
walls = [segmentBot,segmentLef,segmentRit,segmentTop]
for i in walls:
i.elasticity = 1
i.friction = 0.5
i.color = (255,255,255,255)
environmentList.append(i)
class Player(object):
radius = 30
def __init__(self, position, space, color):
self.body = pymunk.Body(mass=5,moment=10)
self.mode = 0 # 0 is gun, 1 is thrust, ? 2 is shield
self.body.position = position
self.shape = pymunk.Circle(self.body, radius = self.radius)
#self.image
#self.shape.friction = 0.9
self.shape.elasticity= 0.2
space.add(self.body,self.shape)
self.angleGun = 0
self.angleThrust = 0
self.health = 100
self.speed = 500
self.gearAngle = 0
self.turningSpeed = 5
self.shape.body.damping = 1000
self.cooldown = 0
self.fireRate = 30
self.shape.collision_type = 1
self.shape.color = color
playerList.append(self)
def force(self,force):
self.shape.body.apply_force_at_local_point(force,(0,0))
def rocketForce(self):
radians = self.angleThrust * math.pi/180
self.shape.body.apply_force_at_local_point((-self.speed * math.cos(radians),-self.speed * math.sin(radians)),(0,0))
def draw(self):
gear = pygame.image.load("gear.png")
gearBox = gear.get_rect(center=self.shape.body.position)
gearRotated = pygame.transform.rotate(gear, self.gearAngle)
#gearRotated.rect.center=self.shape.body.position
x,y = self.shape.body.position
radianGun = self.angleGun * math.pi/180
radianThrust = self.angleThrust * math.pi/180
radiyus = 30 *(100-self.health)/100
screen.blit(gearRotated,gearBox)
self.gearAngle += 1
if radiyus == 30:
radiyus = 32
pygame.draw.circle(screen,self.shape.color,self.shape.body.position,radiyus,0)
pygame.draw.circle(screen,(0,0,0),self.shape.body.position,radiyus,0)
pygame.draw.line(
screen,(0,255,0),
(self.radius * math.cos(radianGun) * 1.5 + x,self.radius * math.sin(radianGun) * 1.5 + y),
(x,y), 5
)
pygame.draw.line(
screen,(200,200,0),
(self.radius * math.cos(radianThrust) * 1.5 + x,self.radius * math.sin(radianThrust) * 1.5 + y),
(x,y), 5
)
#more
def targetAngleGun(self,tAngle):
tempTAngle = tAngle - self.angleGun
tempTAngle = tempTAngle % 360
if(tempTAngle < 180 and not tempTAngle == 0):
self.angleGun -= self.turningSpeed
elif(tempTAngle >= 180 and not tempTAngle == 0):
self.angleGun += self.turningSpeed
self.angleGun = self.angleGun % 360
#print(tAngle, "target Angle")
#print(self.angleGun, "selfangleGun")
#print(tempTAngle, "tempTAngle")
def targetAngleThrust(self,tAngle):
tempTAngle = tAngle - self.angleThrust
tempTAngle = tempTAngle % 360
if(tempTAngle < 180 and not tempTAngle == 0):
self.angleThrust -= self.turningSpeed
elif(tempTAngle >= 180 and not tempTAngle == 0):
self.angleThrust += self.turningSpeed
self.angleThrust = self.angleThrust % 360
#print(tAngle, "target Angle")
#print(self.angleThrust, "selfangleGun")
#print(tempTAngle, "tempTAngle")
def targetAngle(self,tAngle):
if(self.mode == 0):
self.targetAngleGun(tAngle)
elif(self.mode == 1):
self.targetAngleThrust(tAngle)
def shoot(self):
if(self.cooldown == self.fireRate):
x,y = self.shape.body.position
radianGun = self.angleGun * math.pi/180
spawnSpot = (self.radius * math.cos(radianGun) * 1.5 + x,self.radius * math.sin(radianGun)*1.5+y)
self.shape.body.apply_impulse_at_local_point((-20 * math.cos(radianGun),-20 * math.sin(radianGun)),(0,0))
print(spawnSpot)
bT = Bullet(spawnSpot, 5, 50,self.shape.color)
b = copy.deepcopy(bT)
bulletList.append(b)
space.add(b.shape,b.shape.body)
b.getShot(self.angleGun)
self.cooldown = 0
print('pew')
shoot_fx.play()
# HEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEREEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
def tick(self):
self.draw()
if(self.cooldown < self.fireRate):
self.cooldown += 1
#for o in playerList:
# c = self.shape.shapes_collide(o.shape)
# if(len(c.points)>0):
# self.damage(c.points[0].distance/10)
for o in bulletList:
c = self.shape.shapes_collide(o.shape)
#print(c)
for o in walls:
c = self.shape.shapes_collide(o)
if(len(c.points)>0):
self.damage(c.points[0].distance * 3)
def damage(self, damage):
self.health -= abs(damage)
if self.health < 0:
self.health = 0
#maybe make it part of the player class
def drawWallCollision(arbiter, space, data):
for c in arbiter.contact_point_set.points:
r = max(3, abs(c.distance * 5))
r = int(r)
p = tuple(map(int, c.point_a))
pygame.draw.circle(data["surface"], pygame.Color("red"), p, r, 0)
print('magnitude', math.sqrt(arbiter.total_impulse[0]**2 + arbiter.total_impulse[1]**2))
#print('position', p)
#print(data)
print("its all arbitrary")
s1, s2 = arbiter.shapes
collision_fx.play()
def drawBulletCollision(arbiter, space, data):
s1, s2 = arbiter.shapes
for c in arbiter.contact_point_set.points:
magnitude = math.sqrt(arbiter.total_impulse[0]**2 + arbiter.total_impulse[1]**2)
for p in playerList:
avr = ((c.point_a[0] + c.point_b[0])/2, (c.point_a[1] + c.point_b[1])/2)
distance = (math.sqrt((avr[0] - p.shape.body.position[0]) **2 + (avr[1] - p.shape.body.position[1]) **2 ))
if(distance < Bullet.explosionRadius + Player.radius):
if not(s1.color == s2.color):
p.damage(magnitude)
for b in bulletList:
avr = ((c.point_a[0] + c.point_b[0])/2, (c.point_a[1] + c.point_b[1])/2)
distance = (math.sqrt((avr[0] - p.shape.body.position[0]) **2 + (avr[1] - p.shape.body.position[1]) **2 ))
if(distance < Bullet.explosionRadius + Player.radius):
if not(s1.color == s2.color):
b.damage(magnitude)
pygame.draw.circle(data["surface"], pygame.Color("red"), tuple(map(int, c.point_a)), 10, 0)
print('magnitude', magnitude)
#print('position', p)
#print(data)
print("its all arbitrary")
def drawArbitraryCollision(arbiter, space, data):
collision_fx.play()
class Ship(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("gear.png")
self.rect = self.image.get_rect()
self.rect.center = [x, y]
def rotate(self):
self.image = pygame.transform.rotate(self.image,1)
class Bullet(object):
damage = 2
explosionRadius = 5
def __init__(self, position, size, speed,color):
pts = [(-size, -size), (size, -size), (size, size), (-size, size)]
self.body = copy.deepcopy(pymunk.Body(mass=0.1,moment=1))
self.shape = copy.deepcopy(pymunk.Poly(self.body, pts))
self.shape.body.position = position
self.shape.friction = 0.5
self.shape.elasticity = 1
self.shape.color = color
self.speed = speed
self.size = size
self.shape.collision_type = 2
#space.add(self.body,self.shape)
#bulletList.append(self)
self.lifetime = 0
def getShot(self,angle):
radians = angle * math.pi/180
self.shape.body.apply_impulse_at_local_point((self.speed * math.cos(radians),self.speed * math.sin(radians)),(0,0))
def tick(self):
self.lifetime += 1
if(self.lifetime > 300):
self.shape.body.position = (10000,30)
def damage(self, damage):
self.lifetime = 300
#VELOCITY OF BULLET STARTS WITH VELOCITY OF PLAYER
#MAKE VOLUME OF SOUND DEPEND ON THE IMPULSE FOR THE IMPACTS
#error on purpose so you notice this
#INSTANCES NOT WORKING????
def runPyGame():
# Initialise PyGame.
pygame.init()
# Set up the clock. This will tick every frame and thus maintain a relatively constant framerate. Hopefully.
fps = 60.0
fpsClock = pygame.time.Clock()
running = True
font = pygame.font.SysFont("Arial", 16)
p1 = Player((240,240),space,(132, 66, 245,255))
p2 = Player((1200,400),space,(47, 247, 184,255))
space.add(segmentBot,segmentTop,segmentLef,segmentRit)
# Main game loop.
ch = space.add_collision_handler(1, 0)
ch.data["surface"] = screen
ch.post_solve = drawWallCollision
ch = space.add_collision_handler(1, 2)
ch.data["surface"] = screen
ch.post_solve = drawBulletCollision
ch = space.add_collision_handler(0, 2)
ch.data["surface"] = screen
ch.post_solve = drawArbitraryCollision
dt = 1/fps # dt is the time since last frame.
while True: # Loop forever!
keys = pygame.key.get_pressed()
for event in pygame.event.get():
# We need to handle these events. Initially the only one you'll want to care
# about is the QUIT event, because if you don't handle it, your game will crash
# whenever someone tries to exit.
if event.type == QUIT:
pygame.quit() # Opposite of pygame.init
sys.exit() # Not including this line crashes the script on Windows.
if event.type == KEYDOWN:
if event.key == pygame.K_s:
p1.mode = -(p1.mode - 0.5) + 0.5
print(p1.mode)
if (event.key == pygame.K_k and p1.mode == 0):
p1.shoot()
if event.key == pygame.K_KP_5:
p2.mode = -(p2.mode - 0.5) + 0.5
print(p2.mode)
if (event.key == pygame.K_m and p2.mode == 0):
p2.shoot()
#b = Bullet((200,200),51,51)
if(keys[K_w]):
p1.targetAngle(90)
if(keys[K_q]):
p1.targetAngle(45)
if(keys[K_a]):
p1.targetAngle(0)
if(keys[K_z]):
p1.targetAngle(315)
if(keys[K_x]):
p1.targetAngle(270)
if(keys[K_c]):
p1.targetAngle(225)
if(keys[K_d]):
p1.targetAngle(180)
if(keys[K_e]):
p1.targetAngle(135)
if(keys[K_k] and p1.mode == 1):
p1.rocketForce()
if(keys[K_KP_8]):
p2.targetAngle(90)
if(keys[K_KP_7]):
p2.targetAngle(45)
if(keys[K_KP_4]):
p2.targetAngle(0)
if(keys[K_KP_1]):
p2.targetAngle(315)
if(keys[K_KP_2]):
p2.targetAngle(270)
if(keys[K_KP_3]):
p2.targetAngle(225)
if(keys[K_KP_6]):
p2.targetAngle(180)
if(keys[K_KP_9]):
p2.targetAngle(135)
if(keys[K_m] and p2.mode == 1):
p2.rocketForce()
# Handle other events as you wish.
screen.fill((250, 250, 250)) # Fill the screen with black.
# Redraw screen here.
### Draw stuff
draw_bg()
space.debug_draw(draw_options)
for i in playerList:
i.tick()
screen.blit(
font.render("P1 Health: " + str(p1.health), True, pygame.Color("white")),
(50, 10),
)
screen.blit(
font.render("P2 Health: " + str(p2.health), True, pygame.Color("white")),
(50, 30),
)
for i in bulletList:
i.tick()
ship_group.draw(screen)
# Flip the display so that the things we drew actually show up.
pygame.display.update()
dt = fpsClock.tick(fps)
space.step(0.01)
pygame.display.update()
runPyGame()
I cant point to the exact error since the code is quite long and depends on files I dont have. But here is a general advice for troubleshooting:
Try to give a name to each shape when you create them, and then print it out. Also print out the name of each shape that you add or remove from the space. This should show which shape you are actually removing and will probably make it easy to understand whats wrong.
For example:
...
self.shape = pymunk.Circle(self.body, radius = self.radius)
self.shape.name = "circle 1"
print("Created", self.shape.name)
...
print("Adding", self.shape.name)
space.add(self.body,self.shape)
...
(Note that you need to reset the name of shapes you copy, since otherwise the copy will have the same name.)
I was wondering if it was possible to undraw previously drawn shapes from a loop. I have this function that'll create squares on click however I want to make it so that when the same area is clicked a second time the square will undraw.
from graphics import *
def createGrid():
X = 0
Y = 0
gridSize = 5
for i in range(1, gridSize + 1):
for j in range(1, gridSize + 1):
gridSquare = Rectangle(Point(X, Y), Point(X + 100, Y + 100))
gridSquare.draw(win)
X = X + 100
Y = Y + 100
X = 0
def editMode():
SelectedSquare = []
instruction = input("> ")
if instruction == "s":
selectionMode(SelectedSquare)
def selectionMode(SelectedSquare):
editSquare = Rectangle(Point(0, 0), Point(20, 20))
editSquare.setFill("black")
editSquare.draw(win)
while True:
selection = win.getMouse()
clickXPos = selection.getX()
clickYPos = selection.getY()
if clickXPos > 20 and clickYPos > 20:
PosX, PosY = clickXPos - (clickXPos % 100), clickYPos - (clickYPos % 100)
SelectedSquare = SelectedSquare + [Point(PosX, PosY)]
rect = Rectangle(Point(PosX, PosY), Point(PosX + 100, PosY + 100))
rect.setWidth(5)
rect.draw(win)
else:
editSquare.undraw()
break
win = GraphWin("GRID", 500, 500)
createGrid()
while True:
editMode()
As you can see, on click, there will be a thicker border around the grid square that was selected, I would like to be able to
1) remove the thickened border if clicked a second time
2) be able to remove all thickened borders surrounding grid squares
but I just cannot seem to figure this out, any help would be greatly appreciated!
The general problem seems to be that you have no underlying data structure or logic for your program -- you're drawing the interface first and then trying to make its behaviors define the program.
Below I've patched your code to have the points on the selected squares list remember what rectangle was drawn to highlight them, so if they are selected again, the highlight can be undone and the point removed:
from graphics import *
GRID_SIZE = 5
SQUARE_SIZE = 100
EDIT_BUTTON_SIZE = 20
BORDER_WIDTH = 5
def createGrid():
X, Y = 0, 0
for _ in range(1, GRID_SIZE + 1):
for _ in range(1, GRID_SIZE + 1):
gridSquare = Rectangle(Point(X, Y), Point(X + SQUARE_SIZE, Y + SQUARE_SIZE))
gridSquare.draw(win)
X += SQUARE_SIZE
Y += SQUARE_SIZE
X = 0
def editMode():
selectedSquares = []
instruction = input("> ")
if instruction == "s":
selectionMode(selectedSquares)
def checkSelected(point, squares):
for selected in squares:
if point.getX() == selected.getX() and point.getY() == selected.getY():
return selected
return None
def selectionMode(selectedSquares):
editSquare = Rectangle(Point(0, 0), Point(EDIT_BUTTON_SIZE, EDIT_BUTTON_SIZE))
editSquare.setFill("black")
editSquare.draw(win)
while True:
selection = win.getMouse()
clickXPos = selection.getX()
clickYPos = selection.getY()
if clickXPos <= EDIT_BUTTON_SIZE and clickYPos <= EDIT_BUTTON_SIZE:
break
PosX, PosY = clickXPos - clickXPos % SQUARE_SIZE, clickYPos - clickYPos % SQUARE_SIZE
point = Point(PosX, PosY)
selected = checkSelected(point, selectedSquares)
if selected:
selected.rect.undraw()
selectedSquares.remove(selected)
else:
rect = Rectangle(point, Point(PosX + SQUARE_SIZE, PosY + SQUARE_SIZE))
rect.setWidth(BORDER_WIDTH)
rect.draw(win)
point.rect = rect
selectedSquares.append(point)
editSquare.undraw()
win = GraphWin("GRID", GRID_SIZE * SQUARE_SIZE, GRID_SIZE * SQUARE_SIZE)
createGrid()
while True:
editMode()
But this is only a band-aid -- as you add more functionality the issue of a lack of data structure and spelled out logic will continue to frustrate you.
I'm trying to make a simple PSO (particle-swarm optimization) program.
Below is my current code, and I've been tweaking the weights only to find the "optimization" not working.
import random as ran
import math
# import threading as thr
import pygame as gm
# import pycuda as cuda
# import matplotlib.pyplot as plt
p_max = 10 # Maximum number of particles
rand_max = 100 # Maximum random vector value
# history = 10 # Number of iterations to record as history (including most current)
width = 600
height = 600
func_dict = {
"sphere" : ( lambda x, y: ( (x-(width/2))**2 + (y-(height/2))**2 ) ),
"booth" : ( lambda x, y: (((x-(width/2)) + 2*(y-(height/2)) - 7) ** 2) + ((2*(x-(width/2)) + (y-(height/2)) - 5) ** 2) ),
"matyas" : ( lambda x, y: (0.26 * ((x-(width/2))**2 + (y-(height/2))**2) - 0.48*(x-(width/2))*(y-(height/2))) )
} # (x-(width/2)) and (y-(height/2)) to shift the Zero to the display center
func = "sphere" # Choose function from func_dict
# Weights (0<w<1)
wLocal = 0.4 # Explore weight
wGlobal = 0.8 # Exploit weight
wRandom = 0.02 # Weight of random vector
global_best = [None, None, None] # Initial blank
class particle: # particles
global global_best
def __init__(self):
global global_best
global width, height
global func_dict, func
self.vel_x = 0
self.vel_y = 0
self.pos_x = ran.randint(0, width)
self.pos_y = ran.randint(0, height)
self.pos_z = func_dict[func](self.pos_x, self.pos_y)
self.local_best = [self.pos_x, self.pos_y, self.pos_z]
if (global_best[0] == None) or (global_best[1] == None) or (global_best[2] == None): # Is 1st particle
global_best = self.local_best
def update(self): # Update vectors
global width, height
global rand_max
global wGlobal, wLocal, wRandom
global global_best
self.vel_x = (wGlobal * (global_best[0] - self.pos_x)) + (wLocal * (self.local_best[0] - self.pos_x)) + (wRandom * ran.randint(-rand_max, rand_max))
self.vel_y = (wGlobal * (global_best[1] - self.pos_y)) + (wLocal * (self.local_best[1] - self.pos_y)) + (wRandom * ran.randint(-rand_max, rand_max))
# self.pos_x = (self.pos_x + self.vel_x) % width
# self.pos_y = (self.pos_y + self.vel_y) % height
self.pos_x += self.vel_x
self.pos_y += self.vel_y
if self.pos_x < 0:
self.pos_x = 0
if self.pos_y < 0:
self.pos_y = 0
if self.pos_x > width:
self.pos_x = width
if self.pos_y > height:
self.pos_y = height
self.pos_z = func_dict[func](self.pos_x, self.pos_y)
if self.pos_z < global_best[2]:
global_best = [self.pos_x, self.pos_y, self.pos_z]
particles = [None for _ in range(p_max)]
def initialize():
global_best = [None, None, None]
for foo in range(p_max):
particles[foo] = particle() # create new particles
# def dist(p1, p2): # distance
# return(math.sqrt( ( (p1.pos_x - p2.pos_y)**2) + ((p1.pos_y - p2.pos_y)**2) ) )
# def update(this): # this = particle
# this.vel_x = (wGlobal * (global_best[0] - this.pos_x)) + (wLocal * (this.local_best[0] - this.pos_x)) + (wRandom * ran.randint(0, rand_max))
# this.vel_y = (wGlobal * (global_best[1] - this.pos_y)) + (wLocal * (this.local_best[1] - this.pos_y)) + (wRandom * ran.randint(0, rand_max))
# # this.pos_x = (this.pos_x + this.vel_x) % width
# # this.pos_y = (this.pos_y + this.vel_y) % height
# this.pos_x += this.vel_x
# this.pos_y += this.vel_y
# if this.pos_x < 0:
# this.pos_x = 0
# if this.pos_y < 0:
# this.pos_y = 0
# if this.pos_x > width:
# this.pos_x = width
# if this.pos_y > height:
# this.pos_y = height
# # return this
# def update_multi(things): # things = list() of particles
# these = things
# for item in these:
# item = update(item)
# return these
gm.init()
main = gm.display.set_mode((width, height))
end_program = False
initialize()
main.fill((255, 255, 255))
while end_program == False:
# main.fill((255, 255, 255)) #Comment/Uncomment to leave trace
# plt.plot() # Plot functions
for event in gm.event.get():
if event.type == gm.QUIT:
end_program = True
for foo in range(len(particles)):
particles[foo].update()
gm.draw.circle(main, (0, 0, 0), (int(particles[foo].pos_x), int(particles[foo].pos_y)), 5, 0)
gm.display.flip()
Problem 1: Program only runs when mouse is moving
I'm not sure why but the program only runs fairly quickly for a few iterations but seems to just stop afterwards, but continues when the mouse is moved.
Problem 2: Particles appear to stay local
As I move the mouse around, it kinda runs. What emerges is clumps of traces left when the 2nd # main.fill((255, 255, 255)) is uncommented. The 1st initial traces from before the program stops without the mouse's movement seem more spread out and I'm not sure if that's the global variables or the randoms at work.
Edit: I've fixed the problem where the program only runs when the mouse moves by unindenting:
for foo in range(len(particles)):
particles[foo].update()
gm.draw.circle(main, (0, 0, 0), (int(particles[foo].pos_x), int(particles[foo].pos_y)), 5, 0)
However, the particles still seem to hardly move from their own positions, oscilating locally.
Problem 1 was solved thanks to Marius. I fixed it by simply putting update outside the event loop.
Problem 2 was fixed by adding the local update that I forgot.
if self.pos_z < global_best[2]: # This was not forgotten
global_best = [self.pos_x, self.pos_y, self.pos_z]
if self.pos_z < local_best[2]: # This was forgotten
local_best = [self.pos_x, self.pos_y, self.pos_z]
I used OpenGL to draw about 20 circles. Each circle has 2 lines, ~10 segments, and all of them have different colors and lenght. FPS ~=4. How can I do this faster?
I am using Python 3 on Ubuntu
Code:
class ScreenOpenGL(Screen):
def __init__(self,layers,layers_lock):
""" Инициализирует экран и запускает его, потом всю программу """
Screen.__init__(self,"OpenGL",layers,layers_lock)
self.window = 0
self.quad = None
self.keypress = []
print("Fuck")
# self.infoScreen = ScreenCursesInfo()
self.infoScreen = ScreenStandartInfo()
GLUT.glutInit(sys.argv)
GLUT.glutInitDisplayMode(GLUT.GLUT_RGBA | GLUT.GLUT_DOUBLE | GLUT.GLUT_ALPHA | GLUT.GLUT_DEPTH)
GLUT.glutInitWindowSize(640, 480)
GLUT.glutInitWindowPosition(400, 400)
self.window = GLUT.glutCreateWindow(b"Project Evoluo alpha")
GLUT.glutDisplayFunc(self._loop) # Функция, отвечающая за рисование
GLUT.glutIdleFunc(self._loop) # При простое перерисовывать
GLUT.glutReshapeFunc(self._resize) # изменяет размеры окна
GLUT.glutKeyboardFunc(self._keyPressed) # Обрабатывает нажатия
self._initGL(640, 480)
field_params(640, 480)
print("Fuck")
def run(self):
# для threading
GLUT.glutMainLoop()
def _initGL(self,Width,Height):
GL.glShadeModel(GL.GL_SMOOTH);
GL.glClearColor(0.0, 0.0, 0.0, 0.0) # This Will Clear The Background Color To Black
GL.glClearDepth(1.0) # Enables Clearing Of The Depth Buffer
GL.glDepthFunc(GL.GL_LESS) # The Type Of Depth Test To Do
GL.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST)
GL.glEnable(GL.GL_BLEND); # Enable Blending
GL.glLineWidth(1.);
GL.glDisable(GL.GL_LINE_SMOOTH)
GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
self.width = Width
self.height = Height
self.quad = GLU.gluNewQuadric()
GLU.gluQuadricNormals(self.quad, GLU.GLU_SMOOTH)
GLU.gluQuadricTexture(self.quad, GL.GL_TRUE)
def _resize(self,Width,Height):
if Height == 0:
Height = 1
self.width = Width
self.height = Height
field_params(Width,Height)
GL.glViewport(0, 0, Width, Height) # Reset The Current Viewport And Perspective Transformation
GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
GL.glOrtho(0.0,Width,0.0,Height,-1.0,1.0)
GL.glMatrixMode(GL.GL_MODELVIEW) # Select The Modelview Matrix
GL.glLoadIdentity()
def update(self):
GLUT.glutSwapBuffers()
def clear(self):
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
GL.glLoadIdentity() # Reset The View
def write(self,pos,str):
pass
def __del__(self):
del(self.infoScreen)
GLUT.glutDestroyWindow(self.window)
self._end()
# sys.exit()
def getch(self):
if self.keypress != []:
# print
return self.keypress.pop(-1)[0]
else:
return None
def _keyPressed(self,*args):
if args != None:
self.keypress.append(args)
print(self.keypress)
def _draw_prepare(self):
del(self._layers)
self._layers = []
for layer in layers:
if layer.__class__ == LayerObjects:
self._layers.append([layer.type,copy.deepcopy(layer.get_objs()),copy.copy(layer._attacked)])
def draw_eyes(self,vis,r_max,dphi):
for x in range(0,7):
GLU.gluPartialDisk(self.quad,
1,
vis[x][0] * r_max,
5,
3,
- ((x - 3) * 15 + 7.5 + dphi / pi * 180) + 90,
15)
def draw_sensitivity(self,sens,r_max,dphi):
for x in range(0,5):
GLU.gluPartialDisk(self.quad,
1,
sens[x] * r_max,
5,
3,
- (52.5 + (x+1) * 51 + dphi / pi * 180) + 90,
51)
pass
def draw_obj(self,obj,_id,pos,circle,lines,attacked):
# Кружок
GL.glLoadIdentity()
GL.glTranslatef(pos[0]-1,pos[1]-1,0)
red,green,blue = obj.color # берём цвет
GL.glColor3f(red,green,blue)
GLU.gluDisk(self.quad,*circle)
#Глазки
GL.glColor3f(1-red,1-green,1-blue)
try:
eyes = obj.eyes
except NameError:
pass
else:
self.draw_eyes(obj.eyes.eyes,obj.radius * k_screen,obj.pos[1])
# Прикосновения
GL.glColor3f(1,0,0)
try:
sensitivity = obj.sensitivity
except NameError:
pass
else:
self.draw_sensitivity(obj.sensitivity._sens,obj.radius * k_screen,obj.pos[1])
# Полосочки
GL.glBegin(GL.GL_LINES)
for color,x,y in lines:
GL.glColor3f(*color)
GL.glVertex3f(0,0,0)
GL.glVertex3f(x,y,0)
GL.glEnd()
def draw(self,layer):
global width,height
if layer[0] == "Layer Objects":
attacked = layer[2]
for obj in layer[1]:
#Стрелочки-направления
pos = [int(x) for x in obj.get_pos_screen()]
positions = [pos,]
radius_scr = obj.radius * k_screen
att = Vector(radius_scr * (1 +obj._attack_range*obj._attack),
obj.pos[1],
isPolar = True
)
speed = obj.speed[0] * k_screen * 5
if pos[0] < radius_scr:
positions.append([pos[0] + self.width,pos[1]])
if pos[0] + radius_scr > self.width:
positions.append([pos[0] - self.width,pos[1]])
if pos[1] < radius_scr:
positions.append([pos[0],pos[1] + self.height])
if pos[1] + radius_scr > self.height:
positions.append([pos[0],pos[1] - self.height])
for ps in positions:
self.draw_obj(obj,obj._id, ps , [0,obj.radius*k_screen,20,1], [ [ (1,0,0) , att.x, att.y ], [ (0,0,1) , speed.x, speed.y] ] , attacked)
self.infoScreen.draw()
Function code, that draws:
def _draw_prepare(self):
""" Копирует из глобальной переменной всё, что ей нужно """
self._layers = copy.deepcopy(layers)
def _loop(self):
global tick
if (self.ch == b'q') or (self.ch == b'\xb1') or (self.ch == 27) or (self.ch == 113):
isEnd = True
self.__del__()
del(self)
return 0
elif (self.ch == b's'):
self._is_draw = not self._is_draw
print("changed to %d" %self._is_draw)
else:
if (self.last_tick != tick) and (self._is_draw):
self.layers_lock.acquire(1)
self._draw_prepare()
self.layers_lock.release()
self.last_tick = tick
# рисует сцену
return self._main()
def _main(self):
global tick
self.clear()
if self._is_draw:
for layer in self._layers:
self.draw(layer)
self.update()
self.ch = self.getch()
And on GitHub