Skip to content

Commit

Permalink
Merge pull request #17 from Mekire/master
Browse files Browse the repository at this point in the history
added some documentation; tomato slinger; removed grass background
  • Loading branch information
Mekire committed Jul 24, 2013
2 parents 26f32ff + 4d9a3fc commit 3095071
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 25 deletions.
8 changes: 7 additions & 1 deletion data/components/plants_mek.py
Expand Up @@ -43,11 +43,17 @@ def __init__(self,coords,location):
frame_coords = [(0,0),(1,0)]
_Plant.__init__(self,coords,location,frame_coords,"SHOOTER")

class Tomato(_Plant):
def __init__(self,coords,location):
frame_coords = [(0,2),(1,2),(2,2),(3,2),(4,2),
(0,3),(1,3),(2,3),(3,3),(4,3)]
_Plant.__init__(self,coords,location,frame_coords,"TOMATO")

class Sunflower(_Plant):
def __init__(self,coords,location):
_Plant.__init__(self,coords,location,[(0,1)],"SUNFLOWER")


PLANT_DICT = {"SHOOTER" : Shooter,
"SUNFLOWER" : Sunflower}
"SUNFLOWER" : Sunflower,
"TOMATO" : Tomato}
24 changes: 21 additions & 3 deletions data/components/select_mek.py
Expand Up @@ -11,7 +11,8 @@ def __init__(self,location,plant_names):
self.pad_item = (self.rect.x+19,self.rect.y+3)
self.spacer = 77
self.plant_dict = {"SHOOTER" : ShooterSelect,
"SUNFLOWER" : SunflowerSelect}
"SUNFLOWER" : SunflowerSelect,
"TOMATO" : TomatoSelect}
self.plants = self.setup_plants(plant_names)
self.selected = False
self.current_time = 0.0
Expand All @@ -37,6 +38,7 @@ def update(self,surface,current_time):


class _SelectPlant(object):
"""Prototype for plants in the selector window."""
def __init__(self,location,sheet_coord,name):
self.rect = pg.Rect(location,setup.CELL_SIZE)
sheet = setup.GFX["plant_sheet"].copy()
Expand All @@ -51,12 +53,15 @@ def __init__(self,location,sheet_coord,name):
self.make_all_highlights()

def deployed(self):
"""This function is called if a selected plant is placed on the grid."""
self.ready = False
self.timer = pg.time.get_ticks()#self.current_time
self.timer = pg.time.get_ticks() #A direct call here is justified.
self.recharge_highlight = pg.Surface((setup.CELL_SIZE)).convert_alpha()
self.recharge_highlight.fill((0,0,0,200))

def make_all_highlights(self):
"""Creates the highlights for hovering and selected plants and
creates an initial surface and rect for the recharge highlight."""
self.highlight = pg.Surface((self.rect.width+2,self.rect.height+21)).convert_alpha()
self.select_highlight = self.highlight.copy()
self.highlight.fill((100,100,255,100))
Expand All @@ -66,6 +71,10 @@ def make_all_highlights(self):
self.ghost = self.make_ghost()

def make_ghost(self):
"""Creates the semi-transparent ghost image that appears at the location
a plant would grow if confirmed. As the images already contain
per-pixel-alpha, it is necessary to change the alpha as follows; using
pygame.Surface.set_alpha won't work unfortunately."""
ghost = self.image.copy()
array = pg.surfarray.pixels_alpha(ghost)
for j,y in enumerate(array):
Expand All @@ -74,7 +83,10 @@ def make_ghost(self):
return ghost

def make_recharge_highlight(self):
elapsed = pg.time.get_ticks()-self.timer
"""Creates the clock style recharging highlight. I wanted to use
pygame.draw.arc for this but unfortunately that draw method is badly
written and leaves moire patterns."""
elapsed = self.current_time-self.timer
percent_recharged = elapsed/(self.time_for_recharge*1000)
angle = 2*math.pi*percent_recharged
x = self.recharge_rect.centerx+50*math.cos(angle)
Expand All @@ -86,13 +98,16 @@ def make_recharge_highlight(self):
return self.recharge_highlight

def setup_cost(self,cost):
"""Creates rendered cost and appropriately centered rect."""
self.cost = cost
target_rect = pg.Rect(self.rect.x,self.rect.bottom,setup.CELL_SIZE[0],21)
font = pg.font.Font(setup.FONTS["Fixedsys500c"],20)
self.cost_txt = font.render(str(self.cost),1,(0,0,0))
self.cost_txt_rect = self.cost_txt.get_rect(center=target_rect.center)

def update(self,surface,selected,current_time):
"""Updates for selector window plants, including highlights and
recharging."""
self.current_time = current_time
if self != selected:
if self.ready and self.rect.collidepoint(pg.mouse.get_pos()):
Expand All @@ -111,6 +126,9 @@ def __init__(self,location):
self.setup_cost(100)
self.time_for_recharge = 10.0

