box around cursor pygame - python

In the little games I made in pygame there's always a box around my cursor in which all colours are reversed (e.g. if I hold my cursor over a black and red background the square around the cursor will be white and cyan). This initially wasn't a problem, since the first few projects only required keyboard inputs, but now I want to make a game where you have to click a lot, so it would look very ugly. How do I remove this box? I am using macOS High Sierra, python3 and pygame 1.9.3.

I'm putting this as an answer, because it's too much for a comment. Also, I don't have a Mac, so this answer is supposition.
Looking at the github issue #Keno posted:
There's an image of a white cursor (black filled outline), on a black background.
It looks to me, that with the latest OS upgrade, MacOS is no longer working correctly with whatever mouse-cursor-image functions PyGame is using. Obviously the pixels outside the cursor should be transparent.
Anecdotal evidence (i.e.: a google search) suggests that other software has cursor issues with macOS High Sierra too.
Maybe it's possible to work around the problem.
If the PyGame application is not using the mouse, it may be useful to just hide the cursor.
pygame.mouse.set_visible() # Perhaps this just gives a black-box though
However if PyGame is "hiding" the mouse by setting a fully-transparent cursor, the result may still be a completely black square. So the mouse can be moved outside the window (or at least to the bottom-right corner):
w, h = pygame.display.get_surface().get_size() # get window size
pygame.mouse.set_pos( [w, h] ) # move cursor outside window
I got a bit carried away with this problem, and ended up writing a bunch of test cases.
import sys
import time
import pygame
from pygame.locals import *
WHITE = 255,255,255
BLUE = 0,0,60
WINDOW_WIDTH=600
WINDOW_HEIGHT=500
pygame.init()
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.font.init()
clock = pygame.time.Clock()
text_font = pygame.font.Font(None,60)
STARTUP_MS = int(time.time() * 1000.0) # Epoch time programme started
MANUAL_CURSOR = pygame.image.load('finger_cursor_16.png').convert_alpha()
cursor_test = 0
time_last_test = 0
while (True):
NOW_MS = int(time.time() * 1000.0) - STARTUP_MS # current time in milliseconds-since-start
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Try different cursor styles
if ( cursor_test == 4 ):
text_image = text_font.render( 'Off-Screen-Cursor', True, WHITE )
pygame.mouse.set_pos( [ WINDOW_WIDTH, WINDOW_HEIGHT ])
pygame.mouse.set_visible(True)
elif ( cursor_test == 3 ):
text_image = text_font.render( 'Manual-Cursor', True, WHITE )
pygame.mouse.set_visible(False)
# cursor drawn as part of the screen, see below
elif ( cursor_test == 2 ):
text_image = text_font.render( 'Transparent-Cursor', True, WHITE )
pygame.mouse.set_cursor((8,8),(0,0),(0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0))
pygame.mouse.set_visible(True)
elif ( cursor_test == 1 ):
text_image = text_font.render( 'Hidden-Cursor', True, WHITE )
pygame.mouse.set_visible(False)
elif ( cursor_test == 0 ):
text_image = text_font.render( 'Default-Arrow-Cursor', True, WHITE )
pygame.mouse.set_visible(True)
pygame.mouse.set_cursor(*pygame.cursors.arrow)
# test for 3-seconds each
if ( NOW_MS - time_last_test > 3000 ):
pygame.mouse.set_pos( [ WINDOW_WIDTH//2, WINDOW_HEIGHT//2 ])
time_last_test = NOW_MS
cursor_test += 1
if ( cursor_test > 4 ):
cursor_test = 0
# Paint the screen
screen.fill(BLUE)
# Write the mode
screen.blit(text_image, ( 0, 0 ))
# if we're in manual-cursor mode, paint a cursor too
if (cursor_test == 3):
screen.blit( MANUAL_CURSOR, ( pygame.mouse.get_pos() ) )
pygame.display.update()
clock.tick_busy_loop(60)
EDIT: I forgot to upload the finger_cursor_16.png image:

Just adding to #Kingsley answer without the tests and out of window cursor detection, still super hacky and probably more trouble than it's worth but might help you while there's a fix.
import sys, pygame, os
from pygame.locals import *
def main():
pygame.init()
screen = pygame.display.set_mode((600,600))
screen.fill((100, 100, 100))
# http://tobiasahlin.com/blog/common-mac-os-x-lion-cursors/
custom_cursor = pygame.image.load(os.path.join('yourPath', 'pointer.png')).convert_alpha()
# MAIN LOOP:
while True:
# EVENTS :
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
# Press Q to quit
elif event.type == KEYDOWN and event.key == K_q:
sys.exit()
pygame.mouse.set_visible(False)
screen.fill((100,100,100))
if pygame.mouse.get_focused():
screen.blit( custom_cursor, ( pygame.mouse.get_pos() ) )
pygame.display.flip()
if __name__ == '__main__': main()

Related

Problem with making Circle properly appear on screen in Pygame

I think my understanding of Pygame is a little bit weak. I would appreciate any help in general about the intricacies of the code (since this was given by the teacher) or simply how I can at least make the obstacle visible.
def draw(screen, background, boids, obstaclearray):
#redrawing the whole window
boids.clear(screen, background)
dirty = boids.draw(screen)
for element in obstaclearray:
pygame.draw.circle(screen, (255,255,255), (element.x, element.y), element.radius)
pygame.display.update(dirty)
Above is where I actually do the drawing and attempt to draw the circle.
The CircularObstacle class is a very simple class that looks like this:
import pygame
class CircularObstacle():
def __init__(self, x, y, radius): #MAYBE ADD A SIZE
self.x = x
self.y = y
self.radius = radius
The problem is that the circle only draws itself when the boids have went over it, which is really weird. I think it has to do with the way the pygame has been setup with and the Surfaces and everything, so below is all the code in main. Of course the obstacle does not work as intended, but I plan to fix that later, first I want to at least get a circle to show.
Below is my full code because I believe it is crucial to solving the issue:
import pygame
from pygame.locals import *
import argparse
import sys
from boid import Boid
from Obstacle import CircularObstacle
def add_boids(boids,num_boids):
for boid in range (num_boids):
boids.add(Boid())
def update(dt, boids):
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN:
mods = pygame.key.get_mods()
if event.key == pygame.K_q:
# quit
pygame.quit()
sys.exit(0)
elif event.key == pygame.K_UP:
# add boids
if mods & pygame.KMOD_SHIFT:
add_boids(boids, 100)
else:
add_boids(boids, 10)
elif event.key == pygame.K_DOWN:
# remove boids
if mods & pygame.KMOD_SHIFT:
boids.remove(boids.sprites()[:100])
else:
boids.remove(boids.sprites()[:10])
#ADD STUFF LIKE THE SLIDER AND STUFF
for b in boids:
b.update(dt, boids)
def draw(screen, background, boids, obstaclearray):
#redrawing the whole window
boids.clear(screen, background)
dirty = boids.draw(screen)
for element in obstaclearray:
pygame.draw.circle(screen, (255,255,255), (element.x, element.y), element.radius)
pygame.display.update(dirty)
default_boids = 0
default_geometry = "1000x1000"
# Initialise pygame.
pygame.init()
pygame.event.set_allowed([pygame.QUIT, pygame.KEYDOWN, pygame.KEYUP])
# keep a good framerate so the graphics are better
fps = 60.0
fpsClock = pygame.time.Clock()
# Set up pygamme window
window_width, window_height = 800,600
flags = DOUBLEBUF
screen = pygame.display.set_mode((window_width, window_height), flags)
screen.set_alpha(None)
background = pygame.Surface(screen.get_size()).convert()
background.fill(pygame.Color('black'))
boids = pygame.sprite.RenderUpdates()
add_boids(boids, default_boids)
obstaclearray = []
defaultcircleobstacle = CircularObstacle(200,200,13)
obstaclearray.append(defaultcircleobstacle)
#The "game loop"
dt = 1/fps # here dt means the amount of time elapsed since the last frame
#it seems like thie is a forever loop but in reality this is not since in the update method we provide functinality to quit the program
while True:
update(dt, boids)
draw(screen, background, boids, obstaclearray)
dt = fpsClock.tick(fps)
When you call pygame.display.update() you have 2 options. You can call it without any parameter. In this case the complete screen is updated.
pygame.display.update()
Or call it with a list of rectangular regions that need to be updated. In this case, only the rectangular areas will be updated.
pygame.display.update(rect_list)
You do the 2nd option, but the areas where the circles are drawn are not in the dirty list, therefore this regions are not updated.
pygame.display.update(dirty)
Either update the whole screen with pygame.display.update() or add the regions of the circles to the dirty list:
def draw(screen, background, boids, obstaclearray):
boids.clear(screen, background)
dirty = boids.draw(screen)
for element in obstaclearray:
dirty_rect = pygame.draw.circle(screen, (255,255,255), (element.x, element.y), element.radius)
dirty.append(dirty_rect)
pygame.display.update(dirty)

Is there a way to get pygame to detect what color my cursor is on

I'm trying to make a game where it spawns another circle every time you click on a circle. And the error i'm getting is "TypeError: 'bool' object is not callable". I'm looking for a solution that doesn't completly change the code since i'm new and want to understand the code myself. But at this point i'll take any help.
import pygame
import random
import time
from pygame.math import Vector2
# Define some colors
BLACK = (0, 0, 0)
WHITE = (247, 247, 247)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (225,225,0)
tuple1 = (247, 247, 247, 255)
# Setup
pygame.init()
# Set the width and height of the screen [width,height]
surface = pygame.display.set_mode( (2560, 1440) )
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# Hide the mouse cursor
pygame.mouse.set_visible(0)
# Speed in pixels per frame
x_speed = 0
y_speed = 0
# Current position
cursor = pygame.image.load('cursor.png').convert_alpha()
pygame.image.load("pattern.jpg")
background_image = pygame.image.load("pattern.jpg").convert()
circposy = 770
circposx = 1280
# -------- Main Program Loop -----------
while done ==False:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN:
done = True
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Drawing Code
surface.fill(WHITE)
# First, clear the screen to WHITE. Don't put other drawing commands
# above this, or they will be erased with this command.\
player_position = pygame.mouse.get_pos()
a = 0
b = 1
p=player_position[a]
o=player_position[b]
player_position = (p,o)
pygame.draw.circle(surface,RED,[circposx,circposy], 40)
tuple2 = surface.get_at(pygame.mouse.get_pos())
print (tuple2)
q = p - 2545
w = o - 2545
surface.blit( cursor, (q, w) )
a=0
result = tuple(map(int, tuple2)) > tuple1
print (result)
while event.type == pygame.MOUSEBUTTONDOWN:
done = True
if result == True():
a+1
surface.fill(WHITE)
pygame.draw.circle(surface,RED,[circposx + randint, circposy+randint],40)
print (a)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit frames per second
clock.tick(144)
# Close the window and quit.
pygame.quit()
cursor.png
The short answer is that the code is trying to call True(), which isn't a function.
while event.type == pygame.MOUSEBUTTONDOWN:
done = True
if result == True(): # <<-- HERE
a+1
surface.fill(WHITE)
pygame.draw.circle(surface,RED,[circposx + randint, circposy+randint],40)
Simply change this to True.
But you will also need to define what randint is a few lines lower. Did you mean random.randint( 0, 500 ) or suchlike? And fixing this leads to another error, because the surrounding loop to this code, is an infinite loop:
while event.type == pygame.MOUSEBUTTONDOWN: # <<-- HERE
done = True
if result == True:
a+1
surface.fill(WHITE)
rand_x = random.randint( 0, 500 )
rand_y = random.randint( 0, 500 )
pygame.draw.circle(surface,RED,[circposx + rand_x, circposy+rand_y],40)
Because there is no way event.type can ever change inside that loop. This should probably read:
if event.type == pygame.MOUSEBUTTONDOWN:
If I may make some suggestions:
Put all your event handling to a single place.
There's some doubling-up of event handling, and it would have prevented that infinite loop.
Move your screen dimensions into variables
SCREEN_WIDTH = 2560
SCREEN_HEIGHT = 1440
Instead of having constant numbers through the code (e.g.: 2545) make these functions of the screen size.
SCREEN_MARGIN = SCREEN_WIDTH - round( SCREEN_WIDTH * 0.10 )
q = p - SCREEN_MARGIN
If you want to detect what color your cursor is on, you can use pyautogui. Make sure you have pyautogui installed. type pip install pyautogui. If it doesn't install successfully, you already have it installed.
# Import everything
import pygame
import pyautogui
from pyautogui import *
# Initialize
pygame.init()
# Get mouse position
mouse_pos = pygame.mouse.get_pos()
x = mouse_pos[0]
y = mouse_pos[1]
# Get Color
r = pyautogui.pixel(x,y)[0]
g = pyautogui.pixel(x,y)[1]
b = pyautogui.pixel(x,y)[2]
color = [r,g,b]
Hopefully, you found this helpful!

Pygame mouse event.rel not working outside window [duplicate]

This question already has answers here:
pygame capture keyboard events when window not in focus
(2 answers)
Get Inputs without Focus in Python/Pygame?
(3 answers)
Closed 3 months ago.
I'm trying to implement a feature in Pygame where if the user moves the mouse outside the window the relative position (event.rel) can be returned. I'm trying to do this because I want to make a game where you can keep turning left or right from mouse input.
I know this is possible from the docs:
If the mouse cursor is hidden, and input is grabbed to the current display the mouse will enter a virtual input mode, where the relative movements of the mouse will never be stopped by the borders of the screen. See the functions pygame.mouse.set_visible() and pygame.event.set_grab() to get this configured.
For this reason, I've implemented these lines in my code
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)
However this doesn't help. The actual behaviour is:
when the mouse is moving in the window, event.rel prints to the console (expected)
when the mouse is moving outside the window, event.rel doesn't print to the console (not expected)
Other strange behaviour:
Initially event.rel is set to (300, 300) which is the center of my 600x600 screen. Ideally initial event.rel should be (0,0)
Possible cause:
I'm running the code below in trinket.io or repl.it. Because this is a browser the demo window might cause problems. Maybe this is solved by downloading python locally but i don't want to do this as it takes up too much space (my laptop sucks) and also it would be good to have an online demo to easily show employers that are too lazy to paste code into their IDEs.
Similar issue:
This guy on reddit had a very similar issue but I think his solution is not related to my situation
This block of code was what I asked originally but it doesn't demonstrate the question as well as the last block. Please scroll down to see the last block of code instead :)
import pygame
pygame.init()
# screen
X = 600 # width
Y = 600 # height
halfX = X/2
halfY = Y/2
screen = pygame.display.set_mode((X, Y), pygame.FULLSCREEN)
clock = pygame.time.Clock()
# Colors
WHITE = (255, 255, 255)
RED = (255, 0, 0)
# From the docs:
# "If the mouse cursor is hidden, and input is grabbed to the
# current display the mouse will enter a virtual input mode, where
# the relative movements of the mouse will never be stopped by the
# borders of the screen."
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)
def drawCross(point, size, color):
pygame.draw.line(screen, color, (point[0]-size,point[1]-size), (point[0]+size,point[1]+size), 2)
pygame.draw.line(screen, color, (point[0]+size,point[1]-size), (point[0]-size,point[1]+size), 2)
canvas_rel = (halfX,halfY)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
print('event.rel = ' + str(event.rel))
canvas_rel = [10 * event.rel[0] + halfX, 10 * event.rel[1] + halfY]
print(' canvas_rel = ' + str(canvas_rel))
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
print('escape')
running = False
break
screen.fill(WHITE)
# Red sight to represent pygame mouse event.rel
drawCross(canvas_rel, 10, RED)
pygame.display.flip()
clock.tick(20)
pygame.quit()
EDIT:
The above code doesn't fully demonstrate my problem. I've added a better sample below to make the the question easier to understand. This sample will draw a triangle in the centre of the screen. The triangle will rotate with relative horizontal motion of the mouse. Note the attempt to use pygame.mouse.set_pos
import pygame
from math import pi, cos, sin
pygame.init()
# screen
X = 600 # width
Y = 600 # height
halfX = X/2
halfY = Y/2
screen = pygame.display.set_mode((X, Y), pygame.FULLSCREEN)
clock = pygame.time.Clock()
# for getting relative mouse position when outside the screen
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)
# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
# sensitivity
senseTheta = 0.01
# player
stand = [halfX, halfY]
t = 0 # angle in radians from positive X axis to positive x axis anticlockwise about positive Z
# draws a white cross in the screen center for when shooting is implemented :)
def drawPlayer():
p = stand
d = 50
a1 = 0.25*pi-t
a2 = 0.75*pi-t
P = (p[0],p[1])
A1 = (p[0] + d*cos(a1), p[1] + d*sin(a1)) # P + (d*cos(a1), d*sin(a1))
A2 = (p[0] + d*cos(a2), p[1] + d*sin(a2)) # P + (d*cos(a2), d*sin(a2))
pygame.draw.line(screen, BLACK, P, A1, 2)
pygame.draw.line(screen, BLACK, A1, A2, 2)
pygame.draw.line(screen, BLACK, A2, P, 2)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
mouseMove = event.rel
print('mouseMove = ' + str(mouseMove))
t -= mouseMove[0] * senseTheta
# "Fix" the mouse pointer at the center
# pygame.mouse.set_pos((screen.get_width()//2, screen.get_height()//2))
# But I think set_pos triggers another MOUSEMOTION event as moving in positive x
# seems to move backward the same amount in x (i.e. the triangle doesn't
# rotate). See the console log.
# If you uncomment this line it works ok (the triangle rotates) but still
# glitches when the mouse leaves the window.
# uncommented or not I still cant get the mouse to work outside the window
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
break
screen.fill(WHITE)
drawPlayer()
pygame.display.flip()
clock.tick(40)
pygame.quit()

