I have the following code:
drawing = False # true if mouse is pressed
mode = True # if True, draw rectangle. Press 'm' to toggle to curve
ix,iy = -1,-1
# mouse callback function
def draw_circle(event,x,y,flags,param):
global ix,iy,drawing,mode
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
else:
cv2.circle(img,(x,y),20,(0,0,255),-1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
if mode == True:
cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)
else:
cv2.circle(img,(x,y),20,(0,0,255),-1)
I don't understand the use of xi and yi on the rectangle. There is a line which stated that xi,yi = x,y. Would it be the same? How would it draw rectangle? From what I understand, to draw a rectangle, there should be two sets of coordinates. I can't see which part in the line that shows that ix,iy will be different with x and y value.
Can anyone explain?
Its pretty straightforward here is what happens in steps:
the user clicks down - current mouse position x,y is stored as ix,iy and drawing is set to true
the user moves the mouse - if drawing is true and mode is true draws a rectangle using the saved ix,iy and the new current x,y (note that ix,iy does NOT equal x,y anymore since its only saved when the mouse button down triggers)
the user releases the mouse - drawing is set to false so the mouse can be moved without drawing anything and any current images are saved
Related
Using the graphics.py library, Write a program to draw 3 rectangles on the screen. If the user clicks the left mouse button inside one of the rectangles change its color. Feel free to use whatever colors you like. If the user clicks inside the graphics window, but outside one of the three rectangles, close the window and exit the program.
When you click on a rectangle it changes colors then you should be able to click on the next and change its color and so on until you click outside. But as soon as I click the first rectangle and it changes colors it ends the program with object already drawn error.
Result: if self.canvas and not self.canvas.isClosed(): raise GraphicsError(OBJ_ALREADY_DRAWN)
Here is the code:
win3 = graphics.GraphWin("",500,500)
rect1 = graphics.Rectangle(graphics.Point(150,100),graphics.Point(350,200))
rect2 = graphics.Rectangle(graphics.Point(150,220),graphics.Point(350,320))
rect3 = graphics.Rectangle(graphics.Point(150,340),graphics.Point(350,440))
rect1.draw(win3)
rect2.draw(win3)
rect3.draw(win3)
def inside(point, rectangle): # checks if the click is inside of the rectangle
ll = rectangle.getP1() # lower left corner of the rectangle
ur = rectangle.getP2() # upper right corner of the rectangle
return ll.getX() < point.getX() < ur.getX() and ll.getY() < point.getY() < ur.getY()
outside = False
while outside == False:
click = win3.getMouse()
if inside(click,rect1):
rect1.setFill("Red")
rect1.draw(win3)
elif inside(click,rect2):
rect2.setFill("Green")
rect2.draw(win3)
elif inside(click,rect3):
rect3.setFill("Blue")
rect3.draw(win3)
else:
win3.close()
outside = True
I am trying to create an inventory system in Python using the module pygame. The inventory system is similar to Minecraft. It is a slot-based inventory system, meaning that each item is attached to a slot, and can be moved around the inventory.
This is the code:
#Module that allows me to create a screen and add images to the screen
import pygame
pygame.init()
win = pygame.display.set_mode((800,600))
#Variable that will keep track of the index of what slot the player is
#selecting
selectedSlot = None
#Function that checks whether there is collision or not
def collision(x,y,x2,y2,w):
if x + w > x2 > x and y+w > y2 > y:
return True
else:
return False
#Slot Class
class slotClass:
def __init__(self,x,y):
self.x = x
self.y = y
def draw(self,win):
#Draws the slots using the x and y values
pygame.draw.rect(win,(255,0,0),(self.x,self.y,50,50))
#Uses a function to test for collision with the mouse's x and y values
if collision(self.x,self.y,mx,my,66):
global selectedSlot
pygame.draw.rect(win,(128,0,0),(self.x,self.y,50,50))
#This will set an integer value to a varaible, dependent on what the index of the element the player selecting is
selectedSlot = slotArray.index(self)
#Problem with code:
#When the following 2 lines are uncommmented, the variable selectedSlot is set to "None", regardless of whether there is collision or not
#else:
#selectedSlot = None
#Slot array
slotArray = []
#Slot information
slotCount = 9
#Populates the slotArray with the desired slotCount
while len(slotArray) != slotCount:
slotArray.append(slotClass(100+len(slotArray)*70,50))
#main loop
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
print(selectedSlot)
#Mouse x and y value to set to the vars mx and my
mx,my = pygame.mouse.get_pos()
win.fill((0,0,0))
#For every element in the slotArray, the function draw is called from the slotClass
for i in slotArray:
i.draw(win)
pygame.display.update()
pygame.quit()
How it works is I have a class, which will hold the information for each slot. Such as the x value, y value and what item is in every slot.
Then I have an array, which will contain every slot instance. I also defined how many slots I want entirely.
To populate this array with the slots, I first started by constantly appending to this array of slots until it equals the desired amount of slots in each row. I multiply 55 by the number of elements in the array to spread apart the slots.
The problem I am having comes when trying to create the ability for the player to mouse over/select each slot. What I want is for the player to simply be able to hover over a slot, that slot will turn a different colour, and then the player can select an item out of said slot.
I created a collision function for that and I'm calling that function within the draw function inside the slotClass. I also have a variable called slotSelected, which keeps track of the index of the slot that the player is mousing over with/hovering over.
The problem I am experiencing is, that whenever the player hovers over a slot and then stops hovering over any slots, the slot index that I am setting still remains to be the index of the slot the player was just on. When I add an else statement to check if there is no collision with a slot, and set the var slotSelected to something like None for example (to show that the player isn't colliding with any slot) the var slotSelected is constantly set to None, regardless of whether there is collision or not. I have a print statement that prints the value of slotSelected. You'll notice that it prints the index of the slot the player is colliding with. However, when you uncomment the else statement I have contained in the slotClass, the var slotSelected will always be set to None.
Any suggestions on how to fix this?
Perhaps you could try testing for another collision with the background as well. I'm not an expert at pygame, but this is the pseudo-code I would use:
if collision("with game window"): # If mouse is within your game screen
global selectedSlot
if collision(self.x, self.y, mx, my, 66): # mouse is on screen AND on a box
selectedSlot = slotArray.index(self)
else: # mouse on screen, but not on box -> return None
selectedSlot = None
So that you can assign None when the mouse is in your game window but not on an item slot.
EDIT
I figured out why it is responding as such. You have the lines:
for i in slotArray:
i.draw(win)
Which will go to slot 0, see it is selected -> set selectedSlot = 0, then go to slot 1, see it is unselected -> set selectedSlot = None OVERWRITING the value you had previously set. You will need to break your loop if selectedSlot is not None!! Here is code to solve that:
#Module that allows me to create a screen and add images to the screen
import pygame
pygame.init()
win = pygame.display.set_mode((800,600))
#Variable that will keep track of the index of what slot the player is
#selecting
selectedSlot = None
#Function that checks whether there is collision or not
def collision(x,y,x2,y2,w):
if x + w > x2 > x and y+w > y2 > y:
return True
else:
return False
#Slot Class
class slotClass:
def __init__(self,x,y):
self.x = x
self.y = y
def draw(self, win):
#Draws the slots using the x and y values
pygame.draw.rect(win, (255, 0, 0), (self.x, self.y, 50, 50))
#Uses a function to test for collision with the mouse's x and y values
if collision(self.x, self.y, mx, my, 66):
global selectedSlot
pygame.draw.rect(win, (128, 0, 0), (self.x, self.y, 50, 50))
#This will set an integer value to a varaible, dependent on what the index of the element the player selecting is
selectedSlot = slotArray.index(self)
#Problem with code:
#When the following 2 lines are uncommmented, the variable selectedSlot is set to "None", regardless of whether there is collision or not
else:
selectedSlot = None
#Slot array
slotArray = []
#Slot information
slotCount = 9
#Populates the slotArray with the desired slotCount
while len(slotArray) != slotCount:
slotArray.append(slotClass(100+len(slotArray)*70,50))
#main loop
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#Mouse x and y value to set to the vars mx and my
mx,my = pygame.mouse.get_pos()
win.fill((0,0,0))
#For every element in the slotArray, the function draw is called from the slotClass
selectedSlot = None
for i in slotArray:
i.draw(win)
if selectedSlot is not None:
break
print(selectedSlot)
pygame.display.update()
pygame.quit()
The problem is you've combined drawing the items and selecting them into one function (very bad). So now when the loop is broken the rest of the boxes are not drawn!!
I will show my code below. I think when I def moveDot, something wrong I can feel it. However, I just code as my instructor's presentation. She's code can work and mine cannot. I don't know the reason. I think the order of moveDot's variances may have some problems. Is that right? I will appreciate anyone who can help me! Thanks a lot!
# Poke The Dots
# There are two dots that are moving on a 500 by 400 window
# There is a score board that displays the time in seconds
# since the game started
# If the player clicks inside the window, the dots disappear
# and reappear at some random location
# If the dots collide, the dots stop moving, the score stops
# changing and Game Over is displayed.
# Version 1
import pygame, sys, time
from pygame.locals import *
# User-defined classes
# User-defined functions
def main():
# Initialize pygame
pygame.init()
# Set window size and title, and frame delay
surfaceSize = (500, 400) # window size
windowTitle = 'Poke The Dots' #window title
frameDelay = 0.02 # smaller is faster game
# Create the window
surface = pygame.display.set_mode(surfaceSize, 0, 0)
pygame.display.set_caption(windowTitle)
# create and initialize red dot and blue dot
gameOver = False
color1=pygame.Color('red')
center1 = [50, 75]
radius1=30
speed1=[1,2]
color2=pygame.Color('blue')
center2=[200,100]
radius2=40
speed2=[2,1]
# Draw objects
pygame.draw.circle(surface, color1, center1, radius1, 0)
pygame.draw.circle(surface, color2,center2,radius2,0)
gameOver = update(surface, color1, center1, radius1, speed1, color2, center2, radius2, speed2)
# Refresh the display
pygame.display.update()
# Loop forever
while True:
# Handle events
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Handle additional events
# Update and draw objects for the next frame
#gameOver = update(center, surface)
# Refresh the display
pygame.display.update()
# Set the frame speed by pausing between frames
time.sleep(frameDelay)
def update(surface, color1, center1, radius1, speed1, color2, center2, radius2, speed2):
#Check if the game is over. If so, end the game and
#returnTrue. Otherwise, update the game objects, draw
#them, and return False.
#This is an example update function - replace it.
#- center is a list containing the x and y int coords
#of the center of a circle
#- surface is the pygame.Surface object for the window
erasecolor=pygame.Color('black')
if False: # check if the game is over
return True
else: # continue the game
surface.fill(erasecolor)
moveDot(surface, color1, center1, radius1)
moveDot(surface, color2, center2, radius2)
pygame.draw.circle(surface,color1,center1,radius1,0,0)
pygame.draw.circle(surface,color2,center2,radius2,0,0)
return False
def moveDot(surface,center,radius,speed):
size=surface.get_size()
for coord in range(0,2):
center[coord]=center[coord]+speed[coord]
if center [coord]<radius:
speed[coord]=-speed[coord]
if center[coord]+radius>size(coord):
speed[coord]=-speed[coord]
main()
The order of your arguments being passed when you call moveDot is incorrect. It should be
moveDot(surface, center1, radius1, speed)
For both statements. Speed should be the speed of movement of the circle.
Recently began a new pygame project, asteroids. I've been working on getting an image to rotate in the direction of the cursor, which i'm finding irritatingly hard. Any help is appreciated, here is the code for the rotation so far:
import sys, pygame, math, time;
from pygame.locals import *;
spaceship = ('spaceship.png')
mouse_c = ('crosshair.png')
backg = ('background.jpg')
fire_beam = ('beam.png')
pygame.init()
screen = pygame.display.set_mode((800, 600))
bk = pygame.image.load(backg).convert_alpha()
mousec = pygame.image.load(mouse_c).convert_alpha()
space_ship = pygame.image.load(spaceship).convert_alpha()
f_beam = pygame.image.load(fire_beam).convert_alpha()
clock = pygame.time.Clock()
pygame.mouse.set_visible(False)
x, y = 357, 300 #position of space_ship, (line 38 btw, second from bottom)
while True:
screen.blit(bk, (0, 0))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN and event.button == 1:
print("Left Button Pressed")
elif event.type == MOUSEBUTTONDOWN and event.button == 3:
print("Right Button Pressed")
if event.type == MOUSEMOTION:
clock.tick(60)
x1, y1 = pygame.mouse.get_pos()
x2, y2 = x, y
dx, dy = x2 - x1, y2 - y1
rads = math.atan2(dx, dy)
degs = math.degrees(rads)
pygame.transform.rotate(space_ship, (degs))
print degs #Prints correct output..
pygame.display.update() #the image flickers, but does not rotate
pos = pygame.mouse.get_pos()
screen.blit(mousec, (pos))
screen.blit(space_ship, (375, 300))
pygame.display.update()
From the documentation: "A Surface transform is an operation that moves or resizes the pixels. All these functions take a Surface to operate on and return a new Surface with the results."
As it is, you operate the transform, but throw away the result.
You could just change the line
pygame.transform.rotate(space_ship, (degs))
to:
space_ship = pygame.transform.rotate(space_ship, (degs))
In order to see it working, but it would not be a good :
you'd need to re-calculate your degrees to have only the difference
in degrees from one iteration to the next - but worse, successive raster-picture
transforms would degenerate your spaceship into an amorphous blob of pixels very fast.
The right thing to do is to keep a reference to your original spacehsip pictures, and always rotate that instead.
So, before your main loop, you do:
space_ship_image = pygame.image.load(spaceship).convert_alpha()
And inside the loop, the aforementioned:
space_ship = pygame.transform.rotate(space_ship_image, (degs))
BTW, raster artifacts being what they are, yo probably will want to use a larger
version of your ship in your "spaceship.png" file, and use "rotozoom" instead of "rotate",
scaling down as you rotate the ship to get your final image.
I'm new to stackoverflow, but was hoping for a little insight from more advanced programmers. I am switching majors to Computer Science next semester and am taking an intro class learning some beginner's Python programming. I have already finished the program below (the assignment was to make a program that draws ovals on the window surface by filling in some of the professor's code, not too bad at all) but I wanted to add a little something extra: As you can see, I have the color of the ovals set to be random, but it stays the same until the program is restarted entirely i.e. all of the ovals are that particular color for the length of the program. With the code written the way it is, I can't figure out a way to get the color to change for each oval. Keep in mind, this is all for kicks, but if anyone's feeling especially helpful or creative, I'm curious to see what you have to say. Let me know if I can expound on anything. Thanks!
import pygame, random, sys
WINDOWWIDTH = 700
WINDOWHEIGHT = 700
BACKGROUNDCOLOR = (150,160,100)
#A different color every run
OVAL_COLOR = (random.randint (0,255),random.randint (0,255),
random.randint (0,255))
pygame.init()
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption("Mobile Ovals")
#The draw variable is used later to indicate the mouse is still pressed
ovals = []
completedOvals = []
finished = False
draw = False
startXY = (-1, -1)
while not finished:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYUP and
event.key == pygame.K_ESCAPE):
finished = True
elif event.type == pygame.KEYDOWN:
pressed = pygame.key.get_pressed()
if pressed[pygame.K_F4] and (pressed[pygame.K_LALT] or
pressed[pygame.K_RALT]):
finished = True
elif event.type == pygame.MOUSEBUTTONDOWN:
startXY = event.pos
draw = True
elif event.type == pygame.MOUSEBUTTONUP:
draw = False
for oval in ovals:
completedOvals.append (oval)
if draw == True:
del ovals [:]
#The above function ensures only one oval is onscreen at any given time
endXY = event.pos
width = (abs(endXY[0]-startXY[0]))
height = (abs(endXY[1]-startXY[1]))
#The code below allows the user to drag any direction
if endXY[0] < startXY[0]:
left = endXY[0]
else:
left = startXY[0]
if endXY[1] < startXY[1]:
top = endXY[1]
else:
top = startXY[1]
ovals.append (pygame.Rect (left, top, width, height))
windowSurface.fill(BACKGROUNDCOLOR)
for oval in ovals:
pygame.draw.ellipse(windowSurface, OVAL_COLOR, oval)
for completedOval in completedOvals:
pygame.draw.ellipse(windowSurface, OVAL_COLOR, completedOval)
pygame.display.update()
pygame.quit()
Your problem is quite simple. You set OVAL_COLOR once. But every time you make reference to the variable OVAL_COLOR, you're not creating a new random color, you're re-using the RGB color that was randomly generated when you created the variable.
Now, the way your program is structured, you maintain a list of all complete ovals that you're re-drawing every time the draw variable is set to true. If you place the OVAL_COLOR variable inside the for loop, you will update the color with every mouse movement, changing the color of the oval being drawn, as well as the color of all the old ovals being re-drawn.
The solution to have a new random oval color is to set the variable OVAL_COLOR when the mouse button goes down. That way, the oval color won't change as you drag the mouse to adjust the oval. But, given the current structure of the program, you'll need to save the oval colors assigned to completed ovals, or you'll still have the oval color change each time.
When the mouse button is pressed down, we want a new random color for our circle. Generate a random value, which will be used every time the circle is re-drawn.
elif event.type == pygame.MOUSEBUTTONDOWN:
startXY = event.pos
OVAL_COLOR = (random.randint (0,255),random.randint (0,255),
random.randint (0,255))
draw = True
When the mouse button is released, save the coordinates for the oval, along with the color that it was drawn with.
elif event.type == pygame.MOUSEBUTTONUP:
draw = False
# print len(ovals) # (always ==1)
completedOvals.append ((ovals[-1], OVAL_COLOR))
When we iterate through these completed ovals, draw them with the same color each time.
for (completedOval, color) in completedOvals:
pygame.draw.ellipse(windowSurface, color, completedOval)
Create a simple Oval() class, that contains it's color, and size.
import pygame
from pygame.locals import *
class Oval(object):
"""handle, and draw basic ovals. stores Rect() and Color()"""
def __init__(self, startXY, endXY):
self.color = Color(random.randint(0,255), random.randint(0,255), random.randint(0,255))
self.rect = Rect(0,0,1,1)
self.coord_to_oval(startXY, endXY)
def draw(self):
pygame.draw.ellipse(windowSurface, self.color, self.rect)
def coord_to_oval(self, startXY, endXY):
width = (abs(endXY[0]-startXY[0]))
height = (abs(endXY[1]-startXY[1]))
#The code below allows the user to drag any direction
if endXY[0] < startXY[0]:
left = endXY[0]
else:
left = startXY[0]
if endXY[1] < startXY[1]:
top = endXY[1]
else:
top = startXY[1]
self.rect = Rect(left, top, width, height)
# main loop
while not finished:
for event in pygame.event.get():
# events, and creation:
# ... your other events here ...
elif event.type == MOUSEBUTTONDOWN:
startXY = event.pos
draw = True
elif event.type ==MOUSEBUTTONUP:
# on mouseup, create instance.
endXY = event.pos
oval_new = Oval(startXY, endXY)
completedOvals.append(oval_new)
# draw them:
for oval in ovals:
oval.draw()
for oval in completedOvals:
oval.draw()
I mostly left out your non-completed ovals. Was that to show the size before clicking?