Add collison detection to enemy sprites?
Posted
by
xBroak
on Game Development
See other posts from Game Development
or by xBroak
Published on 2012-11-30T14:38:32Z
Indexed on
2012/11/30
17:21 UTC
Read the original article
Hit count: 710
i'd like to add the same collision detection used by the player sprite to the enemy sprites or 'creeps' ive added all the relevant code I can see yet collisons are still not being detected and handled, please find below the class, I have no idea what is wrong currently, the list of walls to collide with is 'wall_list'
import pygame
import pauseScreen as dm
import re
from pygame.sprite import Sprite
from pygame import Rect, Color
from random import randint, choice
from vec2d import vec2d
from simpleanimation import SimpleAnimation
import displattxt
black = (0,0,0)
white = (255,255,255)
blue = (0,0,255)
green = (101,194,151)
global currentEditTool
currentEditTool = "Tree"
global editMap
editMap = False
open('MapMaker.txt', 'w').close()
def draw_background(screen, tile_img):
screen.fill(black)
img_rect = tile_img.get_rect()
global rect
rect = img_rect
nrows = int(screen.get_height() / img_rect.height) + 1
ncols = int(screen.get_width() / img_rect.width) + 1
for y in range(nrows):
for x in range(ncols):
img_rect.topleft = (x * img_rect.width,
y * img_rect.height)
screen.blit(tile_img, img_rect)
def changeTool():
if currentEditTool == "Tree":
None
elif currentEditTool == "Rock":
None
def pauseGame():
red = 255, 0, 0
green = 0,255, 0
blue = 0, 0,255
screen.fill(black)
pygame.display.update()
if editMap == False:
choose = dm.dumbmenu(screen, [
'Resume',
'Enable Map Editor',
'Quit Game'], 64,64,None,32,1.4,green,red)
if choose == 0:
print("hi")
elif choose ==1:
global editMap
editMap = True
elif choose ==2:
print("bob")
elif choose ==3:
print("bob")
elif choose ==4:
print("bob")
else:
None
else:
choose = dm.dumbmenu(screen, [
'Resume',
'Disable Map Editor',
'Quit Game'], 64,64,None,32,1.4,green,red)
if choose == 0:
print("Resume")
elif choose ==1:
print("Dis ME")
global editMap
editMap = False
elif choose ==2:
print("bob")
elif choose ==3:
print("bob")
elif choose ==4:
print("bob")
else:
None
class Wall(pygame.sprite.Sprite):
# Constructor function
def __init__(self,x,y,width,height):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([width, height])
self.image.fill(green)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class insertTree(pygame.sprite.Sprite):
def __init__(self,x,y,width,height, typ):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images/map/tree.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class insertRock(pygame.sprite.Sprite):
def __init__(self,x,y,width,height, typ):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images/map/rock.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Creep(pygame.sprite.Sprite):
""" A creep sprite that bounces off walls and changes its
direction from time to time.
"""
change_x=0
change_y=0
def __init__(
self, screen, creep_image, explosion_images,
field, init_position, init_direction, speed):
""" Create a new Creep.
screen:
The screen on which the creep lives (must be a
pygame Surface object, such as pygame.display)
creep_image:
Image (surface) object for the creep
explosion_images:
A list of image objects for the explosion
animation.
field:
A Rect specifying the 'playing field' boundaries.
The Creep will bounce off the 'walls' of this
field.
init_position:
A vec2d or a pair specifying the initial position
of the creep on the screen.
init_direction:
A vec2d or a pair specifying the initial direction
of the creep. Must have an angle that is a
multiple of 45 degres.
speed:
Creep speed, in pixels/millisecond (px/ms)
"""
Sprite.__init__(self)
self.screen = screen
self.speed = speed
self.field = field
self.rect = creep_image.get_rect()
# base_image holds the original image, positioned to
# angle 0.
# image will be rotated.
#
self.base_image = creep_image
self.image = self.base_image
self.explosion_images = explosion_images
# A vector specifying the creep's position on the screen
#
self.pos = vec2d(init_position)
# The direction is a normalized vector
#
self.direction = vec2d(init_direction).normalized()
self.state = Creep.ALIVE
self.health = 15
def is_alive(self):
return self.state in (Creep.ALIVE, Creep.EXPLODING)
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def update(self, time_passed, walls):
""" Update the creep.
time_passed:
The time passed (in ms) since the previous update.
"""
if self.state == Creep.ALIVE:
# Maybe it's time to change the direction ?
#
self._change_direction(time_passed)
# Make the creep point in the correct direction.
# Since our direction vector is in screen coordinates
# (i.e. right bottom is 1, 1), and rotate() rotates
# counter-clockwise, the angle must be inverted to
# work correctly.
#
self.image = pygame.transform.rotate(
self.base_image, -self.direction.angle)
# Compute and apply the displacement to the position
# vector. The displacement is a vector, having the angle
# of self.direction (which is normalized to not affect
# the magnitude of the displacement)
#
displacement = vec2d(
self.direction.x * self.speed * time_passed,
self.direction.y * self.speed * time_passed)
self.pos += displacement
# When the image is rotated, its size is changed.
# We must take the size into account for detecting
# collisions with the walls.
#
self.image_w, self.image_h = self.image.get_size()
bounds_rect = self.field.inflate(
-self.image_w, -self.image_h)
if self.pos.x < bounds_rect.left:
self.pos.x = bounds_rect.left
self.direction.x *= -1
elif self.pos.x > bounds_rect.right:
self.pos.x = bounds_rect.right
self.direction.x *= -1
elif self.pos.y < bounds_rect.top:
self.pos.y = bounds_rect.top
self.direction.y *= -1
elif self.pos.y > bounds_rect.bottom:
self.pos.y = bounds_rect.bottom
self.direction.y *= -1
# collision detection
old_x=bounds_rect.left
new_x=old_x+self.direction.x
bounds_rect.left = new_x
# hit a wall?
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
bounds_rect.left=old_x
old_y=self.pos.y
new_y=old_y+self.direction.y
self.pos.y = new_y
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
self.pos.y=old_y
elif self.state == Creep.EXPLODING:
if self.explode_animation.active:
self.explode_animation.update(time_passed)
else:
self.state = Creep.DEAD
self.kill()
elif self.state == Creep.DEAD:
pass
#------------------ PRIVATE PARTS ------------------#
# States the creep can be in.
#
# ALIVE: The creep is roaming around the screen
# EXPLODING:
# The creep is now exploding, just a moment before dying.
# DEAD: The creep is dead and inactive
#
(ALIVE, EXPLODING, DEAD) = range(3)
_counter = 0
def _change_direction(self, time_passed):
""" Turn by 45 degrees in a random direction once per
0.4 to 0.5 seconds.
"""
self._counter += time_passed
if self._counter > randint(400, 500):
self.direction.rotate(45 * randint(-1, 1))
self._counter = 0
def _point_is_inside(self, point):
""" Is the point (given as a vec2d) inside our creep's
body?
"""
img_point = point - vec2d(
int(self.pos.x - self.image_w / 2),
int(self.pos.y - self.image_h / 2))
try:
pix = self.image.get_at(img_point)
return pix[3] > 0
except IndexError:
return False
def _decrease_health(self, n):
""" Decrease my health by n (or to 0, if it's currently
less than n)
"""
self.health = max(0, self.health - n)
if self.health == 0:
self._explode()
def _explode(self):
""" Starts the explosion animation that ends the Creep's
life.
"""
self.state = Creep.EXPLODING
pos = ( self.pos.x - self.explosion_images[0].get_width() / 2,
self.pos.y - self.explosion_images[0].get_height() / 2)
self.explode_animation = SimpleAnimation(
self.screen, pos, self.explosion_images,
100, 300)
global remainingCreeps
remainingCreeps-=1
if remainingCreeps == 0:
print("all dead")
def draw(self):
""" Blit the creep onto the screen that was provided in
the constructor.
"""
if self.state == Creep.ALIVE:
# The creep image is placed at self.pos. To allow for
# smooth movement even when the creep rotates and the
# image size changes, its placement is always
# centered.
#
self.draw_rect = self.image.get_rect().move(
self.pos.x - self.image_w / 2,
self.pos.y - self.image_h / 2)
self.screen.blit(self.image, self.draw_rect)
# The health bar is 15x4 px.
#
health_bar_x = self.pos.x - 7
health_bar_y = self.pos.y - self.image_h / 2 - 6
self.screen.fill( Color('red'),
(health_bar_x, health_bar_y, 15, 4))
self.screen.fill( Color('green'),
( health_bar_x, health_bar_y,
self.health, 4))
elif self.state == Creep.EXPLODING:
self.explode_animation.draw()
elif self.state == Creep.DEAD:
pass
def mouse_click_event(self, pos):
""" The mouse was clicked in pos.
"""
if self._point_is_inside(vec2d(pos)):
self._decrease_health(3)
#begin new player
class Player(pygame.sprite.Sprite):
change_x=0
change_y=0
frame = 0
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
# LOAD PLATER IMAGES
# Set height, width
self.images = []
for i in range(1,17):
img = pygame.image.load("images/player/" + str(i)+".png").convert() #player images
img.set_colorkey(white)
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.health = 15
self.image_w, self.image_h = self.image.get_size()
health_bar_x = self.rect.x - 7
health_bar_y = self.rect.y - self.image_h / 2 - 6
screen.fill( Color('red'),
(health_bar_x, health_bar_y, 15, 4))
screen.fill( Color('green'),
( health_bar_x, health_bar_y,
self.health, 4))
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def _decrease_health(self, n):
""" Decrease my health by n (or to 0, if it's currently
less than n)
"""
self.health = max(0, self.health - n)
if self.health == 0:
self._explode()
def update(self,walls):
# collision detection
old_x=self.rect.x
new_x=old_x+self.change_x
self.rect.x = new_x
# hit a wall?
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
self.rect.x=old_x
old_y=self.rect.y
new_y=old_y+self.change_y
self.rect.y = new_y
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
self.rect.y=old_y
# right to left
if self.change_x < 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
# Grab the image, divide by 4
# every 4 frames.
self.image = self.images[self.frame//4]
# Move left to right.
# images 4...7 instead of 0...3.
if self.change_x > 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4]
if self.change_y > 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4+4]
if self.change_y < 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4+4+4]
score = 0
# initialize pyGame
pygame.init()
# 800x600 sized screen
global screen
screen = pygame.display.set_mode([800, 600])
screen.fill(black)
#bg_tile_img = pygame.image.load('images/map/grass.png').convert_alpha()
#draw_background(screen, bg_tile_img)
#pygame.display.flip()
# Set title
pygame.display.set_caption('Test')
#background = pygame.Surface(screen.get_size())
#background = background.convert()
#background.fill(black)
# Create the player
player = Player( 50,50 )
player.rect.x=50
player.rect.y=50
movingsprites = pygame.sprite.RenderPlain()
movingsprites.add(player)
# Make the walls. (x_pos, y_pos, width, height)
global wall_list
wall_list=pygame.sprite.RenderPlain()
wall=Wall(0,0,10,600) # left wall
wall_list.add(wall)
wall=Wall(10,0,790,10) # top wall
wall_list.add(wall)
#wall=Wall(10,200,100,10) # poke wall
wall_list.add(wall)
wall=Wall(790,0,10,600) #(x,y,thickness, height)
wall_list.add(wall)
wall=Wall(10,590,790,10) #(x,y,thickness, height)
wall_list.add(wall)
f = open('MapMaker.txt')
num_lines = sum(1 for line in f)
print(num_lines)
lineCount = 0
with open("MapMaker.txt") as infile:
for line in infile:
f = open('MapMaker.txt')
print(line)
coords = line.split(',')
#print(coords[0])
#print(coords[1])
#print(coords[2])
#print(coords[3])
#print(coords[4])
if "tree" in line:
print("tree in")
wall=insertTree(int(coords[0]),int(coords[1]), int(coords[2]),int(coords[3]),coords[4])
wall_list.add(wall)
elif "rock" in line:
print("rock in")
wall=insertRock(int(coords[0]),int(coords[1]), int(coords[2]),int(coords[3]),coords[4] )
wall_list.add(wall)
width = 20
height = 540
height = height - 48
for i in range(0,23):
width = width + 32
name = insertTree(width,540,790,10,"tree")
#wall_list.add(name)
name = insertTree(width,height,690,10,"tree")
#wall_list.add(name)
CREEP_SPAWN_TIME = 200 # frames
creep_spawn = CREEP_SPAWN_TIME
clock = pygame.time.Clock()
bg_tile_img = pygame.image.load('images/map/grass.png').convert()
img_rect = bg_tile_img
FIELD_RECT = Rect(50, 50, 700, 500)
CREEP_FILENAMES = [
'images/player/1.png',
'images/player/1.png',
'images/player/1.png']
N_CREEPS = 3
creep_images = [
pygame.image.load(filename).convert_alpha()
for filename in CREEP_FILENAMES]
explosion_img = pygame.image.load('images/map/tree.png').convert_alpha()
explosion_images = [
explosion_img, pygame.transform.rotate(explosion_img, 90)]
creeps = pygame.sprite.RenderPlain()
done = False
#bg_tile_img = pygame.image.load('images/map/grass.png').convert()
#draw_background(screen, bg_tile_img)
totalCreeps = 0
remainingCreeps = 3
while done == False:
creep_images = pygame.image.load("images/player/1.png").convert()
creep_images.set_colorkey(white)
draw_background(screen, bg_tile_img)
if len(creeps) != N_CREEPS:
if totalCreeps < N_CREEPS:
totalCreeps = totalCreeps + 1
print(totalCreeps)
creeps.add(
Creep( screen=screen,
creep_image=creep_images,
explosion_images=explosion_images,
field=FIELD_RECT,
init_position=( randint(FIELD_RECT.left,
FIELD_RECT.right),
randint(FIELD_RECT.top,
FIELD_RECT.bottom)),
init_direction=(choice([-1, 1]),
choice([-1, 1])),
speed=0.01))
for creep in creeps:
creep.update(60,wall_list)
creep.draw()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed(-2,0)
creep.changespeed(-2,0)
if event.key == pygame.K_RIGHT:
player.changespeed(2,0)
creep.changespeed(2,0)
if event.key == pygame.K_UP:
player.changespeed(0,-2)
creep.changespeed(0,-2)
if event.key == pygame.K_DOWN:
player.changespeed(0,2)
creep.changespeed(0,2)
if event.key == pygame.K_ESCAPE:
pauseGame()
if event.key == pygame.K_1:
global currentEditTool
currentEditTool = "Tree"
changeTool()
if event.key == pygame.K_2:
global currentEditTool
currentEditTool = "Rock"
changeTool()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(2,0)
creep.changespeed(2,0)
if event.key == pygame.K_RIGHT:
player.changespeed(-2,0)
creep.changespeed(-2,0)
if event.key == pygame.K_UP:
player.changespeed(0,2)
creep.changespeed(0,2)
if event.key == pygame.K_DOWN:
player.changespeed(0,-2)
creep.changespeed(0,-2)
if event.type == pygame.MOUSEBUTTONDOWN and pygame.mouse.get_pressed()[0]:
for creep in creeps:
creep.mouse_click_event(pygame.mouse.get_pos())
if editMap == True:
x,y = pygame.mouse.get_pos()
if currentEditTool == "Tree":
name = insertTree(x-10,y-25, 10 , 10, "tree")
wall_list.add(name)
wall_list.draw(screen)
f = open('MapMaker.txt', "a+")
image = pygame.image.load("images/map/tree.png").convert()
screen.blit(image, (30,10))
pygame.display.flip()
f.write(str(x) + "," + str(y) + ",790,10, tree\n")
#f.write("wall=insertTree(" + str(x) + "," + str(y) + ",790,10)\nwall_list.add(wall)\n")
elif currentEditTool == "Rock":
name = insertRock(x-10,y-25, 10 , 10,"rock")
wall_list.add(name)
wall_list.draw(screen)
f = open('MapMaker.txt', "a+")
f.write(str(x) + "," + str(y) + ",790,10,rock\n")
#f.write("wall=insertRock(" + str(x) + "," + str(y) + ",790,10)\nwall_list.add(wall)\n")
else:
None
#pygame.display.flip()
player.update(wall_list)
movingsprites.draw(screen)
wall_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
© Game Development or respective owner