Pygame - adding background image

I am new to python and created a small game. I want to add a background image, but is is not working. The image is not displayed.
i tried it with the following code:
background = pygame.image.load("images\\background.png")
screen.blit(background,(0,0))
The code in the question does not really illustrate the problem. But if the code is generating the error:
background = pygame.image.load('images/background.png')
pygame.error: Couldn't open images/background.png
Then it is simply that PyGame can't find the specified image file.
However I expect that your code is simply not "flushing" the updates to the window / screen with a call to pygame.display.flip()
import pygame
# Window size
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 400
### MAIN
pygame.init()
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
pygame.display.set_caption("Background Image")
background_image = pygame.image.load('images/grass.png')
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
# Movement keys
keys = pygame.key.get_pressed()
if ( keys[pygame.K_UP] ):
print("up")
#elif ...
# Update the window, but not more than 60fps
window.blit( background_image, ( 0,0 ) )
pygame.display.flip() # <-- Flush drawing ops to the screen
# Clamp FPS
clock.tick_busy_loop( 60 )
pygame.quit()
Note the 4th-last line.
Take a look at this page on StackOverflow. It has multiple solutions that you can use. I'll write one of them here.
You can make an image the size of your game window, then before anything else is displayed, blit it to (0,0).
bg = pygame.image.load("background.png")
#INSIDE OF THE GAME LOOP
gameDisplay.blit(bg, (0, 0))
#OTHER GAME ITEMS
I hope this helps you!

