This question already has answers here:
How to rotate an image(player) to the mouse direction?
(2 answers)
Still Having Problems With Rotating Cannon's Properly Towards The Player Pygame
(1 answer)
How do I make image rotate with mouse python [duplicate]
(1 answer)
How do I make my player rotate towards mouse position?
(1 answer)
Closed 4 months ago.
I have a shotgun attached to my player. I want this shotgun to point at the cursor. Ive tried searching this up on google, but each time i tried the answer my shotgun kinda moved and rotated. How can i make it so it only rotates?
My code:
import pygame
import numpy
import math
import random
screen = pygame.display.set_mode((1280, 720))
class Player:
def __init__(self, pos: tuple, gravity: tuple, sprite: pygame.Surface, maxVel, minVel, maxVelY):
self.pos = pos
self.velocity = (0,0)
self.gravity = gravity
self.sprite = sprite
self.maxVel = maxVel
self.minVel = minVel
self.maxVelY = maxVelY
def addForce(self, force: tuple):
self.velocity = numpy.add(self.velocity, force)
def resetVelocity(self):
self.velocity = (0,0)
def update(self):
global scene, highscore, score, playerrect
self.velocity = numpy.add(self.velocity, (0, self.gravity/10))
if self.velocity[0] > self.maxVel:
self.velocity[0] = self.maxVel
elif self.velocity[0] < self.minVel:
self.velocity[0] = self.minVel
if self.velocity[1] > self.maxVelY:
self.velocity[1] = self.maxVelY
self.pos = numpy.subtract(self.pos, self.velocity)
if self.pos[1] < -50:
self.pos[1] += 770
elif self.pos[1] > 770:
scene = menu
self.pos = (self.sprite.get_rect(center=(1280/2, 720/2))[0], self.sprite.get_rect(center=(1280/2, 720/2))[1])
if highscore < score:
highscore = score
if self.pos[0] < 0:
self.pos[0] += 1330
if self.pos[0] > 1280:
self.pos[0] -= 1330
def draw(self): # Here is the problem
global shotgun
screen.blit(self.sprite, self.pos)
mouse_x, mouse_y = pygame.mouse.get_pos()
rel_x, rel_y = mouse_x - self.pos[0], mouse_y - self.pos[1]
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
rotshotgun = pygame.transform.rotate(shotgun, int(angle)) # Im thinking this doesnt work correctly
screen.blit(rotshotgun, (self.pos[0]+50, self.pos[1]+50))
class Particle:
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
def draw(self):
pygame.draw.rect(screen, self.color, (self.x, self.y, 10, 10))
player = pygame.image.load("other/player.png").convert_alpha()
player = pygame.transform.scale(player, (100, 100))
player = Player((590, 310), -9.81, player, 10, -10, 20)
clock = pygame.time.Clock()
new_velocity = (0,0)
game = 0
menu = 1
scene = menu
shotgun = pygame.image.load("other/shotgun.png").convert_alpha()
shotgun = pygame.transform.scale(shotgun, (83, 66))
pygame.font.init()
font = pygame.font.Font("font/AlfaSlabOne-Regular.ttf", 150)
font2 = pygame.font.Font("font/PoorStory-Regular.ttf", 50)
font3 = pygame.font.SysFont("Arial", 350)
font4 = pygame.font.Font("font/Nunito-Black.ttf", 75)
titel = font.render("ShootShot", True, (0, 255, 0))
clicktext = font2.render("Click to start!", True, (0,0,0))
scoretext = font3.render("0", True, (0,0,0))
with open("other/highscore.txt", "r") as f:
highscore = f.read()
highscore.replace("\n", "")
highscore = int(highscore)
highscoretext = font4.render(f"Highscore: {highscore}", True, (0,0,0))
coins = []
for x in range(6):
coins.append(pygame.transform.scale(pygame.image.load(f"coin/coin{x+1}.png"), (50, 50)))
number = 0
particles = []
colors = [(255, 0, 0),
(0, 0, 255),
(255, 255, 0),
(255, 0, 255),
(0, 255, 255),
(255, 125, 0),
(125, 255, 0),
(0, 255, 125),
(0, 125, 255),
(125, 0, 255)]
r = True
scoretext.set_alpha(75)
scoretext = scoretext.convert_alpha()
coinLocation = (random.randint(0, 1280), random.randint(0, 720))
titlerect = titel.get_rect(center=(1280/2, 150))
scorerect = scoretext.get_rect(center=(1280/2, 720/2))
highscorerect = highscoretext.get_rect(center=(1280/2, 50))
number2 = 0
currentCoin = 0
coin = pygame.Rect(coinLocation[0], coinLocation[1], 50, 50)
score = 0
while r:
clock.tick(45)
screen.fill((255,255,255))
mousePos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
r = False
if event.type == pygame.MOUSEBUTTONDOWN:
if scene == game:
new_velocity = numpy.subtract(player.pos, mousePos)*-1
player.resetVelocity()
player.addForce(new_velocity/10)
else:
scene = game
score = 0
new_velocity = numpy.subtract(player.pos, mousePos) * -1
player.resetVelocity()
player.addForce(new_velocity / 10)
screen.blit(scoretext, scorerect)
player.draw()
if scene == game:
player.update()
screen.blit(coins[currentCoin], coinLocation)
number2 += 0.15
currentCoin = math.ceil(number2)
if currentCoin > 5:
currentCoin = 0
number2 = -1
playerrect = pygame.Rect(player.pos[0], player.pos[1], 50, 50)
if coin.colliderect(playerrect):
score += 1
scoretext = font3.render(str(score), True, (0, 0, 0))
scoretext.set_alpha(75)
coinLocation = (random.randint(0, 1280), random.randint(0, 720))
coin = pygame.Rect(coinLocation[0], coinLocation[1], 50, 50)
elif scene == menu:
highscoretext = font4.render(f"Highscore: {highscore}", True, (0, 0, 0))
scoretext = font3.render("0", True, (0, 0, 0))
scoretext = scoretext.convert_alpha()
scoretext.set_alpha(75)
score = 0
screen.blit(titel, titlerect)
number += 0.1
clickTextAddY = math.cos(number)*30
screen.blit(clicktext, (525, 600-clickTextAddY))
particles.append(Particle(random.randint(250, 1075), random.randint(100, 200), random.choice(colors)))
for particle in particles:
particle.draw()
if len(particles) > 70:
particles.pop(random.randint(0, len(particles)-1))
screen.blit(highscoretext, highscorerect)
pygame.display.flip()
with open("other/highscore.txt", "w") as f:
f.write(str(highscore))
pygame.quit()
I hope anyone can help me with this.
As i already said, i have tried searcing it up. The shotgun pointed to my mouse, but it also moved.
Related
I have recently been trying to make a Snake game in python. The program shows no errors at all, yet the sprites do not draw when I run the program. I've tried to run the program in Python instead on in Visual Studio Code, I tried to change the name of Variables, I have reviewed the code many times as well. Please Help.
import pygame
import sys
import random
#Snake
class snake(object):
def __init__(self):
self.length = 1
self.positions = [((Screen_Width / 2), (Screen_Height / 2))]
self.direction = random.choice([Up, Down, Left, Right])
self.color = (0, 0, 0)
def head_position(self):
return self.positions[0]
def turn(self,point):
if self.length > 1 and (point[0] * -1, point[1] * -1) == self.direction:
return
else:
self.direction = point
def move(self):
cur = self.head_position()
x, y = self.direction
new = (((cur[0] + (x * Grid_Size)) % Screen_Width), (cur[1] + (y * Grid_Size)) % Screen_Height)
if len(self.positions) >2 and new in self.positions[2:]:
self.reset()
else:
self.positions.insert(0, new)
if len(self.positions) > self.length:
self.positions.pop()
def reset(self):
self.length = 1
self.positions = [((Screen_Width / 2), (Screen_Height / 2))]
self.direction = random.choice([Up, Down, Left, Right])
def draw(self, surface):
for p in self.positions:
r = pygame.Rect((p[0], p[1]), (Grid_Size, Grid_Size))
pygame.draw.rect(surface, self.color, r)
pygame.draw.rect(surface, (93, 216, 228), r, 1)
def handle_keys(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
self.turn(Up)
elif event.key == pygame.K_DOWN:
self.turn(Down)
elif event.key == pygame.K_LEFT:
self.turn(Left)
if event.key == pygame.K_RIGHT:
self.turn(Right)
#Apple
class apple(object):
def __init__(self):
self.position = (0, 0)
self.color = (192, 7, 7)
self.randomize_position()
def randomize_position(self):
self.position = (random.randint(0, Grid_Width - 1) * Grid_Size, random.randint(0, Grid_Height -1) * Grid_Size)
def draw(self, surface):
r = pygame.Rect((self.position[0], self.position[1]), (Grid_Size, Grid_Size))
pygame.draw.rect(surface, self.color, r)
pygame.draw.rect(surface, (9, 196, 46), r, 1)
#Draw The Grid
def draw_grid(surface):
for y in range(0, int(Grid_Height)):
for x in range(0, int(Grid_Width)):
if (x + y) % 2 == 0:
r = pygame.Rect((x*Grid_Size, y*Grid_Size), (Grid_Size, Grid_Size))
pygame.draw.rect(surface, (9, 196, 46), r)
else:
rr = pygame.Rect((x*Grid_Size, y*Grid_Size), (Grid_Size, Grid_Size))
pygame.draw.rect(surface, (7, 138, 33), rr)
#Screen
Screen_Width = 500
Screen_Height = 500
Grid_Size = 20
Grid_Width = Screen_Height / Grid_Size
Grid_Height = Screen_Width / Grid_Size
#Movement
Up = (0, -1)
Down = (0, 1)
Left = (-1, 0)
Right = (1, 0)
#Main Game Loop
def Main():
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((Screen_Width, Screen_Height), 0, 32)
surface = pygame.Surface(screen.get_size())
surface = surface.convert()
draw_grid(surface)
the_snake = snake()
food = apple()
my_font = pygame.font.SysFont("monospace", 16)
score = 0
#Handling Events.
while (True):
clock.tick(10)
the_snake.handle_keys()
draw_grid(surface)
the_snake.move()
if the_snake.head_position() == food.position:
snake.length += 1
score += 1
food.randomize_position()
screen.blit(surface, (0, 0))
text = my_font.render("Score {0}".format(score), 1, (0, 0, 0))
screen.blit(text, (5, 10))
pygame.display.update()
#Call On The Main Function.
Main()
dear programmer
I think the error in your code is that you defined the function to draw the snake and the apple but you forgot to call them so you just need to add this code to the main loop and it will run fine
the_snake.draw(surface)
food.draw(surface)
I'm trying my best to make a dino game replica and I'm stuck at increasing the speed of the obstacles that comes towards the character. The speed of 5 just seems to be the magic number but when I change it to six the rock doesn't get detected and ultimately doesn't spawn the next rock.
I don't know why.
there are no errors except for when the rock doesn't get spawned and I get an index out of range:
Traceback (most recent call last):
File "C:\Users\austi\OneDrive\Desktop\scroller game\main.py", line 109, in <module>
main()
File "C:\Users\austi\OneDrive\Desktop\scroller game\main.py", line 102, in main
if game.collide():
File "C:\Users\austi\OneDrive\Desktop\scroller game\main.py", line 71, in collide
olh = self.obstacles[0].hitBox[0]
IndexError: list index out of range
here is what I got:
main.py
import pygame
import math
import random
from player import Player
from objects import Obstacle
WIDTH, HEIGHT = 700, 400
class Game:
def __init__(self, playerSprite=None, obSprite= None):
self.playerSprite = playerSprite
self.obSprite = obSprite
self.player = Player(50, 50, 50, 50, 8, (0, 0, 0), None)
self.obstacle = Obstacle(1, (800, 350, 50, 50), 5, None)
self.obstacles = [self.obstacle]
self.spawnGap = -100
self.speed = 5
def spawn(self):
for obstacle in self.obstacles:
#if its at the specific spot than spawn a rock
if obstacle.pos.x + obstacle.w == WIDTH/2 + self.spawnGap:
#get shape of rock
type = round(random.randint(0, 3))
rect = (700, 350, 50, 50)
if self.obSprite != None:
self.obSprite = pygame.transform.scale(self.obSprite, (50, 50))
if type == 1:
rect = (700, 350, 25, 50)
if self.obSprite != None:
self.obSprite = pygame.transform.scale(self.obSprite, (25, 50))
if type == 2 :
rect = (700, 375, 50, 25)
if self.obSprite != None:
self.obSprite = pygame.transform.scale(self.obSprite, (50, 25))
if type == 3:
rect = (700, 350, 75, 50)
if self.obSprite != None:
self.obSprite = pygame.transform.scale(self.obSprite, (75, 50))
#increase the place in which the rock spawns
self.spawnGap += 10
#create a new obstacle and append it to the obstacle array
self.obstacle = Obstacle(type, rect, 5, None)
self.obstacles.append(self.obstacle)
#delete obstacle when its at the end
if obstacle.pos.x < -obstacle.w:
index = self.obstacles.index(obstacle)
del self.obstacles[index]
def draw(self, win):
self.spawn()
self.hitBoxes()
self.player.draw(window)
for obstacle in self.obstacles:
obstacle.draw(window)
def collide(self):
plh = self.player.hitBox[0]
prh = self.player.hitBox[0] + self.player.hitBox[2]
pth = self.player.hitBox[1]
pbh = self.player.hitBox[1] + self.player.hitBox[3]
olh = self.obstacles[0].hitBox[0]
orh = self.obstacles[0].hitBox[0] + self.obstacles[0].hitBox[2]
oth = self.obstacles[0].hitBox[1]
obh = self.obstacles[0].hitBox[1] + self.obstacles[0].hitBox[3]
if prh >= olh and plh <= orh:
if pbh >= oth:
return True
else:
return False
def hitBoxes(self):
key = pygame.key.get_pressed()
if key[pygame.K_a]:
self.player.showHitBoxes = True
for obstacle in self.obstacles:
obstacle.showHitBoxes = True
if key[pygame.K_s]:
self.player.showHitBoxes = False
for obstacle in self.obstacles:
obstacle.showHitBoxes = False
def main():
done = False
pressed = False
game = Game()
time = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
window.fill((255, 255, 255))
game.draw(window)
if game.collide():
done = True
pygame.draw.line(window, (255, 0, 0), (WIDTH/2, 0), (WIDTH/2, HEIGHT))
pygame.draw.line(window, (0, 0, 255), (WIDTH/2 + game.spawnGap, 0), (WIDTH/2 + game.spawnGap, HEIGHT))
pygame.display.update()
time.tick(60)
pygame.quit()
main()
objects.py
import pygame
from pygame.math import Vector2
class Obstacle:
def __init__(self, type, rect, speed, rockSprite=None):
self.obSprite = rockSprite
self.xSpawn = rect[0]
self.ySpawn = rect[1]
self.pos = Vector2(self.xSpawn, self.ySpawn)
self.w = rect[2]
self.h = rect[3]
self.type = type
self.speed = speed
self.hitBox = ()
self.showHitBoxes = False
def draw(self, win):
self.hitBox = (self.pos.x, self.pos.y, self.w, self.h)
if self.showHitBoxes:
pygame.draw.rect(win, (255, 0, 0), self.hitBox, 2)
if self.obSprite != None:
win.blit(self.obSprite, self.pos)
else:
pygame.draw.rect(win, (0, 0, 0), (self.pos.x, self.pos.y, self.w, self.h))
self.update()
def update(self):
self.pos.x -= self.speed
player.py
import pygame
from pygame.math import Vector2
WIDTH, HEIGHT = 700, 400
class Player:
def __init__(self, x, y, w, h, jumpVel, color, sprite=None):
self.playerSprite = sprite
self.x = x
self.y = y
self.w = w
self.h = h
self.pos = Vector2(self.x, self.y)
self.color = color
self.gravity = 0.3
self.vel = self.gravity
self.jVel = jumpVel
self.touching_surface = False
self.canJump = True
self.jumping = False
self.hitBox = ()
self.showHitBoxes = False
def draw(self, win):
self.hitBox = (self.pos.x + 0, self.pos.y + 10, 50, 30)
if self.showHitBoxes:
pygame.draw.rect(win, (255, 0, 0), self.hitBox, 2)
if self.playerSprite != None:
win.blit(self.playerSprite, self.pos)
else:
pygame.draw.rect(win, (255, 0, 0), (self.pos.x, self.pos.y, 50, 50))
self.update()
def update(self):
mouse = pygame.mouse.get_pressed()
if self.pos.y + self.h >= HEIGHT:
self.touching_surface = True
self.vel = 0
self.pos.y = HEIGHT - self.h
else:
self.touching_surface = False
self.vel += self.gravity
if self.pos.x <= 0:
self.pos.x = 0
elif self.pos.x + self.w >= WIDTH:
self.pos.x = WIDTH - self.w
if self.touching_surface:
self.canJump = True
else:
self.canJump = False
if mouse[0] == 1 and self.canJump and not self.jumping:
self.jumping = True
self.canJump = False
self.vel = -self.jVel
if mouse[0] == 0:
self.jumping = False
self.pos.y += self.vel
and I suspect the issue is in the spawn function in the Game class in main.py
I've been trying to work on this for a couple days now and I still cannot solve my issue.
The problem is the condition
if obstacle.pos.x + obstacle.w == WIDTH/2 + self.spawnGap:
# [...]
This condition is only True when the obstacle is exactly at a certain position. If the speed changes, the obstacle does not exactly hit the position.
Test on a small range instead of a position. e.g.:
right = obstacle.pos.x + obstacle.w
target = WIDTH/2 + self.spawnGap
if traget <= right < traget + speed:
# [...]
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Closed 1 year ago.
I have been trying to solve this for weeks. This is a free-falling pit game, where my character (in this case a chimpanzee png) falls from the top of the screen to the bottom while trying to dodge the random black circles. I have tried so many angles at tackling this, I have tried the standard collision I was taught (pygame.sprite.groupcollide(Group1, Group2, False, True, collided = None) I have tried doing collisions with the colour black only, different formats of spawning my image and all that, and I haven't been able to find anything that works with my code. It has resulted in the code being very messy. I have tried to clean it up for this, but it still might be hard to understand, but if anybody has any solution to this, please let me know as I have been stumped for weeks. I just want the game to close or "game over" when they touch a circle Code:
import sys
import pygame as pg
RED = (255, 0, 0)
GRAY = (150, 150, 150)
GREEN =(34, 177, 76)
BLACK = (0,0,0)
import random
import math
def main():
width, height = 1024, 768
hbox, vbox = 80, 80
w, h = 640, 240
screen = pg.display.set_mode((width, height))
BG = pg.image.load('jungle.jpg').convert()
img = pg.image.load('MONKEY.png')
img = pg.transform.scale(img, (80, 80))
img.convert()
rect = img.get_rect()
rect.center = w//2, h//2
clock = pg.time.Clock()
Score = 0
class Circle(pg.sprite.Sprite):
def __init__(self):
#You can initialise the size to a random value
self.pos = [random.randint(0, 1000), random.randint(180, 600)]
self.color = (0,0, 0)
self.radius = 20
def draw(self):
pg.draw.circle(screen, self.color, (self.pos[0], self.pos[1]), self.radius)
circles = []
for i in range(20):
circles.append(Circle())
def checkIntersection(c1, c2):
dx = c1.pos[0] - c2.pos[0]
dy = c1.pos[1] - c2.pos[1]
d = math.hypot(dx, dy)
if d < c1.radius + c2.radius:
return True
return False
for i in range(19):
while checkIntersection(circles[i], circles[i + 1]):
circles[i].pos = random.randint(0, 1000), random.randint(0, 700)
velocity = (0, 0)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
keys = pg.key.get_pressed()
# booster
move = 8 if keys[pg.K_LSHIFT] else 4
if keys[pg.K_a]: #to move left
rect.x -= move
if rect.x < 0 : rect.x = 0
if keys[pg.K_d]: #to move right
rect.x += move
if rect.x > width-hbox : rect.x = width - hbox
Score += 1
rect.y += 2.5
screen.blit(BG, (0,0))
screen.blit(img,rect)
pg.draw.rect(screen, RED, rect, 1)
pg.draw.polygon(screen, GREEN, ((1024,768), (0,768), (0,640),(1024,640)))
font = pg.font.SysFont("comicsansms", 45)
text = font.render (" " + str(Score), 1, BLACK)
screen.blit(text,(480,700))
pg.event.get()
for circle in circles:
circle.draw()
pg.display.update()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()
Use a "mask" collision. See How can I made a collision mask? and Pygame mask collision
Create a Sprite class with mask (see pygame.mask.from_surface):
class Circle(pg.sprite.Sprite):
def __init__(self):
super().__init__()
self.pos = [random.randint(0, 1000), random.randint(180, 600)]
self.color = (0,0, 0)
self.radius = 20
self.image = pg.Surface((self.radius*2, self.radius*2), pg.SRCALPHA)
pg.draw.circle(self.image , self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = self.pos)
self.mask = pg.mask.from_surface(self.image)
Create a Sprite class for the player (also with a mask)
class Player(pg.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pg.image.load('MONKEY.png')
self.image = pg.transform.scale(self.image, (80, 80)).convert()
self.rect = self.image.get_rect()
self.rect.center = x, y
self.mask = pg.mask.from_surface(self.image)
Manage the Sprites in pygame.sprite.Group and use pygame.sprite.spritecollide and pygame.sprite.collide_mask() for the collision test:
if pg.sprite.spritecollide(player, circles, False, collided = pg.sprite.collide_mask):
done = True
Complete example:
import sys
import pygame as pg
RED = (255, 0, 0)
GRAY = (150, 150, 150)
GREEN =(34, 177, 76)
BLACK = (0,0,0)
import random
import math
class Circle(pg.sprite.Sprite):
def __init__(self):
super().__init__()
self.pos = [random.randint(0, 1000), random.randint(180, 600)]
self.color = (0,0, 0)
self.radius = 20
self.image = pg.Surface((self.radius*2, self.radius*2), pg.SRCALPHA)
pg.draw.circle(self.image , self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = self.pos)
self.mask = pg.mask.from_surface(self.image)
class Player(pg.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pg.image.load('MONKEY.png')
self.image = pg.transform.scale(self.image, (80, 80)).convert()
self.rect = self.image.get_rect()
self.rect.center = x, y
self.mask = pg.mask.from_surface(self.image)
def main():
width, height = 1024, 768
hbox, vbox = 80, 80
w, h = 640, 240
screen = pg.display.set_mode((width, height))
BG = pg.image.load('jungle.jpg').convert()
clock = pg.time.Clock()
Score = 0
player = Player(w//2, h//2)
all_sprites = pg.sprite.Group(player)
circles = pg.sprite.Group()
for i in range(20):
circle = Circle()
circles.add(circle)
all_sprites.add(circle)
def checkIntersection(c1, c2):
dx = c1.pos[0] - c2.pos[0]
dy = c1.pos[1] - c2.pos[1]
d = math.hypot(dx, dy)
if d < c1.radius + c2.radius:
return True
return False
c = circles.sprites()
for i in range(19):
while checkIntersection(c[i], c[i + 1]):
c[i].pos = random.randint(0, 1000), random.randint(0, 700)
velocity = (0, 0)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
keys = pg.key.get_pressed()
# booster
move = 8 if keys[pg.K_LSHIFT] else 4
if keys[pg.K_a]: #to move left
player.rect.x -= move
if player.rect.x < 0 : player.rect.x = 0
if keys[pg.K_d]: #to move right
player.rect.x += move
if player.rect.x > width-hbox : player.rect.x = width - hbox
Score += 1
player.rect.y += 2.5
screen.blit(BG, (0,0))
pg.draw.rect(screen, RED, player.rect, 1)
pg.draw.polygon(screen, GREEN, ((1024,768), (0,768), (0,640),(1024,640)))
font = pg.font.SysFont("comicsansms", 45)
text = font.render (" " + str(Score), 1, BLACK)
screen.blit(text,(480,700))
pg.event.get()
all_sprites.draw(screen)
pg.display.update()
clock.tick(30)
if pg.sprite.spritecollide(player, circles, False, collided = pg.sprite.collide_mask):
done = True
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()
import pygame #importing the pygame library
pygame.init()
all_sprites = pygame.sprite.Group()
obstacle_group = pygame.sprite.Group()
player_group = pygame.sprite.Group()
defines the sprite groups we'll be calling on later
####Variables
width, height = 626, 375
fontObj = pygame.font.Font('Alsina Ultrajada.TTF', 16)
pygame.display.set_caption("side scroller")
screen = pygame.display.set_mode((width, height))
bg = pygame.image.load("achtergrondPixel.png")
gameOver = pygame.image.load("gameOver.png")
R_char = pygame.transform.scale(pygame.image.load("character.png"), (100, 100))
L_char = pygame.transform.flip((R_char), True, False)
char = R_char
jade = (55, 255, 20)
red = (255, 0, 0)
hitbox = (150, 200, 100, 100)
here we are making our player class, first we are initializing our player
class Player(pygame.sprite.Sprite): #making a class for our character so we can easily call the variables
def __init__(self, x, y, width, height, pos):
global player_group
super().__init__(player_group, all_sprites)
self.x = x
self.y = y
self.width = width
self.height = height
self.charFlip = False
self.isJump = False
self.jumpCount = 10
self.isFalling = False
self.fallCount = int(1)
self.pos = pos
self.rect = pygame.Rect((self.x - self.pos + 21),(self.y + 20), (self.width - 33), (self.height- 33))
self.add(player_group)
here we are making the function that draws our character, we also have a jump system and an falling system
def draw(self, screen):
screen.blit(char, (self.x, self.y))
if self.isFalling:
if self.y <= 200 and self.x < 488 and self.x > 573: #hier moet var worden aangemaakt voor als hij op platform staat
self.y -= (self.fallCount**2) * 0.1 * -1
self.fallCount += 1
else:
self.isFalling = False
self.fallCount = 1
if self.isJump:
if self.jumpCount >= 0:
neg = 1
if self.jumpCount == 0:
self.isFalling = True
self.y -= (self.jumpCount**2) * .25 * neg
self.jumpCount -= 1
else:
self.isJump = False
self.jumpCount = 10
self.hitbox = pygame.Rect((self.x - self.pos + 21),(self.y + 20), (self.width - 33), (self.height- 33))
if pygame.sprite.spritecollideany(self, obstacle_group):
print("collide")
Here we are making the green rectangle that is our obstacle in the game, first initializing it and that drawing it to the screen in the color jade
class Obstacle(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, pos):
global obstacle_group
super().__init__(obstacle_group, all_sprites)
self.pos = pos
self.x = x
self.y = y
self.width = width
self.height = height
self.rect = pygame.Rect((self.x - self.pos),self.y, self.width, self.height)
#self.add(obstacle_group)
def draw(self, screen, pos):
pygame.draw.rect(screen, jade, pygame.Rect((self.x - self.pos), self.y, self.width, self.height))
self.hitbox = pygame.Rect((self.x - self.pos),self.y, self.width, self.height)
pygame.draw.rect(screen, red, self.hitbox, 1)
pos is the variable we use to scroll the background
pos = 0
here we are making the player character and the only obstacle in the side scroller
obstacle2 = Obstacle(300, 200, 100, 20, pos)
nkdMonkey = Player(150, 200, 100, 100, pos)
FPS = 60
run = True
clock = pygame.time.Clock()
this is our main drawing function that we call on in our main while loop
def draw_window():
screen.blit(bg, ((-1 * pos), 0))
textSurfaceObj = fontObj.render((str(pos)), False, (240,240,240, 255))
screen.blit(textSurfaceObj, (40,40))
obstacle2.draw(screen, pos)
nkdMonkey.draw(screen)
#pygame.draw.rect(screen, red, nkdMonkey.hitbox, 1)
#for if you want to see the hitbox of the player which is used for collisions
pygame.display.update()
this is our while loop
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#all_sprites = pygame.sprite.Group()
#obstacle_group = pygame.sprite.Group()
#player_group = pygame.sprite.Group()
keys_pressed = pygame.key.get_pressed()
#Checks if the front and and back button is pressed and if so, changes pos.
if keys_pressed[pygame.K_d] and pos < 1874:
pos += 2
char = R_char
if keys_pressed[pygame.K_d] and keys_pressed[
pygame.K_LSHIFT] and pos < 2000:
pos += 5
char = R_char
if keys_pressed[pygame.K_a] and pos > 0:
pos -= 2
char = L_char
if keys_pressed[pygame.K_a] and keys_pressed[pygame.K_LSHIFT] and pos > 0:
pos -= 5
char = L_char
if keys_pressed[pygame.K_w] and nkdMonkey.isJump == False:
nkdMonkey.isJump = True
if nkdMonkey.y > 200 and nkdMonkey.x > 488 and nkdMonkey.x < 573:
nkdMonkey.y -= 1
#if nkdMonkey.x > 488 and nkdMonkey.x < 573:
#nkdMonkey.isFalling = True
if pos > 1980:
run = False
this is the point we can't figure out, we want it to print collide when the two sprites are colliding
if pygame.sprite.spritecollideany(nkdMonkey, obstacle_group):
print("collide")
all_sprites.update()
draw_window()
Here we made a simple end screen
screen.fill(jade)
screen.blit(pygame.image.load("character.png"), (0, 70))
text = fontObj.render('You win!!', True, (0,0,0, 255))
textRect = text.get_rect()
score = fontObj.render(str(pos), True, red)
screen.blit(score, (40,40))
textRect.center = (width // 2, (height // 2 + 20))
screen.blit(text, textRect)
pygame.display.flip()
pygame.sprite.spritecollideany attributes of the pygame.sprite.Sprite objects to detect a collision. Therefore you have to update the location of the rectangle by the position of the player:
nkdMonkey.rect.topleft = (nkdMonkey.x - nkdMonkey.pos), nkdMonkey.y)
if pygame.sprite.spritecollideany(nkdMonkey, obstacle_group):
print("collide")
In my game I can place a cannon on user player's location. I'm able to make the cannon fire once but can't make it repeat the firing process multiple times. I want the bullet to be reset at its original value after it travels a certain distance and repeat the firing process. I'm attaching my whole code below along with the part that places the cannon. Thank you for your help.
import pygame
import random
import math
pygame.font.init()
width = 900
height = 600
screen = pygame.display.set_mode([width, height])
walkRight = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'),
pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'),
pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]
walkLeft = [pygame.image.load('L1.png'), pygame.image.load('L2.png'), pygame.image.load('L3.png'),
pygame.image.load('L4.png'), pygame.image.load('L5.png'), pygame.image.load('L6.png'),
pygame.image.load('L7.png'), pygame.image.load('L8.png'), pygame.image.load('L9.png')]
char = pygame.image.load('standing.png')
bomb_pic = pygame.transform.scale(pygame.image.load('bomb.png'), (20, 20))
bomb_explosion = pygame.transform.scale(pygame.image.load('explosion1.png'), (40, 40))
pics = [bomb_pic, bomb_explosion]
shop = pygame.transform.scale(pygame.image.load("shop.png"), (60, 60))
boss = pygame.image.load("enemyboss.png")
player = [walkLeft, walkRight, char]
enemy_Left = [pygame.image.load('L1E.png'), pygame.image.load('L2E.png'), pygame.image.load('L3E.png'),
pygame.image.load('L4E.png'), pygame.image.load('L5E.png'), pygame.image.load('L6E.png'),
pygame.image.load('L7E.png'), pygame.image.load('L8E.png'), pygame.image.load('L9E.png')]
enemy_pic = pygame.image.load('L1E.png')
boss = pygame.image.load('pixel_monster.png')
cannon = pygame.image.load('tank_cannon.png')
bullet = pygame.image.load('bullet.png')
position = [60, 60]
x = 50 # same as position
y = 50 # same as position
width = 40
height = 60
vel = 5
isJump = False
jumpCount = 10
left = False
right = False
down = False
up = False
walkCount = 0
run_once = False
enemy_list = []
clock = pygame.time.Clock()
FPS = 60
font = pygame.font.Font('freesansbold.ttf', 32)
font_large = pygame.font.Font('freesansbold.ttf', 45)
items_font = pygame.font.Font('freesansbold.ttf', 16)
font_small = pygame.font.Font('freesansbold.ttf', 18)
font_tiny = pygame.font.Font('freesansbold.ttf', 13)
font_verytiny =pygame.font.Font('freesansbold.ttf', 9)
bombs = []
explosions = []
bag = {'bomb': 0, 'heal': 0, 'cannon': 0}
health = 100
base_health = 150
normal_enemies = []
kills = 0
cannon_list = []
bullet_list = []
class Button():
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 20)
text = font.render(self.text, 1, (0, 0, 0))
win.blit(text, (
self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def shop_run():
bright_green = (0, 255, 0)
green = (0, 200, 0)
shop_bomb = Button((0, 200, 0), 820, 150, 70, 20, text="Bomb_b")
shop_bomb.draw(screen)
shop_heal = Button((0, 200, 0), 820, 120, 70, 20, text="Heal_h")
shop_heal.draw(screen)
shop_cannon = Button((0, 200, 0), 820, 180, 70, 20, text="Cannon_c")
shop_cannon.draw(screen)
def walk():
global walkCount
global walkcount
if walkCount + 1 >= 27:
walkCount = 0
if left:
screen.blit(player[0][walkCount // 3], (x, y))
walkCount += 1
elif right:
screen.blit(player[1][walkCount // 3], (x, y))
walkCount += 1
elif down:
screen.blit(player[2], (x, y))
walkcount = 0
elif up:
screen.blit(player[2], (x, y))
walkcount = 0
else:
screen.blit(player[2], (x, y))
walkCount = 0
def enemy_spawn(number_of_enemies):
global normal_enemies
global health
global base_health
global kills
# for random_velocity in range(number_of_enemies):
player_rect = pygame.Rect(x+20, y+20, 20, 20)
for ne in range(number_of_enemies):
random_velocity = random.uniform(0.3, 1.3)
random_enemy_location_y = random.randrange(170, 470)
random_enemy_location_x = random.randrange(800, 1000)
normal_enemies.append([random_enemy_location_x, random_enemy_location_y, random_velocity])
# print(normal_enemies[ne][0], normal_enemies[ne][1], normal_enemies[ne][2])
for e in range(number_of_enemies):
ex, ey, evel = normal_enemies[e]
screen.blit(enemy_pic, (ex, ey))
if ex > 75:
normal_enemies[e][0] -= evel
else:
base_health -= 0.02
normal_enemy_rect = pygame.Rect(ex, ey, 50, 50)
if player_rect.colliderect(normal_enemy_rect):
health -= 0.2
for j in reversed(range(len(explosions))):
pos, end_time_2, hurt = explosions[j]
explosion_rect = pygame.Rect(pos[0], pos[1], 20, 20)
if explosion_rect.colliderect(normal_enemy_rect):
normal_enemies.pop(e)
kills += 1
def redrawGameWindow():
global walkCount
global font
global font_small
global font_tiny
global font_verytiny
global bag
global items_font
global enemy_list
global pics
global position
global health
global base_health
global run_once
global explosions
global bullet_list
current_time = pygame.time.get_ticks()
dx = []
dy = []
dist = []
screen.fill([166, 166, 166])
pygame.draw.rect(screen, (220, 0, 0), (700, 500, 100, 100))
# for five_enemies in range(5):
# random_enemy_location_y = random.randrange(170, 470)
# random_enemy_location_x = random.randrange(700, 840)
# enemy_list.append([random_enemy_location_x, random_enemy_location_y])
# for enemies in range(5):
# screen.blit(enemy_Left[enemies], enemy_list[enemies])
# dx.append(position[0] - enemy_list[enemies][0])
# dy.append(position[1] - enemy_list[enemies][1])
# dist.append(math.hypot(dx[enemies], dy[enemies]))
# dx[enemies], dy[enemies] = dx[enemies] / dist[enemies], dy[enemies] / dist[enemies]
# enemy_list[enemies][0] += dx[enemies] * 2
# enemy_list[enemies][1] += dy[enemies] * 2
pygame.draw.rect(screen, (70, 0, 220), (0, 120, 100, 400)) # main base
pygame.draw.rect(screen, (220, 0, 0), (50, 470, 5, -300))
pygame.draw.rect(screen, (0, 220, 0), (50, 470, 5, -base_health*2))
screen.blit(font.render("B", True, (0, 0, 0)), (10, 200 + 40))
screen.blit(font.render("A", True, (0, 0, 0)), (10, 235 + 40))
screen.blit(font.render("S", True, (0, 0, 0)), (10, 270 + 40))
screen.blit(font.render("E", True, (0, 0, 0)), (10, 305 + 40))
enemy_spawn(5)
# cannon_balls()
pygame.draw.rect(screen, (0, 0, 0), (800, 0, 100, 600))
if x + char.get_width() < 60 and y + char.get_height() < 60:
shop_run()
screen.blit(shop, (0, 0))
screen.blit(font_small.render("Shop", True, (0, 0, 0)), (5, 5))
pygame.draw.rect(screen, (220, 0, 0), (position[0] - 3, position[1], 50, 5))
pygame.draw.rect(screen, (0, 220, 0), (position[0] - 3, position[1], health/2, 5))
screen.blit(font.render("Menu", True, (255, 255, 255)), (805, 10))
screen.blit(items_font.render("Bombs: " + str(bag["bomb"]), True, (255, 255, 255)), (805, 550))
screen.blit(items_font.render("Heal: " + str(bag["heal"]), True, (255, 255, 255)), (805, 570))
screen.blit(items_font.render("Cannon: " + str(bag["cannon"]), True, (255, 255, 255)), (805, 530))
# screen.blit(bullet, (450, 300))
# screen.blit(bomb_explosion, (450, 300))
# screen.blit(boss, (450, 300))
walk()
for i in reversed(range(len(bombs))):
pos, end_time = bombs[i]
if current_time > end_time:
end_time_2 = end_time + 5000
pos2 = (pos[0] - 10, pos[1] - 20)
explosions.append((pos2, end_time_2, False))
bombs.pop(i)
else:
screen.blit(pics[0], pos)
for j in reversed(range(len(explosions))):
pos, end_time_2, hurt = explosions[j]
if current_time > end_time_2:
explosions.pop(j)
else:
screen.blit(pics[1], pos)
if not hurt:
explosion_rect = pygame.Rect(pos[0], pos[1], 20, 20)
player_rect = pygame.Rect(x+20, y+20, 20, 20)
if player_rect.colliderect(explosion_rect):
explosions[j] = (pos, end_time_2, True)
health -= 5
# print(health)
for i in cannon_list:
screen.blit(cannon, i)
for j in bullet_list:
screen.blit(bullet, j)
j[0] += 3
screen.blit(font_tiny.render("Health: " + str("{:.2f}".format(health)), True, (255, 255, 255)), (805, 60))
screen.blit(font_verytiny.render("Base Health: " + str("{:.2f}".format(base_health)), True, (255, 255, 255)), (805, 90))
screen.blit(font_tiny.render("Kills: " + str(kills), True, (255, 255, 255)), (805, 110))
pygame.display.update()
def main():
run = True
pygame.display.set_caption("bomb-mania")
global x
global y
global width
global height
global vel
global left
global right
global down
global up
global walkCount
global bomb_pic
global font
global bombs
global explosions
global position
global health
global kills
global cannon_list
global bullet_list
while run:
current_time = pygame.time.get_ticks()
redrawGameWindow()
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
run = False
shop_rect = pygame.Rect(0, 0, 40, 40)
player_rect = pygame.Rect(x+20, y+20, 20, 20)
if player_rect.colliderect(shop_rect):
buy = pygame.key.get_pressed()
if buy[pygame.K_b]:
bag["bomb"] += 1
# print(bag["bomb"])
if buy[pygame.K_h]:
bag["heal"] += 1
if buy[pygame.K_c] and kills > 3:
kills -= 3
bag["cannon"] += 1
# print(bag["cannon"])
if event.type == pygame.KEYDOWN and not player_rect.colliderect(shop_rect):
if (event.key == pygame.K_SPACE or event.key == pygame.K_b) and bag["bomb"] >= 1:
current_time_2 = pygame.time.get_ticks()
pos = x + char.get_width() / 2, y + char.get_height() - 20
pos2 = ((x + char.get_width() / 2) - 10), (y + char.get_height() - 30)
end_time = current_time + 3000 # 3000 milliseconds = 3 seconds
bombs.append((pos, end_time))
bag["bomb"] -= 1
if event.key == pygame.K_h and not player_rect.colliderect(shop_rect) and health < 90 and bag["heal"] >= 1:
health += 10
bag["heal"] -= 1
if event.key == pygame.K_c and not player_rect.colliderect(shop_rect):
print("reached")
cannon_list.append([x,y])
bullet_list.append([x,(y-20)])
if health <= 0 or base_health <= 0:
main_menu()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel - 15:
x -= vel
position[0] -= vel
left = True
right = False
down = False
up = False
# print(position)
elif keys[pygame.K_RIGHT] and x < 800 - vel - width:
x += vel
position[0] += vel
left = False
right = True
down = False
up = False
# print(position)
elif keys[pygame.K_DOWN] and y < 600 - height:
y += vel
position[1] += vel
left = False
right = False
down = True
up = False
# print(position)
elif keys[pygame.K_UP] and y > vel - 15:
y -= vel
position[1] -= vel
left = False
right = False
down = False
up = True
# print(position)
else:
left = False
right = False
down = False
up = False
walkCount = 0
clock.tick(FPS)
pygame.display.flip()
def main_menu():
global width
global height
global health
global base_health
global bag
global position
global x
global y
global left
global right
global down
global up
global walkCount
global normal_enemies
global explosions
global bombs
global enemy_list
global kills
global cannon_list
cannon_list =[]
kills = 0
enemy_list = []
normal_enemies = []
bombs = []
explosions = []
position = [60, 60]
x = 50 # same as position
y = 50 # same as position
left = False
right = False
down = False
up = False
walkCount = 0
enemy_vel = 2
enemy_list = []
bag["bomb"] = 0
bag["heal"] =0
health = 100
base_health = 150
pygame.display.set_caption("Main Menu")
run = True
bright_green = (0, 255, 0)
green = (0, 200, 0)
screen.fill((163, 163, 194))
while run:
mouse = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
run = False
if 400 + 100 > mouse[0] > 400 and 275 + 50 > mouse[1] > 275:
pygame.draw.rect(screen, bright_green, (400, 275, 100, 50))
if event.type == pygame.MOUSEBUTTONDOWN:
main()
else:
pygame.draw.rect(screen, green, (400, 275, 100, 50))
screen.blit(font_large.render("Bomb-Mania", True, (255, 255, 255)), (325, 50))
screen.blit(font.render("Play", True, (0, 0, 0)), (417, 285))
pygame.display.flip()
clock.tick(FPS)
main_menu()
The code below is the part that places the cannon.
This is part of main()
if event.key == pygame.K_c and not player_rect.colliderect(shop_rect):
print("reached")
cannon_list.append([x,y])
bullet_list.append([x,(y-20)])
This is part of redrawGameWindow()
for i in cannon_list:
screen.blit(cannon, i)
for j in bullet_list:
screen.blit(bullet, j)
j[0] += 3
Edits
bullet_list.append([x,(y+25),0, 0])
The changes i"ve made to keep track of the distance traveled are given below
for i in cannon_list:
screen.blit(cannon, i)
for j in bullet_list:
screen.blit(bullet, (j[0], j[1]))
j[3] = j[0]
if j[0] == j[3]:
j[0] += 3
j[2] += 3
if j[2] >= 100:
j[0] = j[3]
Edits2
I'm implementing OOP, Please help me debug.
class Cannon():
global cannon_list
global bullet_list
def __init__(self, x, y, track, old_x):
self.x = x
self.y = y
self.track = track
self.old_x = old_x
def spawnBullet(self):
for j in bullet_list:
self.old_x = j[3]
self.track = j[2]
screen.blit(bullet, (j[0], j[1]))
def moveBullet(self):
if self.x <= self.track:
self.x += 3
self.track += 3
def resetBullet(self):
if self.x >= self.track:
self.x = self.old_x
def spawnCannon(self):
for i in cannon_list:
screen.blit(cannon, i)
Using class Cannon
for j in bullet_list:
cannonsAndBullets = Cannon(j[0], j[1], j[2], j[0])
cannonsAndBullets.spawnCannon()
cannonsAndBullets.spawnBullet()
cannonsAndBullets.moveBullet()
cannonsAndBullets.resetBullet()
You say that you want the canons bullet to travel a fixed distance and then refire. What have you done to try to achieve that?
This appears to be the code that causes the bullet to move:
for j in bullet_list:
screen.blit(bullet, j)
j[0] += 3
There is nothing in here that stops it after it has travelled some specific distance or triggers a re-firing.
Your code would significantly benefit from object oriented restructuring and use of classes, in particular I would recommend that you make player, enemy, canon. bullet into classes. It not only cleans up the code but makes it simpler to keep track of the objects and all the respective state information that you need for each object.
For example for you question of re-firing after a certain distance has been traveled by the bullet. Right now the only information that you are keeping on the bullet is its position. To make it stop after a certain distance, you also need to know either its initial position or how far it has traveled since being fired. To re-fire you again need to know the canon it was fired from or possibly just its initial position if you just want to restart from the same place (assuming the canon is stationary). What about if the bullet hits something? Can the canon immediately re-fire, or does it have to wait for the same amount of time to elapse as if it had not hit anything and had to travel the full distance? If later you want your canon to be rate limited or something rather than just only one existing bullet at a time you will need state information in the canon about firing rate and the last time it fired.
Structuring your elements as objects allows you to cleanly keep all of that specific state information together for each instance of each object. It makes it simpler for you to modify behaviour when you want to since the logic related to the objects can be contained and you know where it all is. That is very important as the code gets larger and more complicated, but is always good practice regardless.
It also generally makes it simpler for other to look at, understand your code when you are asking for assistance, or if you were to pass a project on to someone else.
Edit after OP modified question based on comments:
You edited your code and added this:
for j in bullet_list:
screen.blit(bullet, (j[0], j[1]))
j[3] = j[0]
if j[0] == j[3]:
j[0] += 3
j[2] += 3
if j[2] >= 100:
j[0] = j[3]
Which does not make sense. The line if j[0] == j[3]: will always be true since in the line immediately before it you set j[3] = j[0].
I think what you are trying to do is have this state information for initial position and distance traveled in the list along with the x,y position, and that j[3] is supposed to be the initial position and j[2] is the distance? This is not how I would do this at all, but ... You might try this instead:
bullet_list.append([x,(y+25),0, x])
and
for j in bullet_list:
screen.blit(bullet, (j[0], j[1]))
j[0] += 3
j[2] += 3
if j[2] >= 100:
j[0] = j[3]
Again, you really should be using a class for this, not trying to keep the state as parts of a list.