Function doesn't work
I tried to make a game, and at the some point all start going wrong.(my english isn't best, i know, sorry)
I use library pygame for my project. I made a function which detect the contact of objects, but when i start the game function doesn't work. I tried to start it without function and then all start working. I'm wondering why the function doesn't work. I hope that you can tell me something about it.
In the file sets i wrote some variables like speed.
from sets import *
import pygame as pg
import time
pg.init()
sc = pg.display.set_mode((1280,720))
test = pg.Surface((100,100))
test.fill((122,122,122))
block = pg.Surface((50,50))
block.fill((0,0,0))
def colis(x,y,player_width,player_height,width,height,xx,yy):
if x + player_width > xx:
if x < xx + width - 20:
if y + player_height > yy + 10:
if y < yy + height - 10:
x = xx - player_width
if x < xx + width:
if x > xx:
if y + player_height > yy + 10:
if y < yy + height - 10:
x = xx + width
if y < yy + height:
if y > yy + 20:
if x + player_width > xx:
if x < xx + width:
y = yy + height
if y + player_height > yy:
if y < yy + height - 20:
if x + player_width > xx:
if x < xx + width:
y = yy - player_height
while True:
clock.tick(60)
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
pg.QUIT
elif event.type == pg.KEYDOWN:
if event.key == pg.K_w:
w = 1
if event.key == pg.K_a:
a = 1
if event.key == pg.K_s:
s = 1
if event.key == pg.K_d:
d = 1
if w > 0:
w += speed
if w > 10:
w = 0
if a > 0:
a += speed
if a > 10:
a = 0
if s > 0:
s += speed
if s > 10:
s = 0
if d > 0:
d += speed
if d > 10:
d = 0
x += d - a
y += s - w
colis(x,y,50,50,100,100,200,200)
pg.display.update()
sc.fill((255,255,255))
sc.blit(block,(x,y))
sc.blit(test,(xx,yy))
Your function colis doesn't do anything. There is no return value. All it does is change the values of a few local variables, variables which go out of scope when the function finishes. Thus the function call colis(x,y,50,50,100,100,200,200) has no effect. The values of x and y are not changed by the function call.
Instead, return x and y from the function:
def colis(x,y,player_width,player_height,width,height,xx,yy):
if x + player_width > xx:
if x < xx + width - 20:
if y + player_height > yy + 10:
if y < yy + height - 10:
x = xx - player_width
if x < xx + width:
if x > xx:
if y + player_height > yy + 10:
if y < yy + height - 10:
x = xx + width
if y < yy + height:
if y > yy + 20:
if x + player_width > xx:
if x < xx + width:
y = yy + height
if y + player_height > yy:
if y < yy + height - 20:
if x + player_width > xx:
if x < xx + width:
y = yy - player_height
return x,y
(I eliminated most of the blank lines since all those blank lines makes it harder to read).
After that change, replace colis(x,y,50,50,100,100,200,200) by
x,y = colis(x,y,50,50,100,100,200,200)
Disclaimer: I don't have pygame installed so am unable to see if there are any other problems with your code, but making the above changes will at least give you code which makes more sense.
Related
This is a physics simulation constraining balls in a circular area.
I made the original code in Scratch and converted it to Python in Pygame.
When I run the simulation, all the balls were shaking, compared to the original code.
I constrained the velocity to be maximum 20, but it didn't help.
I created substeps for each frame, but that wasn't helping either.
import pygame
import math
import random
screen = pygame.display.set_mode((16*120,9*120))
pygame.display.set_caption('')
clock = pygame.time.Clock()
mx = 16*60
my = 9*60
global x
global y
x = []
y = []
xv = []
yv = []
prevx = []
prevy = []
for i in range(20):
x.append(random.randint(-200,200))
y.append(random.randint(-200,200))
xv.append(0)
yv.append(0)
prevx.append(0)
prevy.append(0)
r = 25
size = 300
sub = 20
maxvel = 20
global dist
global dx
global dy
global d
#points at something
def pointat(px,py):
global d
dx = px-x[i]
dy = py-y[i]
if dy == 0:
if dx < 0:
d = -90
else:
d = 90
else:
if dy < 0:
d = 180+math.atan(dx/dy)
else:
d = math.atan(dx/dy)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.fill((10,10,10))
pygame.draw.circle(screen,(100,100,100),(mx,my),size)
for i in range(len(x)):
pygame.draw.circle(screen,(255,255,255),(mx+x[i],my+y[i]*-1),r)
for i in range(len(x)):
prevx[i] = x[i]
prevy[i] = y[i]
for j in range(sub):
x[i] += xv[i]/sub
y[i] += yv[i]/sub
y[i] -= 1/sub
a = 0
for k in range(len(x)-1):
if a == i:
a += 1
dist = math.sqrt(((x[i]-x[a])*(x[i]-x[a]))+((y[i]-y[a])*(y[i]-y[a])))
if dist < r*2:
pointat(x[a],y[a])
x[i] += (math.sin(d)*(dist-(r*2)))
y[i] += (math.cos(d)*(dist-(r*2)))
x[a] -= (math.sin(d)*(dist-(r*2)))
y[a] -= (math.cos(d)*(dist-(r*2)))
dist = math.sqrt((x[i]*x[i])+(y[i]*y[i]))
if dist > size-r:
pointat(0,0)
x[i] += (math.sin(d)*(dist-(size-r)))
y[i] += (math.cos(d)*(dist-(size-r)))
a += 1
xv[i] = x[i]-prevx[i]
yv[i] = y[i]-prevy[i]
if xv[i] > maxvel:
xv[i] = maxvel
if xv[i] < -maxvel:
xv[i] = -maxvel
if yv[i] > maxvel:
yv[i] = maxvel
if yv[i] < -maxvel:
yv[i] = -maxvel
pygame.display.update()
clock.tick(60)
The angle of the trigonometric functions in the math module is measured in Radian, but not in Degrees. d should not be a global variable, you can just return the angle from pointat:
def pointat(px,py):
dx = px-x[i]
dy = py-y[i]
if dy == 0:
if dx < 0:
d = -math.pi/2
else:
d = math.pi/2
else:
if dy < 0:
d = math.pi+math.atan(dx/dy)
else:
d = math.atan(dx/dy)
return d
while True:
# [...]
for i in range(len(x)):
# [...]
for j in range(sub):
# [...]
for k in range(len(x)-1):
if a == i:
a += 1
dist = math.sqrt(((x[i]-x[a])*(x[i]-x[a]))+((y[i]-y[a])*(y[i]-y[a])))
if dist < r*2:
d = pointat(x[a],y[a])
x[i] += (math.sin(d)*(dist-(r*2)))
y[i] += (math.cos(d)*(dist-(r*2)))
x[a] -= (math.sin(d)*(dist-(r*2)))
y[a] -= (math.cos(d)*(dist-(r*2)))
dist = math.sqrt((x[i]*x[i])+(y[i]*y[i]))
if dist > size-r:
d = pointat(0,0)
x[i] += (math.sin(d)*(dist-(size-r)))
y[i] += (math.cos(d)*(dist-(size-r)))
a += 1
Overall, the code in the loops can be simplified a lot. I suggest to refactor your code as follows:
while True:
# [...]
for i in range(len(x)):
prevx[i] = x[i]
prevy[i] = y[i]
for j in range(sub):
x[i] += xv[i]/sub
y[i] += yv[i]/sub
y[i] -= 1/sub
for a in range(len(x)):
if a == i:
continue
dx = x[i]-x[a]
dy = y[i]-y[a]
dist = math.sqrt(dx*dx + dy*dy)
if dist < r*2 and dist != 0:
x[i] -= dx/dist * (dist-r*2)
y[i] -= dy/dist * (dist-r*2)
x[a] += dx/dist * (dist-r*2)
y[a] += dy/dist * (dist-r*2)
dist = math.sqrt(x[i]*x[i] + y[i]*y[i])
if dist > size-r:
x[i] -= x[i]/dist * (dist-(size-r))
y[i] -= y[i]/dist * (dist-(size-r))
xv[i] = max(-maxvel, min(maxvel, x[i]-prevx[i]))
yv[i] = max(-maxvel, min(maxvel, y[i]-prevy[i]))
I have been messing around with pygame lately and I have encountered a problem. I'm coding a platformer and I have given the map creation a class. On the map module, I have a function that creates chunks based on the movement -specifically the "scroll" of the camera. My problem is that my game map is divided on a grid of 16x16 tiles and my platform tiles are 48x16 pixels which may be 3 tiles on my grid. I don't really know how to make my code understand it is 3 tiles so I can randomly generate platforms as the player goes up. Let me know if you know how to implement it.
import pygame, sys, random
from pygame.locals import *
class Map:
def __init__(self):
self.path_img = pygame.image.load("assets/imgs/path.png").convert()
self.walls_img = pygame.image.load("assets/imgs/walls.png").convert()
self.mossy_wall_img = pygame.image.load("assets/imgs/mossy_wall.png").convert()
self.game_map = {}
self.TILE_SIZE = self.walls_img.get_width()
self.CHUNK_SIZE = 8
self.tile_index = {1:self.path_img,
2:self.walls_img,
3:self.mossy_wall_img}
self.platforms = []
def draw_map(self, screen, scroll):
self.tile_rects = []
for y in range(3):
for x in range(4):
self.target_x = x - 1 + int(round(scroll[0]/(self.CHUNK_SIZE*16)))
self.target_y = y - 1 + int(round(scroll[1]/(self.CHUNK_SIZE*16)))
self.target_chunk = str(self.target_x) + ';' + str(self.target_y)
if self.target_chunk not in self.game_map:
self.game_map[self.target_chunk] = self.generate_chunk(self.target_x,self.target_y)
for tile in self.game_map[self.target_chunk]:
screen.blit(self.tile_index[tile[1]],(tile[0][0]*16-scroll[0],tile[0][1]*16-scroll[1]))
if tile[1] in [1,2,3,4]:
self.tile_rects.append(pygame.Rect(tile[0][0]*16,tile[0][1]*16,16,16))
def generate_chunk(self,x,y):
self.chunk_data = []
platform = False
for y_pos in range(self.CHUNK_SIZE):
for x_pos in range(self.CHUNK_SIZE):
self.target_x = x * self.CHUNK_SIZE + x_pos
self.target_y = y * self.CHUNK_SIZE + y_pos
tile_type = 0
if self.target_x > 30:
if random.randint(1,5) == 1:
tile_type = 3
else:
tile_type = 2
if self.target_x < 0:
if random.randint(1,5) == 1:
tile_type = 3
else:
tile_type = 2
if self.target_y > 10:
if random.randint(1,5) == 1:
tile_type = 3
else:
tile_type = 2
if self.target_y == 10:
if self.target_x > 30 or self.target_x < 0:
if random.randint(1,5) == 1:
tile_type = 3
else:
tile_type = 2
else:
tile_type = 1
if self.target_y < 10 and self.target_x < 30 and self.target_x > 0:
if random.randint(1,100) == 1:
platform = True
if tile_type != 0:
self.chunk_data.append([[self.target_x, self.target_y],tile_type])
if platform:
self.chunk_data.append([[self.target_x, self.target_y],1])
self.chunk_data.append([[self.target_x + 1, self.target_y],1])
self.chunk_data.append([[self.target_x + 2, self.target_y],1])
return self.chunk_data
Would have to see one generated to get a better idea. Something like this might do, but then I'm guessing you'd want your CHUNK_SIZE to be evenly divisible by 3, so self.CHUNK_SIZE = 9 instead?
for y_pos in range( self.CHUNK_SIZE ):
for x_pos in range( self.CHUNK_SIZE /3 ):
...
self.target_x = x *self.CHUNK_SIZE +x_pos *3
...
if tile_type != 0:
self.chunk_data.append([ [ self.target_x, self.target_y ], tile_type ])
self.chunk_data.append([ [ self.target_x +1, self.target_y ], tile_type +1 ])
self.chunk_data.append([ [ self.target_x +2, self.target_y ], tile_type +2 ])
I am having a difficulty in implementing drawing a tan function in python since it doesn't look smooth, and when having reached 90/180, it doesn't look nice, so im looking for some improvements on this part.
def tan_wave():
pyautogui.click()
theta = 0
step = 10
length = 10
curr_x, curr_y = pyautogui.position()
prev = (curr_x, curr_y)
decrease_flag = False
while theta <= 180:
if (theta % 90) == 0:
theta -= 0.99999
decrease_flag = True
x = curr_x + theta
y = curr_y - math.tan(math.radians(theta))*length
print(x, y, theta)
pyautogui.click(*prev)
pyautogui.dragTo(x, y)
pyautogui.click(x, y)
prev = (x, y)
if decrease_flag:
theta += 0.99999
decrease_flag = False
theta += step
print('Done')
tan_wave()
I want to check if the mouse clicked on a line on Tkinter canvas or not, if on a line then which line.
I had made this to detect mouse clicks.
class Link:
def __init__(self,Node1,Node2,canvas,width=5):
if self not in canvas.LinkList:
self.start_coor = Node1.Centre
self.final_coor = Node2.Centre
self.Canvas = canvas
self.Width = width
self.Shape = canvas.create_line(self.start_coor,self.final_coor,width=width)
Node1.connected(Node2)
self.Canvas.LinkList.append(self)
self.Nodes = [Node1,Node2]
self.Clicked = False
dy = self.final_coor[1] - self.start_coor[1]
dx = self.final_coor[0] - self.start_coor[0]
self.m = dy/dx
self.c = self.start_coor[1] - self.m*self.start_coor[0]
def onLineCheck(self,x,y,field=False):
#y = mx + c
#y - mx - c = 0
if not field:
field = self.Width
if (x < self.start_coor[0] and x < self.final_coor[1]) or (x > self.start_coor[0] and x > self.final_coor[1]) or (y < self.start_coor[1] and y < self.final_coor[1]) or (y > self.start_coor[1] and y > self.final_coor[1]):
return False
temp = y - (self.m*x) - self.c
if abs(temp) <= field:
return True
return False
class InputCanvas(Canvas):
def __init__(self,master=None, **kw):
super().__init__(master,**kw)
self.NodeList = []
self.LinkList = []
self.Mode = "Nodes"
def anyLinkClicked(self,e):
x,y = getMousePosition(e)
for l in self.LinkList:
if l.onLineCheck(x,y):
return l
return False
Every time when a link is created, it will automatically append itself to the canvas.LinkList. I am sure this part of the code is working properly.
So far the program works well with 1 line on Canvas(even if I remove it and draw a new one it is still working) but cannot handle more than 1 line, it can only respond to the first line created. Even if I remove the first line, the second created line won't work.
I've tried printing out the result of each onLineCheck(), it seems like the loop is looping properly through each line but it is not catching mouse clicks.
Any idea to help?
The issue is on the following line:
if (x < self.start_coor[0] and x < self.final_coor[1]) or (x > self.start_coor[0] and x > self.final_coor[1]) or (y < self.start_coor[1] and y < self.final_coor[1]) or (y > self.start_coor[1] and y > self.final_coor[1]):
return False
x < self.final_coor[1] should be x < self.final_coor[0]
x > self.final_coor[1] should be x > self.final_coor[0]
Also you should also cater vertical line, i.e. dx is zero as your code will raise ZeroDivisionError: division by zero.
You can use Canvas.find_overlapping() function to find which Link is clicked:
def anyLinkClicked(self, e):
x, y = getMousePosition(e)
found = self.find_overlapping(x, y, x, y)
if found:
for l in self.LinkList:
if found[0] == l.Shape:
return l
return False
Below code is taking excessively long time when executed for larger inputs such as x = 23!!!! and y = 5!!!!!. The output of the code should be comparison between x and y. small example regarding the inputs is, if input is 3!!, this means (3!)!) = 6! = 720.
def large()
t = int(input())
i = 0
fact_str = ""
fact_stry = ""
res, resy = 1, 1
counter = 0
countery = 0
while(i < t):
x = input()
y = input()
for char in x:
if char == '!' and counter == 0:
fact_str = int(fact_str)
for num in range(fact_str, 0, -1):
res = res * num
counter = counter + 1
elif counter > 0:
for num in range(res-1, 0, -1):
res = res * num
else:
fact_str = str(fact_str)
fact_str = fact_str + char
for chary in y:
if chary == '!' and countery == 0:
fact_stry = int(fact_stry)
for numy in range(fact_stry, 0, -1):
resy = resy * numy
countery = countery + 1
elif countery > 0:
for num in range(resy-1, 0, -1):
resy = resy * numy
else:
print("at esle", resy)
fact_stry = str(fact_stry)
fact_stry = fact_stry + chary
if len(str(x)) == len(str(fact_str)):
fact_str = int(fact_str)
x = fact_str
else:
x = res
if len(str(y)) == len(str(fact_stry)):
fact_stry = int(fact_stry)
y = fact_stry
else:
y = res
x = int(x)
y = int(y)
if x == y:
print("x=y")
elif x > y:
print("x>y")
else:
print("x<y")
i = i + 1
large()
can this code be optimized so that it can execute faster if inputs are large values ? Or python is limited to smaller inputs ?