I recently started coding in Pygame Zero before starting Pygame. I was making a game and the I need to see if two of the sprites are colliding. How should I approach this?
The two sprites:
[1]: https://i.stack.imgur.com/bRcqC.png
[2]: https://i.stack.imgur.com/FwlES.png
import pgzrun
import rando[enter image description here][1]m
WIDTH=400
HEIGHT=400
score=0
game_over=False
coin=Actor("coin")
fox=Actor("fox")
x=random.randint(0,WIDTH)
y=0
xf=170
fox.pos=(xf,150)
coin.pos=(x, 0 )
def draw():
screen.fill((144,238,144))
fox.draw()
coin.draw()
screen.draw.text("Score: "+str(score),(20,20),fontsize=30)
def relocate():
global x
global y
y+=1
coin.pos=(x, y )
def move():
if keyboard.left :
fox.x-=1
if keyboard.right:
fox.x+=1
def collide():
global score
global x
global y
if fox.rect.center==coin.rect.center:
score+=1
coin.pos=(x, 0 )
def update():
global x
global y
relocate()
if y>WIDTH-10:
x=random.randint(0,WIDTH)
y=0
coin.pos=(x, y )
move()
collide()
pgzrun.go()
To tell if two sprites collide, use the colliderect() method.
Change the line:
if fox.rect.center==coin.rect.center:
to
if fox.colliderect(coin):
Actors have all the same attributes and methods as Rect, including methods like .colliderect() which can be used to test whether two actors have collided. – Pygame Zero Builtins
Related
I am trying to create buttons in tkinter within a for loop. And with each loop pass the i count value out as an argument in the command value. So when the function is called from the command value I can tell which button was pressed and act accordingly.
The problem is, say the length is 3, it will create 3 buttons with titles Game 1 through Game 3 but when any of the buttons are pressed the printed value is always 2, the last iteration. So it appears the buttons are being made as separate entities, but the i value in the command arguments seem to be all the same. Here is the code:
def createGameURLs(self):
self.button = []
for i in range(3):
self.button.append(Button(self, text='Game '+str(i+1),
command=lambda: self.open_this(i)))
self.button[i].grid(column=4, row=i+1, sticky=W)
def open_this(self, myNum):
print(myNum)
Is there a way to get the current i value, each iteration, to stick with that particular button?
This problem can be considered a special case of Creating functions in a loop. There's also What do lambda function closures capture?, for a more technical overview.
See also How to pass arguments to a Button command in Tkinter? for the general problem of passing arguments to Button callbacks.
Change your lambda to lambda i=i: self.open_this(i).
This may look magical, but here's what's happening. When you use that lambda to define your function, the open_this call doesn't get the value of the variable i at the time you define the function. Instead, it makes a closure, which is sort of like a note to itself saying "I should look for what the value of the variable i is at the time that I am called". Of course, the function is called after the loop is over, so at that time i will always be equal to the last value from the loop.
Using the i=i trick causes your function to store the current value of i at the time your lambda is defined, instead of waiting to look up the value of i later.
This is how closures work in python. I ran into this problem myself once.
You could use functools.partial for this.
for i in range(3):
self.button.append(Button(self, text='Game '+str(i+1), command=partial(self.open_this, i)))
Simply attach your buttons scope within a lambda function like this:
btn["command"] = lambda btn=btn: click(btn) where click(btn) is the function that passes in the button itself.
This will create a binding scope from the button to the function itself.
Features:
Customize gridsize
Responsive resizing
Toggle active state
#Python2
#from Tkinter import *
#import Tkinter as tkinter
#Python3
from tkinter import *
import tkinter
root = Tk()
frame=Frame(root)
Grid.rowconfigure(root, 0, weight=1)
Grid.columnconfigure(root, 0, weight=1)
frame.grid(row=0, column=0, sticky=N+S+E+W)
grid=Frame(frame)
grid.grid(sticky=N+S+E+W, column=0, row=7, columnspan=2)
Grid.rowconfigure(frame, 7, weight=1)
Grid.columnconfigure(frame, 0, weight=1)
active="red"
default_color="white"
def main(height=5,width=5):
for x in range(width):
for y in range(height):
btn = tkinter.Button(frame, bg=default_color)
btn.grid(column=x, row=y, sticky=N+S+E+W)
btn["command"] = lambda btn=btn: click(btn)
for x in range(width):
Grid.columnconfigure(frame, x, weight=1)
for y in range(height):
Grid.rowconfigure(frame, y, weight=1)
return frame
def click(button):
if(button["bg"] == active):
button["bg"] = default_color
else:
button["bg"] = active
w= main(10,10)
tkinter.mainloop()
I am following a tutorial for a game of ships, and when creating the Player class in the init function I have a strange problem when wanting to access the functions of the Sprite module: when I write the name of the variable and put the point to access its functions remain in white, instead of being colored yellow indicating that it is a reserved word (I am using visual studio)
(Sorry if I do not express myself correctly I am using google translator.)
so the strange is this:
code screenshot
what is indicated in the red boxes should be in yellow (like what I underlined in yellow), since theoretically it would be accessing the functions of a Sprite object therefore it should be highlighted in yellow ...
the problem is that it appears white, as if it did not recognize the variable as a Sprite object
Here is where i create the image directory.
import pygame, random, os, sys
from os import path
img_dir = path.join(path.dirname(__file__), 'img')
And here is the Meteor class:
class Meteor(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image_orig = random.choice(meteor_images)
self.image_orig.set_colorkey("black")
self.image_orig.set_clip()
self.image = self.image_orig.copy()
self.rect = self.image.get_rect()
self.radius = int(self.rect.width*0.85/2) # *0.85 <- se leeria como (el 85% del width) / 2
pygame.draw.circle(self.image, "red", self.rect.center, self.radius)
self.rect.x = random.randrange(0, width)
self.rect.bottom = random.randrange(-100, -50)
self.speedx = random.randrange(-4, 4)
self.speedy = random.randrange(2, 8)
self.rot = 0
self.rot_speed = random.randrange(-8, 8)
self.last_update = pygame.time.get_ticks()
and then here is where create the meteors list:
meteor_images = []
meteor_list = ['meteorBrown_big1.png',
'meteorBrown_big2.png',
'meteorBrown_big3.png',
'meteorBrown_big4.png']
for img in meteor_list:
meteor_images.append(pygame.image.load(path.join(img_dir, img)).convert())
I am not very expert on the subject, what could be the problem??
I am not trying to make a game, just a drawing. However I am not sure how to proceed.
I'm using this article: https://lti.flvsgl.com/flvs-cat-content/jviqsic79osifb0qmtbb1dhea2/flvs-cat-session/educator_foundofprog_v18_gs/global/interactives/python_idle/python_idle.htm
My code so far is:
# Writing Functions
import turtle
def main():
jim = turtle.turtle()
jim.speed(10)
#draw a stickman
# move to position
jim.setpos(0, -20)
jim.left(90)
# draw body
jim.color("black")
jim.forward(60)
# draw head
jim.color("black")
jim.forward(90)
jim.circle(45)
# move to position
jim.penup()
jim.setpos(20, -20) #Sets the position of the turtle
jim.left(90)
jim.pendown()
main()
but I don't know how to make it work.
Here you go:
import turtle
def main():
jim = turtle.Turtle() #Remember the capital T
jim.speed(0) #A speed of 0 makes him go as fast as possible
arm_length = 100 #Change these if you want
leg_length = 120
def reset(): #reset sends him back to the center
jim.pu() #pu is short for penup. Either work, you can use them interchangeably
jim.setpos(0,0)
jim.pd() #pd is short for pendown
#draw a stickman
reset()
#head
jim.seth(90) #seth is short for set_heading, and it changes the direction jim is facing.
jim.fd(30)
jim.rt(90)
jim.circle(50)
reset()
#arm 1
jim.seth(160)
jim.fd(arm_length/2)
jim.rt(20)
jim.fd(arm_length/2)
reset()
#arm 2
jim.seth(20)
jim.fd(arm_length/2)
jim.lt(20)
jim.fd(arm_length/2)
reset()
#leg 1
jim.seth(270)
jim.fd(50)
jim.seth(230)
jim.fd(leg_length/2)
jim.lt(40)
jim.fd(leg_length/2)
reset()
#leg 2
jim.seth(270)
jim.fd(50)
jim.seth(310)
jim.fd(leg_length/2)
jim.rt(40)
jim.fd(leg_length/2)
main()
I have two groups of codes and the first part is a turtle graphics window and second part is a Tkinter window. How should I those two parts together to one window?
My first part of the code
from turtle import *
def move(thing, distance):
thing.circle(250, distance)
def main():
rocket = Turtle()
ISS = Turtle()
bgpic('space.gif')
register_shape("ISSicon.gif")
ISS.shape("ISSicon.gif")
rocket.speed(10)
ISS.speed(10)
counter = 1
title("ISS")
screensize(750, 750)
ISS.hideturtle()
rocket.hideturtle()
ISS.penup()
ISS.left(90)
ISS.fd(250)
ISS.left(90)
ISS.showturtle()
ISS.pendown()
rocket.penup()
rocket.fd(250)
rocket.left(90)
rocket.showturtle()
rocket.pendown()
rocket.fillcolor("white")
while counter == 1:
move(ISS, 3)
move(rocket, 4)
main()
Second part
from Tkinter import *
control=Tk()
control.title("Control")
control.geometry("200x550+100+50")
cline0=Label(text="").pack()
cline1=Label(text="Speed (km/s)").pack()
control.mainloop()
Thanks a lot ;)
Uhm, I'm not sure if mixing them is a good idea. This turtle module frequently uses the update command from Tcl, and this will very likely cause problems when more involved code is added in the mix (it is nice that apparently turtle can live with it). Anyway, one way to mix both is by using RawTurtle in place of Turtle, so you can pass your own Canvas which turtle will adjust for its needs.
Here is an example (I also replaced the infinite loop by an infinite re-schedule, basically):
import Tkinter
import turtle
def run_turtles(*args):
for t, d in args:
t.circle(250, d)
root.after_idle(run_turtles, *args)
root = Tkinter.Tk()
root.withdraw()
frame = Tkinter.Frame(bg='black')
Tkinter.Label(frame, text=u'Hello', bg='grey', fg='white').pack(fill='x')
canvas = Tkinter.Canvas(frame, width=750, height=750)
canvas.pack()
frame.pack(fill='both', expand=True)
turtle1 = turtle.RawTurtle(canvas)
turtle2 = turtle.RawTurtle(canvas)
turtle1.ht(); turtle1.pu()
turtle1.left(90); turtle1.fd(250); turtle1.lt(90)
turtle1.st(); turtle1.pd()
turtle2.ht(); turtle2.pu()
turtle2.fd(250); turtle2.lt(90)
turtle2.st(); turtle2.pd()
root.deiconify()
run_turtles((turtle1, 3), (turtle2, 4))
root.mainloop()
I'll try to be as clear as possible, though this is all a bit muddled in my head.
I have a PyQt application that has been working for about a year now. After updating to PyQt 4.5.1 (from 4.3.3) none of my icons appear in the QTableView anymore (this update was concurrent with an update to python 2.6.5 from 2.5.1). Reverting to the older python and PyQt, everything works as expected.
The breakdown is this:
I am using the model-view methodology. My model, when requested via a Qt.DecorationRole in the data() method, will return a custom object (ColorSwatch) that is a subclass of the QIcon class. This has always worked (with the caveat that I, for reasons I don't understand, have to recast it as a QVariant first). After updating to PyQt 4.5.1 it appears to run correctly (i.e. I am not getting any errors), but the icon does not draw (though the space where it would be drawn is "reserved" i.e. the text has been shifted to the right to make way for this invisible icon).
Here are some things that I have tried:
I have verified that the ColorSwatch class does still function. This same class is used to draw icons into a contextual menu - and they appear correctly.
I have verified that the data() method is actually getting called and is returning this ColorSwatch object (recast into a QVariant <- though I have tested without this recasting as well).
Pouring snake blood onto my keyboard and lighting it afire.
Nothing so far has given me any clue as to what I should do. Any hints would be greatly appreciated. Thanks.
Here is some of the (potentially) relevant code (note that paramObj.get_icon() returns a ColorSwatch object):
#---------------------------------------------------------------------------
def data(self, index, role=QtCore.Qt.DisplayRole):
"""
Returns the text or formatting for a particular cell, depending on the
role supplied.
"""
blah
blah
blah
elif role == QtCore.Qt.DecorationRole:
if platform.system()=='Darwin':
return QtGui.QIcon(paramObj.get_icon())
else:
return QtCore.QVariant(paramObj.get_icon())
and
import os
import tempfile
import sys
import colorsys
import copy
import fnmatch
import time
from PyQt4 import QtGui
from PyQt4 import QtCore
################################################################################
class ColorSwatch(QtGui.QIcon):
"""
A subclass of QIcon, this class draws a colored paint chip with a border
The color and size are determined at construction time, and cannot
be changed later.
"""
#---------------------------------------------------------------------------
def __init__(self, r=1, g=1, b=1, br = 0, bg = 0, bb = 0, w=20, h=20):
"""
Constructor for the ColorSwatch class. Takes the passed arguments and
creates a square icon filled with the given color and with a border
color determined by br, bg, bb. All colors should be in floating point
format.
"""
QtGui.QIcon.__init__(self)
#normalize the color
r8, g8, b8 = self.normalize_color((r, g, b))
#convert the r, g, b values to 8 bit colors
r8, g8, b8 = self.fp_to_8b_color((r8, g8, b8))
#Create the pixmap and painter objects
paintChip = QtGui.QPixmap(w, h)
painter = QtGui.QPainter()
painter.begin(paintChip)
#fill the swatch
baseColor = QtGui.QColor(r8, g8, b8)
painter.fillRect(0, 0, w, h, baseColor)
#if any of the values were super brights (>1), draw a smaller, white
#box inset to make sure the user knows
if r > 1 or g > 1 or b > 1:
painter.fillRect(5, 5, w-10, h-10, QtGui.QColor(255, 255, 255))
#if all values are 0, put a faint x through the icon
# # # brush = QtGui.QBrush()
# # # brush.setColor(QtGui.QColor(30, 30, 30))
painter.setPen(QtGui.QColor(200, 200, 200))
if r ==0 and g == 0 and b == 0:
painter.drawLine(0, 0, w, h)
painter.drawLine(w-1, 0, -1, h)
# # #
# # # #normalize the color
# # # r8, g8, b8 = self.normalize_color((r8, g8, b8))
#now draw the border(s)
#convert the r, g, b values to 8 bit colors
r8, g8, b8 = self.fp_to_8b_color((br, bg, bb))
#draw the border
painter.setPen(QtGui.QColor(r8, g8, b8))
painter.drawRect(0,0,w-1,h-1)
#if any of the values were super brights (>1), draw a border around the
#inset box as well.
if r > 1 or g > 1 or b > 1:
painter.drawRect(5,5,w-11,h-11)
#done drawing
painter.end()
#add it (both to the normal and the selected modes)
self.addPixmap(paintChip, QtGui.QIcon.Normal)
self.addPixmap(paintChip, QtGui.QIcon.Selected)
#---------------------------------------------------------------------------
def fp_to_8b_color(self, color):
"""
Convert a floating point color value (passed in the form of a three
element tuple) to a regular 8-bit 0-255 value. Returns a 3 item tuple.
"""
r = max(min(int(color[0]*255),255),0)
g = max(min(int(color[1]*255),255),0)
b = max(min(int(color[2]*255),255),0)
return (r,g,b)
#---------------------------------------------------------------------------
def normalize_color(self, color):
"""
"normalizes" a color value so that if there are any super-whites, it
balances all the other floating point values so that we end up with a
"real" color. Negative values will result in undefined behavior.
Mainly used to make the color chip "look right" when using super whites.
"""
maxValue = max(color)
if maxValue > 1:
return (color[0]/maxValue, color[1]/maxValue, color[2]/maxValue)
else:
return color
Ivo answered my question above.
the actual code that works is:
#---------------------------------------------------------------------------
def data(self, index, role=QtCore.Qt.DisplayRole):
"""
Returns the text or formatting for a particular cell, depending on the
role supplied.
"""
blah
blah
blah
elif role == QtCore.Qt.DecorationRole:
if platform.system()=='Darwin':
return QtGui.QIcon(paramObj.get_icon())
else:
return QtCore.QVariant(QtGui.QIcon(paramObj.get_icon()))
#Note that it is first cast as a QIcon before
#being cast as a QVariant.
Thanks again Ivo.