ZX81 BASIC to Pygame Conversion of "Dropout" Game - python

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.

Related

Pygame: How do I fix the issue of randomly generated platforms on PyGame moving in the wrong direction in the wrong section of the screen?

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!

Having an image appear multiple times Pygame

I have a single battery image appearing once here and it moves from right to left then goes away. I want batteries constantly coming and going until the player hits one of them.
My question is how do I get the batteries to keep on coming until a player hits it? I want them to appear maybe 100 units apart.
from pygame import *
import os
import random
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d, %d" %(0, 0)
init()
#set screen size
size = width, height = 800, 600
screen = display.set_mode(size)
#set fonts
fontGame=font.SysFont("Times New Roman", 30)
fontBack=font.SysFont("Ariel", 30)
fontTitle=font.SysFont("Ariel", 100)
fontResearch=font.SysFont ("Times New Roman", 18)
#set button and page to 0
button = 0
page=0
#setting colours
BLACK = (0, 0, 0)
RED = (255,0,0)
GREEN = (0, 255, 0)
BLUE = (106,186,232)
#loading image
backgroundPic=image.load("Background.jpg")
backgroundGame=image.load("gameBackground.jpg")
backgroundGame=transform.scale(backgroundGame,(800,600))
battery=image.load("Battery.png")
battery=transform.scale(battery,(100,100))
backgroundx=0
playerPic=image.load("player.png")
playerPic=transform.scale(playerPic,(70,70))
batteryx=[]
#defining what is going to be shown on the screen
def drawScene(screen, button,page,locationx,locationy):
global batteryx
mx, my = mouse.get_pos() #will get where the mouse is
#if the user does nothing
if page==0:
draw.rect(screen, BLACK, (0,0, width, height))
screen.fill(BLACK)
rel_backgroundx= backgroundx % backgroundGame.get_rect().width
screen.blit(backgroundGame, (rel_backgroundx - backgroundGame.get_rect().width,0))
if rel_backgroundx < width:
screen.blit (backgroundGame, (rel_backgroundx,0))
screen.blit(playerPic,(locationx,locationy))
screen.blit(battery,(batteryx,420))
batteryx-=1
display.flip()
return page
#def collision (battery, playerPic):
#if battery.colliderect(playerPic):
#return True
#return False
running = True
myClock = time.Clock()
KEY_LEFT= False
KEY_RIGHT= False
KEY_UP= False
KEY_DOWN= False
locationx=0
jumping=False
accel=20
onGround= height-150
locationy=onGround
batteryx=random.randrange(50,width,10)
# Game Loop
while running:
button=0
print (KEY_LEFT, KEY_RIGHT)
for evnt in event.get(): # checks all events that happen
if evnt.type == QUIT:
running=False
if evnt.type == MOUSEBUTTONDOWN:
mx,my=evnt.pos
button = evnt.button
if evnt.type== KEYDOWN:
if evnt.key==K_LEFT:
KEY_LEFT= True
KEY_RIGHT= False
if evnt.key==K_RIGHT:
KEY_RIGHT= True
KEY_LEFT= False
if evnt.key==K_UP and jumping==False:
jumping=True
accel=20
if evnt.key== K_DOWN:
KEY_DOWN= True
KEY_UP= False
if evnt.type==KEYUP:
if evnt.key==K_LEFT:
KEY_LEFT= False
if evnt.key==K_RIGHT:
KEY_RIGHT= False
if evnt.key==K_DOWN:
KEY_DOWN=False
if KEY_LEFT== True:
locationx-=10
backgroundx+=10
if KEY_RIGHT== True:
locationx+=10
backgroundx-=10
if jumping==True:
locationy-=accel
accel-=1
if locationy>=onGround:
jumping=False
locationy=onGround
#player cannot move off screen
if locationx<0:
locationx=0
if locationx>400:
locationx=400
#if collision(battery, playerPic)==True:
#screen.fill(BLACK)
page=drawScene(screen,button,page,locationx,locationy)
myClock.tick(60) # waits long enough to have 60 fps
if page==6: #if last button is clicked program closes
running=False
quit()
Create a list of rects which serve as the positions of the batteries. Use for loops to update the rects and blit the battery image at the rects. Remove rects that have left the screen and append new rects to create new batteries
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray12')
battery_image = pg.Surface((30, 50))
battery_image.fill(pg.Color('sienna1'))
# Append pygame.Rect objects to this list.
batteries = []
batteries.append(battery_image.get_rect(topleft=(700, 100)))
battery_speed = -5
battery_timer = 40
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
# A simple frame based timer.
battery_timer -= 1
if battery_timer <= 0:
battery_timer = 40
# After 40 frames a new rect gets appended to the list.
batteries.append(battery_image.get_rect(topleft=(700, 100)))
temp_list = []
# Iterate over the rects to update them.
for battery_rect in batteries:
battery_rect.x += battery_speed
# Rects with x <= 50 won't be appended to the temp_list.
if battery_rect.x > 50:
temp_list.append(battery_rect)
# Assign the list with the remaining rects to the batteries variable.
batteries = temp_list
# Blit everything.
screen.fill(BG_COLOR)
for battery_rect in batteries:
screen.blit(battery_image, battery_rect)
pg.display.flip()
clock.tick(30)
pg.quit()

