make enemy ricochet off walls pygame [duplicate] - pygame

This question already has answers here:
How do I make my monster move randomly in my game
(1 answer)
How do I randomly move objects in a maze using pygame? [closed]
(1 answer)
Closed 24 days ago.
This post was edited and submitted for review 23 days ago and failed to reopen the post:
Original close reason(s) were not resolved
Note: This is different to my previous question. The previous question I posted was about the enemy following the player, but here I want the zombie to roam around. My plan is to link these together (once they both work correctly) and have the zombie roam around until the player is within a certain radius. I would appreciate if this can be reopened as this is a different problem!
So i am trying to create an enemy that moves around the map and 'bounces' off any walls it collides with. I have tried to adapt some code i used making pong a while ago. I tried to break the problem down and consider where the enemy is hitting the wall from, but i feel like i may be overcomplicating it? Here is a video of the bug: https://imgur.com/a/H2qOMZD
This is my current code.
class Enemy(pygame.sprite.Sprite):
def __init__(self, position):
super().__init__(enemy_group, all_sprites_group)
self.position = pygame.math.Vector2(position)
self.wander_speed = pygame.math.Vector2((6 * random.choice((-1,1))), (6 * random.choice((-1,1))))
def walk_around(self):
self.velocity = self.wander_speed
print(self.velocity)
self.position += self.velocity
self.base_zombie_rect.centerx = self.position.x
self.base_zombie_rect.centery = self.position.y
self.base_zombie_rect.centerx, self.base_zombie_rect.centery = self.position.x, self.position.y
self.check_collision_2()
self.rect.center = self.base_zombie_rect.center
self.position = (self.base_zombie_rect.centerx, self.base_zombie_rect.centery)
def check_collision_2(self):
for sprite in obstacles_group:
if sprite.rect.colliderect(self.base_zombie_rect):
if self.base_zombie_rect.top < sprite.rect.bottom and self.base_zombie_rect.centery > sprite.rect.bottom: # UP collision
print("UP COLLISION")
self.velocity.y *= -1
if self.base_zombie_rect.bottom > sprite.rect.top and self.base_zombie_rect.centery < sprite.rect.top: # DOWN collision
print("DOWN COLLISION")
self.velocity.y *= -1
if self.base_zombie_rect.left < sprite.rect.right and self.base_zombie_rect.centerx > sprite.rect.right: # LEFT collision
print("RIGHT COLLISION")
self.velocity.x *= -1
if self.base_zombie_rect.right > sprite.rect.left and self.base_zombie_rect.centerx < sprite.rect.left: # RIGHT collision
print("LEFT COLLISION")
self.velocity.x *= -1

Related

Pygame need to build sprite from a rotating and non rotating image [duplicate]

This question already has answers here:
How to set the pivot point (center of rotation) for pygame.transform.rotate()?
(5 answers)
How can you rotate an image around an off center pivot in Pygame
(1 answer)
How do I rotate an image around its center using Pygame?
(6 answers)
Closed 22 days ago.
I have an interesting problem with sprits in pygame.
Essentially, I am trying to create an archer sprite which will follow a target.
To do so, I need it to rotate. Naturally, I don't want the whole archer to rotate - just his shoulders/head etc. To do so I have create two separate spritesheets (for the top and bottom)
I can then create the sprite image using:
class Archer(pygame.sprite.Sprite):
def __init__(self, group, pos, size):
super().__init__(group)
self.pos = pos
self.assets_legs = GetAssets('../graphics/archer_fixed.png', size)
self.frames_legs = self.assets_legs.sprite_images
self.assets_body = GetAssets('../graphics/archer_rotate.png', size)
self.frames_body = self.assets_body.sprite_images
self.frame_index = 0
self.angle = 0
self.archer = [self.frames_legs[round(self.frame_index)], self.frames_body[round(self.frame_index)]]
self.image = pygame.Surface((size), pygame.SRCALPHA)
for image in self.archer:
self.image.blit(image, (0,0))
This is fine and works well. However, when I want to rotate the top half and blit this to the self.image, as in:
def rotate(self):
self.rot_img = self.archer[1]
self.rot_img = pygame.transform.rotate(self.rot_img, 1)
self.image = pygame.Surface((75,75), pygame.SRCALPHA)
self.archer = [self.frames_legs[round(self.frame_index)], self.rot_img]
for image in self.archer:
self.image.blit(image, (0,0))
self.rect = self.image.get_rect(center = self.pos)
I get strange artifacts. I suspect because I am trying to blit a surface with a rotated dimension to a self.image. The only work around I can think of is to create two separate sprites and then have them track each other, but the must be a way to do this in one class.
Any ideas?
Cheers

