This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 6 years ago.
I'm still new to python, and have started with pygame. I'm making an endless runner game, but I've run into a problem with my run cycle. Here's my code:
import pygame
import sys
from pygame.locals import *
pygame.init()
clock = pygame.time.Clock()
clock2 = pygame.time.get_ticks()
screen = pygame.display.set_mode((640, 575))
bgx = 0
bgx2 = -800
scroll = 10
pose = 1
background = pygame.image.load("images/background2.png").convert_alpha();
player = pygame.image.load("images/character1.png").convert_alpha();
screen.blit(background, (0, 0))
def draw_screen(x):
screen.blit(background, (x, 0))
def draw_screen2(x2):
screen.blit(background, (x2, 0))
def draw_player(pose):
if pose == 1:
player = pygame.image.load("images/character1.png").convert_alpha();
screen.blit(player, (0, 0))
elif pose == 2:
player = pygame.image.load("images/character2.png").convert_alpha();
screen.blit(player, (0, 0))
elif pose == 3:
player = pygame.image.load("images/character3.png").convert_alpha();
screen.blit(player, (0, 0))
elif pose == 4:
player = pygame.image.load("images/character2.png").convert_alpha();
screen.blit(player, (0, 0))
def set_poses(pose):
if pose == 1:
pose = 2
if pose == 2:
pose = 3
if pose == 3:
pose = 4
if pose == 4:
pose = 1
while True: #Loop
clock2 = pygame.time.get_ticks()
#Quitting Function
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
quit()
clock.tick(50)
#Screen Scrolling
if bgx != 800:
bgx += scroll
else:
bgx = 0
if bgx2 != 0:
bgx2 += scroll
else:
bgx2 = -800
#Drawing Items
draw_screen2(bgx2)
draw_screen(bgx)
draw_player(pose)
if clock2%6 == 0:
set_poses(pose)
pygame.display.update()
So the screen is scrolling, and my character appears but he stays in his first position (Frame I guess.) at the part where it runs set_poses(pose) I tried having it also print something right before setting the pose, which it did, but its not setting the pose. I tried having it printing the pose, and it showed that the poses wasn't changing. So, yea, I've found my problem, but I can't for the life of me find a solution.
Rather than trying to pass by reference - which is what you're doing, try something like this:
def set_pose(pose):
if pose >= 4:
return 1
else:
return pose + 1
Then when you're trying to update the pose variable elsewhere:
pose = set_pose(pose)
Would you agree that you can call the arguments to your function whatever you want? For example, set_pose could look like this and do exactly the same thing:
def set_pose(foo):
if foo >= 4:
return 1
else:
return foo + 1
In other words, just because it's called pose inside the function doesn't mean it will refer to pose outside the function.
Related
I based the code below on this article: http://kevman3d.blogspot.com/2015/07/basic-games-in-python-1982-would-be.html
and on the ZX BASIC in this image:
10 LET P=0
20 LET T=P
30 FOR Z=1 T0 10
35 CLS
37 PRINT AT 12,0;T
40 LET R=INT (RND*17)
50 FOR Y=0 TO 10
60 PRINT AT Y,R;"O"
70 LET N=P(INKEY$="4")-(INKEY$="1")
80 IF N<0 OR N>15 THEN LET N=P
100 PRINT AT 11,P;" ";AT 11,N;"┗┛";AT Y,R;" "
110 LET P=N
120 NEXT Y
130 LET T=T+(P=R OR P+1=R)
150 NEXT Z
160 PRINT AT 12,0;"YOU SCORED ";T;"/10"
170 PAUSE 4E4
180 RUN
I also shared it on Code Review Stack Exchange, and got a very helpful response refactoring it into high quality Python code complete with type hints.
However, for my purposes I'm wanting to keep the level of knowledge required to make this work a little less advanced, including avoiding the use of OOP. I basically want to maintain the "spirit of ZX BASIC" but make the code "not awful." The use of functions is fine, as we were allowed GOSUB back in the day.
I'm pretty dubious about the approach of using nested FOR loops inside the main game loop to make the game work, but at the same time I'm curious to see how well the BASIC paradigm maps onto the more event driven approach of Pygame, so I'd welcome any comments on the pros and cons of this approach.
More specifically,
Is there somewhere I can put the exit code if event.type == pygame.QUIT where it will work during game rounds, without having to repeat the code elsewhere?
How would this game be implemented if I were to avoid the use of FOR loops / nested FOR loops?
Are there any points of best practice for pygame/Python which I have violated?
What improvements can you suggest, bearing in mind my purpose is to write good Pygame code while maintaining the "spirit" of the ZX81 games?
Any input much appreciated. I'm also curious to see a full listing implementing some of the ideas arising from my initial attempt if anyone is willing to provide one.
import pygame
import random
import sys
# Define colors and other global constants
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
TEXT_SIZE = 16
SCREEN_SIZE = (16 * TEXT_SIZE, 13 * TEXT_SIZE)
NUM_ROUNDS = 5
def print_at_pos(row_num, col_num, item):
"""Blits text to row, col position."""
screen.blit(item, (col_num * TEXT_SIZE, row_num * TEXT_SIZE))
# Set up stuff
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption("Dropout")
game_font = pygame.font.SysFont('consolas', TEXT_SIZE)
# Create clock to manage how fast the screen updates
clock = pygame.time.Clock()
# initialize some game variables
player_pos, new_player_pos, coin_row, score = 0, 0, 0, 0
# -------- Main Program Loop -----------
while True:
score = 0
# Each value of i represents 1 round
for i in range(NUM_ROUNDS):
coin_col = random.randint(0, 15)
# Each value of j represents one step in the coin's fall
for j in range(11):
pygame.event.get()
pressed = pygame.key.get_pressed()
if pressed[pygame.K_RIGHT]:
new_player_pos = player_pos + 1
elif pressed[pygame.K_LEFT]:
new_player_pos = player_pos - 1
if new_player_pos < 0 or new_player_pos > 15:
new_player_pos = player_pos
# --- Game logic
player_pos = new_player_pos
coin_row = j
if player_pos + 1 == coin_col and j == 10:
score += 1
# --- Drawing code
# First clear screen
screen.fill(WHITE)
player_icon = game_font.render("|__|", True, BLACK, WHITE)
print_at_pos(10, new_player_pos, player_icon)
coin_text = game_font.render("O", True, BLACK, WHITE)
print_at_pos(coin_row, coin_col, coin_text)
score_text = game_font.render(f"SCORE: {score}", True, BLACK, WHITE)
print_at_pos(12, 0, score_text)
# --- Update the screen.
pygame.display.flip()
# --- Limit to 6 frames/sec maximum. Adjust to taste.
clock.tick(8)
msg_text = game_font.render("PRESS ANY KEY TO PLAY AGAIN", True, BLACK, WHITE)
print_at_pos(5, 0, msg_text)
pygame.display.flip()
waiting = True
while waiting:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit(0)
if event.type == pygame.KEYDOWN:
waiting = False
Here's my reorganisation of your code:
import pygame
import random
# Define global constants
TEXT_SIZE = 16
SCREEN_SIZE = (16 * TEXT_SIZE, 13 * TEXT_SIZE)
NUM_ROUNDS = 5
def print_at_pos(row_num, col_num, item):
"""Blits text to row, col position."""
screen.blit(item, (col_num * TEXT_SIZE, row_num * TEXT_SIZE))
# Set up stuff
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption("Dropout")
game_font = pygame.font.SysFont("consolas", TEXT_SIZE)
# Create clock to manage how fast the screen updates
clock = pygame.time.Clock()
# draw the images
player_icon = game_font.render("|__|", True, "black", "white")
# if we don't specify a background color, it'll be transparent
coin_text = game_font.render("O", True, "black")
msg_text = game_font.render("PRESS ANY KEY TO PLAY AGAIN", True, "black", "white")
# initialize some game variables
waiting = False # start in game
player_pos = 0
score = 0
game_round = 0
coin_row = 0
coin_col = random.randint(0, 15)
running = True # For program exit
# -------- Main Program Loop -----------
while running:
# event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if waiting:
waiting = False
score = 0 # reset score
elif event.key == pygame.K_LEFT:
player_pos -= 1
elif event.key == pygame.K_RIGHT:
player_pos += 1
# --- Game logic
if waiting:
# don't update the game state or redraw screen
print_at_pos(5, 0, msg_text)
else:
coin_row += 1 # TODO: decouple from frame rate
if -1 > player_pos:
player_pos = -1 # so we can catch a coin at zero
elif 15 < player_pos:
player_pos = 15
# coin is in scoring position
if coin_row == 10:
if player_pos + 1 == coin_col:
score += 1
elif coin_row > 10: # round is over
coin_col = random.randint(0, 15)
coin_row = 0
game_round+= 1
if game_round >= NUM_ROUNDS:
waiting = True
game_round = 0 # reset round counter
# --- Drawing code
screen.fill("white") # clear screen
print_at_pos(10, player_pos, player_icon)
print_at_pos(coin_row, coin_col, coin_text)
score_text = game_font.render(f"SCORE: {score}", True, "black", "white")
print_at_pos(12, 0, score_text)
# --- Update the screen.
pygame.display.flip()
# --- Limit to 6 frames/sec maximum. Adjust to taste.
clock.tick(6)
pygame.quit()
I've used a boolean waiting to allow for common event and game state handling that only moves during gameplay. For more complex interactions, you'll want a state machine.
The coin movement is currently coupled to the frame rate, which is easy, but ideally you'd specify a rate/time interval, e.g. 200ms between row drops and then you could have a refresh rate similar to the monitor refresh rate.
I was trying to create a function that will load an image and move the image downwards while loading another image and still moving with the same speed as the first. But I don't know how to do it, all I can do for now is to load the next image when the y coordinate of the first is at 500
def aliens():
s = 0
i = "345678"
c = 1
b = int("".join(random.sample(i, c)))
h = 1
while h < 2:
while s <= b:
alien = pygame.image.load("ali.jpg")
alien = pygame.transform.scale(alien, (100, 100))
pos = "0123456789"
l = 3
x = int("".join(random.sample(pos, l)))
y = 0
if x > 500:
h = 3
crash = False
s +=1
while not crash :
scn.blit(alien, (x, y))
y +=2
pygame.display.flip()
if y > 500:
crash = True
The core of your problem is the fact that you are trying to do too many things in the same function. Try to follow the SRP (Single Responsability Principle).
Personnally I would use OOP (Object Oriented Programming) here but I don't know if you are familar with the concept, so first let's stick to the basics.
Here is how I would separate things up, if I wasn't allowed to use OOP:
First I would define two constants:
ALIEN_SIZE = 100
ALIEN_IMG = pg.image.load("green_square.png").convert()
ALIEN_IMG = pg.transform.scale(ALIEN_IMG, (ALIEN_SIZE, ALIEN_SIZE))
Since you are always using the same values, there is no need to load your image all the time. Loading your image just once will have a very positive impact on game's performances.
(Note that I used a diffrent image since you did not provide the image you use but feel free to put the link to your image back)
Then I would define an alien list:
aliens = []
I don't know how you plan to spawn aliens in your project ? For this example I used a custom event with a timer:
# Custom event
SPAWN_ALIEN = pg.USEREVENT
pg.time.set_timer(SPAWN_ALIEN, 2000)
# This function handles all pygame events
def handle_evt():
for evt in pg.event.get():
if evt.type == pg.QUIT:
exit()
if evt.type == SPAWN_ALIEN:
spawn_alien()
# This function spawns an alien
def spawn_alien():
pos = [rd.randint(0, screen.get_width() - ALIEN_SIZE), 0]
aliens.append(pos)
To make aliens move, I use a update() function:
# update aliens position and check if they leave the screen
def update():
for alien in aliens:
move_alien(alien)
if out_of_screen(alien):
kill_alien(alien)
# This function update alien's y position
def move_alien(alien):
alien[1]+=1
# This function remove the given alien from the aliens list
def kill_alien(alien):
aliens.remove(alien)
# This function returns True if the given position is outside screen's boundries
def out_of_screen(pos):
x, y = pos
if x < 0 or x > screen.get_width():
return True
elif y < 0 or y > screen.get_height():
return True
return False
Finally to render things :
def draw():
# Clear screen
screen.fill((0,0,0))
# Draw aliens
for alien in aliens:
screen.blit(ALIEN_IMG, alien)
Here is the full code, so you can see how everything is interacting :
# General imports
import pygame as pg
import random as rd
import sys
# Init
pg.init()
# Vars & consts
screen = pg.display.set_mode((500, 500))
pg.display.set_caption("Example")
FPS = 60
clock = pg.time.Clock()
ALIEN_SIZE = 100
ALIEN_IMG = pg.image.load("green_square.png").convert()
ALIEN_IMG = pg.transform.scale(ALIEN_IMG, (ALIEN_SIZE, ALIEN_SIZE))
# Custom event
SPAWN_ALIEN = pg.USEREVENT
pg.time.set_timer(SPAWN_ALIEN, 2000)
# Main functions
def update():
for alien in aliens:
move_alien(alien)
if out_of_screen(alien):
kill_alien(alien)
def draw():
# Clear screen
screen.fill((0,0,0))
# Draw aliens
for alien in aliens:
screen.blit(ALIEN_IMG, alien)
def handle_evt():
for evt in pg.event.get():
if evt.type == pg.QUIT:
exit()
if evt.type == SPAWN_ALIEN:
spawn_alien()
def exit():
pg.quit()
sys.exit()
# Other functions
def spawn_alien():
pos = [rd.randint(0, screen.get_width() - ALIEN_SIZE), 0]
aliens.append(pos)
def move_alien(alien):
alien[1]+=1
def kill_alien(alien):
aliens.remove(alien)
def out_of_screen(pos):
x, y = pos
if x < 0 or x > screen.get_width():
return True
elif y < 0 or y > screen.get_height():
return True
return False
# Main loop
if __name__ == '__main__':
aliens = []
spawn_alien()
while True:
handle_evt()
update()
draw()
clock.tick(FPS)
pg.display.flip()
And just in case, here is an OOP approach :
# General imports
import pygame as pg
import random as rd
import sys
# Init
pg.init()
# Vars
screen = pg.display.set_mode((500, 500))
pg.display.set_caption("Example")
FPS = 60
clock = pg.time.Clock()
# Class
class Alien():
LIST = []
SIZE = 100
IMG = pg.image.load("green_square.png").convert()
IMG = pg.transform.scale(IMG, (SIZE, SIZE))
def __init__(self, screen_width):
self.img = Alien.IMG
self.pos = (rd.randint(0, screen_width - Alien.SIZE), 0)
# Add alien to the list
Alien.LIST.append(self)
def move(self):
x, y = self.pos
self.pos = (x, y+1)
def has_crashed(self, boundries):
x, y = self.pos
if x < 0 or x > boundries[0]:
return True
elif y < 0 or y > boundries[1]:
return True
return False
def kill(self):
Alien.LIST.remove(self)
# Custom event
SPAWN_ALIEN = pg.USEREVENT
pg.time.set_timer(SPAWN_ALIEN, 2000)
# Main functions
def update():
for alien in Alien.LIST:
alien.move()
if alien.has_crashed(screen.get_size()):
alien.kill()
def draw():
# Clear screen
screen.fill((0,0,0))
# Draw aliens
for alien in Alien.LIST:
screen.blit(alien.img, alien.pos)
def handle_evt():
for evt in pg.event.get():
if evt.type == pg.QUIT:
exit()
if evt.type == SPAWN_ALIEN:
spawn_alien()
def exit():
pg.quit()
sys.exit()
# Other functions
def spawn_alien():
Alien(screen.get_width())
# Main loop
if __name__ == '__main__':
while True:
handle_evt()
update()
draw()
clock.tick(FPS)
pg.display.flip()
I hope all those informations can help you solve your problem. It's hard to know if this, really is the behavior you wanted for your aliens. That's because your variables names are not exactly explicit. One letter variable names are rarely a good idea. But anyway even if you need them to move a little diffrently, you can take inspiration of this code organization.
Have fun !
so I have been following some guides, and taking some of my own initiative, but I've now gotten stuck. I am at a point where platforms are being generated randomly (yay) and are appearing on the screen (double yay), but are going from the bottom of the screen to the top instead of right to left which I would like. I am finding it difficult to understand how to modify this.
I have (foolishly) tried changing a variable name.
I tried changing what's within randint and the append parts. But there's not much I want to tinker around with like the "pos", for example, as I am just not too sure what's even going on with it.
# For the program, it was necessary to import the following.
import pygame, sys, random
import pygame.locals as GAME_GLOBALS
import pygame.event as GAME_EVENTS
import pygame.time as GAME_TIME
pygame.init() # To initialise the program, we need this command. Else nothing will get started.
StartImage = pygame.image.load("Assets/Start-Screen.png")
GameOverImage = pygame.image.load("Assets/Game-Over-Screen.png")
# Window details are here
windowWidth = 1000
windowHeight = 400
surface = pygame.display.set_mode((windowWidth, windowHeight))
pygame.display.set_caption('GAME NAME HERE')
oneDown = False
gameStarted = False
gameEnded = False
gamePlatforms = []
platformSpeed = 3
platformDelay = 4000
lastPlatform = 0
gameBeganAt = 0
timer = 0
player = {
"x": 10,
"y": 200,
"height": 25,
"width": 10,
"vy": 5
}
def drawingPlayer():
pygame.draw.rect(surface, (248, 255, 6), (player["x"], player["y"], player["width"], player["height"]))
def movingPlayer():
pressedKey = pygame.key.get_pressed()
if pressedKey[pygame.K_UP]:
player["y"] -= 5
elif pressedKey[pygame.K_DOWN]:
player["y"] += 5
def creatingPlatform():
global lastPlatform, platformDelay
platformY = windowWidth
gapPosition = random.randint(0, windowWidth - 100)
gamePlatforms.append({"pos": [0, platformY], "gap": gapPosition})
lastPlatform = GAME_TIME.get_ticks()
def movingPlatform():
for idx, platform in enumerate(gamePlatforms):
platform["pos"][1] -= platformSpeed
if platform["pos"][1] < -10:
gamePlatforms.pop(idx)
def drawingPlatform():
global platform
for platform in gamePlatforms:
pygame.draw.rect(surface, (214, 200, 253), (platform["gap"], platform["pos"][1], 40, 10))
def gameOver():
global gameStarted, gameEnded, platformSpeed
platformSpeed = 0
gameStarted = False
gameEnded = True
def quitGame():
pygame.quit()
sys.exit()
def gameStart():
global gameStarted
gameStarted = True
while True:
surface.fill((95, 199, 250))
pressedKey = pygame.key.get_pressed()
for event in GAME_EVENTS.get():
if event.type == pygame.KEYDOWN:
# Event key for space should initiate sound toggle
if event.key == pygame.K_1:
oneDown = True
gameStart()
if event.type == pygame.KEYUP:
if event.key == pygame.K_1:
oneDown = False
#KEYUP for the space bar
if event.type == GAME_GLOBALS.QUIT:
quitGame()
if gameStarted is True:
drawingPlayer()
movingPlayer()
creatingPlatform()
movingPlatform()
drawingPlatform()
elif gameEnded is True:
surface.blit(GameOverImage, (0, 0))
else:
surface.blit(StartImage, (0, 0))
pygame.display.update()
Expected result: Platforms approaching the yellow rectangle from the right side of the screen to the left, also the rectangle being tall instead of wide.
Actual result: Platforms coming from the bottom of the screen to the top, and the platforms being wide. But I can probably fix the latter, I just want to work on the direction first.
OK, so here were the changes I made:
In creatingPlatform() I created a variable to hold the vertical position of the platforms. I also renamed your platformY to platformX, because it's a random x-position, not a random y-position.
I used the new vertical position as part of the "pos" attribute of the platform, and put them in the conventional (x, y) ordering. Here's the code for the modified function:
def creatingPlatform():
global lastPlatform, platformDelay
platformX = windowWidth
gapPosition = random.randint(0, windowWidth - 100)
verticalPosition = random.randint(0, windowHeight)
gamePlatforms.append({"pos": [platformX, verticalPosition], "gap": gapPosition})
lastPlatform = GAME_TIME.get_ticks()
Next, I had to modify movingPlatform() so that it updated the x-position, and not the y-position. That just involved changing the index of platform["pos"] from 1 to 0:
def movingPlatform():
for idx, platform in enumerate(gamePlatforms):
platform["pos"][0] -= platformSpeed
if platform["pos"][0] < -10:
gamePlatforms.pop(idx)
Lastly, I just passed the platform positions into the draw function:
def drawingPlatform():
global platform
for platform in gamePlatforms:
pygame.draw.rect(surface, (214, 200, 253), (platform["pos"][0], platform["pos"][1], 40, 10))
This produced platforms moving right-to-left, and they are also wide and not tall!
I am trying to learn pyGame. And I ran into a problem. I have a rectangle which can be moved with arrow buttons. Then I created another thread which generates smaller rectangles which can be picked up. But when I run my game, the small generated rectangles blink too much. How can I make them be stable? I think I dont understand time concept here well. Could someone explain me etc
My code:
import pygame
import random
import threading
import thread
import sys
import time
pygame.init()
screen = pygame.display.set_mode((400, 300))
done = False
is_blue = True
entityList = []
x = 30
y = 30
clock = pygame.time.Clock()
class Entity():
def __init__(self, x, y):
self.x = x
self.y = y
def getX(self):
return self.x
def getY(self):
return self.y
def drawStuff(entityList):
# pygame.draw.rect(screen, (255, 100, 0), pygame.Rect(55, 45, 10, 10))
for x in range (0, entityList.__len__()):
pygame.draw.rect(screen, (255, 100, 0), pygame.Rect(entityList[x].getX(), entityList[x].getY(), 10, 10))
pygame.display.flip()
clock.tick(60)
class EntityManager(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
while True:
entityList = generateEntities()
drawStuff(entityList)
def endJob(self):
thread.exit()
time.sleep(2)
def detect_collision(x,y):
if x > 340:
x -= 1
if y > 240:
y -= 1
if y < 0:
y += 1
if x < 0:
x += 1
return x,y
def generateEntities():
itemlist = []
for x in range (0,4):
x = random.randint(1,339)
y = random.randint(1,239)
entity = Entity(x,y)
itemlist.append(entity)
return itemlist
entityList = generateEntities()
a = EntityManager()
a.setDaemon(True)
a.start()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
is_blue = not is_blue
pressed = pygame.key.get_pressed()
if pressed[pygame.K_UP]:
y -= 1
x,y = detect_collision(x, y)
if pressed[pygame.K_DOWN]:
y += 1
x,y = detect_collision(x, y)
if pressed[pygame.K_LEFT]:
x -= 1
x,y = detect_collision(x, y)
if pressed[pygame.K_RIGHT]:
x += 1
x,y = detect_collision(x, y)
screen.fill((0, 0, 0))
if is_blue: color = (0, 128, 255)
else: color = (255, 100, 0)
pygame.draw.rect(screen, color, pygame.Rect(x, y, 60, 60))
pygame.display.flip()
clock.tick(60)
clock.tick() actually means FPS (frames per second); instead of changing it, change another variable.
Watch this tutorial, it might help you understand FPS.
Issues about smoothness are sometimes about the size of your object and how many pixels you are moving it when key events are True. Be careful about that; imagine you have a little box and you are trying to move it. If you move it with big steps, it seems 'laggy', but if you move it with little steps then it may look smoother. Hope you understand what I mean.
For your second question please check this documentation.
Okay, I figured it out now. OMG, I feel such an idiot after this. But I forgive myself that I am also doing parallell learning of Python. I used to code in Java more.
Anyway: problem was that my drawStuff function drew things in function but when it left this function, it did nothing. Changes were made locally. I solved this problem by using global keyword. I made in my code changes that thread computes entity coordinates and then main loop does update. This leads me to another idea that maybe there should be some game info object which gets updated all the time and all rectangles info go to that game info object.
Anyway, soon I will edit this post code too to see what i did
I'm jumping around tutorials trying to successfully complete my first game. I was taking a heavy object oriented approach for managing resources, but I felt that was clouding my understanding a bit, so I restarted. I currently have my character moving smoothly across the screen at a speed I like, my problem is my "walk cycle" of three images goes way to fast, and I get a persistence of vision effect on my little chicken's legs. I need to slow it down, so far I was able to achieve a desired effect by popping in a call to the clock after each decision loop, but I am worried that will slow down the entire game logic, as I am not sure if calling clock more than once is "freezing" my game update in time while the character decides to move. I had considered maybe making some type of equation comparing the time on the clock to the time on the clock before, to slow down the walk cycle key frames. Any help or suggestions, is there an easier method? Thanks a bunch.
import pygame, sys
from pygame.locals import *
pygame.init()
#Contstants
BLACK = (0, 0, 0)
SCREENWIDTH = 300
SCREENHEIGHT = 300
game_running = True
clock = pygame.time.Clock()
#variables
current = 0
class Player(object):
def __init__(self):
self.avatar_front = pygame.image.load("chicken_front.png")
self.avatar_back = pygame.image.load("chicken_back.png")
self.avatar_right = pygame.image.load("chicken_right_stand.png")
self.avatar_left = pygame.image.load("chicken_left_stand.png")
self.avatar_left_walk = pygame.image.load("chicken_left_walk1.png")
self.avatar_left_walk2 = pygame.image.load("chicken_left_walk2.png")
self.avatar_right = pygame.image.load("chicken_right_stand.png")
self.avatar_right_walk = pygame.image.load("chicken_right_walk1.png")
self.avatar_right_walk2 = pygame.image.load("chicken_right_walk2.png")
self.position = [0, 0]
self.current_direction = self.avatar_front
#SetUp
myScreen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
pygame.display.set_caption("Chicken Rush!")
pygame.display.set_icon(pygame.image.load("chicken_front.png"))
myPlayer = Player()
while game_running:
myScreen.fill(BLACK)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
#RIGHT HERE DETERMINES WHICH IMAGE TO DISPLAY FOR WALKING LEFT->This is the part I need to # slow down
keys_pressed = pygame.key.get_pressed()
if keys_pressed[K_LEFT] and myPlayer.position[0] >= 0:
if current == 0:
myPlayer.current_direction = myPlayer.avatar_left
current += 1
elif current == 1:
myPlayer.current_direction = myPlayer.avatar_left_walk
current += 1
elif current == 2:
myPlayer.current_direction = myPlayer.avatar_left_walk2
current = 0
myPlayer.position[0] -= 3
if keys_pressed[K_RIGHT] and myPlayer.position[0] < SCREENWIDTH - 32:
myPlayer.position[0] += 3
if keys_pressed[K_UP] and myPlayer.position[1] >= 0:
myPlayer.position[1] -= 3
if keys_pressed[K_DOWN] and myPlayer.position[1] < SCREENHEIGHT - 35:
myPlayer.position[1] += 3
myScreen.blit(myPlayer.current_direction, (myPlayer.position[0], myPlayer.position[1]))
pygame.display.update()
clock.tick(28)
It seems like you could use a longer interval to slow down the image transitions. Keep in mind you'll need to play with the value of imageTransitionSpeed to get it to your liking, but something like this should help slow the transition down:
#RIGHT HERE DETERMINES WHICH IMAGE TO DISPLAY FOR WALKING LEFT->This is the part I need to # slow down
imageTransitionSpeed = 10
keys_pressed = pygame.key.get_pressed()
if keys_pressed[K_LEFT] and myPlayer.position[0] >= 0:
if current == 0:
myPlayer.current_direction = myPlayer.avatar_left
current += 1
elif current == imageTransitionSpeed:
myPlayer.current_direction = myPlayer.avatar_left_walk
current += 1
elif current == (imageTransitionSpeed * 2):
myPlayer.current_direction = myPlayer.avatar_left_walk2
current = 0
else:
current += 1
myPlayer.position[0] -= 3
if keys_pressed[K_RIGHT] and myPlayer.position[0] < SCREENWIDTH - 32:
myPlayer.position[0] += 3
if keys_pressed[K_UP] and myPlayer.position[1] >= 0:
myPlayer.position[1] -= 3
if keys_pressed[K_DOWN] and myPlayer.position[1] < SCREENHEIGHT - 35:
myPlayer.position[1] += 3
myScreen.blit(myPlayer.current_direction, (myPlayer.position[0], myPlayer.position[1]))
pygame.display.update()
clock.tick(28)