This commit is contained in:
commit
a83e8d581a
|
@ -0,0 +1,51 @@
|
|||
Slacker
|
||||
===============
|
||||
|
||||
Entry in PyWeek #4 <http://www.pyweek.org/4/>
|
||||
Team: Last Minute Frivolities
|
||||
Members: Clint "HanClinto" Herron (coding)
|
||||
Jennifer Herron (graphics)
|
||||
|
||||
DEPENDENCIES:
|
||||
|
||||
You might need to install some of these before running the game:
|
||||
|
||||
Python: http://www.python.org/
|
||||
PyGame: http://www.pygame.org/
|
||||
|
||||
|
||||
RUNNING THE GAME:
|
||||
|
||||
Open a terminal / console and "cd" to the game directory and run:
|
||||
|
||||
python run_game.py
|
||||
|
||||
|
||||
HOW TO PLAY THE GAME:
|
||||
|
||||
Keys:
|
||||
Spacebar - advance menus, or place your stacking boxes.
|
||||
|
||||
Description:
|
||||
Boxes will move back and forth at varying speeds. Press the spacebar to stop the boxes and move on to the next row. Only boxes that have something underneath them will be stacked. As the tower rises, the game will make your tower thinner. You win a minor prize at the 10th level (the blocks change color), and if you reach the 15th level, you will win the major prize. Good luck!
|
||||
|
||||
GAME BACKGROUND:
|
||||
|
||||
"Slacker" is a clone/parody of the popular arcade game "Stacker", in which you must stack blocks to the top of the screen in order to win the game. In the arcade version, credits are expensive (often $1 per play), but the prizes are excellent (the one that I played let you choose between an iPod, a PSP, a DS, or a camcorder). As you might guess, it is an extremely difficult game to win. I have made my own version of the game correspondingly hard, so that the next time I go back to the restaurant, I will have a better chance to win a good prize. Despite the hard nature of the game, I hope will enjoy it, and if you wind up practicing with the game and getting so good that you win an extra iPod, I wouldn't mind if you sent it my way. :)
|
||||
|
||||
Please forgive the small scope of the project - I started it on the last day of the competition, and didn't have much time to put into it. Still, I hope you enjoyed it!
|
||||
|
||||
VERSION HISTORY:
|
||||
1.0 - First version, submitted to PyWeek #4
|
||||
1.2 - Released shortly after PyWeek, adding a number of updates:
|
||||
- Game no longer quits after losing, but restarts automatically
|
||||
- ESC exits
|
||||
- Added animations for showing falling blocks that are missed
|
||||
- Updated graphics for consistency
|
||||
- Added a more fun and rewarding win screen to congratulate the player
|
||||
- Tower is shown after win/lose so that you can see how you did
|
||||
- Packaging is now supported for Mac/Windows
|
||||
|
||||
LICENSE:
|
||||
|
||||
This game, its source code, and graphics, are freely available for modification as well as use in private, commercial, or open-source projects. Credit is appreciated, but not necessary. We hope you have fun and learn something.
|
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
#This is an automatically generated file that can be deleted
|
||||
import main
|
||||
main.main()
|
|
@ -0,0 +1,27 @@
|
|||
'''Simple data loader module.
|
||||
|
||||
Loads data files from the "data" directory shipped with a game.
|
||||
|
||||
Enhancing this to handle caching etc. is left as an exercise for the reader.
|
||||
'''
|
||||
|
||||
import os
|
||||
import pygame
|
||||
|
||||
data_py = os.path.abspath(os.path.dirname(__file__))
|
||||
data_dir = os.path.normpath(os.path.join(data_py, '..', 'data'))
|
||||
|
||||
# The following is only used when packaging for .app
|
||||
#data_dir = os.path.normpath(os.path.join(data_py, '..', '..', '..', 'data'))
|
||||
|
||||
|
||||
def filepath(filename):
|
||||
'''Determine the path to a file in the data directory.
|
||||
'''
|
||||
return os.path.join(data_dir, filename)
|
||||
|
||||
def load_image(filename):
|
||||
# Open a file in the data directory.
|
||||
return pygame.image.load(os.path.join(data_dir, filename))
|
||||
#return open(os.path.join(data_dir, filename), mode)
|
||||
|
Binary file not shown.
|
@ -0,0 +1,237 @@
|
|||
'''Game main module.
|
||||
|
||||
Last Day Game Entry, by Clint Herron
|
||||
'''
|
||||
|
||||
import data
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from data import *
|
||||
from math import sin
|
||||
|
||||
BOARD_SIZE = BOARD_WIDTH, BOARD_HEIGHT = 12, 20
|
||||
SCREEN_SIZE = SCREEN_WIDTH, SCREEN_HEIGHT = 240, 400
|
||||
TILE_SIZE = TILE_WIDTH, TILE_HEIGHT = SCREEN_WIDTH / BOARD_WIDTH, SCREEN_HEIGHT / BOARD_HEIGHT
|
||||
|
||||
TILE_COLOR = (127, 127, 255)
|
||||
TILE_COLOR_ALT = (255, 127, 127)
|
||||
TILE_COLOR_LOSE = (64, 64, 128)
|
||||
TILE_COLOR_ALT_LOSE = (127, 64, 64)
|
||||
|
||||
BLACK = (0,0,0)
|
||||
|
||||
LEVEL_SPEED = ( 80, 80, 75, 75, 70, 70, 65, 60, 55, 50,
|
||||
45, 40, 35, 30, 32 )
|
||||
MAX_WIDTH = (3, 3, 3, 3, 2, 2, 2, 2, 1, 1,
|
||||
1, 1, 1, 1, 1)
|
||||
|
||||
COLOR_CHANGE_Y = 10 # The block below which are displayed in the alternate color
|
||||
WIN_LEVEL = 15
|
||||
|
||||
current_speed = 50 # Current tile speed in milliseconds
|
||||
board = []
|
||||
lose_tiles = []
|
||||
current_direction = 1
|
||||
current_x, current_y, current_width = 0, BOARD_HEIGHT - 1, 3
|
||||
current_level = 0
|
||||
|
||||
INTRO = 0
|
||||
PLAYING = 1
|
||||
LOSE = 2
|
||||
WIN = 3
|
||||
|
||||
game_state = INTRO
|
||||
|
||||
bg_images = ( load_image("intro.png"), load_image("game.png"), load_image("lose.png"), load_image("win.png") )
|
||||
|
||||
bg_images[WIN].set_colorkey(BLACK)
|
||||
bg_images[LOSE].set_colorkey(BLACK)
|
||||
|
||||
keep_running = True
|
||||
|
||||
def main():
|
||||
global game_state, current_x, current_y, current_speed, keep_running, current_width, current_level
|
||||
|
||||
pygame.init()
|
||||
screen = pygame.display.set_mode( SCREEN_SIZE )
|
||||
|
||||
reset_game()
|
||||
|
||||
while(keep_running):
|
||||
update_movement()
|
||||
update_board_info()
|
||||
update_screen(screen)
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
keep_running = False
|
||||
elif event.type == KEYDOWN:
if event.key == K_SPACE:
key_hit()
|
||||
elif event.key == K_ESCAPE:
|
||||
if game_state == INTRO:
|
||||
keep_running = False
|
||||
else:
|
||||
reset_game()
|
||||
elif event.key == K_F1: # Yes, this is a cheat.
|
||||
current_x -= 1
|
||||
if (current_x < 0): current_x = 0
|
||||
current_width += 1
|
||||
if (current_width >= BOARD_WIDTH): current_width = BOARD_WIDTH - 1
|
||||
|
||||
pygame.display.quit()
|
||||
|
||||
def reset_game():
|
||||
global game_state, current_x, current_y, current_speed, keep_running, current_width, current_level, lose_tiles
|
||||
|
||||
clear_board()
|
||||
lose_tiles = []
|
||||
|
||||
keep_running = True
|
||||
|
||||
game_state = INTRO
|
||||
|
||||
current_x = 0
|
||||
current_y = BOARD_HEIGHT - 1
|
||||
current_level = 0
|
||||
current_speed = LEVEL_SPEED[current_level]
|
||||
current_width = MAX_WIDTH[current_level]
|
||||
|
||||
def key_hit():
|
||||
global keep_running, game_state, current_x, current_y, current_width, current_speed, current_level, lose_tiles
|
||||
|
||||
if game_state == PLAYING:
|
||||
if current_y < BOARD_HEIGHT - 1:
|
||||
for x in range(current_x, current_x + current_width):
|
||||
if board[x][current_y + 1] == 0: # If they're standing on a block that did not work
|
||||
current_width -= 1 # Then next time, give them one less block
|
||||
board[x][current_y] = 0 # Also, get rid of this block that isn't standing on solid ground.
|
||||
# Then, add a lose tile for that missed block
|
||||
# Lose tile format is (x, y, color, start time)
|
||||
lose_tiles.append( (x, current_y,
|
||||
pygame.time.get_ticks()) )
|
||||
|
||||
current_level += 1
|
||||
check_win_lose()
|
||||
current_y -= 1
|
||||
elif game_state == INTRO:
|
||||
game_state = PLAYING
|
||||
elif (game_state == LOSE) or (game_state == WIN):
|
||||
reset_game()
|
||||
game_state = INTRO
|
||||
else:
|
||||
keep_running = False
|
||||
|
||||
def check_win_lose():
|
||||
global game_state, current_width, current_level, current_speed, keep_running, TILE_COLOR
|
||||
|
||||
if current_width == 0:
|
||||
game_state = LOSE
|
||||
elif current_level == WIN_LEVEL:
|
||||
current_speed = 100
|
||||
game_state = WIN
|
||||
else:
|
||||
current_speed = LEVEL_SPEED[current_level]
|
||||
if current_width > MAX_WIDTH[current_level]:
|
||||
current_width = MAX_WIDTH[current_level]
|
||||
|
||||
last_time = 0
|
||||
def update_movement():
|
||||
global game_state, last_time, current_x, current_y, current_width, current_speed, current_direction
|
||||
|
||||
current_time = pygame.time.get_ticks()
|
||||
if (last_time + current_speed <= current_time):
|
||||
if game_state == PLAYING:
|
||||
new_x = current_x + current_direction
|
||||
|
||||
if (new_x < 0) or (new_x + current_width > BOARD_WIDTH):
|
||||
current_direction = -current_direction
|
||||
|
||||
current_x += current_direction
|
||||
|
||||
last_time = current_time
|
||||
|
||||
def update_screen(screen):
|
||||
global game_state
|
||||
|
||||
if game_state == PLAYING:
|
||||
draw_background(screen)
|
||||
draw_board(screen)
|
||||
elif game_state == INTRO:
|
||||
draw_background(screen)
|
||||
pass
|
||||
elif (game_state == LOSE) or (game_state == WIN):
|
||||
screen.fill(BLACK)
|
||||
draw_board(screen)
|
||||
draw_background(screen)
|
||||
|
||||
pygame.display.flip()
|
||||
|
||||
def draw_background(screen):
|
||||
global game_state
|
||||
screen.blit(bg_images[game_state], (0,0,SCREEN_WIDTH,SCREEN_HEIGHT), (0,0,SCREEN_WIDTH,SCREEN_HEIGHT))
|
||||
|
||||
|
||||
def update_board_info():
|
||||
global game_state
|
||||
|
||||
if game_state == PLAYING:
|
||||
clear_row(current_y)
|
||||
fill_current_row()
|
||||
|
||||
def draw_board(screen):
|
||||
for x in range(BOARD_WIDTH):
|
||||
for y in range(BOARD_HEIGHT):
|
||||
if board[x][y] == 1:
|
||||
draw_tile(screen, x, y)
|
||||
|
||||
draw_lose_tiles(screen)
|
||||
|
||||
def draw_tile(screen, x, y):
|
||||
xoffset = 0 # XOffset is used to draw some wiggle in the tower when you win
|
||||
col = TILE_COLOR
|
||||
if (y < COLOR_CHANGE_Y):
|
||||
col = TILE_COLOR_ALT
|
||||
|
||||
if (game_state == LOSE):
|
||||
col = TILE_COLOR_LOSE
|
||||
if (y < COLOR_CHANGE_Y):
|
||||
col = TILE_COLOR_ALT_LOSE
|
||||
|
||||
if game_state == WIN:
|
||||
xoffset = sin(pygame.time.get_ticks() * 0.004 + y * 0.5) * (SCREEN_WIDTH / 4)
|
||||
|
||||
pygame.draw.rect(screen, col, (x * TILE_WIDTH + xoffset, y * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT))
|
||||
pygame.draw.rect(screen, BLACK, (x * TILE_WIDTH + xoffset, y * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT), 2)
|
||||
|
||||
# Lose tiles are ones that fall off from the edge when you miss placing them on the proper stack
|
||||
def draw_lose_tiles(screen):
|
||||
for lt in lose_tiles:
|
||||
deltaT = (pygame.time.get_ticks() - lt[2]) * 0.008 # How long it has been falling
|
||||
x = lt[0] * TILE_WIDTH
|
||||
y = lt[1] * TILE_HEIGHT + deltaT * deltaT
|
||||
|
||||
col = TILE_COLOR_LOSE
|
||||
if (lt[1] < COLOR_CHANGE_Y):
|
||||
col = TILE_COLOR_ALT_LOSE
|
||||
|
||||
if (y > SCREEN_HEIGHT):
|
||||
lose_tiles.remove(lt)
|
||||
else:
|
||||
pygame.draw.rect(screen, col, (x+2, y+2, TILE_WIDTH-3, TILE_HEIGHT-3))
|
||||
|
||||
def clear_board():
|
||||
global board
|
||||
|
||||
board = []
|
||||
for x in range(BOARD_WIDTH):
|
||||
board.append([])
|
||||
for y in range (BOARD_HEIGHT):
|
||||
board[x].append(0)
|
||||
|
||||
def clear_row(y):
|
||||
for x in range(BOARD_WIDTH):
|
||||
board[x][y] = 0
|
||||
|
||||
def fill_current_row():
|
||||
global current_x, current_y, current_width
|
||||
for x in range(current_x, current_x + current_width):
|
||||
board[x][current_y] = 1
|
Binary file not shown.
|
@ -0,0 +1,27 @@
|
|||
"""
|
||||
Script for building the example.
|
||||
|
||||
Usage:
|
||||
python setup.py py2app
|
||||
"""
|
||||
from setuptools import setup
|
||||
|
||||
NAME = 'Slacker'
|
||||
VERSION = '1.2'
|
||||
|
||||
plist = dict(
|
||||
CFBundleIconFile='Slacker.icns',
|
||||
CFBundleName=NAME,
|
||||
CFBundleShortVersionString=VERSION,
|
||||
CFBundleGetInfoString=' '.join([NAME, VERSION]),
|
||||
CFBundleExecutable=NAME,
|
||||
CFBundleIdentifier='pyweek.4.slacker',
|
||||
)
|
||||
|
||||
setup(
|
||||
data_files=['../data'],
|
||||
app=[
|
||||
dict(script="Slacker.py", plist=plist),
|
||||
],
|
||||
setup_requires=["py2app"],
|
||||
)
|
|
@ -0,0 +1,13 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
import sys
|
||||
import os
|
||||
try:
|
||||
libdir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib'))
|
||||
sys.path.insert(0, libdir)
|
||||
except:
|
||||
# probably running inside py2exe which doesn't set __file__
|
||||
pass
|
||||
|
||||
import main
|
||||
main.main()
|
Loading…
Reference in New Issue