Final touch up for the boy boundary detection mechanism

Sorry for not posting yesterday as I am terribly sick, although I am still sick today mine condition is a lot more better now. After the previous article we have basically developed a boundary detection mechanism for the player object and in this article, we will do the final touch up for that mechanism. Here are the final rules that we need to apply in order to complete the boundary detection mechanism for the boy.

1. If the boy is halfway up or down when he is insides a ladder then he can either move up or down but not side-way.
2. If the boy has touched the bottom of the ladder then he can move both side or go up the ladder again but not go downward.
3. The boy will not be able to move even further if there is an empty space below his feet to avoid him from falling down.

With the above three rules in place, we will slightly modify the boy object class by introducing a new side boundary list which will prevent the boy from going even further if the bottom of his feet is an empty space.

class BoyObject(object):

def __init__(self):

self.list_1 = [

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]

self.ladder_boundary_1 = [[9 * 64, 8 * 64],
[9 * 64, 7 * 64],
[5 * 64, 6 * 64],
[5 * 64, 5 * 64],
[2 * 64, 3 * 64],
[2 * 64, 4 * 64],
[0 * 64, 1 * 64],
[0 * 64, 2 * 64],
] # the boundary of the ladder

self.boundary_bottom_1 = [[9 * 64, 9 * 64],
[5 * 64, 7 * 64],
[2 * 64, 5 * 64],
[0 * 64, 3 * 64]]  # the bottom boundary of the ladder

self.boundary_side_1 = [[4 * 64, 6 * 64],
[1 * 64, 4 * 64],
[6 * 64, 2 * 64], ]  # the side boundary of the player

self.initial_1 = [0, 8 * 64]

def get_original_position(self, level):

if (level == 1):
return self.initial_1

def get_object_list(self, level):

if(level == 1):
return self.list_1

def get_object_boundary(self, level):

if (level == 1):

def get_object_bottom_boundary(self, level):

if (level == 1):
return self.boundary_bottom_1

def get_object_side_boundary(self, level):

if (level == 1):
return self.boundary_side_1

Next, we will need to check the side boundary of the boy to make sure he will not fall down beside checking the ladder boundary and the bottom boundary of the ladder.

from BoyObject import BoyObject
from pygame import math as mt
from pygame.locals import *
from GameSprite import GameSprite

class BoySprite(object):

def __init__(self, scene, level):

self.row = 10
self.column = 10
self.scene = scene # game scene instance
self.space = 64 # image width and height
self.level = level # current game level
self.frame = 3
self.prepare_boy(self.level)
self.WIDTH = 640

def prepare_boy(self, level):
self.boy_object = BoyObject()
self.boy_object_list = self.boy_object.get_object_list(level)
self.boy_original_position = self.boy_object.get_original_position(level)
self.x = self.boy_original_position
self.y = self.boy_original_position
self.speed = 2
self.boy_image_sprite_right = 'Asset/bright.png'
self.boy_image_sprite_left = 'Asset/bleft.png'
self.boy_sprite = self.boy_image_sprite_right
self.left = False
self.up = False
self.boy_rect = Rect(self.frame * 64, 0, 64, 64)
self.sprite_boy = GameSprite(self.boy_sprite, self.boy_rect)
self.boy_surface = self.sprite_boy.getImage()
self.boy_bottom_boundary_list = self.boy_object.get_object_bottom_boundary(level)
self.boy_side_boundary_list = self.boy_object.get_object_side_boundary(level)
self.initialize()

# set the x and y direction for the player object

def setX(self, x):

return
self.x += x
if (self.up == True and x < 0):
self.frame = 1
self.up = False
elif(self.up == True and x > 0):
self.frame = 0
self.up = False
if(x < 0):
self.left = True
self.frame += 1
if (self.frame > 5):
self.frame = 1
self.boy_sprite = self.boy_image_sprite_left
elif(x > 0):
self.frame += 1
self.left = False
if (self.frame > 4):
self.frame = 0
self.boy_sprite = self.boy_image_sprite_right
elif(x == 0):
if(self.left == True):
self.frame = 2
self.boy_sprite = self.boy_image_sprite_left
elif(self.left == False):
self.frame = 3
self.boy_sprite = self.boy_image_sprite_right

self.boy_rect = Rect(self.frame * 64, 0, 64, 64)
self.sprite_boy = GameSprite(self.boy_sprite, self.boy_rect)
self.boy_surface = self.sprite_boy.getImage()

def setY(self, y):

self.boy_rect = Rect(self.x, self.y+y, 64, 64)
if(self.isUpDown(self.boy_rect, y) == True):
self.y += y
if(y == 0):
self.frame = 6
elif(self.up == False):
self.frame = 6
self.up = True
else:
if(y < 0):
self.frame -= 1
elif(y > 0):
self.frame += 1
if(self.frame > 10):
self.frame = 6
elif(self.frame < 6):
self.frame += 2
self.boy_sprite = self.boy_image_sprite_right
self.boy_rect = Rect(self.frame * 64, 0, 64, 64)
self.sprite_boy = GameSprite(self.boy_sprite, self.boy_rect)
self.boy_surface = self.sprite_boy.getImage()