How to use timers in pygame to trigger an event at an interval? [duplicate]

I'm making an arcade game using pygame and I'm trying to have a sprite change positions every few seconds.
I've tried using time.sleep(1) and changing the frame rate to .5 (clock.tick(.5)).
Both worked to make the object change position only after the time interval has passed, however they also make the sprite following my mouse update coordinates at the same rate.
I've been researching and can't seem to find another way to make the sprite move without making my program refresh slower or 'sleep' every time it runs.
You can use an Event for this together with pygame.time.set_timer():
pygame.time.set_timer()
repeatedly create an event on the event queue
set_timer(eventid, milliseconds) -> None
Set an event type to appear on the event queue every given number of milliseconds
Here's a simple, complete example. Note how the enemies move every 1000ms sideways, every 3500ms downwards, and you can shoot every 450ms (all using events).
import pygame
# you'll be able to shoot every 450ms
RELOAD_SPEED = 450
# the foes move every 1000ms sideways and every 3500ms down
MOVE_SIDE = 1000
MOVE_DOWN = 3500
screen = pygame.display.set_mode((300, 200))
clock = pygame.time.Clock()
pygame.display.set_caption("Micro Invader")
# create a bunch of events
move_side_event = pygame.USEREVENT + 1
move_down_event = pygame.USEREVENT + 2
reloaded_event = pygame.USEREVENT + 3
move_left, reloaded = True, True
invaders, colors, shots = [], [] ,[]
for x in range(15, 300, 15):
for y in range(10, 100, 15):
invaders.append(pygame.Rect(x, y, 7, 7))
colors.append(((x * 0.7) % 256, (y * 2.4) % 256))
# set timer for the movement events
pygame.time.set_timer(move_side_event, MOVE_SIDE)
pygame.time.set_timer(move_down_event, MOVE_DOWN)
player = pygame.Rect(150, 180, 10, 7)
while True:
clock.tick(40)
if pygame.event.get(pygame.QUIT): break
for e in pygame.event.get():
if e.type == move_side_event:
for invader in invaders:
invader.move_ip((-10 if move_left else 10, 0))
move_left = not move_left
elif e.type == move_down_event:
for invader in invaders:
invader.move_ip(0, 10)
elif e.type == reloaded_event:
# when the reload timer runs out, reset it
reloaded = True
pygame.time.set_timer(reloaded_event, 0)
for shot in shots[:]:
shot.move_ip((0, -4))
if not screen.get_rect().contains(shot):
shots.remove(shot)
else:
hit = False
for invader in invaders[:]:
if invader.colliderect(shot):
hit = True
i = invaders.index(invader)
del colors[i]
del invaders[i]
if hit:
shots.remove(shot)
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]: player.move_ip((-4, 0))
if pressed[pygame.K_RIGHT]: player.move_ip((4, 0))
if pressed[pygame.K_SPACE]:
if reloaded:
shots.append(player.copy())
reloaded = False
# when shooting, create a timeout of RELOAD_SPEED
pygame.time.set_timer(reloaded_event, RELOAD_SPEED)
player.clamp_ip(screen.get_rect())
screen.fill((0, 0, 0))
for invader, (a, b) in zip(invaders, colors):
pygame.draw.rect(screen, (150, a, b), invader)
for shot in shots:
pygame.draw.rect(screen, (255, 180, 0), shot)
pygame.draw.rect(screen, (180, 180, 180), player)
pygame.display.flip()
How about
var = 0
while True:
event_handling()
game_logic()
if var == 5:
sprite.update.position()
var = 0
pygame.display.flip()
var += 1
Obviously, this is just pseudo code, but you get the idea.

Python clicking game, updating score

