The desired behavior is:
When user hold the mouse on the button, the dark gray progress bar appears and starts to get incremented at a constant pace. I want to be able to determine how long it will take for it to completely fill (like 2 seconds).
If the mouse move out the button BEFORE the progress bar has reached 100%, the progress bar should go straight to 0%.
If the bar reaches 100%, the program should print something in the terminal.
Here is the code:
import sys
import pygame
import time
from pygame.locals import *
from os import path
pygame.init()
screen = pygame.display.set_mode((900, int(900 * (16 / 9))))
clock = pygame.time.Clock()
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
BACKGROUND_COLOR = (237, 225, 192)
LIGHT_GRAY = (60, 60, 60)
GRAY = (30, 30, 30)
class Button:
def __init__(self, screen, x, y, w, h, button_color_active, button_color_inactive, text, font, size = 50, text_color = BLACK):
self.screen = screen
self.game_folder = path.dirname(__file__)
self.font = path.join(self.game_folder, font + '.ttf')
self.x, self.y, self.w, self.h = x, y, w, h
self.button_color_active = button_color_active
self.button_color_inactive = button_color_inactive
self.text, self.size = text, size
self.text_color = text_color
self.button_rect = pygame.Rect(self.x, self.y, self.w, self.h)
self.button_font = pygame.font.Font(self.font, self.size)
self.label = self.button_font.render(self.text, 1, self.text_color)
def draw(self):
if self.button_rect.collidepoint(pygame.mouse.get_pos()):
#pygame.draw.rect(self.screen, self.button_color_inactive, self.button_rect)
for progress in range(42):
pygame.draw.rect(screen, LIGHT_GRAY, pygame.Rect(50,600,10*progress,80))
pygame.display.update()
else:
pygame.draw.rect(self.screen, self.button_color_active, self.button_rect)
self.screen.blit(self.label, (self.x + 20, self.y + 5))
def is_clicked(self, mouse_pos):
return bool(self.button_rect.collidepoint(mouse_pos))
def set_new_color(self, active_color, inactive_color):
self.button_color_active = active_color
self.button_color_inactive = inactive_color
button_start = Button(screen, 50, 600, 400, 80, GRAY, LIGHT_GRAY, 'START', 'roboto-black', 50, WHITE)
while True:
screen.fill(BACKGROUND_COLOR)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
#pygame.draw.rect(screen, GRAY, pygame.Rect(50,600,400,80))
#pygame.draw.rect(screen, LIGHT_GRAY, pygame.Rect(50,600,10*progress,80))
button_start.draw()
pygame.display.flip()
clock.tick(60)
a = str(input('shomething: '))
First you need a timer. You can use the dt (delta time) that pygame.clock.tick(fps) returns to increase a time variable. Do this only if the mouse is hovering over the button, otherwise reset the timer.
To calculate the width of the rect you can do this (proportionality):
width = time * coefficient
Here's a minimal example:
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
FONT = pg.font.Font(None, 36)
BACKGROUND_COLOR = (237, 225, 192)
LIGHT_GRAY = (120, 120, 120)
GRAY = (30, 30, 30)
# Button variables.
button_rect = pg.Rect(50, 100, 200, 80)
max_width = 200 # Maximum width of the rect.
max_time = 4 # Time after which the button should be filled.
# Coefficient to calculate the width of the rect for a given time.
coefficient = max_width / max_time
time = 0
dt = 0
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
mouse_pos = pg.mouse.get_pos()
if button_rect.collidepoint(mouse_pos):
# If mouse is over the button, increase the timer.
if time < max_time: # Stop increasing if max_time is reached.
time += dt
if time >= max_time:
time = max_time
else: # If not colliding, reset the time.
time = 0
width = time * coefficient
screen.fill(BACKGROUND_COLOR)
pg.draw.rect(screen, LIGHT_GRAY, (51, 100, width, 80))
pg.draw.rect(screen, GRAY, button_rect, 2)
txt = FONT.render(str(round(time, 2)), True, GRAY)
screen.blit(txt, (20, 20))
pg.display.flip()
dt = clock.tick(60) / 1000
pg.quit()
Related
I want to display text on the text box that says if I hit and how much damage I do and vice versa for the enemy, but I just can't figure out how to make the text to display in this manner.
Here is the code I'm working on:
def textBox(textv):
lText = []
text = font.render(str(textv),True,(1,1,1))
lText.append(text)
if len(lText) >= 10:
lText.pop(9)
screen.blit(lText[0],(20,400))
screen.blit(lText[1],(20,380))
while True:
battle_screen()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.blit(enemy_background,(20,20))
player.drawPlayer()
enemy.newEnemy()
textBox("Daniel")
textBox("Jenny")
pygame.display.update()
Rendere the text an add the rendered text into a list:
text_surf_list = []
text_surf = font.render("Daniel", True, (255, 255, 0))
text_surf_list.append(text_surf)
text_surf = font.render("Jenny", True, (255, 255, 0))
text_surf_list.append(text_surf)
Define a rectangular area for the text box:
text_box_rect = pygame.Rect(20, 20, 250, 360)
Iterate through list in reversed order. Draw the text from the bottom up. Remove the text from the list if it is not in the box (see How to remove items from a list while iterating?):
text_y = box_rect.bottom - font.get_height()
for text_surf in reversed(text_surf_list[:]):
if text_y <= box_rect.top:
text_surf_list.remove(text_surf)
else:
surf.blit(text_surf, (box_rect.left + 10, text_y))
text_y -= font.get_height()
Set a temporary clipping area while drawing the text box withpygame.Surface.set_clip:
# set clipping
surf.set_clip(box_rect)
# draw text box
# [...]
# disable clipping
surf.set_clip(None)
Minimal example:
import pygame, random
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
def draw_scroll_text_box(surf, font, box_rect, text_surf_list):
surf.set_clip(box_rect)
text_y = box_rect.bottom - font.get_height() - 10
for text_surf in reversed(text_surf_list[:]):
if text_y <= box_rect.top:
text_surf_list.remove(text_surf)
else:
surf.blit(text_surf, (box_rect.left + 10, text_y))
text_y -= font.get_height()
pygame.draw.rect(surf, (164, 164, 164), box_rect, 5)
surf.set_clip(None)
font = pygame.font.SysFont(None, 50)
text_box_rect = pygame.Rect(20, 20, 250, 360)
text_surf_list = []
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, 200)
background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *background.get_size(), (32, 32, 32), (64, 64, 64)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
[pygame.draw.rect(background, color, rect) for rect, color in tiles]
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == timer_event:
names = ["Daniel", "Jenny", "Patrick", "Sandy", "Bob"]
text_surf = font.render(random.choice(names), True, (255, 255, 0))
text_surf_list.append(text_surf)
window.blit(background, (0, 0))
draw_scroll_text_box(window, font, text_box_rect, text_surf_list)
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()
I am learning the basics of pygame in my free time at work. I wanted to move the bottom boundary of my program up, but when I changed the boundary collision condition, the ball moves in a straight line instead of at an angle.
When I delete the 525 part of the condition in the bounceCircle definition, it moves as expected. When I place it back, it moves in a horizontal line.
import pygame
import sys
import random
import math
# Initalize the game engine
pygame.init()
# Define common colors:
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
# Set window size, title, and background color
(width, height) = (900, 600)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Ball Playground")
screen.fill(WHITE)
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# Ball class
class Particles():
def __init__(self, position, radius):
self.x = position[0]
self.y = position[1]
self.radius = radius
self.color = (BLUE)
# thickness = 0 means filled
# thickness > 0 thicker border
# thickness < 0 nothing
self.thickness = 1
self.speed = 0
self.angle = 0
# Definition for drawing circle
def drawCircle(self):
pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), self.radius, self.thickness)
# Definition for moving the circle
def moveCircle(self):
self.x += math.sin(self.angle) * self.speed
self.y -= math.cos(self.angle) * self.speed
# Definition for bouncing off of surfaces
def bounceCircle(self):
if (self.x > width - self.radius) or (self.x < self.radius):
self.angle = - self.angle
elif (self.y > height - self.radius) or (self.y < 525 - self.radius):
self.angle = math.pi - self.angle
ball = Particles((450, 300), 40)
ball.speed = 2
ball.angle = random.uniform(0, math.pi*2)
# --------- Main Program Loop ----------
while True:
# --- Main Event Loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
screen.fill(WHITE)
#--- Game Logic
ball.moveCircle()
ball.bounceCircle()
ball.drawCircle()
#--- Drawings
pygame.draw.line(screen, BLACK, [0, 525], [900, 525], 2)
# Prints tiny diaginal lines to mark surface
x1 = 0
x2 = 5
for i in range(0, width):
pygame.draw.line(screen, BLACK, [x1, 530], [x2, 525], 2)
x1 += 5
x2 += 5
pygame.display.flip()
clock.tick(60)
You need to edit the bounceCircle function to:
def bounceCircle(self):
if (self.x + self.radius > width ) or (self.x - self.radius < 0):
self.angle = - self.angle
elif (self.y + self.radius > (525)) or (self.y - self.radius < 0):
self.angle = math.pi - self.angle
Whole Code (fixed a few bugs):
import pygame
import sys
import random
import math
# Initalize the game engine
pygame.init()
# Define common colors:
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
# Set window size, title, and background color
(width, height) = (900, 600)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Ball Playground")
screen.fill(WHITE)
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# Ball class
class Particles():
def __init__(self, position, radius):
self.x = position[0]
self.y = position[1]
self.radius = radius
self.color = (BLUE)
# thickness = 0 means filled
# thickness > 0 thicker border
# thickness < 0 nothing
self.thickness = 1
self.speed = 0
self.angle = 0
# Definition for drawing circle
def drawCircle(self):
pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), self.radius, self.thickness)
# Definition for moving the circle
def moveCircle(self):
self.x += math.sin(self.angle) * self.speed
self.y -= math.cos(self.angle) * self.speed
print(self.angle, self.x, self.y)
# Definition for bouncing off of surfaces
def bounceCircle(self):
if (self.x > width - self.radius) or (self.x < self.radius):
self.angle = - self.angle
elif (self.y + self.radius > (height-100)) or (self.y - self.radius < 0):
self.angle = math.pi - self.angle
ball = Particles((450, 300), 40)
ball.speed = 20
ball.angle = random.uniform(0, math.pi*2)
print(ball.angle)
# --------- Main Program Loop ----------
while True:
# --- Main Event Loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
screen.fill(WHITE)
#--- Game Logic
ball.moveCircle()
ball.bounceCircle()
ball.drawCircle()
#--- Drawings
pygame.draw.line(screen, BLUE, [0, 525], [900, 525], 2)
# Prints tiny diaginal lines to mark surface
x1 = 0
x2 = 5
for i in range(0, width):
pygame.draw.line(screen, BLUE, [x1, 530], [x2, 525], 2)
x1 += 5
x2 += 5
pygame.display.flip()
clock.tick(60)
I am trying to build my first Platformer Game. So far, I have make moving left and right but unfortunately, I have encountered a error that I have not been able to fix when I implemented collisions and gravity. My player keeps on dissolving like spider man if it lands on the platform. The character is still existent, and lands on the platform, but unfortunately, he becomes invisible. There is no error message, and I suspect is has to do with the collision check.
hits = pygame.sprite.spritecollide(object, allPlatforms, False)
if hits:
object.rect.y = hits[0].rect.top + 1
object.vy = 0
print(object.rect.midbottom)
It prints out the Players location in the code, and the player is still existent and movable, but it just doesn't show. Is there something that I did that makes the character vanish?
import pygame
import random
WIDTH = 500
HEIGHT = 400
FPS = 30
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
playerImage = "blockBandit/BlockBandit.png"
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 50))
self.image = pygame.image.load(playerImage).convert()
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT / 2)
self.vx = 0
self.vy = 0
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((w, h))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Block Bandit")
clock = pygame.time.Clock()
allPlatforms = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
p1 = Platform(0, HEIGHT - 40, WIDTH, 40)
all_sprites.add(p1)
allPlatforms.add(p1)
def moveCharacter(object):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
object.vx += -2
if keys[pygame.K_RIGHT]:
object.vx += 2
object.vx = object.vx * 0.9
if (abs(object.vx) < 1):
object.vx = 0
if (abs(object.vx) > 10):
if(object.vx < 0):
object.vx = -10
else:
object.vx = 10
object.vy = object.vy + 1
object.rect.x += object.vx
object.rect.y += object.vy
hits = pygame.sprite.spritecollide(object, allPlatforms, False)
if hits:
object.rect.y = hits[0].rect.top + 1
object.vy = 0
print(object.rect.midbottom)
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
moveCharacter(player)
#Update State
all_sprites.update()
#Render
screen.fill(BLACK)
all_sprites.draw(screen)
#screen.blit(player.icon, (20, 40))
pygame.display.flip()
pygame.quit()
Am I doing something wrong? Thanks!
The y attribute of the rect is the same as the top coordinate, so you're setting the top of the player sprite to the top of the platform sprite here object.rect.y = hits[0].rect.top + 1. And if the platform comes later in the sprite group, it will be blitted after the player and the player won't be visible.
Just change that line to object.rect.bottom = hits[0].rect.top + 1.
So when I and my acquaintance were working in pygame, we came across a problem:Every time the progress bar reached over 100, it would crash and show us an error. The error code reads:
"Traceback (most recent call last):
File "C:/Users/Tip/Documents/loading bar/load.py", line 150, in <module>
loading(progress/2)
File "C:/Users/Tip/Documents/loading bar/load.py", line 60, in loading
screen.blit(text, (300, 100))
TypeError: argument 1 must be pygame.Surface, not str
libpng warning: iCCP: known incorrect sRGB profile".
And to help, here is the code:
import pygame
import random
pygame.init()
progress = 0
into = True
black = [0, 0, 0]
white = [255, 255, 255]
intoWhite = [249, 244, 244]
green = [0, 255, 0]
screenWidth = 600
screenHeigth = 450
size = [screenWidth, screenHeigth]
font = pygame.font.SysFont("Comic Sans MS", 25)
intoPic = pygame.image.load("images/Can You Surive Pic.png")
cory = "audio/Cory in the House - Opening Sequence.mp3"
coryPic = pygame.image.load("images/CoryBaxterFull.png")
coryMusicBool = False
coryPicBool = False
basic = "audio/basic song.mp3"
shrekPicBool = False
shrekMusicBool = False
shrek = "audio/Shrek's Fairytale Freestyle.mp3"
shrekPic = pygame.image.load("images/shrek.png")
clock = pygame.time.Clock()
clock.tick(10)
count = 0
escPressed = False
screen = pygame.display.set_mode(size)
pygame.display.set_caption('Loading...')
escMessageText = "Press Esc to cancel"
escMessage = font.render(escMessageText, False, white)
escMessageText_2 = "You Can't Leave"
escMessage_2 = font.render(escMessageText_2, False, white)
def textobjecte(text, color, size):
if size == "small":
textsuraface = font.render(text, True, color)
return textsuraface, textsuraface.get_rect()
def loading(progress):
text = ""
if progress < 100:
text = font.render("loading: " + str(int(progress)) + "%", True, green)
screen.blit(text, (300, 100))
def message_to_screen(msg, color, y_displace, size="small"):
textsurf, textrect = textobjecte(msg, color, size)
textrect.center = (screenWidth/2), (screenHeigth/2) + y_displace
screen.blit(textsurf, textrect)
def playcory():
pygame.mixer.music.load(cory)
pygame.mixer.music.play(-1)
def playshrek():
pygame.mixer.music.load(shrek)
pygame.mixer.music.play(-1)
def basicsong():
pygame.mixer.music.load(basic)
pygame.mixer.music.play(-1)
basicsong()
while into == True:
pygame.event.pump()
screen.fill(intoWhite)
screen.blit(intoPic, (75, 0))
intoKey = pygame.key.get_pressed()
pygame.display.flip()
if intoKey[pygame.K_SPACE]:
into = False
while progress/2 < 100:
timeCount = random.randint(1, 10000)
increase = random.randint(1, 10)
progress += increase/10000
screen.fill(black)
pygame.event.pump()
pygame.draw.rect(screen, white, [300, 50, 200, 50])
pygame.draw.rect(screen, black, [301, 51, 198, 48])
if (progress/2) > 100:
pygame.draw.rect(screen, white, [302, 52, 196, 46])
else:
pygame.draw.rect(screen, white, [302, 52, progress, 46])
if coryMusicBool == True:
pygame.mixer.music.stop()
playcory()
coryMusicBool = False
if coryPicBool== True:
screen.blit(coryPic, (0, 0))
if shrekMusicBool == True:
pygame.mixer.music.stop()
playshrek()
shrekMusicBool = False
if shrekPicBool == True:
screen.blit(shrekPic, (100, 0))
if escPressed == False:
screen.blit(escMessage, (50, 50))
if escPressed == True:
screen.blit(escMessage_2, (50, 50))
keys = pygame.key.get_pressed()
if keys[pygame.K_ESCAPE]:
pygame.mixer.music.stop()
progress = 0
escPressed = True
keys2 = pygame.key.get_pressed()
if keys2[pygame.K_c]:
coryMusicBool = True
coryPicBool = True
keys3 = pygame.key.get_pressed()
if keys3[pygame.K_s]:
shrekPicBool = True
shrekMusicBool = True
if progress/2 >= 100:
progress = 200
loading(progress/2)
pygame.display.flip()
Our code is supposed to be a loading bar. The text that shows the problem of the progression is in the loading x % part.
Please help, and thank you.
Try This
import pygame
import random
pygame.init()
progress = 0
into = True
black = [0, 0, 0]
white = [255, 255, 255]
intoWhite = [249, 244, 244]
green = [0, 255, 0]
screenWidth = 600
screenHeigth = 450
size = [screenWidth, screenHeigth]
font = pygame.font.SysFont("Comic Sans MS", 25)
intoPic = pygame.image.load("images/Can You Surive Pic.png")
cory = "audio/Cory in the House - Opening Sequence.mp3"
coryPic = pygame.image.load("images/CoryBaxterFull.png")
coryMusicBool = False
coryPicBool = False
basic = "audio/basic song.mp3"
shrekPicBool = False
shrekMusicBool = False
shrek = "audio/Shrek's Fairytale Freestyle.mp3"
shrekPic = pygame.image.load("images/shrek.png")
clock = pygame.time.Clock()
clock.tick(10)
count = 0
escPressed = False
screen = pygame.display.set_mode(size)
pygame.display.set_caption('Loading...')
escMessageText = "Press Esc to cancel"
escMessage = font.render(escMessageText, False, white)
escMessageText_2 = "You Can't Leave"
escMessage_2 = font.render(escMessageText_2, False, white)
def textobjecte(text, color, size):
if size == "small":
textsuraface = font.render(text, True, color)
return textsuraface, textsuraface.get_rect()
def loading(progress):
text = ""
if progress < 101:
text = font.render("loading: " + str(int(progress)) + "%", True, green)
screen.blit(text, (300, 100))
def message_to_screen(msg, color, y_displace, size="small"):
textsurf, textrect = textobjecte(msg, color, size)
textrect.center = (screenWidth/2), (screenHeigth/2) + y_displace
screen.blit(textsurf, textrect)
def playcory():
pygame.mixer.music.load(cory)
pygame.mixer.music.play(-1)
def playshrek():
pygame.mixer.music.load(shrek)
pygame.mixer.music.play(-1)
def basicsong():
pygame.mixer.music.load(basic)
pygame.mixer.music.play(-1)
basicsong()
while into == True:
pygame.event.pump()
screen.fill(intoWhite)
screen.blit(intoPic, (75, 0))
intoKey = pygame.key.get_pressed()
pygame.display.flip()
if intoKey[pygame.K_SPACE]:
into = False
while progress/2 < 100:
timeCount = random.randint(1, 10000)
increase = random.randint(1, 10)
progress += increase/10000
screen.fill(black)
pygame.event.pump()
pygame.draw.rect(screen, white, [300, 50, 200, 50])
pygame.draw.rect(screen, black, [301, 51, 198, 48])
if (progress/2) > 100:
pygame.draw.rect(screen, white, [302, 52, 196, 46])
else:
pygame.draw.rect(screen, white, [302, 52, progress, 46])
if coryMusicBool == True:
pygame.mixer.music.stop()
playcory()
coryMusicBool = False
if coryPicBool== True:
screen.blit(coryPic, (0, 0))
if shrekMusicBool == True:
pygame.mixer.music.stop()
playshrek()
shrekMusicBool = False
if shrekPicBool == True:
screen.blit(shrekPic, (100, 0))
if escPressed == False:
screen.blit(escMessage, (50, 50))
if escPressed == True:
screen.blit(escMessage_2, (50, 50))
keys = pygame.key.get_pressed()
if keys[pygame.K_ESCAPE]:
pygame.mixer.music.stop()
progress = 0
escPressed = True
keys2 = pygame.key.get_pressed()
if keys2[pygame.K_c]:
coryMusicBool = True
coryPicBool = True
keys3 = pygame.key.get_pressed()
if keys3[pygame.K_s]:
shrekPicBool = True
shrekMusicBool = True
if progress/2 >= 100:
progress = 200
loading(progress/2)
pygame.display.flip()
For the SRGb error add this to your code pngcrush -ow -rem allb -reduce file.png. its from this link. libpng warning: iCCP: known incorrect sRGB profile
For your game quitting at 100% its because your while loop ends when you reach 100% so you should make it so the draw screen statement is in a separate loop from the draw the loading bar one
In the loading function, text is either a string if the progress is >= 100 or a pygame.Surface if the progress is < 100.
Since the pygame.Surface.blit method only takes a pygame.Surface as the first argument, a TypeError will be raised when you pass a string.
A simple fix would be to blit the text surface in the if clause:
def loading(progress):
if progress < 100:
text = font.render("loading: " + str(int(progress)) + "%", True, green)
screen.blit(text, (300, 100))
You could also blit a transparent surface or do text = font.render("", True, green), but that would be pointless. Just don't blit anything when the progress is >= 100.
This question already has answers here:
Pygame how to let balls collide
(2 answers)
pygame Get the balls to bounce off each other
(1 answer)
Closed 2 years ago.
I am trying to create my first game, where I have successfully added a bouncing ball and another ball around the mouse-pointer. The collision between these two circles works fine except sometimes the circles intersects each other hugely and the collision does not occur in a single frame, and some strange behaviour thereafter. How do I fix this?
import pygame
from pygame.locals import *
import numpy as np
# Define the colors we will use in RGB format
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
BLUE = ( 0, 0, 255)
GREEN = ( 0, 255, 0)
RED = (255, 0, 0)
width = 800
height = 600
radius = 40
mRadius = 60
base = 20
g = 0.2
pygame.init()
screen = pygame.display.set_mode((width,height))
pygame.display.set_caption('Testing')
clock = pygame.time.Clock()
class Circle:
def __init__(self):
self.pos = np.array([100,100])
self.velocity = np.array([2,0])
def upgrade(self,mouse):
self.pos = np.add(self.velocity,self.pos)
if ((self.pos[0] > width - radius - 1) or (self.pos[0] < 0 + radius)):
self.velocity[0] *= -1
if self.pos[1] > height - radius - base - 1:
self.velocity[1] *= -1
#print(str(self.velocity[1])+"\t"+str(self.pos[1]))
else:
self.velocity = np.add(self.velocity,[0,g])
if ((radius + mRadius)**2 >= ((self.pos[0] - mouse[0])**2 +(self.pos[1] - mouse[1])**2)):
self.pos = np.subtract(self.pos,self.velocity)
lx = self.pos[0] - mouse[0]
ly = self.pos[1] - mouse[1]
A = (lx**2 - ly**2)/(lx**2 + ly**2)
B = 2*lx*ly/(lx**2 + ly**2)
M = np.array([[A,B],[B,(-1)*A]])
self.velocity = list((-1)*M.dot(self.velocity))
print(str(lx)+"\t"+str(ly)+"\t"+str(mouse))
pygame.draw.circle(screen, GREEN, [int(self.pos[0]),int(self.pos[1])], radius)
return True
def main():
mouse = [100,100]
running = True
ball = Circle()
while running:
(mouse[0],mouse[1]) = pygame.mouse.get_pos()
screen.fill(WHITE)
pygame.draw.circle(screen, BLUE, mouse, mRadius)
running = ball.upgrade(mouse)
pygame.draw.rect(screen,RED,(0,height-base,width,base))
pygame.display.update()
clock.tick(120)
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN and event.key == K_ESCAPE:
running = False
pygame.display.quit()
if __name__ == '__main__':
main()
Here is the github link