Draw detection radius around square sprite [duplicate]

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Pygame collision with masks
(1 answer)
Closed 6 months ago.
I would like to draw sprites with 2 features: a base image (let's say a square image that I pass as argument) and a togglable view of their circular detection radius, for debug purposes and checking that collisions with a circular mask actually work.
Note: the main question is not about to detect collisions as in How do I detect collision in pygame?, but rather can a sprite have several surfaces attached to it and why is my draw_mask_outline function returning croppped circles? (see attached screenshots)
Here's an example of my class:
class Robot(pygame.sprite.Sprite):
def __init__(self, x, y, image, detection_radius, mouse_group, *groups):
super().__init__(*groups)
# extra image added for changing color if mouse is detected within
# detection radius
# I have used the mouse as a debug tool but in the end the Robot
# should have no knowledge of the other groups positions (and should
# not be able to compute a euclidean distance from a sprite group) but
# simply detect if a sprite of a certain sprite group has entered its
# radius
other_img = pygame.Surface((30, 30))
other_img.fill('black')
self.img_idx = 0
self.images = [image, other_img]
self.image = self.images[self.img_idx]
self.pos = pygame.Vector2(x, y)
self.rect = image.get_rect(center=self.pos)
self.detection_radius = detection_radius
self.mask_surface = pygame.Surface((detection_radius * 2, detection_radius * 2), pygame.SRCALPHA)
self.detection_mask = self.make_circle(self.notice_radius)
self.mask = pygame.mask.from_surface(
self.make_circle_surface(detection_radius))
sekf.mouse_group = mouse_group
def draw_mask_outline(self):
# this function should draw the outline of the circular detection mask
display_surf = pygame.display.get_surface()
pts = self.mask.outline()
for pt in pts:
x = pt[0] + self.rect.centerx
y = pt[1] + self.rect.centery
pygame.draw.circle(display_surf, 'black', (x, y), 1)
def make_circle_surface(self, radius):
# I used this function to generate the circular surface
mask_surf = pygame.Surface((radius * 2, radius * 2), pygame.SRCALPHA)
pygame.draw.circle(mask_surf, (0, 0, 0), (self.rect.centerx, self.rect.centery), radius)
return mask_surf
def collision(self):
# collision detection function, if mouse inside detection radius do something
if pygame.sprite.spritecollide(self, self.mouse_group, False, pygame.sprite.collide_mask):
pygame.draw.circle(pygame.display.get_surface(), (0, 0, 0), (self.rect.centerx, self.rect.centery), self.notice_radius, 1)
self.img_idx = 1
self.image = self.images[self.img_idx]
else:
self.img_idx = 0
self.image = self.images[self.img_idx]
def update(self):
# the overall update function where all the robot logic will happen
self.draw_mask_outline()
As fas as I've understood how the lib works, I should create a surface around the original image, big enough to fit the circle but this does not seem compatible with already having a self.image. Then I should draw a circle on that new surface.
Will this new surface follow the sprite when it moves too?
I managed to draw the circle inside the original image but this is not what is expected since the starting is smaller than the circle. In some cases, I also managed to generate surfaces, transform them to mask, then using the mask to generate an outline (hence the self.mask) but these outlines are always drawn far away from the sprite positions, are incomplete or completely missing...
Here are some screenshots of the current version and what I could achieve.
When the mouse is outside the detection ring, outlines are drawn with a severe offset, are sometimes incomplete and some robots have no outline.
Displaced and incomplete outlines
When the mouse is inside, the collision function draws the correct circle (but this is not the mask).
Collisions debug ring
Here are links to some solutions that I have tested and that did not work (if I've understood them correctly that is...):
pygame: mask non-image type surfaces
Pygame: Why i can't draw a circle sprite
how to create a circular sprite in pygame
OOP Pygame Circle
Ultimately the goal is to have the robots roam around and detect sprites from another group of robots that enter their detection radius.
Any help would be very much appreciated!

How can I make my sprite move accross the screen? [duplicate]

This question already has answers here:
How to make a circle move diagonally from corner to corner in pygame
(1 answer)
How to make smooth movement in pygame
(2 answers)
Closed 2 years ago.
When a certain value is met I want my enemy sprite to return to his intial position,but now hes just disappearing and reappearing in that position.
I'm only changing the Y position
def update(self):
self.count += 1
x_component = self.ship.rect.centerx-self.enemy2X
y_component = self.ship.rect.centery-self.enemy2Y
distance = math.hypot(x_component, y_component)
if distance < 200:
self.currentState = 1
print distance
elif distance > 200:
self.currentState = 0
self.enemy2Y=68
print self.enemy2Y

Need help creating game close to "Pong" (Pygame)

As you read from the description (or not), I need help creating a game close to Pong.
I am really new in programming, and I am learning all by myself. The game you help me create will be my first game ever.
My version of game, explained:
Picture (Can't post a picture here since I am new):
http://www.upload.ee/image/3307299/test.png (THIS LINK IS SAFE)
So, number 1 stands for walls (black ones)
Number 2 marks the area, where time stops (game over)
3 is your time survived.
Number 4 is the ball that bounces (like they do in Pong).
Code:
import pygame
import random
pygame.init()
screen = pygame.display.set_mode([640, 480])
paddle = pygame.image.load("pulgake.png")
pygame.display.set_caption("PONG!")
back = pygame.image.load("taust.png")
screen.blit(back, (0, 0))
screen.blit(paddle, (600, 240))
pygame.display.flip()
xpaddle = 600
ypaddle = 240
delay = 10
interval = 10
pygame.key.set_repeat(delay, interval)
while True:
screen.blit(back, (0,0))
screen.blit(paddle, (xpaddle, ypaddle))
pygame.display.flip()
pygame.time.delay(20)
for i in pygame.event.get():
if i.type == pygame.QUIT:
sys.exit()
elif i.type == pygame.KEYDOWN:
if i.key == pygame.K_UP:
ypaddle = ypaddle - 10
if ypaddle < 10:
ypaddle = 10
elif i.key == pygame.K_DOWN:
ypaddle = ypaddle + 10
if ypaddle > 410:
ypaddle = 410
I would like to have a bouncing ball, but i don't have the knowledge to create it.
It doesn't have to be really difficult(maybe using pygame.draw.circle?)
Actually it has to be simple, because sprites are maybe too much for me.
My idea was to change coordinates every time ball gets to specific coordinates.
I am not just asking somebody to make a game I like, it's for educational purposes.
I would love to see some comments with the code you provide.
As I told, i just started learning it.
My english isn't best. Sorry about that.
Thanks in advance!
(I know that my post is a bit confusing and unspecific)
If needed, I will upload the background and paddle picture too.
You could create a Ball class, that will have 2 methods:
update() - that will move the ball according to speed_x and speed_y and
check if any collisions are detected
draw() - that will blit the surface/ or draw a circle at ball position.
another thing you have to think about, is collisions.
You can find if a point is in a rectangle like this:
We have a rectangle with points : p1,p2,p3,p4, p0 is our testing point.
p0 is in the rectangle if dist(p0,p1) + disp(p0,p2) + ... + disp(p0,p4) == WIDTH+HEIGHT
you can try to figure out the equation for a circle. Hint: radius is what you need.
EDIT: The class example:
class Ball:
def __init__(self):
self.pos = [0,0]
self.velocity = [1,0]
def move():
self.pos[0] += self.velocity[0]
self.pos[1] += self.velocity[1]
def draw(screen):
pygame.draw.circle(screen,WHITE,self.pos,5)
To extend on #Bartlomiej Lewandowski, To make the ball you need to
Every loop ball.update() will do:
ball.x += ball.xvel
ball.y += ball.yvel`
Then
if you collide with left/right walls ball.x *= -1
if you collide with top/bot walls ball.y *= -1
Using pygame.Rect will simplfy logic
# bounce on right side
ball.rect.right >= screen.rect.right:
ball.yvel *= -1
# bounce top
ball.rect.top <= screen.rect.top:
# bot
ball.rect.bottom >= screen.rect.bot:
# etc...
edit: Bart added different names but it's the same thing.

Pygame - Limiting instances of sprites

I'm using an example regarding sprite generation for a space scroller shootup that I'm developing. By slowly trying to understand how it works, I've managed to get multiple sprites to transverse across the screen. However, there are many sprites that are generated.
So what I'm having trouble with is limiting the initial number of sprites instead of the multitude that the code produces. I thought of using if sprites.__len__ < 10: sprites.add(drone) but when I tried that, it didn't work.
My thinking was that each time it looped, it would check the number of sprites in the group and if it was less then 10, add a sprite to the group until it hit 10. That way if it went off screen or is destroyed, then it would keep doing the check and keeping it constant.
This is the player class:
class Player(pygame.sprite.Sprite):
def __init__(self, *groups):
super(Player, self).__init__(*groups)
self.image = pygame.image.load('player.png')
self.rect = pygame.rect.Rect((screen_width, (random.randrange(0,screen_height))), self.image.get_size())
self.dx = -10
self.pos = random.randrange(0,screen_height)
def update(self):
self.rect.centerx += self.dx
if self.rect.right < 0:
self.kill()
and this is the section regarding the adding of the sprite.
sprites.update()
screen.fill((200, 200, 200))
sprites.draw(screen)
drone = Player()
self.y = random.randrange(0,screen_height)
sprites.add(drone)
pygame.display.flip()
It's probably obvious, but I'm still learning so guidance would be great.
Second question - More of a confirmation of thought. If I don't want the sprite to be half drawn on the bottom of the screen. Do I basically say that if self.rect.bottom > screen_height, then position the sprite # screen_height
Full source: http://pastebin.com/PLRVHtxz
EDIT - I think I've solved it, just need to make the sprites run smoother.
while 1:
clock.tick(40)
numberAlien = 5
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
return
sprites.update()
screen.fill((200, 200, 200))
sprites.draw(screen)
drone = Player()
if sprites.__len__() < numberAlien:
self.y = random.randrange(0,screen_height)
sprites.add(drone)
pygame.display.flip()
You could subclass SpriteGroup, add a new field of the total number of sprites, and check in the add method to see if it can be added.
You shouldn't test check any variables with __.
As for the movement, i believe, you do not see a smooth movement because of clock.tick(40).
It waits for 40ms until it resumes running. You could reduce tick to 10, and tune the dx you change for the sprites, or try a more universal approach.
A call to clock.tick() returns amount of ms since the last call. This will be your time delta. You can then have a global SPEED. The amount of pixels to be moved would be calculated from SPEED * delta.