import pygame
from pygame.locals import *
import random
import time
pygame.init()
randomNumber = random.randint(1,600)
randomNumber2 = random.randint(1,600)
x = 0
text = ""
squareCount = 0
beenHere = 0
# colours = (red, green, blue)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
LBLUE = (0, 123, 255)
colour = RED
# Make a window appear
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Square Chase | Score: 0")
screen.fill(LBLUE)
pygame.display.flip()
pygame.time.set_timer(USEREVENT + 1, 1500)
done = False
clock = pygame.time.Clock()
while done == False:
for event in pygame.event.get():
print(event)
if event.type == pygame.QUIT:
done = True
if event.type == USEREVENT + 1:
screen.fill(LBLUE)
randomNumber = random.randint(1,625)
randomNumber2 = random.randint(1,420)
mySquare = pygame.draw.rect(screen,colour,(randomNumber,randomNumber2,50,50),5)
squareCount = squareCount + 1
if squareCount == 50:
done == true
pygame.display.flip()
if event.type == pygame.MOUSEBUTTONDOWN:
y, z = pygame.mouse.get_pos()
is_inside = mySquare.collidepoint(y, z)
if is_inside and colour == GREEN:
x = x+1
text = str(x)
pygame.display.set_caption("Square Chase | Score " + text)
colour = RED
elif is_inside:
x = x+1
text = str(x)
pygame.display.set_caption("Square Chase | Score " + text)
colour = GREEN
clock.tick(20)
pygame.quit()
I am aiming to create a game in which the user has to click on a square for their score to increase. They get 50 chances to do this. If they click in the square within the 1.5 seconds the colour of the square changes.
The above code works apart from each time a new square is drawn the user could click on it say 5 times and their score will go up by 5. Any suggestions as to how to get the score to increase by just one? Thanks in advance.
Wish I could just use a comment but I have lack of reputation.
I didn't look through all your code, but your description makes it sound like a simple flag would be able to help you.
Once you recognize it has been clicked, increment the score AND set a boolean.
So in essence you will want something along the lines of
if clicked == false
score = score+1
clicked = true
You will want to clear the flag back to false once another block has appeared.
Wouldn't it be better, if a new square would show up after a successful keypress? That way the game would be more dynamic.
It's easy to change this. Instead of using user events that are called every 1.5 sec, sum the value returned by clock.tick() and when their sum will be greater than 1500 ms, create a new rectangle. This is a better approach, because you can call the method that creates a new square and reset the timer right after a successful keypress.
Some code to get you started:
def new_rect(screen,colour):
screen.fill(LBLUE)
randomNumber = random.randint(1,625)
randomNumber2 = random.randint(1,420)
mySquare = pygame.draw.rect(screen,colour,(randomNumber,randomNumber2,50,50),5)
return mySquare
done = False
clock = pygame.time.Clock()
timer_var = 0
while done == False:
if(timer_var > 1500):
timer_var = 0
mySquare = new_rect(screen,color)
squareCount = squareCount + 1
if squareCount == 50:
done == true
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
y, z = pygame.mouse.get_pos()
is_inside = mySquare.collidepoint(y, z)
if is_inside:
x = x+1
text = str(x)
pygame.display.set_caption("Square Chase | Score " + text)
timer_var = 0
new_rect(screen,colour)
squareCount = squareCount + 1
if squareCount == 50:
done == true
if colour == GREEN:
colour = RED
else:
colour = GREEN
timer_var += clock.tick(20)
pygame.quit()

Speed of an object in pygame?

I am writing a simple pygame program that only consists of moving a box around the screen. The box moves very fast and I want to know how to control the speed. In my code the updated position is moved by 1 and not smaller because if the number is not an integer it makes things more complicated.
import os, sys
import pygame
from pygame.locals import *
pygame.init()
mainClock = pygame.time.Clock()
WINDOWWIDTH = 400
WINDOWHEIGHT = 400
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption("Box")
BLACK = (0, 0, 0)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
size1 = 20
size2 = 2
#character = pygame.Rect(30, 30, 20, 30)
player = pygame.Surface((40,40))
pos1 = 100
pos2 = 100
MOVESPEED = 6
x = 1
while True:
if pos1 == WINDOWWIDTH - 40 and pos1 > 0:
pos1 -= 1
x += 1
elif pos1 < WINDOWWIDTH - 40 and x == 1:
pos1 += 1
elif x ==2:
pos1 -= 1
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_LEFT:
pos1 -= 5
if event.key == K_RIGHT:
pos1 += 4
windowSurface.fill(WHITE)
#screen.blit(character)
windowSurface.blit(player, (pos1, pos2))
pygame.display.update()
You should put the following bit of code in your "while True:" loop somewhere:
clock.tick([insert fps here])
and put this somewhere before the loop:
clock=pygame.time.Clock()
This will not allow the loop to run more than the number of times you enter per second, and hopefully slow the cube down.
Just don't alter the position in every iteration of your loop.
Instead of
while True:
if ... :
pos1 += 1
...
use somethinig like this:
tmp = 0
while True:
if ... :
tmp += 1
if tmp == 10:
pos1 += 1
tmp = 0
...
or
tmp = 0
while True:
if ... and not tmp % 10:
pos1 += 1
...
where you adjust 10 to a value that will suit you.
Also, you may want to limit the framerate of your programm to get a (more or less) constant framerate using a Clock.
You could use floats to store the positions after all. Change the update values in the while loop to something smaller, e.g. pos1 += 0.25. Then just make sure to blit integers: windowSurface.blit(player, (int(pos1), int(pos2))).
I normally also use integers for most positions but when I say pygame to draw my object/sprite/... to the screen I always divide the position by 10 so that I have 10 steps of values since the objects moves one step on the screen.
Organisation of this is not too hard.
The minimum velocity you can have is 1 but there is a way to slow it down more by controlling time.
For example, moving the box with velocity 1 every 100ms instead of every frame makes the movement appear significantly slower.
See implementation below:
# initialize clock object outside of main loop
clock = pygame.time.Clock()
time = 0
while 1:
time = time + clock.get_time()
if time >= 100:
# Your movement implementation here
time = 0 # Reset timer at the end

Categories

Resources