How do I add more than 2 sprites into an animation in pygame?

#Importing the pygame functions
import pygame
import sys
import os
from pygame.locals import *
#Allows for the editing of a window
pygame.init()
#Sets screen size
window = pygame.display.set_mode((800,600),0,32)
#Names the window
pygame.display.set_caption("TEST")
#Types of colors (red,green,blue)
black = (0,0,0)
blue = (0,0,255)
green = (0,255,0)
yellow = (255,255,0)
red = (255,0,0)
purple = (255,0,255)
lightblue = (0,255,255)
white = (255,255,255)
pink = (255,125,125)
clock = pygame.time.Clock()
L1="bolt_strike_0001.PNG"
L1=pygame.image.load(L1).convert_alpha()
L2="bolt_strike_0002.PNG"
L2=pygame.image.load(L2).convert_alpha()
L3="bolt_strike_0003.PNG"
L3=pygame.image.load(L3).convert_alpha()
L4="bolt_strike_0004.PNG"
L4=pygame.image.load(L4).convert_alpha()
lightingCurrentImage = 1
#Loop
gameLoop = True
while gameLoop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameLoop=False #Allows the user to exit the loop/game
window.fill(black) #used to fill the creen with the certian color variables
if (lightingCurrentImage==1):
window.blit(L1, (0,0))
if (lightingCurrentImage==2):
window.blit(L2, (0,0))
if (lightingCurrentImage==3):
window.blit(L3, (0,0))
if (lightingCurrentImage==4):
window.blit(L4, (0,0))
if (lightingCurrentImage==2):
lightingCurrentImage=1
if (lightingCurrentImage==3):
lightingCurrentImage=2
if (lightingCurrentImage==4):
lightingCurrentImage=3
else:
lightingCurrentImage+=3;
pygame.display.flip() #must flip the image o the color is visable
clock.tick(5)
pygame.quit() #quit the pygame interface
exit(0)
I'm having problems stitching together 10 images of a lightning bolt animation in pygame. What I have at the moment works but its not what I want it to look like. What happens when I run this is the lightning bolt creates the animation sequence once then disappears and never restarts the sequence again. If I set lightingCurrentImage+=3 to lightingCurrentImage+=2 it appears and stays on the screen but doesn't ever disappear. Please help me to see what the problem is if you can. Thanks! (I want the lightning bolt to begin and go all the way through the animation then disappear. Then begin again and repeat).
First create list of images then you can use it this way:
bold_imgs = []
bold_imgs.append( pygame.image.load("bolt_strike_0001.PNG").convert_alpha() )
bold_imgs.append( pygame.image.load("bolt_strike_0002.PNG").convert_alpha() )
bold_imgs.append( pygame.image.load("bolt_strike_0003.PNG").convert_alpha() )
bold_imgs.append( pygame.image.load("bolt_strike_0004.PNG").convert_alpha() )
lightingCurrentImage = 0
while True:
# here ... your code with events
window.fill(black)
window.blit( bold_imgs[ lightingCurrentImage ], (0,0))
lightingCurrentImage += 1
if lightingCurrentImage = len( bold_imgs ):
lightingCurrentImage = 0
pygame.display.flip()
clock.tick(5)
You can use tick(25) to get faster but smoother animation.
Human eye needs at least 25 images per second to see it as smooth animation.

Categories