def checkboundary(self):

if(self.x < 0):
self.x = 0
elif(self.x > self.WIDTH - self.space):
self.x = self.WIDTH - self.space
else:
self.isLeftRight()

def isUpDown(self, rect, y):

for boundary in self.boy_ladder_list:
boundary_rect = Rect(boundary, boundary, 64, 64)
if ((boundary_rect.collidepoint(self.x, self.y+y) == True or boundary_rect.collidepoint(self.x, self.y+self.space+y) == True) and (self.x % self.space == 0)):
for boundary_bottom in self.boy_bottom_boundary_list:
boundary_rect = Rect(boundary_bottom, boundary_bottom, 64, 64)
if (boundary_rect.colliderect(rect) == True):
return False
return True
return False

def isLeftRight(self):

for boundary in self.boy_side_boundary_list:
boundary_rect = Rect(boundary, boundary, 64, 64)
boy_rect = Rect(self.x, self.y, 64, 64)
if (boundary_rect.colliderect(boy_rect) == True):
if(self.left == True):
self.x += self.speed
else:
self.x -= self.speed

def update(self):
self.checkboundary()
self.move_boy()

def move_boy(self):
self.draw_pos = mt.Vector2(self.x, self.y)  # the position of the image on game scene

def initialize(self):
for row in range(self.row):
for column in range(self.column):

if(self.boy_object_list[row][column] == 1):

self.draw_pos = mt.Vector2(self.x, self.y)  # the position of the image on game scene
self.scene.blit(self.boy_surface, self.draw_pos)  # draw enemy frame

def draw(self):

self.scene.blit(self.boy_surface, self.draw_pos)  # draw enemy frame

Before the boy can move even further the pygame program needs to make sure he can go up, down, left or right.

Like, share or follow me on twitter.

The beginning of Game AI

We have basically finished including all the game features in our pygame project and we are now ready to further tune up this pygame project. In this article, we will further tune up the path of the enemy ships. In the previous program, the enemy ship is moving downward in the vertical position and shooting missile at the player if the distance between the player and the enemy is close enough. In this article, we will make the enemy a lot smarter than previously by making it moves toward the direction of the player when it spots the player within a certain range.

We will need to modify the enemy class’s update method by including the x and the y parameter into it that will be used to adjust the path of the enemy ship to make it moves toward the player direction during the game.

from pygame import math as mt
from Objectpool import Objectpool

class Enemy(object):

def __init__(self, enemy_surface, x, y):

self.on = True
self.enemy_surface = enemy_surface
self.x = x
self.y = y
self.hit = False
self.enemy_pos = mt.Vector2(self.x, self.y)
self.missile_count = 10
self.missile_timer = 0
self.missile_object_pool = Objectpool(self.missile_count)
self.missile_list = []

def update(self, x, y):
self.y += y
self.x += x
self.enemy_pos = mt.Vector2(self.x, self.y)
self.missile_update(self.missile_object_pool)

def missile_update(self, pool):

for item in list(self.missile_list):
if (item.on == False):
self.missile_list.remove(item)
pool.recycle(item)
else:
item.update()

def missile_draw(self, scene): # draw enemy missiles on game scene
for item in list(self.missile_list):
scene.blit(item.missile_surface, item.missile_pos)

def create_enemy_missile(self, enemy_missile_manager):

if(self.missile_timer &gt; 300):

self.missile_timer = 0

if (self.missile_object_pool.getSize() &gt; 0):
enemy_missile_manager.create_missile(self.x + 5, self.y + 4, self.missile_object_pool, self.missile_list)
else:
enemy_missile_manager.create_missile(self.x + 5, self.y + 4, None, self.missile_list)

else:

self.missile_timer += 1

The next class we need to modify is the enemy manager class which we will adjust the range where the enemy will fire a missile at the player as well as creating the range where the enemy will start to move toward the player during the game.

from Enemy import Enemy
from GameSprite import GameSprite
from pygame.locals import *
from EnemyMissileManager import EnemyMissileManager
import random
from Objectpool import Objectpool
from Enemy1 import Enemy1

class EnemyManager(object):

def __init__(self, scene, player, game_level):

self.enemy_missile_manager = EnemyMissileManager()
self.scene = scene
self.player = player
self.enemy_count = 10
self.horizontal_enemy_count = 1
self.missile_count = 60
self.enemy_list = []
self.horizontal_enemy_list = []
self.image = 'Asset/enemy0.png'
self.image1 =  'Asset/enemy1.png'
self.image2 = 'Asset/enemy2.png'
self.width = 30
self.height = 30
self.width1 = 130
self.height1 = 130
self.rect = Rect(0, 0, self.width, self.height)
self.rect1 = Rect(0, 0, self.width1, self.height1)
self.more_enemy = 0
self.y = -50
self.boundary_width = 660
self.boundary_height = 660
self.object_pool = Objectpool(self.enemy_count)
self.horizontal_object_pool = Objectpool(self.horizontal_enemy_count)
self.next_enemy = 0
self.level = game_level

