I've been working through this online tutorial on Pygame (Python Version 3.3.1), and have come to a point where my sprite can jump, but can walk only a few pixels in either direction. I'd really like to move forward with this code as I like how it is structured (not a lot of code in the Main method). Can anyone spot what might be causing my sprite to get stuck?
import pygame
# Define some colors
black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = ( 0, 255, 0)
red = ( 255, 0, 0)
class Player(pygame.sprite.Sprite):
def __init__(self, *groups):
super(Player, self).__init__(groups)
self.image = pygame.image.load('Images\player1.png')
self.rect = pygame.rect.Rect((50, 650), self.image.get_size())
self.resting = False
self.dy = 0 #dy represents change in y velocity
def update(self, dt, game):
last = self.rect.copy()
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
self.rect.x -= 300 * dt
if key[pygame.K_RIGHT]:
self.rect.x += 300 * dt
#if key[pygame.K_UP]:
# self.rect.y -= 300 * dt
#if key[pygame.K_DOWN]:
# self.rect.y += 300 * dt
if self.resting and key[pygame.K_SPACE]:
self.dy = -500 #If space bar is pressed, increase velocity.
self.dy = min(400, self.dy + 40) #Speed capped at 400. Gravity set at 40.
self.rect.y += self.dy * dt
new = self.rect
self.resting = False
for cell in pygame.sprite.spritecollide(self, game.walls, False):
#self.rect = last
cell = cell.rect
if last.right <= cell.left and new.right > cell.left:
new.right = cell.left
if last.left >= cell.right and new.left < cell.right:
new.left = cell.right
if last.bottom <= cell.top and new.bottom > cell.top:
#if you hit something while jumping, stop.
self.resting = True
new.bottom = cell.top
self.dy = 0
if last.top >= cell.bottom and new.top < cell.bottom:
new.top = cell.bottom
self.dy = 0 #If you hit the floor while jumping, stop
class Game(object):
def main(self, screen):
clock = pygame.time.Clock()
dt = clock.tick(30)
#image = pygame.image.load('Images\player1.gif')
background = pygame.image.load('Images\_rec_bg.png')
sprites = pygame.sprite.Group()
self.player = Player(sprites)
self.walls = pygame.sprite.Group()
block = pygame.image.load('Images\dia_tile.png')
for x in range(0, 800, 20):
for y in range(0, 800, 20):
if x in (0, 800-20) or y in (0, 800-20):
wall = pygame.sprite.Sprite(self.walls)
wall.image = block
wall.rect = pygame.rect.Rect((x, y), block.get_size())
sprites.add(self.walls)
running = True
while running:
clock.tick(30) #run no more than 30 time per second
dt - clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT or \
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
running = False
#sprites.update()
#sprites.update(dt / 1000.)
#screen.fill(black)
sprites.update(dt / 1000., self)
#screen.blit(image, (320, 240)) #Transfer to video RAM
screen.blit(background, (0,0))
sprites.draw(screen)
pygame.display.flip() #Dispaly to Screen
if __name__ == '__main__':
pygame.init()
screen = pygame.display.set_mode((800, 800))
Game().main(screen)
Im not sure but it looks like you're only letting the player move from side to side if the player is in the air (jumping)
If i'm right you need to enable youre player to move side to side even when self.resting = True
what happens if you do something like this:
if key[pygame.K_LEFT]:
self.rect.x -= 75
if key[pygame.K_RIGHT]:
self.rect.x += 75
the thing about that is the player will move from side to sdie but when you jump and press right or left the player will fly all over instead of going into a steady jump and fall
so you need to figure out how to include the *dt to regulate the players movement in air but at the same time have the player be able to move while on the ground to
try having two sets of if statments:
if key[pygame.K_LEFT]:
self.rect.x -= 300 * dt
if key[pygame.K_RIGHT]:
self.rect.x += 300 *dt
if key[pygame.K_LEFT]and self.resting:
self.rect.x -= 50
if key[pygame.K_RIGHT]and self.resting:
self.rect.x += 50
the first one is for in the air the second is for when the player is on the ground
try that and tell me if it works
i tried it on my computer and it worked but i probably used differnt art that could also be the problem becuase it might be blitting behind something so check everything
Good Luck!!
Related
This question already has an answer here:
Sometimes the ball doesn't bounce off the paddle in pong game
(1 answer)
Closed 1 year ago.
I am currently trying to create a pong game but for some reason, the ball would not bounce off of the rectangles and I am not sure where I have made a mistake even though I followed a video about rectangle collision online. Please let me know where I made a mistake and how I can improve my code. Thanks!
import pygame, sys, random, time
from pygame.time import Clock
pygame.init()
#colours
black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = ( 0, 255, 0)
red = ( 255, 0, 0)
# Display
screen_width = 1000
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("2-player Pong")
# Rectangles
class Rectangle():
def __init__(self, screen, x):
self.screen = screen
self.screen_rect= screen.get_rect()
self.x = x
self.y = 250
self.width = 30
self.height = 100
self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
self.colour = black
self.velocity = 5
def draw_rectangle(self):
pygame.draw.rect(self.screen, self.colour, self.rect)
rect1 = Rectangle(screen, 50)
rect2 = Rectangle(screen, 920)
class Ball():
def __init__(self, colour):
self.screen = screen
self.colour = colour
self.width = 20
self.height = 20
self.x = screen_width//2 - 25
self.y = screen_height//2 - 25
self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
self.possible_velocities_x = [-4, 4]
self.possible_velocities_y = [-2, 2]
self.velocity = [random.choice(self.possible_velocities_x), random.choice(self.possible_velocities_y)]
def draw_ball(self):
pygame.draw.rect(self.screen, self.colour, self.rect)
def move_ball(self):
global rect1, rect2
self.rect.x += self.velocity[0]
self.rect.y += self.velocity[1]
# Collision with Screen
if self.rect.top <= 10 or self.rect.bottom >= screen_height - 10:
self.velocity[1] *= -1
# Collision with Rectangles
if self.rect.colliderect(rect1) or self.rect.colliderect(rect2):
if self.rect.left - rect1.rect.right == 0:
self.possible_velocities_x *= -1
if self.rect.right - rect2.rect.left == 0:
self.possible_velocities_x *= -1
clock = pygame.time.Clock()
ball = Ball(white)
pong = True
while pong:
pygame.time.delay(10)
clock.tick(100)
# Watch for keyboard and mouse events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pong = False
keys = pygame.key.get_pressed()
if keys[pygame.K_UP] and rect2.rect.y >= 0:
rect2.rect.y -= rect2.velocity
if keys[pygame.K_DOWN] and rect2.rect.y <= 600 - rect2.rect.height:
rect2.rect.y += rect2.velocity
if keys[pygame.K_w] and rect1.rect.y >= 0:
rect1.rect.y -= rect1.velocity
if keys[pygame.K_s] and rect1.rect.y <= 600 - rect1.rect.height:
rect1.rect.y += rect1.velocity
screen.fill(green)
rect1.draw_rectangle()
rect2.draw_rectangle()
ball.draw_ball()
ball.move_ball()
# pygame.draw.rect(screen, black, (rect_x2, rect_y2, rect_width2, rect_height2))
pygame.display.update() # Make the most recently drawn screen visible.
pygame.quit()
You must change self.velocity[0] when the ball touches the paddle. Since the movement of the ball is more than 1 pixel per frame, the ball does not exactly touch the paddle. This mans the condition self.rect.left - rect1.rect.right == 0 and self.rect.right - rect2.rect.left == 0 will not be fulfilled. If the movement in x direction is negative, the new movement needs to be positive (abs(self.velocity[0])). If the movement in x direction is positive, the new movement needs to be negative (-abs(self.velocity[0])):
class Ball():
# [...]
def move_ball(self):
self.rect.x += self.velocity[0]
self.rect.y += self.velocity[1]
# Collision with Screen
if self.rect.top <= 10 or self.rect.bottom >= screen_height - 10:
self.velocity[1] *= -1
# Collision with Rectangles
if self.rect.colliderect(rect1) or self.rect.colliderect(rect2):
if self.velocity[0] < 0:
self.velocity[0] = abs(self.velocity[0])
else:
self.velocity[0] = -abs(self.velocity[0])
See also Sometimes the ball doesn't bounce off the paddle in pong game
Right now my game works as so: My sprite can move right or left, jump and shoot fireballs (bullets). However, once my sprite walks past the limit of my background surface, it goes off-screen. So I want to make the background move along with my sprite. As soon as my player sprite moves about 50 pixels towards the edges of the screen, the background moves too. How do I create this with Pygame? I've found quite an amount of sources which shows you how to do this but with a plain colour background. But my background is an image I load into the game, so I would like to learn how to do so with an image as background. How to make it repeat once the sprite comes near the limit of both sides. I separated my codes into 3 different files: a Main.py, settings.py and Sprite1.py. Here's Main.py:
import pygame
import os
import sys
import time
from pygame import mixer
from Sprite1 import *
from settings import *
'''
Setup
'''
pygame.init()
clock = pygame.time.Clock()
pygame.mixer.music.load('.\\sounds\\Fairy.mp3')
pygame.mixer.music.play(-1, 0.0)
all_sprites = pygame.sprite.Group()
player = Player(all_sprites)
player.rect.x = 50
player.rect.y = 500
showStartScreen(surface)
'''
Main loop
'''
main = True
while main == True:
background = pygame.image.load(os.path.join('images', 'Bg.png'))
surface.blit(background, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
main = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(-steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(steps,0)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(-steps,0)
keys = pygame.key.get_pressed()
if not(isJump):
if keys[pygame.K_UP]:
isJump = True
else:
if jumpCount >= -10:
player.rect.y -= (jumpCount * abs(jumpCount)) * 1
jumpCount -= 2
else:
jumpCount = 10
isJump = False
# dt = time since last tick in milliseconds.
dt = clock.tick(60) / 1000
all_sprites.update(dt)
player.update(dt)
all_sprites.draw(surface) #refresh player position
pygame.display.flip()
Here's settings.py:
import pygame
isJump = False
jumpCount = 10
width = 960
height = 720
fps = 40 # frame rate
#ani = 4 # animation cycles
pygame.display.set_caption('B.S.G.')
surface = pygame.display.set_mode((width, height))
PLAYER_ACC = 0.5
PLAYER_FRICTION = -0.12
PLAYER_GRAV = 0.8
PLAYER_JUMP = 20
PLAYER_LAYER = 2
PLATFORM_LAYER = 1
steps = 10 # how fast to move
And here's Sprite1.py:
import pygame
import sys
import os
import time
from pygame import mixer
from pygame.locals import *
from settings import *
vec = pygame.math.Vector2
def showStartScreen(surface):
show = True
while (show == True):
background = pygame.image.load(os.path.join('images', 'Starting_scr.png'))
# rect = surface.get_rect()
surface.blit(background, (0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
show = False
class Player(pygame.sprite.Sprite):
def __init__(self, all_sprites):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.health = 10
self.jumping = False
self.images = []
self.imagesleft = []
self.imagesright = []
self.direction = "right"
self.alpha = (0,0,0)
self.ani = 4 # animation cycles
self.all_sprites = all_sprites
self.add(self.all_sprites)
self.bullet_timer = .1
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesright.append(img)
self.image = self.imagesright[0]
self.rect = self.image.get_rect()
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img = pygame.transform.flip(img, True, False)
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesleft.append(img)
self.image = self.imagesleft[0]
self.rect = self.image.get_rect()
def control(self,x,y):
'''
control player movement
'''
self.movex += x
self.movey -= y
def update(self, dt):
'''
Update sprite position
'''
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesleft[self.frame//self.ani]
self.direction = "left"
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesright[self.frame//self.ani]
self.direction = "right"
#enemy_hit_list = pygame.sprite.spritecollide(self,enemy_list, False)
#for enemy in enemy_hit_list:
#self.health -= 1
#print(self.health)
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
self.bullet_timer -= dt # Subtract the time since the last tick.
if self.bullet_timer <= 0:
self.bullet_timer = 100 # Bullet ready.
if keys: # Left mouse button.
# Create a new bullet instance and add it to the groups.
if self.direction == "right":
Bullet([self.rect.x + self.image.get_width(), self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
else:
Bullet([self.rect.x, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
self.bullet_timer = .1 # Reset the timer.
class Bullet(pygame.sprite.Sprite):
IMAGE = None
FLIPPED_IMAGE = None
def __init__(self, pos, direction, *sprite_groups):
super().__init__(*sprite_groups)
# cache images
if not Bullet.IMAGE:
Bullet.IMAGE = pygame.image.load(os.path.join('images','fireball.png'))
Bullet.FLIPPED_IMAGE = pygame.transform.flip(Bullet.IMAGE, True, False)
if direction == "right":
self.vel = pygame.math.Vector2(750, 0)
self.image = Bullet.IMAGE
else:
self.vel = pygame.math.Vector2(-750, 0)
self.image = Bullet.FLIPPED_IMAGE
self.pos = pygame.math.Vector2(pos)
self.rect = self.image.get_rect(center=pos)
def update(self, dt):
# Add the velocity to the position vector to move the sprite
self.pos += self.vel * dt
self.rect.center = self.pos # Update the rect pos.
if not pygame.display.get_surface().get_rect().colliderect(self.rect):
self.kill()
I'm open to any suggestions. Thanks beforehand!
Here's how I would approach this...
set up a scrolling background as in the tutorial and make sure you can get that working OK by moving the background back & forth instead of the player (just freeze the player's x coordinate in the center and move the background with your left/right keys.
Add some constants into your settings for an edge buffer (the number of x-increments you want the player to avoid the boundaries by
AFTER you get the key input (left or right) set up a conditional statement. For this, you will have to access the player's x-coordinate and compare it to the buffer. Well, either 0+buffer or width-buffer actually and then based on those cases either move the player or the background. See if you can get that working.
Then, you will realize that when you move the background, you are moving the frame of reference for everything else, meaning things like the fireball, so if you are moving the background left or right, you will need to apply those updates to the other objects as well so it looks correct.
If yer stuck, make those updates to code above & message me back in a comment.
this is my first question in stackoverflow. I started learning python 3 months ago, and I'm building a platformer game using sprites. I had to isolate the problem, so I'm only posting the part where the issue is.
Whenever the square is landing on any platform, there is a detection of collision but the square actually goes through the platform approximately 10 pixels down (DURING the collision) and then it goes back up and it stabilizes on top of the platform.
You can SEE the effect better if you adjust the FPS to 2.
How can I fix this? I remember building a previous game BUT without using acceleration in "x" axis (friction) and "y" axis (gravity), just fast&stop movements of the square (left/right/up/down) detecting collision and the square never went through the platfom...
Here is the isolated problem:
import pygame as pg
import random
WIDTH = 900
HEIGHT = 600
NAME = "square"
FPS = 60
green = (0, 150, 0)
white = (255, 255, 255)
black = (0, 0, 0)
class Platform(pg.sprite.Sprite):
def __init__(self, x, y, width, height, color):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((width, height))
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
class Player(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((40, 40))
self.image.fill(black)
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT / 2)
self.posx = WIDTH / 2
self.posy = HEIGHT * 0.10
self.velx = 0
self.vely = 0
self.accx = 0
self.accy = 0
self.jumping = False
self.jump_go = False
def jump(self):
if self.jumping == False:
self.jumping = True
self.vely = -25
def update(self):
self.accx = 0 #FRICTION
self.accy = 1 #GRAVITY
keys = pg.key.get_pressed()
if keys[pg.K_RIGHT]:
self.accx = 1
if keys[pg.K_LEFT]:
self.accx = -1
if self.vely != 0:
self.jump_go = False
#MOVEMENT IN X:
self.accx = self.accx + (self.velx * (-0.10))
self.velx = self.velx + self.accx
self.posx = self.posx + self.velx
self.rect.x = self.posx
if abs(self.velx) < 0.5:
self.velx = 0
#MOVEMENT IN Y:
self.accy = self.accy + (self.vely * (-0.05))
self.vely = self.vely + self.accy
self.posy = self.posy + self.vely
self.rect.y = self.posy
#IF PLAYER FALLS TO EDGE OF SCREEN:
if self.posy > HEIGHT:
self.posy = 0
if self.posx < 0:
self.posx = WIDTH
if self.posx > WIDTH:
self.posx = 0
class Game:
def __init__(self):
pg.init()
pg.mixer.init()
pg.font.init()
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
self.clock = pg.time.Clock()
self.running = True
def new(self):
self.all_sprites = pg.sprite.Group()
self.all_platforms = pg.sprite.Group()
for i in range(3):
self.platform = Platform(random.randint(0, WIDTH), random.randint(HEIGHT * .15,
HEIGHT - 25), random.randint(100, 300), 50, green)
self.all_platforms.add(self.platform)
self.all_sprites.add(self.platform)
self.player = Player()
self.all_sprites.add(self.player)
self.run()
def run(self):
self.playing = True
while self.playing:
self.clock.tick(FPS)
self.eventos()
self.update()
self.draw()
def eventos(self):
for event in pg.event.get():
if event.type == pg.QUIT:
if self.playing:
self.playing = False
self.running = False
if event.type == pg.KEYDOWN:
if self.player.jump_go:
if event.key == pg.K_a:
self.player.jump()
def update(self):
self.all_sprites.update()
# Check if player hit platfom:
if self.player.vely > 0:
hits = pg.sprite.spritecollide(self.player, self.all_platforms, False)
if hits:
for hit in hits:
if self.player.rect.top < hit.rect.top:
self.player.posy = hit.rect.top - self.player.rect.height
self.player.vely = 0
self.player.jumping = False
self.player.jump_go = True
def draw(self):
self.screen.fill(white)
self.all_sprites.draw(self.screen)
pg.display.flip()
g = Game()
while g.running:
g.new()
pg.quit()
In your collision check you get all hits, then you check for each hit
if self.player.rect.top < hit.rect.top:
this is too late.
If your player travels less then its height per frame its bottom will penetrate the hit.rect.top, then be checked, but its top is still above it so nothing happens.
Next frame it travels further, (still not quite fullfilling if self.player.rect.top < hit.rect.top:) and goes a bit further through your hit.
Some frames after it finally fullfills if self.player.rect.top < hit.rect.top: and its position is corrected by
if self.player.rect.top < hit.rect.top:
self.player.posy = hit.rect.top - self.player.rect.height
self.player.vely = 0
self.player.jumping = False
self.player.jump_go = True
leading to the described "pass through and jump up" effect you see.
You can mitigate the effect by changing
if self.player.rect.top < hit.rect.top:
to when the self.player.rect.bottom passes hit.rect.top - if bottom does not exist, use
if (self.player.rect.top - self.player.rect.height) < hit.rect.top:
to lessen the "pass through" effect.
I think you should move your collision detection to the Player.update() and Player.jump() functions.
The reason behind this is the complexity of collision detection. Each update() your player is moving some amount of pixels in two dimensions. But let's consider just a single dimension to make it simpler...
Say your player is moving 5 pixels "right" (+x) and an obstacle is 3 pixels away. Obviously it will collide with an overlap of 2 pixels. So what should happen in this case? That depends on your game logic, but in most cases the player should stop an only +3 pixels, resting next to the obstacle. This is a simple calculation knowing the direction of movement, and sizes of the sprites. The logic can determine: Want to move 5 right; Can only move 3 -> Move 3.
In your existing game code, the player is already moved before you check the collisions. You don't know where the player moved from, just that it now overlaps. This makes it more difficult to correct. You have to correct the collision after the fact, not before/during.
your input really helped me out in finding a soultion, this is what I did to fix my issue:
I created a new variable (instance attribute) in my "Player" class:
self.bottom_quart = self.rect.y + (self.rect.height/2)
Then, in the "Game" class, inside the "def update(self):" method, this is what it looks like now:
def update(self):
self.all_sprites.update()
#Check if player hit platfom:
if self.player.vely > 0:
hits = pg.sprite.spritecollide(self.player, self.all_platforms, False)
if hits:
for hit in hits:
if self.player.rect.bottom > hit.rect.top > self.player.rect.top
and self.player.bottom_quart < hit.rect.top:
self.player.rect.bottom = hit.rect.top
self.player.posy = hit.rect.top - self.player.rect.height
self.player.vely = 0
self.player.jumping = False
self.player.jump_go = True
So basically this fixed 2 things:
BEOFRE, when the player object was landing on a platform, it would "go thru" the platform and then placed itself on top of the platform. NOW, when the player lands on the platform, it DOESNT go thru, and sets itself smoothly on top of the platform. This was fixed by setting:
self.player.rect.bottom = hit.rect.top
self.player.posy = hit.rect.top - self.player.rect.height
The second issue that got fixed was that when the player hit a platform from the side, it would snap really fast back on top of the platform, which is not a normal behavior. That got fixed by creating the instance attribute:
self.bottom_quart = self.rect.y + (self.rect.height/2)
inside the "Player" class. That works as a new boundary that need to be True in the if statement deciding whether or not it sits on top of the platform or just passes thru when hit from the sides.
Thanks for your help!
Complete novice, new to programming in general. I am trying to write a side scroller game in python, using pygame. I have created three different libraries for my sprite classes for: the player, the enemy, and the land. I made the land a sprite so that the player can interact (collide) with different objects in the land class and not be able to pass through them. The issue I am having is that I want the enemy sprite to interact with the land sprite as well. Ideally, I want the enemy sprites to start at point "x" and be set in motion (-2) until it comes into contact with the land sprite, at which point I want it to reverse direction. I have been trying everything I can think of, and searching online for a solution to make this work with no success. It seems like it should be really simple, but I can't make it work.
Thank you for your time.
here's my code:
land sprite :
import pygame
class Object(pygame.sprite.Sprite):
def __init__(self,image_file):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
player sprite :
import pygame
class Player(pygame.sprite.Sprite):
change_x = 0
change_y = 0
jump_ready = False
frame_since_collision = 0
frame_since_jump = 0
frame = 0
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.images = []
for i in range(1,9):
img = pygame.image.load("pit"+str(i)+".png").convert()
img.set_colorkey((0,0,0))
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
def changespeed_x(self,x):
self.change_x = x
def changespeed_y(self,y):
self.change_y = y
def update(self,ground,brick,enemy):
if self.change_x < 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4]
if self.change_x > 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4]
old_x = self.rect.x
new_x = old_x + self.change_x
self.rect.x = new_x
player_health = 5
hurt = pygame.sprite.spritecollide(self,enemy,False)
if hurt:
player_health -= 1
print(player_health)
brick_break = pygame.sprite.spritecollide(self,brick,True)
collide = pygame.sprite.spritecollide(self,ground,False)
if collide:
self.rect.x = old_x
old_y = self.rect.y
new_y = old_y + self.change_y
self.rect.y = new_y
touch_list = pygame.sprite.spritecollide(self,ground,False)
for ground in touch_list:
self.rect.y = old_y
self.rect.x = old_x
self.change_y = 0
self.frame_since_collision = 0
if self.frame_since_collision < 6 and self.frame_since_jump < 6:
self.frame_since_jump = 100
self.change_y -= 8
self.frame_since_collision += 1
self.frame_since_jump += 1
def calc_grav(self):
self.change_y += .35
if self.rect.y >= 450 and self.change_y >= 0:
self.change_y = 0
self.rect.y = 450
self.frame_since_collision = 0
def jump(self,blocks):
self.jump_ready = True
self.frame_since_jump = 0
this is the enemy sprite that works, it only moves left, every time I tried a variation of the collision code like I have in the player class the sprite would just stop when it collided with the land sprite
enemy sprite :
import pygame
class Enemy(pygame.sprite.Sprite):
def __init__(self,image_file):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.image = self.image.convert()
self.image.set_colorkey((0,0,0))
self.rect = self.image.get_rect()
def update(self,ground):
change_x = -2
self.rect.x += change_x
and my main program code :
# first must import
import pygame
import random
import thing
import enemy
import player
# initialize the game engine
pygame.init()
# define some colors
# more color combos at www.colorpicker.com
black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = (0, 255, 0)
red = (255, 0, 0)
blue = (131,226,252)
# open and set window size.
screen_width = 700
screen_height = 350
screen = pygame.display.set_mode([screen_width,screen_height])
break_list = pygame.sprite.Group()
land_list = pygame.sprite.Group()
enemy_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
cloud = pygame.image.load("cumulus-huge.png").convert()
for x in range(300,500,60):
brick = thing.Object("birck.png")
brick.rect.x = x
brick.rect.y = 180
break_list.add(brick)
all_sprites_list.add(brick)
for x in range(0,200,50):
wall = thing.Object("Sky3.png")
wall.rect.x = -180
wall.rect.y = x
land_list.add(wall)
all_sprites_list.add(wall)
for x in range (-50,1400,70):
ground = thing.Object("Ground2.png")
ground.rect.x = x
ground.rect.y = 305
land_list.add(ground)
all_sprites_list.add(ground)
monster = enemy.Enemy("monster1.png")
monster.rect.x = 650
monster.rect.y = 250
enemy_list.add(monster)
all_sprites_list.add(monster)
for x in range(760,1070,300):
pipe = thing.Object("pipe-top.png")
pipe.rect.x = x
pipe.rect.y = 225
land_list.add(pipe)
all_sprites_list.add(pipe)
player = player.Player()
player.rect.x = 10
player.rect.y = 230
all_sprites_list.add(player)
# set the window title
pygame.display.set_caption("Scroller")
# the following code sets up the main program loop
# Boolean Variable to loop until the user clicks the close button.
done = False # loop control
# used to manage how fast the screen updates
clock = pygame.time.Clock() # controls how fast game runs
# Main Program Loop
while done == False:
# ALL EVENT PROCESSING (input) SHOULD GO BELOW THIS COMMENT
for event in pygame.event.get(): # user did something
if event.type == pygame.QUIT: #If user clicked close
done = True # flag that we are done so we exit this loop
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed_x(-6)
if event.key == pygame.K_RIGHT:
player.changespeed_x(6)
if event.key == pygame.K_UP:
player.jump(land_list)
if event.key == pygame.K_DOWN:
player.changespeed_y(6)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed_x(-0)
if event.key == pygame.K_RIGHT:
player.changespeed_x(0)
monster.update()
player.update(land_list,break_list,enemy_list)
player.calc_grav()
# ALL EVENT PROCESSING (input) SHOULD GO ABOVE THIS COMMENT
# ALL GAME LOGIC (process) SHOULD GO BELOW THIS COMMENT
if player.rect.x >= 500:
diff = player.rect.x - 500
player.rect.x=500
for ground in land_list:
ground.rect.x -= diff
for brick in break_list:
brick.rect.x -= diff
for monster in enemy_list:
monster.rect.x -= diff
if player.rect.x <= 15:
diff = 15 - player.rect.x
player.rect.x = 15
for ground in land_list:
ground.rect.x += diff
for brick in break_list:
brick.rect.x += diff
for monster in enemy_list:
monster.rect.x += diff
# ALL GAME LOGIC (process) SHOULD GO ABOVE THIS COMMENT
# ALL CODE TO DRAW (output) SHOULD GO BELOW THIS COMMENT
# First, clear the screen. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.fill(blue)
screen.blit(cloud,[200,0])
cloud.set_colorkey(black)
all_sprites_list.draw(screen)
# ALL CODE TO DRAW (output) SHOULD GO ABOVE THIS COMMENT
# This will update the screen with what's been drawn.
pygame.display.flip()
# limit to 30frames per second
clock.tick(30)
pygame.quit()
Your enemy class should be like this:
class Enemy(pygame.sprite.Sprite):
def __init__(self,image_file):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.image = self.image.convert()
self.image.set_colorkey((0,0,0))
self.rect = self.image.get_rect()
self.vel = -2
def update(self,ground):
self.rect.x += self.vel
Then in your update loop, implement this pseudocode:
...
if monster collides with ground:
monster.vel *= -1
...
I have my window popping up and I can move my sprite around the screen with my arrow keys. I know there's a collision function with sprite on sprite collision, but I can't seem to figure out how to stop them from moving outside of the visible area. Any thoughts?
my move function:
def moveme(self,coords)
#coords=(x,y)
self.rect.move_ip(coords)
for the event handler i'm using something like
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
character.moveme((0, -4))
Any help would be greatly appreciated!
How about using clamp_ip after moving?
Rect.clamp_ip(Rect): return None
It takes a Rectangle which in your case is your window tuple.
So your code would look like this:
screen_rect = pygame.Rect((0, 0), (700, 400))
def moveme(self,x,y):
self.rect.move_ip((x,y))
self.rect.clamp_ip(screen_rect)
Found the answer myself after looking up rect properties.. here's the code
def moveme(self,x,y):
if self.rect.left + x < 0:
self.rect.left = 0
elif self.rect.right + x > 700:
self.rect.right = 700
elif self.rect.top + y < 0:
self.rect.top = 0
elif self.rect.bottom + y > 400:
self.rect.bottom = 400
else:
self.rect.move_ip((x,y))
where 400 is the height of your window, and 700 is the width
I think i got it here:
import pygame
running = True
GREEN = (0, 255, 0)
BLACK = (0, 0, 0)
FPS = 30
pygame.init()
all_sprites = pygame.sprite.Group() #groupes all sprites
all_sprites.update()
tab.fill(BLACK) #any color
all_sprites.draw(tab)
clock = pygame.time.Clock()
WIDTH = 500 #YOUR WIDTH
HEIGHT = 500 #YOUR HEIGHT
tab = pygame.display.set_mode((WIDTH, HEIGHT)) #window width and height
class Player(pygame.sprite.Sprite):
#your Character
def __init__():
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Ship.png") #your image or shape/sprites look
self.rect = self.image.get_rect()
self.rect.center = (WIDTH / 2, (HEIGHT / 2)) #sprites Position
def update(self):
key = pygame.key.get_pressed();
#stop at edge commands (might need to ajust)
if(self.rect.x >= (WIDTH-200)):
self.rect.x -= 10;
elif(self.rect.x <= 0):
self.rect.x += 10;
elif(self.rect.y <= 0):
self.rect.y += 10;
elif(self.rect.y >= (HEIGHT-200)):
self.rect.y -= 10
else:
#sprites move commands
if key[pygame.K_RIGHT]:self.rect.x += 10;
if key[pygame.K_LEFT]:self.rect.x -= 10;
if key[pygame.K_UP]:self.rect.y -= 10;
if key[pygame.K_DOWN]:self.rect.y += 10;
player = Player() #makes the sprite that the player controlles
all_sprites.add(player)
while (running):
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
all_sprites.update() #updates screen
tab.fill(BLACK)
all_sprites.draw(tab) #adds all sprites to the screen
pygame.display.flip()
I got some of this from someone else but i can't remember but i think this will help --------------------------------------------------------------------------------------
note: you might need to ajust some variables and whitespace and more. (p.s.: i'm not good at grammar) also, sorry that its long i don't think it will work without all this stuff.