This question already has answers here:
Pygame mouse clicking detection
(4 answers)
How can I add an image or icon to a button rectangle in Pygame?
(1 answer)
How do I implement option buttons and change the button color in PyGame?
(2 answers)
Closed 1 year ago.
class Button:
buttons = []
def __init__(self, blitX, blitY, textureFile, width, height, rotateAngle=0, hoveredTextureImage=None):
self.textureImage = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(textureFile), (width, height)), rotateAngle)
if hoveredTextureImage is not None:
self.hoveredTextureImage = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(
hoveredTextureImage), (width, height)), rotateAngle)
else:
self.hoveredTextureImage = self.textureImage
self.blitX = blitX
self.blitY = blitY
self.height = height
self.displayImage = self.textureImage
self.addButton(self)
self.createMouseParameters()
def createMouseParameters(self):
self.startX = self.blitX
self.endX = self.startX + self.displayImage.get_width()
self.startY = self.blitY
self.endY = self.startY + self.displayImage.get_height()
def draw(self, window):
window.blit(self.displayImage, (self.blitX, self.blitY))
def mouseOnButton(self, mouseX, mouseY):
if self.startX <= mouseX <= self.endX:
if self.startY <= mouseY <= self.endY:
self.displayImage = self.hoveredTextureImage
return True
else:
self.displayImage = self.textureImage
else:
self.displayImage = self.textureImage
#classmethod
def addButton(cls, button):
cls.buttons.append(button)
#classmethod
def detectMouseHover(cls, mouseX, mouseY):
for button in cls.buttons:
button.mouseOnButton(mouseX, mouseY)
This is my class for a button. The button is supposed to switch to another image (hoveredTextureImage) when the mouse is on the button. I'm calling the class method "detectMouseHover" in my game loop so that the game can update the button's image. The issue I'm having is that the image is not changing. Any ideas on how to fix it?
I would also appreciate it if anyone has any ideas on how to make the code more concise and simple.
Related
This question already has answers here:
how to make sprite move upwards and downwards with joystick in pygame
(1 answer)
How do I get xbox controls outside event loop in pygame?
(1 answer)
problems with pygame controller support
(1 answer)
Closed 2 days ago.
Trying to make mobile joystick, went well until i stumbled on a roadblock, that is trying to make a player move.
the problem is, the player position isn't really moving, its only set on the position of the given x,y mouse pos, thus giving the player position on the center.
from pygame import *;
import pygame;
import math;
import os;
pygame.init();
os.chdir("/storage/emulated/0/Insanity");
ingame = True;
source_dir = os.path.dirname(os.path.abspath(__file__));
screen = pygame.display.set_mode((1280,720));
def get_velo(x,y, dist):
vec1,vect2 = 0,0;
vec1 = y / dist;
vec2 = x / dist;
return vec1,vec2;
class sprite(pygame.sprite.Sprite):
def __init__(self,img, size, pos):
self.img = pygame.image.load(img[1]);
self.size = pygame.transform.scale(self.img, (size[0],size[1])).convert_alpha();
# HITBOX
self.rect = self.size.get_rect(center=pos);
self.pos = self.rect.move(pos);
def display(self):
screen.blit(self.size, self.pos);
HW, HH = 1280/2, 720/2;
AREA = 1280*720;
joystick_body = sprite(["", "circle.png"], [100,100], (0,0));
joystick_control = sprite(["", "circle.png"], [30,30], (0,0));
joystick_body.pos = [0,630];
radius = joystick_body.size.get_rect().center[0];
my_velo = 0;
## PLAYER
player = sprite(["", "player.png"], [100,100], (0,0));
movespeed = 10;
while ingame:
screen.fill((255,255,255));
## JOYSTICK
joystick_body.display();
x, y = pygame.mouse.get_pos();
# CIRCLE COLLISION
v1 = pygame.math.Vector2(0, 630);
v2 = pygame.math.Vector2(x,y);
if v1.distance_to(v2) < radius + radius:
joystick_control.pos = (x,y);
joystick_control.rect.clamp_ip(joystick_body.rect);
vec1,vec2 = x / radius, y / radius# x / v1.distance_to(v2), y / v1.distance_to(v2)
#vec1,vec2 = (x,y, v1.distance_to(v2));
player.pos = (vec1*movespeed,vec2*movespeed);
#joystick_control.pos = joystick_body.pos + (joystick_control.pos - joystick_body.pos).clamped(radius);
else:
joystick_control.pos = (33,664);
player.display();
joystick_control.display();
pygame.display.update();
the video:
https://www.veed.io/view/442d6abd-c072-41bb-98be-be5b1fb1ba42/223fbe52-0cf9-4724-9393-d7a85f9beb68?sharingWidget=true&panel=share
I tried pygame.vector2, rect.move() and the same happened, i felt like i need to use the player.pos x and y but i dont know how i would implement it, if there is a pygame version of godot function (move_and_slide()). I expect to make a working mobile joystick
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Pygame mouse clicking detection
(4 answers)
How to use Pygame touch events in a mobile game?
(1 answer)
Closed 7 days ago.
I'm making a PyGame game and I have made a Button class to make on-screen buttons. This is the code:
import pygame
pygame.font.init()
dfont = pygame.font.Font('mfdfont.ttf', 64)
#button
class Button():
def __init__(self, x, y, image, scale = 1, rot = 0, text_in = '', color = 'WHITE', xoff = 0, yoff = 0):
self.xoff = xoff
self.yof = yoff
self.x = x
self.y = y
self.scale = scale
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.rotozoom(image, rot, scale)
self.text_in = text_in
self.text = dfont.render(self.text_in, True, color)
self.text_rect = self.text.get_rect(center=(self.x +width/(2/scale) + xoff, self.y + height/(2/scale) + yoff))
self.rect = self.image.get_rect()
self.rect.topleft = (x, y)
self.clicked = False
def draw(self, surface):
action = False
#get mouse position
pos = pygame.mouse.get_pos()
#check mouseover and clicked conditions
if self.rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
self.clicked = True
action = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
#draw button on screen
surface.blit(self.image, (self.rect.x, self.rect.y))
surface.blit(self.text, self.text_rect)
return action
The problem is that I'm using two surfaces to draw the game to the screen. One is a dummy surface at 1024x2048 resolution that I draw everything to, and the second one is a surface that I can resize to any resolution. The dummy surface then gets scaled and blit to the real surface and the real surface is drawn on the screen. This allows me to have a resizable window without messing the screen positions of UI and game elements.
The actual problem is that after implementing this second surface, click and touch input on buttons doesn't work anymore because I'm basically clicking on the real surface and not the dummy surface the buttons are drawn on. I wonder if there is a way to redirect clicks from a certain position on the real surface to clicks to the relative position on the dummy surface. Or maybe have the button class listen for input on the real surface instead of the dummy surface it's drawn on.
I added a "mobile mode", so when the game is running on a mobile device the entire two surface rendering process is not used and instead uses the classic one surface rendering, which makes the buttons work on mobile devices (or devices that don't allow window resizing). This is a temporary fix for the mobile version, but that still leaves the desktop application unusable because the on screen buttons don't work. I must mention that the OSBs are needed, I won't add keyboard controls for those buttons instead. They must be on screen.
This question already has answers here:
Pygame mouse clicking detection
(4 answers)
Closed 1 year ago.
I am trying to make a button class in pygame and python but i dont know how i put code for when i will click the button it will execute code
the code i want to execute is :-
num1 = 1
num2 = 100
num2 = int(rand)-1
rand = (num1+num2)//2
text_screen(str(rand),"#DEA33E",font2,795,185)
pygame.display.update()
and this is the Button class
class Button2:
def __init__(self,text,width,height,pos,elevation):
# Core Attributes
self.pressed = False
self.elevation = elevation
self.dynamic_elevation = elevation
self.original_y_pos = pos[1]
# top rectangle
self.top_rect = pygame.Rect(pos,(width,height))
self.top_color = "#475F77"
# bottom rectangle
self.bottom_rect = pygame.Rect(pos,(width,elevation))
self.bottom_color = "#354B5E"
# text
self.text_surf = font3.render(text, True, "#FFFFFF")
self.text_rect = self.text_surf.get_rect(center = self.top_rect.center)
def draw(self):
# elevation logic
ot = 1
ot = ot + 0
self.top_rect.y = self.original_y_pos - self.dynamic_elevation
self.text_rect.center = self.top_rect.center
self.bottom_rect.midtop = self.top_rect.midtop
self.bottom_rect.height = self.top_rect.height + self.dynamic_elevation
pygame.draw.rect(screen,self.bottom_color,self.bottom_rect,border_radius = 12)
pygame.draw.rect(screen,self.top_color,self.top_rect,border_radius=12)
screen.blit(self.text_surf,self.text_rect)
self.check_click()
def check_click(self):
mouse_pos = pygame.mouse.get_pos()
if self.top_rect.collidepoint(mouse_pos):
self.top_color = "#D74B4B"
if pygame.mouse.get_pressed()[0]:
self.dynamic_elevation = 0
self.pressed = True
else:
self.dynamic_elevation = self.elevation
if self.pressed == True:
self.pressed = False
also i want to do so like i can use the rand and num1,num2 variable outside the class
Read about Classes and Instance Objects. A class has no variables, it has attributes. YYou have to create one (or more) instances of the class, then you can access the attributes of the class:
button = Button2(...)
if button.pressed:
# do somthing
# [...]
This question already has answers here:
How can I make a sprite move when key is held down
(6 answers)
Closed 1 year ago.
Hi am new fairly new to programming so I tried to learn by making my hands dirty. I tried making a simple box game program all was working fine until I made my player Class which inherit from the base class of Box_User for some reasons my box(player class object) is no longer moving I tried to see what it prints and it seems like none of the keys work when I press them
Can anyone explain what happened?
import pygame
pygame.init()
# Classes
class Window():
def __init__(self, width, height):
self.width = width
self.height = height
self.window_init() # this functions is to get the window up
def window_init(self):
self.window = pygame.display.set_mode((self.width, self.height)) # this is the main window
self.background = pygame.Surface((self.window.get_size())) # this one is named background but should be use like the main window
self.background.fill((255, 255, 255))
#staticmethod
def draw_objects_to_Screen():
win.window.blit(win.background, (0,0))
win.window.blit(box.box, (box.pos_x - scroll[0], box.pos_y + scroll[1])) # the scroll is used to make it look like its moving
win.window.blit(box2.box, (box2.pos_x - scroll[0], box2.pos_y + scroll[1]))
pygame.display.update()
class Box_User():
jump = 10
jump_status = False
def __init__(self, x, y, height, width):
self.pos_x = x
self.pos_y = y
self.box_height = height
self.box_width = width
self.box = pygame.Surface((self.box_height, self.box_width))
self.color = (0, 20, 0)
self.draw_box()
def draw_box(self):
pygame.draw.rect(self.box, self.color, pygame.Rect(self.pos_x, self.pos_y, self.box_height, self.box_width))
#staticmethod
def _jump():
if Box_User.jump >= -10:
box.pos_y -= (Box_User.jump * abs(Box_User.jump)) * 0.3
scroll[1] += (Box_User.jump * abs(Box_User.jump)) * 0.3
Box_User.jump -= 1
else:
Box_User.jump = 10
Box_User.jump_status = False
class Player(Box_User):
key_pressed = pygame.key.get_pressed()
def __init__(self, x, y, height, width):
super().__init__(x, y, height, width)
# self.pos_x = x
#self.pos_y = y
def movements(self):
if self.key_pressed[pygame.K_a]:
self.pos_x -= 5
if self.key_pressed[pygame.K_d]:
self.pos_x += 5
# place here things that you dont want to move while the box is jumping
if not self.jump_status:
if self.key_pressed[pygame.K_w]:
self.jump_status = True
else:
self._jump() # the box jumps here
class Auto_Box(Box_User):
def __init__(self, x, y, height, width):
super().__init__(x, y, height, width)
pass
# Variables
# window
win = Window(700, 500)
clock = pygame.time.Clock()
FPS = 60
# boxes
box = Player(30, 200, 64, 64)
box2 = Box_User(300, 200, 100, 120)
# The Scroll which controls the things when the box is moving
scroll = [0, 0]
# Functions
# Main Loop
def main():
run = True
while run:
clock.tick(FPS)
# value of the scroll is updated here
scroll[0] += (box.pos_x - scroll[0]-250)
#print("coordinate are")
#print(scroll)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
box.movements()
print(box.pos_x, box.pos_y)
Window.draw_objects_to_Screen()
if __name__ == "__main__":
main()
pygame.key.get_pressed() returns a list of booleans that represent the state of the keyboard when you call the function.
If you continually check that list, no keys will ever change state. It's just a list of Trues and Falses.
You need to reset the values of key_pressed in the loop, updating it with fresh values from pygame.key.get_pressed().
This should do the trick:
def movements(self):
self.key_pressed = pygame.key.get_pressed()
if self.key_pressed[pygame.K_a]:
self.pos_x -= 5
...
The key_pressed class variables is only initialized once. It is never changed. Therefore the pressed keys are not detected.
pygame.key.get_pressed() returns a iterable with the current state of all keyboard buttons. You must get the states of the keys in every frame:
class Player(Box_User):
def __init__(self, x, y, height, width):
super().__init__(x, y, height, width)
def movements(self):
# get the current states of the keys
self.key_pressed = pygame.key.get_pressed()
if self.key_pressed[pygame.K_a]:
self.pos_x -= 5
if self.key_pressed[pygame.K_d]:
self.pos_x += 5
# place here things that you dont want to move while the box is jumping
if not self.jump_status:
if self.key_pressed[pygame.K_w]:
self.jump_status = True
else:
self._jump() # the box jumps here
I am new to python and wanted to create a game to test some knowledge. Please bare with my mistakes. I would also really appreciate an example written out if possible so I can wrap my head around the concept.
I couldn't figure out how to post the entire code without formatting nightmares so I put it in github sorry if this is against terms!
I removed most of the dialogue because it was very very long.
Some background about the same:
It was written as a text-based only game first, then I heard about pygame wanted to figure out how to put the game into the window. So first I created all of the code, which ran perfectly fine even with sound effects / music, but then after trying to figure out pygame's game loop, I can't figure out how to change the background image.
I have 5 scenes that I want 5 images for, that change when I change the scene with user input. Even now, the music changes, but the background images don't change after blitting the first one in the 'naming' scene. I don't really understand how the pygame loop works in conjunction with the game engine I have currently. I know it's looping through the pygame loop as I tested it with printing things, but when trying to add images or saying if scene == naming: blit image, it doesn't work. I also tried putting the images into each of the scenes. I also tried putting the images into a class called background with all 5 scenes and images to each. Can't figure it out.
Any help would be greatly appreciated!
-M
Here is an example of how to use scenes. This is not the only way of doing it, but i though it would be easy to use/understand. I also noticed in your code that you used input(). which is annoying if your using a window, so i also added a button and a textbox input that kinda works.
import pygame as pg
pg.init() # initialize the pg
win = pg.display.set_mode((1080, 720)) # create the game window
pg.display.set_caption("Puppy Love")
white = (255,255,255)
black = (0,0,0)
clock = pg.time.Clock()
fps = 60
class Scene:
def __init__(self):
self.sceneNum = 1
def Scene_1(self):
win.fill(white)
if next_scene_button.draw(): #if clicked button
self.sceneNum += 1
name_Box.Draw()
#anything else you want to draw
def Scene_2(self):
win.fill((0,0,255))
if next_scene_button.draw():
self.sceneNum = 1
#...
def Draw_Scene(self):
if self.sceneNum == 1:
self.Scene_1()
elif self.sceneNum == 2:
self.Scene_2()
class Button:
def __init__(self,x,y,w,h,text):
self.x = x
self.y = y
self.w = w
self.h = h
self.text = text
self.font = pg.font.Font(pg.font.match_font("Calibri"),20)
def draw(self):
button_clicked = False
col = (150,150,150)
if mouse_pos[0] > self.x and mouse_pos[0] < self.x + self.w:
if mouse_pos[1] > self.y and mouse_pos[1] < self.y + self.h:
col = (200,200,200)
if click:
button_clicked = True
pg.draw.rect(win,col,(self.x,self.y,self.w,self.h))
obj = self.font.render(self.text,True, black)
win.blit(obj,(self.x + (self.w-obj.get_width())//2,self.y + (self.h-obj.get_height())//2)) #center the text
return button_clicked #return if the button was clicked or not
class TextBox:
def __init__(self,x = 0, y = 0, w = 0, h = 0, text = "", background = False, font_size = 30, font = "Calibri", text_colour = (0,0,0)):
self.x = x
self.y = y
self.w = w
self.h = h
self.text_colour = text_colour
self.text = text
self.background = background
self.font = pg.font.Font(pg.font.match_font(font),font_size)
def Add_char(self,key):
if key == 8:
self.text = self.text[:-1]
else:
char = pg.key.name(key)
self.text += char
def Draw(self):
if self.background:
pg.draw.rect(win, self.background, (self.x,self.y,self.w,self.h))
obj = self.font.render(self.text,True,self.text_colour)
win.blit(obj,(self.x,self.y))
def Get_pos(self):
return (self.x,self.y)
name_Box = TextBox(x=100, y=200, w=150, h=40, background=(200,200,200))
Scenes = Scene()
next_scene_button = Button(400,400,100,50,"next scene")
click = False
mouse_pos = [0,0]
running = True
while running:
clock.tick(fps)
Scenes.Draw_Scene()
mouse_pos = pg.mouse.get_pos()
click = False
pg.display.update() #no diference between .flip() and .update()
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
running = False
if event.type == pg.MOUSEBUTTONDOWN:
click = True
if event.type == pg.KEYDOWN:
if Scenes.sceneNum == 1:
name_Box.Add_char(event.key)
The main thing to take away from this is to only use one pygame.display.flip(). Hopefully you can use this to improve your program