# initialize game sprite object
self.sprite = GameSprite(self.image, self.rect)
self.sprite1 = GameSprite(self.image1, self.rect)
self.sprite2 = GameSprite(self.image2, self.rect1)

def create_enemy(self, x, y):

if(self.enemy_count &gt; 0):

if(self.object_pool.getSize() &gt; 0): # get the ship from object pool if the pool is not empty
self.enemy_list.append(self.object_pool.obtain())
else: # objects setup based on the level of the game
if(self.level == 1):
self.enemy_surface = self.sprite.getImage()
elif(self.level == 2 or self.level == 3):
if(self.next_enemy == 0):
self.enemy_surface = self.sprite.getImage()
self.next_enemy += 1
elif(self.next_enemy == 1):
self.enemy_surface = self.sprite1.getImage()
self.next_enemy = 0
self.enemy_list.append(Enemy(self.enemy_surface, x, y))
self.enemy_count -= 1

def create_horizontal_enemy(self, x, y):

if (self.horizontal_enemy_count &gt; 0):

if (self.horizontal_object_pool.getSize() &gt; 0):  # get the ship from object pool if the pool is not empty
self.horizontal_enemy_list.append(self.horizontal_object_pool.obtain())
else:  # objects setup based on the level of the game
if (self.level == 3):
self.enemy_surface1 = self.sprite2.getImage()
self.horizontal_enemy_list.append(Enemy1(self.enemy_surface1, x, y))
self.horizontal_enemy_count -= 1

def update(self):

if (self.level == 1 or self.level == 2):

if (self.more_enemy &gt; 600):
self.more_enemy = 0
x = random.randint(30, self.boundary_width - 50)
self.create_enemy(x , self.y)  # create more enemy
else:
self.more_enemy += 1 # increase time

elif(self.level == 3):

if (self.more_enemy &gt; 600):
self.more_enemy = 0
x = random.randint(30, self.boundary_width - 50)
self.create_enemy(x , self.y)  # create more enemy
else:
self.more_enemy += 1 # increase time

if(self.horizontal_enemy_count &gt; 0):
self.create_horizontal_enemy(-130, 200)  # create new enemy

self.create_enemy_missile()
self.enemy_update()
self.check_boundary()

def create_enemy_missile(self):

for item in list(self.enemy_list):

if(self.player.pos.y - item.y  &lt; 200 and abs(self.player.pos.x - item.x) &lt; 160):

item.create_enemy_missile(self.enemy_missile_manager)

if(self.level == 3):

for item in list(self.horizontal_enemy_list):
item.create_enemy_missile(self.enemy_missile_manager)

def enemy_update(self):

for item in list(self.enemy_list):

if(item.on == False):
self.enemy_list.remove(item)
self.enemy_count += 1
item.y = self.y
item.on = True
self.object_pool.recycle(item)
else:
if ((self.player.pos.y - item.y &lt; 200 and self.player.pos.y - item.y &gt; -2) and abs(self.player.pos.x - item.x) &lt; 200):
item.update((self.player.pos.x - item.x) * 0.005, 0.1)
else:
item.update(0, 0.1)

if (self.level == 3):

for item in list(self.horizontal_enemy_list):
if (item.on == False):
self.horizontal_enemy_list.remove(item)
self.horizontal_enemy_count += 1
item.y = 220
item.x = -130
item.on = True
self.horizontal_object_pool.recycle(item)
else:
item.update()

# check the boundary of the enemy ship with the game scene area
def check_boundary(self):

for i in range(len(self.enemy_list)):
if (self.enemy_list[i].y &gt; self.boundary_height):
self.enemy_list[i].on = False

if (self.level == 3):
for i in range(len(self.horizontal_enemy_list)):
if (self.horizontal_enemy_list[i].x &gt; self.boundary_width):
self.horizontal_enemy_list[i].direction = False
elif(self.horizontal_enemy_list[i].x &lt;= -130):
self.horizontal_enemy_list[i].direction = True

def draw(self):

# blit the enemy and enemy missiles on  the scene
for i in range(len(self.enemy_list)):
self.scene.blit(self.enemy_list[i].enemy_surface, self.enemy_list[i].enemy_pos)
self.enemy_list[i].missile_draw(self.scene)

if(self.level == 3):
for i in range(len(self.horizontal_enemy_list)):
self.scene.blit(self.horizontal_enemy_list[i].enemy_surface, self.horizontal_enemy_list[i].enemy_pos)
self.horizontal_enemy_list[i].missile_draw(self.scene)

Now, whenever the enemy spots the player within a certain range it will move toward that player.