After creating an objects, there needs to be ways to update their attributes (position, health, etc.). Change is made when the player inputs commands to influence the game
Updating Objects
By inspecting the draw function, we can see it requires coordinates (x,y) to determine where to draw the object:
pygame.draw.rect(surface, color, (x, y, width, height))
Visually, the (x,y) coordinate is the pixel location within the game window. A higher x value moves the object to the right and a higher y value moves the object down.
Since I use the object's attribute ("Red_Guy.x", "Red_Guy.y") to draw the coordinates, I can use a function to update those values to update the position:
def Move_Object(obj): obj.x += 1 obj.y += 1
The function moves adds 1 pixel to the x and y coordinates, which moves the position down-right by 1 pixel each. Note that the function is modular, so it requires the object to have the "x" and "y" attributes defined. By updating the "pygame.draw.rect" function with the object attributes, the rectangle gets redrawn at the new coordinate. But what will trigger this movement?
User Input & Refresh Game Window
You can't have a game if there's no player input; I can setup the key presses to correspond with the movement of the object, as typical in games. Pygame uses the following function to determine if a key has been pressed:
pygame.key.get_pressed()
This returns a boolean dictionary (True/False) for every key, which returns if they're being pressed.
For example, pressing the "A" key will make the following "True":
pygame.key.get_pressed()[pygame.K_a]
Thus, we can add a simple "If" statement to the "Move_Object" function, so if the "A" key is pressed, the object will move +1 pixel diagonally down-right:
def Move_Object(obj): if pygame.key.get_pressed()[pygame.K_a]: obj.x += 1 obj.y += 1
I insert the function into the "While" loop and press the "A" key once. I get the result below:
As you can tell, there are two things going wrong:
- The rectangle is getting redrawn every single time
- The screen needs to "refresh" every single time, rather than adding onto the existing window. Every single time, the window needs to be "painted" over with black so that there's only a single red rectangle that drawn
- This is solved by adding "win.fill((0,0,0))" to the while loop to repaint the window black for every refresh.
- A single key press goes way too far
- The clock speed of the game has been defined at 30 frames per second, which is 0.033 refreshes per second. When the "A" key is pressed, it will apply the +1 pixel movement 30 times per second, which is way too much for the game window.
- This can be adjusted lowering the added pixels. I adjusted it from +1 to +0.01.
Master Control
The "Move_Object" function can be further refined to correspond with the WASD controls used for movement in FPS games. To keep things modular, I can define the "speed" attribute for easy updating.
- "W" moves object up (-y)
- "A" moves object left (-x)
- "S" moves object down (+y)
- "D" moves object right (+x)
The final code looks like this:
import pygame
class Characters(object):
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
def Move_Object(obj):
speed = 0.01 if pygame.key.get_pressed()[pygame.K_w]: obj.y -= speed if pygame.key.get_pressed()[pygame.K_a]: obj.x -= speed if pygame.key.get_pressed()[pygame.K_s]: obj.y += speed if pygame.key.get_pressed()[pygame.K_d]: obj.x += speed
def main():
win = pygame.display.set_mode((400, 300))
pygame.init()
Red_Guy = Characters(100, 100, (255, 0, 0))
while True:
frames = 30 clock=pygame.time.Clock() clock.tick(frames) for event in pygame.event.get(): #Exit game on red button
if event.type == pygame.QUIT:
return
win.fill((0,0,0))
Move_Object(Red_Guy)
pygame.draw.rect(win, Red_Guy.color, (Red_Guy.x, Red_Guy.y, 5, 10))
pygame.display.flip()
main()
Now I can make the Red_Guy dance around and strafe!
Final Tweaks (Diagonal Movement & Boundaries)
Note that I used all "If" statements, which allows for diagonal movements ("A" and "W" moves up-left). However, the two speeds are summed together, making the displacement twice as fast. The Pythagorean theorem should be used to apply about (0.707, 0.707) pixel displacement for diagonal movement, which equates to the equal speed. Because of these dependencies, the function has to be structured as "Elif" statements, which allows for only a single condition (rather than executing several "If" statements).
Another note is that our Red_Guy can move infinitely outside of the game window. This can be corrected by setting another "If" statement that prevents his (x,y) coordinates from exceeding the range of the game window. If the x-coordinate tries to exceed 400 pixels (window width), the "If" statement will limit it to 400. However, since the actual (x,y) coordinate captures a single pixel, an additional offset needs to be added for the rectangle's shape (5, 10).
These final tweaks are added in the "Move_Object" function below:
def Move_Object(obj): speed = 0.01 if pygame.key.get_pressed()[pygame.K_w]: if pygame.key.get_pressed()[pygame.K_a]: #Move Up-Left obj.x -= speed * 0.707 obj.y -= speed * 0.707 elif pygame.key.get_pressed()[pygame.K_d]: #Move Up-Right obj.x += speed * 0.707 obj.y -= speed * 0.707 else: #Move Up obj.y -= speed elif pygame.key.get_pressed()[pygame.K_s]: if pygame.key.get_pressed()[pygame.K_a]: #Move Down-Left obj.x -= speed * 0.707 obj.y += speed * 0.707 elif pygame.key.get_pressed()[pygame.K_d]: #Move Down-Right obj.x += speed * 0.707 obj.y += speed * 0.707 else: #Move Down obj.y += speed elif pygame.key.get_pressed()[pygame.K_a]: #Move Left obj.x -= speed elif pygame.key.get_pressed()[pygame.K_d]: #Move Right obj.x += speed if obj.x < 0: #If object exceeds left boundary obj.x = 0 elif obj.x > 400-5: #If object exceeds right boundary (width offset) obj.x = 400-5 if obj.y < 0: #If object exceeds top boundary obj.y = 0 elif obj.y > 300-10: #If object exceeds bottom boundary (height offset) obj.y = 300-10
Comments
Post a Comment