class TomatoSelect(_SelectPlant):
def __init__(self,location):
_SelectPlant.__init__(self,location,(2,2),"TOMATO")

class SunflowerSelect(_SelectPlant):
def __init__(self,location):
Expand Down
12 changes: 6 additions & 6 deletions data/components/sun_objects.py
@@ -1,6 +1,6 @@
from sun import Sun
import pygame as pg
from .. import setup as setup, tools
from .sun import Sun
from .. import setup, tools

class SunObjects:
def __init__(self):
Expand All @@ -11,19 +11,19 @@ def __init__(self):
self.sun_timer = 0
self.sun_delay = 5
self.text_update()

def text_update(self):
selected_font = pg.font.Font(setup.FONTS["Fixedsys500c"], 20)
self.sun_amount = selected_font.render(str(self.sun_total), 1, (255,255,255))
self.sun_amount_rect = self.sun_amount.get_rect()

def sun_updates(self, surface):
self.text_update()

if (pg.time.get_ticks() - self.sun_timer) > 1000*self.sun_delay:
self.sun_timer = pg.time.get_ticks()
self.suns.append(Sun(self.large_sun_value))
self.suns.append(Sun(self.large_sun_value))

for obj in self.suns[:]:
if obj.image_rect.collidepoint(pg.mouse.get_pos()) and pg.mouse.get_pressed()[0]:
mouse = pg.mouse.get_pos()
Expand Down
18 changes: 11 additions & 7 deletions data/setup.py
Expand Up @@ -11,33 +11,37 @@
ORIGINAL_CAPTION
SCREEN
SCREEN_RECT
CELL_SIZE
GRID_MARGIN
SELECTOR_MARGIN
FONTS
MUSIC
GFX
SFX
"""

import os
import pygame as pg
from . import tools


SCREEN_SIZE = 800,600
ORIGINAL_CAPTION = "Botany vs Biomass"

#Locations of widgets during gameplay
CELL_SIZE = (72,72)
GRID_MARGIN = (75,165)
SELECTOR_MARGIN = (150,0)

#Initialization
##os.environ['SDL_VIDEO_CENTERED'] = '1'
pg.init()
pg.display.set_caption(ORIGINAL_CAPTION)

SCREEN = pg.display.set_mode(SCREEN_SIZE)
SCREEN_RECT = SCREEN.get_rect()

#Locations of widgets during gameplay
CELL_SIZE = (72,72)
GRID_MARGIN = (75,165)
SELECTOR_MARGIN = (150,0)

#Resource loading (Fonts and music just contain path names).
FONTS = tools.load_all_fonts(os.path.join("resources","fonts"))
MUSIC = tools.load_all_music(os.path.join("resources","music"))
GFX = tools.load_all_gfx(os.path.join("resources","graphics"))
SFX = tools.load_all_sfx(os.path.join("resources","sound"))
SFX = tools.load_all_sfx(os.path.join("resources","sound"))
38 changes: 34 additions & 4 deletions data/states/survive.py
@@ -1,8 +1,37 @@
"""
Module: survive.py
Overview:
This module contains the survive state.
Imports:
random
pygame as pg
from .. import setup,tools
from ..components import sun_mek,select_mek,plants_mek
Classes:
Survive(tools._State):
Methods:
__init__(self)
startup(self,current_time,persistant)
render_font(self,font,size,msg,color=(255,255,255))
update(self,surface,keys,current_time)
update_cursor(self,surface)
get_coordinates(self,mouse)
get_position_from_coordinates(self,coords)
update_suns(self,surface)
update_plants(self,surface)
update_energy(self,surface)
clicked_sun(self,event)
clicked_selector(self,event)
add_plant(self,event)
get_event(self,event)
"""

import random
import pygame as pg
from .. import setup,tools
from ..components import sun_mek,select_mek,plants_mek


class Survive(tools._State):
"""This State is updated while our game shows the Survive screen."""
def __init__(self):
Expand All @@ -19,7 +48,7 @@ def startup(self,current_time,persistant):
self.mode = "READY"
self.energy = 200
self.energy_rect = pg.Rect(31,49,88,32)
self.available_plants = ["SHOOTER","SUNFLOWER"] #Initialized thusly for testing.
self.available_plants = ["SHOOTER","SUNFLOWER","TOMATO"] #Initialized thusly for testing.
self.selector = select_mek.Selector(setup.SELECTOR_MARGIN,self.available_plants)
self.suns = []
self.plants = []
Expand Down Expand Up @@ -85,10 +114,12 @@ def update_suns(self,surface):
sun.update(surface,self.current_time)

def update_plants(self,surface):
"""Update all plants on the grid."""
for plant in self.plants:
plant.update(surface,self.current_time)

def update_energy(self,surface):
"""Render and blit the energy amount to the screen."""
energy_txt = self.render_font("Fixedsys500c",35,str(self.energy),(0,0,0))
energy_txt_rect = energy_txt.get_rect(center=self.energy_rect.center)
surface.blit(energy_txt,energy_txt_rect)
Expand All @@ -110,8 +141,7 @@ def clicked_selector(self,event):
self.selector.select_plant(plant)
self.plant_cursor = plant.image.copy()
return True
else:
self.selector.selected = None
self.selector.selected = None

def add_plant(self,event):
"""Adds currently selected plant to the grid."""
Expand All @@ -131,7 +161,7 @@ def get_event(self,event):
if event.key == pg.K_ESCAPE:
self.next = "MENU"
self.done = True
if event.type == pg.MOUSEBUTTONDOWN:
elif event.type == pg.MOUSEBUTTONDOWN:
if self.mode == "PLAY":
if event.button == 1:
if self.clicked_sun(event):
Expand Down
21 changes: 17 additions & 4 deletions data/tools.py
Expand Up @@ -27,11 +27,12 @@
load_all_music(directory,accept=(".wav",".mp3",".ogg",".mdi"))
load_all_fonts(directory,accept=(".ttf",))
load_all_sfx(directory,accept=(".wav",".mp3",".ogg",".mdi"))
"""

