This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Closed 24 days ago.
my enemy movement is fine except when colliding with walls it teleports.
video: https://imgur.com/a/tuK0yBg
I have tried to simplify my code by deleting any code that could affect this, e.g. the zombies rotation code etc, however I still can not find the issue. I have no idea why it is teleporting.
Enemy class code:
class Enemy(pygame.sprite.Sprite):
def __init__(self, position):
super().__init__(enemy_group, all_sprites_group)
self.position = pygame.math.Vector2(position)
self.zombie_speed = 2
self.image = pygame.image.load("zombieAssets/skeleton-idle_0.png").convert_alpha()
self.image = pygame.transform.rotozoom(self.image, 0, 0.35)
self.base_zombie_image = self.image
self.base_zombie_rect = self.base_zombie_image.get_rect(center = position)
self.rect = self.base_zombie_rect.copy()
self.velocity = pygame.math.Vector2()
def hunt_player(self):
player_position = player.base_player_rect.center
distance_to_player = player_position - self.position
try:
self.velocity = distance_to_player.normalize() * self.zombie_speed
self.position += self.velocity
self.base_zombie_rect.centerx = self.position.x
self.check_collision("horizontal")
self.base_zombie_rect.centery = self.position.y
self.check_collision("vertical")
self.rect.center = self.base_zombie_rect.center
except:
return
def check_collision(self, direction):
for sprite in obstacles_group:
if sprite.rect.colliderect(self.base_zombie_rect):
if direction == "horizontal":
if self.velocity.x > 0:
self.base_zombie_rect.right = sprite.rect.left
if self.velocity.x < 0:
self.base_zombie_rect.left = sprite.rect.right
if direction == "vertical":
if self.velocity.y < 0:
self.base_zombie_rect.top = sprite.rect.bottom
if self.velocity.y > 0:
self.base_zombie_rect.bottom = sprite.rect.top
def update(self):
self.hunt_player()
It seems to me that in your collision code you are keeping the zombie rect updated properly so as not to phase through the wall, but I see no changes to self.position. I think that if you updated the zombie's actual position in the same way as the rect that the teleportation behavior should stop.
Related
This question already has answers here:
Setting up an invisible boundary for my sprite
(1 answer)
Use vector2 in pygame. Collide with the window frame and restrict the ball to the rectangular area
(1 answer)
Closed last month.
Greeting, I trying to set the boundaries for players in a game so they do not go passed the boundaries of the screen. They only move in the x-axis.
Bellow is the code for the player class. Right now In the move method I am trying to set a distance relative to the rectangle object(the player) do that it does not go past a certain points to the left and right of the x-axis. However, right now I keep getting the error
if self.rect.left + dx < 0:
AttributeError: 'tuple' object has no attribute 'left'
when I run the code.
class Player():
def __init__(self, x, y, width, height, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
self.rect = pygame.Rect((x,y, width, height))
def move(self, screen_width, screen_height):
SPEED = 10
dx = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.x -= SPEED
dx = -SPEED
if keys[pygame.K_RIGHT]:
self.x += SPEED
dx = SPEED
# ensure player stays on screen
if self.rect.left + dx < 0:
self.rect.x += -self.rect.left
if self.rect.right + dx > screen_width:
self.rect.x += screen_width - self.rect.right
self.update()
def update(self):
# update player position
self.rect = (self.x, self.y, self.width, self.height)
This question already has answers here:
How can I do a double jump in pygame?
(1 answer)
Pygame: Can someone help me implement double jumping?
(1 answer)
Closed 2 months ago.
When trying to create a double I either can jump infinitely or jump once, struggling to find a solution to only jump once.
I was able to create a double jump using two different keys however I want it to where I only have to use the 'W' key.
here's my code:
import pygame
pygame.init()
class Fighter:
def __init__(self, x, y):
self.x = x
self.y = y
self.rect = pygame.Rect((self.x, self.y, 70, 200))
self.x_vel = 0
self.y_vel = 0
self.jump = False
def draw_player(self, surface):
pygame.draw.rect(surface, "Red", self.rect)
def detect_collisions(self, platforms):
collisions = []
for platform in platforms:
if self.rect.colliderect(platform.rect):
collisions.append(platform)
return collisions
def movement(self, player, platforms, screen_height, screen_width):
self.x = 0
self.y = 0
self.y_vel = 0
pixel_move = 30
gravity = 5
# get key presses
key = pygame.key.get_pressed()
# player one inputs
if player == 1:
if key[pygame.K_a]:
self.x = -pixel_move
if key[pygame.K_d]:
self.x = pixel_move
if key[pygame.K_w] and self.jump == False:
self.y_vel = -pixel_move
self.jump = True
if key[pygame.K_s]:
self.y_vel = pixel_move
# player two inputs
elif player == 2:
if key[pygame.K_LEFT]:
self.x = -pixel_move
if key[pygame.K_RIGHT]:
self.x = pixel_move
# apply gravity
self.y_vel += gravity
# makes sure the player actually moves
self.rect.x += self.x
self.rect.y += self.y_vel
# make sure player stays onto the screen
self.platform_interaction(platforms)
# make sure the player doesn't fall off the screen
if self.rect.bottom + self.y_vel > screen_height:
self.y_vel = 0
self.rect.bottom = screen_height
self.jump = False
# make sure the player doesn't go above the screen
if self.rect.top < 0:
self.rect.top = 0
# make sure the player doesn't go across the right side of the screen
if self.rect.right > screen_width:
self.rect.right = screen_width
# makes sure the player doesn't go across the left side of the screen
if self.rect.left <= 0:
self.rect.left = 0
def platform_interaction(self, platforms):
collisions = self.detect_collisions(platforms)
for platform in collisions:
# player lands on top off platform
if abs(self.rect.bottom - platform.rect.top) < 10:
self.rect.bottom = platform.rect.top
self.jump = False
# player collides with the sides of the platform
elif abs(self.rect.right - platform.rect.left) < 20:
self.rect.right = platform.rect.left
elif abs(self.rect.left - platform.rect.right) < 20:
self.rect.left = platform.rect.right
elif platform.state:
# player hits themselves on bottom of the platform
if abs(self.rect.top + self.y_vel) < platform.rect.bottom:
self.rect.top = platform.rect.bottom
# make sure player doesn't fall through solid platforms
elif abs(self.rect.bottom + self.y_vel) > platform.rect.top:
self.rect.bottom = platform.rect.top
I am creating a game where you shoot enemies in a top-down format. My bullet and enemy function properly in every aspect except where it has to delete itself. I have hooked it up to where if the bullet collides with the enemy or 5 seconds have passed, the bullet would delete itself. It does do that, except the code continually iterates to create a sprite and kill it as the bullet moves for some reason, and still shows the bullet on the screen as if nothing is happening to it. Can someone tell me why the code is iterating the creation of a bullet and the deletion of it so many times?
-------- CODE --------
method in player class
def shoot(self):
pos = pygame.mouse.get_pos()
pos += camera_group.offset
click = pygame.mouse.get_pressed()
if click[0] and not self.shooting:
self.shooting = True
# create bullet instance if player shoots
bullet = Bullet(self.rect.centerx, self.rect.centery, "bullet", pos, camera_group)
bullet_group.add(bullet)
if not click[0]:
self.shooting = False
bullet class
class Bullet(Entity):
def __init__(self, x, y, image, pos, group):
super().__init__(x, y, image, group)
pygame.sprite.Sprite.__init__(self)
# creating and scaling image
self.image = pygame.transform.flip(self.image, True, False)
self.image = pygame.transform.scale(self.image, (32, 16))
# creating rect
self.x = x
self.y = y
self.speed = 8
self.mousepos = pos
# calculating angle of bullet
self.angle = math.atan2(pos[1] - y, pos[0] - x)
self.angle_deg = (self.angle * (180 / math.pi))
self.image = pygame.transform.rotate(self.image, self.angle_deg * -1)
# calculating vel_x/vel_y
dx = self.mousepos[0] - player.rect.centerx
dy = self.mousepos[1] - player.rect.centery
total = abs(dx) + abs(dy)
self.vel_x = (self.speed * (dx / total))
self.vel_y = (self.speed * (dy / total))
# setting variable to store time of bullet creation
self.start_time = pygame.time.get_ticks()
def update(self):
if pygame.time.get_ticks() - self.start_time > 50 and len(bullet_group) >= 1:
bullet_group.sprites()[0].kill()
elif self.rect.colliderect(enemy):
bullet_group.sprites()[0].kill()
enemy.kill()
else:
# movement
self.x += self.vel_x
self.y += self.vel_y
self.rect.x = int(self.x)
self.rect.y = int(self.y)
Don't kill the first bullet in the Group, just delete the bullet object itself:
bullet_group.sprites()[0].kill()
self.kill()
method update in class Bullet:
class Bullet(Entity):
# [...]
def update(self):
if pygame.time.get_ticks() - self.start_time > 50 and len(bullet_group) >= 1:
self.kill()
elif self.rect.colliderect(enemy):
self.kill()
enemy.kill()
else:
# movement
self.x += self.vel_x
self.y += self.vel_y
self.rect.x = int(self.x)
self.rect.y = int(self.y)
I am creating a game where you shoot enemies in a top-down format. My bullet and enemy function properly in every aspect except where it has to delete itself. I have hooked it up to where if the bullet collides with the enemy or 5 seconds have passed, the bullet would delete itself. It does do that, except the code continually iterates to create a sprite and kill it as the bullet moves for some reason, and still shows the bullet on the screen as if nothing is happening to it. Can someone tell me why the code is iterating the creation of a bullet and the deletion of it so many times?
-------- CODE --------
method in player class
def shoot(self):
pos = pygame.mouse.get_pos()
pos += camera_group.offset
click = pygame.mouse.get_pressed()
if click[0] and not self.shooting:
self.shooting = True
# create bullet instance if player shoots
bullet = Bullet(self.rect.centerx, self.rect.centery, "bullet", pos, camera_group)
bullet_group.add(bullet)
if not click[0]:
self.shooting = False
bullet class
class Bullet(Entity):
def __init__(self, x, y, image, pos, group):
super().__init__(x, y, image, group)
pygame.sprite.Sprite.__init__(self)
# creating and scaling image
self.image = pygame.transform.flip(self.image, True, False)
self.image = pygame.transform.scale(self.image, (32, 16))
# creating rect
self.x = x
self.y = y
self.speed = 8
self.mousepos = pos
# calculating angle of bullet
self.angle = math.atan2(pos[1] - y, pos[0] - x)
self.angle_deg = (self.angle * (180 / math.pi))
self.image = pygame.transform.rotate(self.image, self.angle_deg * -1)
# calculating vel_x/vel_y
dx = self.mousepos[0] - player.rect.centerx
dy = self.mousepos[1] - player.rect.centery
total = abs(dx) + abs(dy)
self.vel_x = (self.speed * (dx / total))
self.vel_y = (self.speed * (dy / total))
# setting variable to store time of bullet creation
self.start_time = pygame.time.get_ticks()
def update(self):
if pygame.time.get_ticks() - self.start_time > 50 and len(bullet_group) >= 1:
bullet_group.sprites()[0].kill()
elif self.rect.colliderect(enemy):
bullet_group.sprites()[0].kill()
enemy.kill()
else:
# movement
self.x += self.vel_x
self.y += self.vel_y
self.rect.x = int(self.x)
self.rect.y = int(self.y)
Don't kill the first bullet in the Group, just delete the bullet object itself:
bullet_group.sprites()[0].kill()
self.kill()
method update in class Bullet:
class Bullet(Entity):
# [...]
def update(self):
if pygame.time.get_ticks() - self.start_time > 50 and len(bullet_group) >= 1:
self.kill()
elif self.rect.colliderect(enemy):
self.kill()
enemy.kill()
else:
# movement
self.x += self.vel_x
self.y += self.vel_y
self.rect.x = int(self.x)
self.rect.y = int(self.y)
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Closed 2 years ago.
Walls do block me but if i keep walking into them i teleport through. I've tried a number of things and cant seem to figure it out. Things that make it difficult is that my character rotates based on where my mouse position is. self.level_terrain is a sprite.group. update is called from my state manager.
def update(self, clock):
self.dT = clock.get_time()
pressed = pg.key.get_pressed()
mousePos = pg.mouse.get_pos()
self.player.update(mousePos, pressed, self.dT, self.level_terrain)
def get_angle(origin, destination):
"""Returns angle in radians from origin to destination.
This is the angle that you would get if the points were
on a cartesian grid. Arguments of (0,0), (1, -1)
return pi/4 (45 deg) rather than 7/4.
"""
x_dist = destination[0] - origin[0]
y_dist = destination[1] - origin[1]
return atan2(-y_dist, x_dist) % (2 * pi)
class Player(pg.sprite.Sprite):
def __init__(self, center_pos):
super(Player, self).__init__()
self.original_image = pg.image.load("data/resources/images/playerImage.png").convert_alpha()
self.facing_angle = 90
self.start_angle = 90
self.pos = center_pos
self.velocity = [0, 0]
self.set_image()
self.vx = 0
self.vy = 0
self.keys_dict = {
pg.K_w: (0, -1),
pg.K_s: (0, 1),
pg.K_a: (-1, 0),
pg.K_d: (1, 0)}
self.speed = .2
def set_image(self):
angle = self.facing_angle - self.start_angle
self.image = pg.transform.rotate(self.original_image, angle)
self.rect = self.image.get_rect()
def update(self, mouse_pos, pressed, dt, obstacles):
self.facing_angle = degrees(get_angle(self.pos, mouse_pos))
self.set_image()
last = self.rect.copy()
for k in self.keys_dict:
if pressed[k]:
x, y = self.keys_dict[k]
self.vx = x * self.speed * dt
self.vy = y * self.speed * dt
self.pos = (self.pos[0] + (self.vx),
self.pos[1] + (self.vy))
self.rect.center = self.pos
current = self.rect # Just for readability we 'rename' the objects rect attribute to 'current'.
for wall in pg.sprite.spritecollide(self, obstacles, dokill=False):
wall = wall.rect # Just for readability we 'rename' the wall's rect attribute to just 'wall'.
if last.left >= wall.right > current.left: # Collided left side.
current.left = wall.right
elif last.right <= wall.left < current.right: # Collided right side.
current.right = wall.left
elif last.top >= wall.bottom > current.top: # Collided from above.
current.top = wall.bottom
elif last.bottom <= wall.top < current.bottom: # Collided from below.
current.bottom = wall.top
def draw(self, surface):
surface.blit(self.image, self.rect)