Our Red_Guy can move around in 8-directions within the window boundaries. For this series, I'll create this game into a basic, Smash TV-style shoot 'em up game. So for that, we'll need some bullets!
In yellow, the "pygame.draw.circle" function is called to draw a circle at the object's coordinate of the game surface. The object's color is used and an arbitrary radius is given (2 pixels). Note the function does not accept floating numbers (decimals), so a round function needs to be used.
Projectile Class
I'll first create a "Projectile" class that will be used for creating the bullet objects. This will look very similar to the "Characters" class from the previous post, with some added attributes.
There's also the member function "Move" within the class.
There's also the member function "Move" within the class.
class Projectiles(object):
def __init__(self, x, y, direction, color, speed):
self.x = x
self.y = y
self.direction = direction
self.color = color
self.speed = speed
self.radius = 2
Within the "Projectile" class, I'll add the member function "Move". A member function is exclusive to the objects within the class. The "self" input is automatically input into the function, which allows for all object attributes to be used. def Move(self, win): if self.direction == 'Up Left': self.x -= self.speed * 0.707 self.y -= self.speed * 0.707 elif self.direction == 'Up': self.y -= self.speed elif self.direction == 'Up Right': self.x += self.speed * 0.707 self.y -= self.speed * 0.707 elif self.direction == 'Right': self.x += self.speed elif self.direction == 'Down Right': self.x += self.speed * 0.707 self.y += self.speed * 0.707 elif self.direction == 'Down': self.y += self.speed elif self.direction == 'Down Left': self.x -= self.speed * 0.707 self.y += self.speed * 0.707 elif self.direction == 'Left': self.x -= self.speed pygame.draw.circle(win, self.color, (round(self.x), round(self.y)), self.radius)
In orange, the directions should be self-explanatory based on the previous post on directions. The syntax is a bit different since it's a member function, and there's the interesting "self.direction" conditional that I'll get into.
In yellow, the "pygame.draw.circle" function is called to draw a circle at the object's coordinate of the game surface. The object's color is used and an arbitrary radius is given (2 pixels). Note the function does not accept floating numbers (decimals), so a round function needs to be used.
Shoot the Bullet
Now I have the bullet class created, we need a way to shoot it. I first need to make an adjustment to the "Character" class to add the "self.bullets" list and "self.direction" attribute
class Characters(object): def __init__(self, x, y, color): self.x = x self.y = y self.color = color self.bullets = [] self.direction = 'Left'I'll also update the "Move_Object" function to update the "self.direction" attribute based on which direction the character is moving.
def Move_Object(obj): speed = 1 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 obj.direction = 'Up Left' elif pygame.key.get_pressed()[pygame.K_d]: #Move Up-Right obj.x += speed * 0.707 obj.y -= speed * 0.707 obj.direction = 'Up Right' else: #Move Up obj.y -= speed obj.direction = 'Up' 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 obj.direction = 'Down Left' elif pygame.key.get_pressed()[pygame.K_d]: #Move Down-Right obj.x += speed * 0.707 obj.y += speed * 0.707 obj.direction = 'Down Right' else: #Move Down obj.y += speed obj.direction = 'Down' elif pygame.key.get_pressed()[pygame.K_a]: #Move Left obj.x -= speed obj.direction = 'Left' elif pygame.key.get_pressed()[pygame.K_d]: #Move Right obj.x += speed obj.direction = 'Right'
We'll create another function called "Shoot", which is triggered once the player presses the "J" key. Once triggered, the character's attributes (coordinates & direction) are used to create an object from the "Projectile" class. The bullet object is created and appended to the "self.bullets" list created earlier.
def Shoot(obj):
if pygame.key.get_pressed()[pygame.K_j]:
obj.bullets.append(Projectiles(obj.x, obj.y, obj.direction, (255,255,255), 5))
Lastly, I'll add the While loop to call the "Shoot" function and member function "Projectile.Move(self, win)" to draw and move the bullet.
- For the "Shoot" function, I'll input the "Red_Guy" object.
- For the "Projectile.Move" function, I'll use a "For" loop to iterate over the "Red_Guy.bullets" list.
Now look at that, I can shoot a whole lot of bullets!
Collision
However, like a player moving out of the game window, the bullets will continue moving off the screen infinitely. Since I only care about them within the screen, I'll need to add the same boundary conditions: Once the bullets contact the boundary, I'll delete them from the list.I'll create the "Collision" function using the same "If" statement, but with a different "Then" statement. The line "obj.bullets.pop(obj.bullets.index(proj))" performs the following:
- Finds the location of the projectile object (proj) in the bullets list (obj.bullets.index(proj))
- Deletes the item in the bullet list at that location (obj.bullets.pop( ))
def Collision(obj, proj): if proj.x < 0: #If object exceeds left boundary obj.bullets.pop(obj.bullets.index(proj)) elif proj.x > 400-proj.radius: #If object exceeds right boundary obj.bullets.pop(obj.bullets.index(proj)) if proj.y < 0: #If object exceeds top boundary obj.bullets.pop(obj.bullets.index(proj)) elif proj.y > 300-proj.radius: #If object exceeds bottom boundary obj.bullets.pop(obj.bullets.index(proj))
The function then gets added right after the "bullet.Move()" function, since after each movement we need to check if the bullets should get deleted or not.
Cooldown
One last thing: A single key stroke creates dozens of bullets. Since the cycle time of the code is so fast, it's creating a bullet for the duration the "J" key is depressed. How many times is that? I added a line to count each time the "Shoot" function creates a bullet:Just a tap of the "J" key creates 115 bullets! This is clearly not right, so the solution is add an additional requirement prior to creating the bullet: a cooldown
class Characters(object):
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
self.bullets = []
self.direction = 'Left'
self.cooldown = 0
def Shoot(obj): if pygame.key.get_pressed()[pygame.K_j]: if obj.cooldown == 0: obj.bullets.append(Projectiles(obj.x, obj.y, obj.direction, (255,255,255), 0.05)) obj.cooldown = 10 if obj.cooldown>0: obj.cooldown -= 1
The modifications adds the "Cooldown" attribute to the object. The "Shoot" function checks if the object's "Cooldown" is equal to zero before creating the bullet. If the bullet is created, then the "Cooldown" value is set to 10, preventing any more bullets from being created. The next line ticks down the "Cooldown" value if it's greater than zero. Once ticked down to zero, the next bullet can be created, etc.
Next Steps
So now the bullets get can fire from different directions and are destroyed when they collide with the game window. But there's something missing, right? They need enemies to hit!
Comments
Post a Comment