import os
import pygame as pg


class Control(object):
"""Control class for entire project. Contains the game loop, and contains
the event_loop which passes events to States as needed. Logic for flipping
Expand All @@ -48,12 +49,14 @@ def __init__(self,caption):
self.state_dict = {}
self.state_name = None
self.state = None

def setup_states(self,state_dict,start_state):
"""Given a dictionary of States and a State to start in,
builds the self.state_dict."""
self.state_dict = state_dict
self.state_name = start_state
self.state = self.state_dict[self.state_name]

def update(self):
"""Checks if a state is done or has called for a game quit.
State is flipped if neccessary and State.update is called."""
Expand All @@ -63,6 +66,7 @@ def update(self):
elif self.state.done:
self.flip_state()
self.state.update(self.screen,self.keys,self.current_time)

def flip_state(self):
"""When a State changes to done necessary startup and cleanup functions
are called and the current State is changed."""
Expand All @@ -71,6 +75,7 @@ def flip_state(self):
self.state = self.state_dict[self.state_name]
self.state.startup(self.current_time,persist)
self.state.previous = previous

def event_loop(self):
"""Process all events and pass them down to current State. The f5 key
globally turns on/off the display of FPS in the caption"""
Expand All @@ -81,12 +86,14 @@ def event_loop(self):
self.keys = pg.key.get_pressed()
self.toggle_show_fps()
self.state.get_event(event)

def toggle_show_fps(self):
"""Press f5 to turn on/off displaying the framerate in the caption."""
if self.keys[pg.K_F5]:
self.show_fps = not self.show_fps
if not self.show_fps:
pg.display.set_caption(self.caption)

def main(self):
"""Main loop for entire program."""
while not self.done:
Expand All @@ -98,37 +105,43 @@ def main(self):
with_fps = "{} - {:.2f} FPS".format(self.caption,self.clock.get_fps())
pg.display.set_caption(with_fps)


class _State(object):
"""This is a prototype class for States. All states should inherit from it.
No direct instances of this class should be created. get_event and update
must be overloaded in the childclass. startup and cleanup need to be
overloaded when there is data that must persist between States."""
def __init__(self):
self.start_time = 0.0
self.current_time = 0.0##
self.current_time = 0.0
self.done = False
self.quit = False
self.next = None
self.previous = None
self.persist = {}
def get_event(self,event,keys,mouse):

def get_event(self,event):
"""Processes events that were passed from the main event loop.
Must be overloaded in children."""
pass

def startup(self,current_time,persistant):
"""Add variables passed in persistant to the proper attributes and
set the start time of the State to the current time."""
self.persist = persistant
self.start_time = current_time

def cleanup(self):
"""Add variables that should persist to the self.persist dictionary.
Then reset State.done to False."""
self.done = False
return self.persist

def update(self,surface,keys,current_time):
"""Update function for state. Must be overloaded in children."""
pass


### Resource loading functions.
def load_all_gfx(directory,colorkey=(255,0,255),accept=(".png",".jpg",".bmp")):
"""Load all graphics with extensions in the accept argument. If alpha
Expand Down Expand Up @@ -172,4 +185,4 @@ def load_all_sfx(directory,accept=(".wav",".mp3",".ogg",".mdi")):
name,ext = os.path.splitext(fx)
if ext.lower() in accept:
effects[name] = pg.mixer.Sound(pg.os.path.join(directory,fx))
return effects
return effects
2 changes: 2 additions & 0 deletions plantsvszombies.py
Expand Up @@ -5,10 +5,12 @@
-appended by Mekire June 30th, 2013.
"""

import sys
import pygame as pg
from data.main import main


if __name__ == '__main__':
try:
main()
Expand Down
Binary file modified resources/graphics/plant_sheet.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/graphics/survival.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3095071

Please sign in to comment.