Compare commits
No commits in common. "master" and "V1.0" have entirely different histories.
56
.gitignore
vendored
|
@ -1,57 +1 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
|
126
GUI.py
|
@ -1,147 +1,46 @@
|
|||
from tkinter import *
|
||||
from tkinter.ttk import *
|
||||
import logging
|
||||
from os import system
|
||||
import game
|
||||
from assets import Textures
|
||||
|
||||
PADDING_TITLE = 15
|
||||
PADDING_BUTTON = 9
|
||||
VERSION = {"ID":"2.2", "DATE": "19/05/15"}
|
||||
|
||||
PROGRAM_OPEN = True
|
||||
|
||||
class Main_Window:
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
self.master.title("ATTACK ON BLOCKS")
|
||||
self.master.title("SPACE INVADERS")
|
||||
|
||||
self.title = Label(self.master)
|
||||
self.title.config(text="ATTACK ON BLOCKS!",font=("Courier New", 37))
|
||||
self.title.pack(side="top", padx=PADDING_TITLE, pady=PADDING_TITLE/2)
|
||||
|
||||
self.version_info = Label(self.master)
|
||||
self.version_info.config(text="Version {ID} tagged {DATE}".format(**VERSION), font=("Courier New", 13))
|
||||
self.version_info.pack(side="top", padx=0, pady=PADDING_BUTTON/2)
|
||||
self.title.config(text="SPACE INVADERS!",font=("Courier New", 37))
|
||||
self.title.pack(side="top", padx=PADDING_BUTTON, pady=PADDING_TITLE/2)
|
||||
|
||||
self.start_button = Button(self.master, style="Menu.TButton")
|
||||
self.start_button.config(text="Play Game")
|
||||
self.start_button.pack(fill=BOTH, ipadx=PADDING_BUTTON/2, ipady=PADDING_BUTTON/2, padx=PADDING_BUTTON, pady=PADDING_BUTTON)
|
||||
self.start_button.bind('<Button-1>', self.play_game)
|
||||
|
||||
self.options_button = Button(self.master, style="Menu.TButton")
|
||||
self.options_button.config(text="Show Options")
|
||||
self.options_button.pack(fill=BOTH, ipadx=PADDING_BUTTON/2, ipady=PADDING_BUTTON/2, padx=PADDING_BUTTON, pady=PADDING_BUTTON)
|
||||
self.options_button.bind('<Button-1>', self.show_options)
|
||||
|
||||
self.help_button = Button(self.master, style="About.TButton")
|
||||
self.help_button.config(text="About / Help")
|
||||
self.help_button.pack(fill=BOTH, ipadx=PADDING_BUTTON/4, ipady=PADDING_BUTTON/4, padx=PADDING_BUTTON, pady=PADDING_BUTTON)
|
||||
self.help_button.bind('<Button-1>', self.show_info)
|
||||
|
||||
self.exit_button = Button(self.master, style="Quit.TButton")
|
||||
self.exit_button.config(text="Quit Game")
|
||||
self.exit_button.pack(ipadx=PADDING_BUTTON/3, ipady=PADDING_BUTTON, padx=PADDING_BUTTON, pady=PADDING_BUTTON)
|
||||
self.exit_button.bind('<Button-1>', self.close)
|
||||
|
||||
self.about_info = Label(self.master)
|
||||
self.about_info.config(text="Game Created by TheOrangeOne!", font=("Courier New", 9))
|
||||
self.about_info.bind("<Button-1>", self.show_site)
|
||||
self.about_info.pack(side="top", padx=0, pady=PADDING_BUTTON/2)
|
||||
|
||||
Style().configure("Menu.TButton", font=("Lucida", 21))
|
||||
Style().configure("About.TButton", font=("Lucida", 17))
|
||||
Style().configure("Quit.TButton", font=("Lucida", 13))
|
||||
Style().configure("Menu.TButton", font=("Lucida", 25 ))
|
||||
Style().configure("Quit.TButton", font=("Lucida", 15))
|
||||
|
||||
self.options_window = Options_Window()
|
||||
logging.debug("GUI Generated.")
|
||||
logging.info("GUI Generated.")
|
||||
|
||||
def play_game(self, event):
|
||||
logging.info("Game Started.")
|
||||
self.master.withdraw()
|
||||
exit_code = game.initialise(self.master, self.options_window.options)
|
||||
if exit_code != "QUIT": self.title["text"] = exit_messages[exit_code]
|
||||
|
||||
def show_options(self, event):
|
||||
self.new_window = Toplevel(self.master)
|
||||
self.options_window.display(self.new_window)
|
||||
|
||||
def show_info(self, event):
|
||||
logging.info("Loading About Page...")
|
||||
system("start https://bitbucket.org/theorangeone/attack-on-blocks/wiki/Home")
|
||||
game.initialise(self.master, None)
|
||||
|
||||
def close(self, event):
|
||||
logging.critical("Closing Main Window.")
|
||||
self.master.destroy()
|
||||
|
||||
def show_site(self, event):
|
||||
logging.info("Loading Website")
|
||||
system("start http://theorangeone.net")
|
||||
|
||||
class Options_Window:
|
||||
def __init__(self):
|
||||
self.textures_object = Textures()
|
||||
self.options = {
|
||||
"Difficulty": 120,
|
||||
"Textures": self.textures_object,
|
||||
"Sounds": True
|
||||
}
|
||||
|
||||
def display(self, master):
|
||||
self.master = master
|
||||
self.master.title("ATTACK ON BLOCKS - Options")
|
||||
|
||||
self.title = Label(self.master)
|
||||
self.title.config(text="OPTIONS",font=("Courier New", 37))
|
||||
self.title.pack(side="top", padx=PADDING_TITLE, pady=PADDING_TITLE/2)
|
||||
|
||||
self.difficulty_title = Label(self.master)
|
||||
self.difficulty_title.config(text="Current Difficulty: {}".format(self.options["Difficulty"]), font=("Courier New", 13))
|
||||
self.difficulty_title.pack(ipadx=PADDING_BUTTON/3, padx=PADDING_BUTTON)
|
||||
self.difficulty_scale = Scale(self.master, from_=5, to=500, orient="horizontal", command=self.update_difficulty, length=350)
|
||||
self.difficulty_scale.pack(ipadx=PADDING_BUTTON/3, padx=PADDING_BUTTON/3)
|
||||
self.difficulty_scale["value"] = self.options["Difficulty"]
|
||||
self.difficulty_reset_button = Button(self.master, style="Minor.TButton")
|
||||
self.difficulty_reset_button.config(text="Reset Difficulty")
|
||||
self.difficulty_reset_button.pack(ipadx=PADDING_BUTTON/3, padx=PADDING_BUTTON/3)
|
||||
self.difficulty_reset_button.bind('<Button-1>', self.reset_difficulty)
|
||||
|
||||
Frame(self.master,height=23).pack()
|
||||
|
||||
self.texture_title = Label(self.master)
|
||||
self.texture_title.config(text="Select Texture Pack", font=("Courier New", 13))
|
||||
self.texture_title.pack(ipadx=PADDING_BUTTON/3, padx=PADDING_BUTTON)
|
||||
self.texture_select = Listbox(master)
|
||||
self.texture_select.delete(0, END)
|
||||
for directory in self.options["Textures"].list_packs():
|
||||
if directory == "": continue
|
||||
self.texture_select.insert(END, directory)
|
||||
self.texture_select.pack(ipadx=PADDING_BUTTON/3, padx=PADDING_BUTTON/3)
|
||||
|
||||
Frame(self.master,height=23).pack()
|
||||
|
||||
self.using_sounds = IntVar()
|
||||
self.using_sounds.set(self.options["Sounds"])
|
||||
self.sounds_check = Checkbutton(self.master, text="Use Sound Effects", command=self.update_sounds, variable=self.using_sounds)
|
||||
self.sounds_check.pack(ipadx=PADDING_BUTTON/3, padx=PADDING_BUTTON)
|
||||
|
||||
Style().configure("Minor.TButton", font=("Lucida", 10))
|
||||
self.master.protocol('WM_DELETE_WINDOW', self.close)
|
||||
logging.info("Options menu created.")
|
||||
|
||||
def close(self):
|
||||
self.options["Textures"].pack = self.texture_select.get(ACTIVE) if self.texture_select.get(ACTIVE) != "" else "default" # Because it has no changed event
|
||||
logging.info("Selected Texture Pack: {}".format(self.options["Textures"].pack))
|
||||
self.master.destroy()
|
||||
|
||||
def update_sounds(self):
|
||||
self.options["Sounds"] = self.using_sounds.get()
|
||||
|
||||
def update_difficulty(self, event):
|
||||
self.options["Difficulty"] = int(self.difficulty_scale.get())
|
||||
self.difficulty_title["text"] = "Current Difficulty: {}".format(self.options["Difficulty"])
|
||||
|
||||
def reset_difficulty(self, event):
|
||||
self.options["Difficulty"] = 120
|
||||
self.difficulty_title["text"] = "Current Difficulty: {}".format(self.options["Difficulty"])
|
||||
self.difficulty_scale["value"] = 120
|
||||
|
||||
|
||||
def display():
|
||||
|
@ -151,11 +50,6 @@ def display():
|
|||
root.mainloop()
|
||||
|
||||
|
||||
exit_messages = {
|
||||
"LIVES":"You ran out of lives!",
|
||||
"PLAYER COLLISION":"The enemies got to you!"
|
||||
}
|
||||
|
||||
logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.DEBUG)
|
||||
|
||||
|
||||
|
|
22
LICENSE
|
@ -1,22 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Jake Howard
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
print("Starting Attack on Blocks...\nLoading Main Window...")
|
||||
print("Game Loading...")
|
||||
import GUI
|
||||
GUI.display()
|
18
README.md
|
@ -1,26 +1,24 @@
|
|||
# Attack on Blocks #
|
||||
# Space Invaders #
|
||||
|
||||
This take on space invaders was written for my IT BTEC course, Unit 22 Games Development at college. This version, written in python, includes more advanced features such as resource packs.
|
||||
|
||||
### More Information ###
|
||||
|
||||
For more information, check out the [Wiki](//bitbucket.org/TheOrangeOne/attack-on-blocks/wiki) page.
|
||||
This take on space invaders was written for my IT BTEC course, Unit 21 Games Development at college. This version, written in python, includes more advanced features such as resource packs.
|
||||
|
||||
### Requirements ###
|
||||
|
||||
* Python 3
|
||||
* Python
|
||||
* Pygame
|
||||
* TKinter
|
||||
|
||||
The game is only playable on windows, due to the GUI library only being available on windows. However a cross platform, lightweight version may be made in the future.
|
||||
|
||||
### Playing the game ###
|
||||
|
||||
* Clone the repository, or visit the downloads page
|
||||
* Clone the repository
|
||||
* Install the required libraries (See Above)
|
||||
* Run 'Play The Game.py'
|
||||
|
||||
### Core Contributors ###
|
||||
|
||||
* Jake Howard
|
||||
* Furhan Bhatti (Well not really)
|
||||
* Furhan Bhatti
|
||||
|
||||
# Note #
|
||||
At the moment, the game WILL NOT play at all, as it is still in development, all the time this message is here, the program will not run!
|
BIN
Thumbs.db
Normal file
83
assets.py
|
@ -1,83 +0,0 @@
|
|||
import os, pygame, glob, logging
|
||||
from collections import namedtuple
|
||||
from random import randint
|
||||
|
||||
class Textures():
|
||||
def __init__(self):
|
||||
self.images = {
|
||||
"PLAYER":"player",
|
||||
"BULLET":"bullet",
|
||||
"TARGETS":[],
|
||||
"SHOOTER":"shooter",
|
||||
"TARGET_BULLET":"bullet_target",
|
||||
"POWERUP": "powerup"
|
||||
}
|
||||
self.path=os.path.dirname(os.path.realpath(__file__)) + "\\resources\\texture_packs\\"
|
||||
self.pack = "default"
|
||||
|
||||
def load_texture_pack(self, pack_name):
|
||||
if os.path.exists(self.path + pack_name):
|
||||
self.images["TARGETS"] = []
|
||||
|
||||
targets = glob.glob(self.path+pack_name+"\\target*.png")
|
||||
logging.debug("Found {0} target files.".format(len(targets)))
|
||||
for file in targets:
|
||||
filename = file.split("\\")[-1].replace(".png", "")
|
||||
self.images["TARGETS"].append(filename)
|
||||
|
||||
self.pack = pack_name
|
||||
else: logging.warn("Cannot find texture pack '{}'".format(ppack_name))
|
||||
|
||||
def get_texture(self, objectName):
|
||||
filename = self.path + self.pack + "\\{0}.png".format(self.images[objectName.upper()])
|
||||
return pygame.image.load(filename)
|
||||
|
||||
def get_target_texture(self, ID=False):
|
||||
if not ID:
|
||||
index = randint(0,len(self.images["TARGETS"])-1) if len(self.images["TARGETS"]) >=1 else 0
|
||||
filename = self.path + self.pack + "\\{}.png".format(self.images["TARGETS"][index])
|
||||
return [pygame.image.load(filename), index]
|
||||
else:
|
||||
filename = self.path + self.pack + "\\target{}.png".format(int(ID))
|
||||
return [pygame.image.load(filename), ID]
|
||||
|
||||
def list_packs(self):
|
||||
return [x[0].replace(self.path, "") for x in os.walk(self.path)]
|
||||
|
||||
|
||||
|
||||
Level_Template = namedtuple('Level_Template', ("rows", "padding", "firebacks", "powerups"))
|
||||
Levels = [
|
||||
Level_Template(2, 20, 0, 0),
|
||||
Level_Template(3, 15, 1, 0),
|
||||
Level_Template(4, 15, 3, 1),
|
||||
Level_Template(3, 7, 2, 2),
|
||||
Level_Template(5, 15, 2, 1),
|
||||
Level_Template(2, 20, 100, 2), #All the enemies!
|
||||
Level_Template(3, 15, 2, 1),
|
||||
Level_Template(3, 7, 2, 4),
|
||||
Level_Template(4, 15, 4, 3),
|
||||
Level_Template(5, 35, 4, 6),
|
||||
]
|
||||
|
||||
|
||||
def generate_random_level():
|
||||
logging.info("Generating a random level!")
|
||||
rows = randint(1, 12)
|
||||
padding = randint(5, 30)
|
||||
firebacks = randint(0, 15)
|
||||
powerups = randint(0, 15)
|
||||
return Level_Template(rows, padding, firebacks, powerups)
|
||||
|
||||
|
||||
Sounds = {}
|
||||
def init_sounds():
|
||||
music_files = ["main.ogg", "OP.ogg", "shot.ogg"]
|
||||
for file in music_files:
|
||||
path = os.path.dirname(os.path.realpath(__file__)) + "\\resources\\sounds\\" + file
|
||||
if file == "main.ogg":
|
||||
mixer = pygame.mixer.music
|
||||
mixer.load(path)
|
||||
else: mixer = pygame.mixer.Sound(path)
|
||||
mixer.set_volume(1.0)
|
||||
Sounds[file.replace(".ogg", "")] = mixer
|
18
bullet.py
|
@ -2,20 +2,22 @@ import pygame
|
|||
|
||||
|
||||
class Bullet(pygame.sprite.Sprite):
|
||||
def __init__(self, parent, textures, bigger):
|
||||
def __init__(self, parent):
|
||||
super().__init__()
|
||||
self.width = 6 * (1+int(bigger))
|
||||
self.height = 14 * (1+int(bigger))
|
||||
self.image = pygame.transform.scale(textures.get_texture("BULLET"), (self.width, self.height))
|
||||
self.width = 4
|
||||
self.height = 10
|
||||
self.image = pygame.Surface((self.width, self.height))
|
||||
self.image.fill((255,255,255))
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = parent.rect.x + parent.width/2 - self.width/2
|
||||
self.rect.y = parent.rect.y + parent.height/2
|
||||
self.rect.x = parent.rect.x + parent.width/2
|
||||
self.rect.y = parent.rect.y
|
||||
self.speed = 5
|
||||
self.type = "PLAYER"
|
||||
self.parent = parent
|
||||
|
||||
def set_position(self,x,y):
|
||||
self.rect.x, self.rect.y = x,y
|
||||
|
||||
def update(self):
|
||||
self.rect.y -= self.speed #direction may need editing?
|
||||
|
||||
def at_top(self):
|
||||
return (self.rect.y == 0)
|
13
eggs.py
|
@ -1,13 +0,0 @@
|
|||
import pygame, logging, urllib.request, io
|
||||
from time import sleep
|
||||
|
||||
def r9k(window):
|
||||
logging.warn("Look, you found a pepe!")
|
||||
raw_image = urllib.request.urlopen("http://img.ifcdn.com/images/620f230fad2806fe5305fac45dd673b8fc005b98c1e3b8584abc9c439b050950_1.jpg").read()
|
||||
image_file = io.BytesIO(raw_image)
|
||||
image = pygame.transform.scale(pygame.image.load(image_file), window.get_size())
|
||||
window.blit(image, (0,0))
|
||||
font = pygame.font.SysFont(None, 30, bold=False)
|
||||
window.blit(font.render("A rare pepe has been found. Alert R9k", True, (0,0,0)), (window.get_width()/2-175, window.get_height()/2))
|
||||
pygame.display.update()
|
||||
sleep(9)
|
257
game.py
|
@ -1,210 +1,103 @@
|
|||
import pygame, logging
|
||||
from time import time, sleep
|
||||
from random import randint
|
||||
import eggs
|
||||
|
||||
import bullet, player, textures
|
||||
from bullet import Bullet
|
||||
from player import Shooter
|
||||
from assets import *
|
||||
from target import Target, generate_targets
|
||||
from textures import Textures
|
||||
from target import Target
|
||||
|
||||
|
||||
POWERUPS = ["SPEED", "DOUBLE", "LIVES", "SCORE", "BIGGER"]
|
||||
PLAYING_GAME = False
|
||||
WINDOW_SIZE = (680, 790)
|
||||
HUD_COLOUR = (255,168,72)
|
||||
WINDOW_SIZE = (640,480)
|
||||
FPS = 120
|
||||
|
||||
def rounding(x, base): return int(base * round(float(x)/base))
|
||||
|
||||
def update_score(window, score, colour=HUD_COLOUR):
|
||||
font = pygame.font.SysFont(None, 30, bold=False)
|
||||
window.blit(font.render("Score: {}".format(int(score)), True, colour), (25, WINDOW_SIZE[1] - 30))
|
||||
|
||||
def update_level(window, level, colour=HUD_COLOUR):
|
||||
font = pygame.font.SysFont(None, 30, bold=False)
|
||||
window.blit(font.render("Level: {}".format(int(level)+1), True, colour), (8.5*WINDOW_SIZE[0]/10, WINDOW_SIZE[1] - 30))
|
||||
|
||||
def update_lives(window, lives, colour=HUD_COLOUR):
|
||||
font = pygame.font.SysFont(None, 30, bold=False)
|
||||
window.blit(font.render("Lives Remaining: {}".format(int(lives)), True, colour if lives != 1 else (255,50,0)), (3.8*WINDOW_SIZE[0]/10, WINDOW_SIZE[1] - 30))
|
||||
|
||||
def initialise(menu, options):
|
||||
pygame.mixer.pre_init(44100, -16, 2, 2048)
|
||||
pygame.init()
|
||||
window = pygame.display.set_mode(WINDOW_SIZE)
|
||||
pygame.display.set_caption("Attack on Blocks")
|
||||
exit_code = play(window, options) # Run main game loop
|
||||
for key, value in Sounds.items():
|
||||
value.fadeout(500)
|
||||
pygame.mixer.pre_init(44100, -16, 2, 2048)
|
||||
pygame.init()
|
||||
window = pygame.display.set_mode(WINDOW_SIZE)
|
||||
|
||||
logging.debug("Game Exited with code {}".format(exit_code))
|
||||
if exit_code != "QUIT": sleep(1)
|
||||
|
||||
pygame.quit()
|
||||
menu.deiconify()
|
||||
return exit_code
|
||||
|
||||
def play(window, options):
|
||||
window_rect = window.get_rect()
|
||||
options["Textures"].load_texture_pack(options["Textures"].pack)
|
||||
player = Shooter(window=window, texture=options["Textures"])
|
||||
player.set_position(WINDOW_SIZE[0]/2, WINDOW_SIZE[1]*0.90)
|
||||
player.options = options
|
||||
player_group = pygame.sprite.Group()
|
||||
player_group.add(player)
|
||||
|
||||
target_group = generate_targets(player, WINDOW_SIZE, Levels)
|
||||
bullet_group = pygame.sprite.Group()
|
||||
|
||||
clock = pygame.time.Clock()
|
||||
FPS = player.options["Difficulty"]
|
||||
|
||||
timeouts = {
|
||||
"Target Movement":[FPS*0.65,FPS*0.65],
|
||||
"Powerup":[FPS*15, FPS*15]
|
||||
}
|
||||
init_sounds()
|
||||
if options["Sounds"]: Sounds["main"].play(loops=-1) #Start background music
|
||||
|
||||
logging.info("Game Started.")
|
||||
PLAYING_GAME = True
|
||||
while PLAYING_GAME:
|
||||
window.fill((0,0,0))
|
||||
|
||||
fired = False
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
logging.critical("Exiting Game...")
|
||||
PLAYING_GAME = False
|
||||
return "QUIT"
|
||||
|
||||
if event.type == pygame.KEYDOWN and event.key in [pygame.K_SPACE, pygame.K_w, pygame.K_UP] and not fired:
|
||||
if player.options["Sounds"]: Sounds["shot"].play()
|
||||
temp = Bullet(player, player.options["Textures"], player.powerup == "BIGGER")
|
||||
bullet_group.add(temp)
|
||||
if player.powerup == "DOUBLE":
|
||||
temp = Bullet(player, player.options["Textures"], player.powerup == "BIGGER")
|
||||
temp.rect.y += 20
|
||||
bullet_group.add(temp)
|
||||
fired = True
|
||||
exit_code = play(window) # Run main game loop
|
||||
if exit_code =
|
||||
pygame.quit()
|
||||
# Reshow the main menu
|
||||
|
||||
|
||||
keys = pygame.key.get_pressed()
|
||||
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
|
||||
if player.powerup == "SPEED": player.move(player.speed * 1.5)
|
||||
else: player.move(player.speed)
|
||||
def generate_targets():
|
||||
group = pygame.sprite.Group()
|
||||
target_object = Target()
|
||||
for i in range(10,150,50):
|
||||
for j in range(10, 150, 50):
|
||||
temp = Target()
|
||||
logging.debug("Target generated with position ({},{})".format(j,i))
|
||||
temp.set_position(j,i)
|
||||
group.add(temp)
|
||||
del temp
|
||||
return group
|
||||
|
||||
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
|
||||
if player.powerup == "SPEED": player.move(-player.speed*1.5)
|
||||
else: player.move(-player.speed)
|
||||
|
||||
if keys[pygame.K_KP4] and keys[pygame.K_KP5] and keys[pygame.K_KP6] and player.OP:
|
||||
temp = Bullet(player, player.options["Textures"], False)
|
||||
bullet_group.add(temp)
|
||||
def play(window):
|
||||
window_rect = window.get_rect()
|
||||
|
||||
if keys[pygame.K_r] and [pygame.K_9] and [pygame.K_k] and player.OP:
|
||||
eggs.r9k(window)
|
||||
player = Shooter(window=window)
|
||||
player.set_position(WINDOW_SIZE[0]/2, WINDOW_SIZE[1]*0.93)
|
||||
player_group = pygame.sprite.Group()
|
||||
player_group.add(player)
|
||||
player_group.draw(window)
|
||||
|
||||
if keys[pygame.K_KP4] and keys[pygame.K_KP2] and keys[pygame.K_KP0] and keys[pygame.K_o] and keys[pygame.K_p] and not player.OP:
|
||||
if player.options["Sounds"]:
|
||||
Sounds["main"].stop()
|
||||
Sounds["OP"].play(loops=-1)
|
||||
player.OP = True
|
||||
player.change_colour((255,96,0))
|
||||
logging.warn("OP mode engaged.")
|
||||
target_group = generate_targets()
|
||||
bullet_group = pygame.sprite.Group()
|
||||
|
||||
if keys[pygame.K_KP_MINUS] and player.OP:
|
||||
if player.options["Sounds"]:
|
||||
Sounds["OP"].stop()
|
||||
Sounds["main"].play(loops=-1)
|
||||
player.OP = False
|
||||
player.reset_image()
|
||||
logging.warn("OP mode disabled.")
|
||||
clock = pygame.time.Clock()
|
||||
PLAYING_GAME = True
|
||||
|
||||
for sprite in bullet_group:
|
||||
sprite.update()
|
||||
if sprite.rect.y < 0 or (sprite.rect.y > player.rect.y and sprite.type == "TARGET"):
|
||||
bullet_group.remove(sprite)
|
||||
while PLAYING_GAME:
|
||||
window.fill((0,0,0))
|
||||
player_group.update()
|
||||
|
||||
for bullet in bullet_group:
|
||||
hit_list = pygame.sprite.spritecollide(bullet, target_group, False)
|
||||
for target in hit_list:
|
||||
if bullet.type != "TARGET":
|
||||
target.lives -= 1
|
||||
if target.lives <= 0:
|
||||
target_group.remove(target)
|
||||
player.score += 1
|
||||
bullet_group.remove(bullet)
|
||||
if target.lives <= 0 and target.type == "POWERUP":
|
||||
player.powerup = POWERUPS[randint(0,len(POWERUPS)-1)]
|
||||
logging.info("Powerup set to {}".format(player.powerup))
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
logging.critical("Exiting Game...")
|
||||
PLAYING_GAME = False
|
||||
return "QUIT"
|
||||
|
||||
hit_list = pygame.sprite.spritecollide(bullet, player_group, False)
|
||||
for player in hit_list:
|
||||
if bullet.type == "TARGET":
|
||||
bullet_group.remove(bullet)
|
||||
logging.info("You were hit by a target's bullet!")
|
||||
if not player.OP: player.lives -= 1
|
||||
if player.lives <= 0:
|
||||
return "LIVES"
|
||||
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
|
||||
temp = Bullet(player)
|
||||
bullet_group.add(temp)
|
||||
|
||||
if timeouts["Target Movement"][0] <=0:
|
||||
drop_targets = False
|
||||
for target in target_group:
|
||||
target.move()
|
||||
if target.rect.x <= 30 or target.rect.x >=WINDOW_SIZE[0] - target.width/2 - 30:
|
||||
drop_targets = True
|
||||
keys = pygame.key.get_pressed()
|
||||
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
|
||||
player.move(player.speed)
|
||||
|
||||
if target.rect.y >= player.rect.y + target.height/2:
|
||||
PLAYING_GAME = False
|
||||
return "PLAYER COLLISION"
|
||||
if keys[pygame.K_LEFT] or keys[pygame.K_a]:
|
||||
player.move(-player.speed)
|
||||
|
||||
if drop_targets:
|
||||
logging.debug("The targets are moving down a level!")
|
||||
for target in target_group:
|
||||
target.drop()
|
||||
if keys[pygame.K_KP4] and keys[pygame.K_KP5] and keys[pygame.K_KP6]:
|
||||
temp = Bullet(player)
|
||||
bullet_group.add(temp)
|
||||
|
||||
timeouts["Target Movement"][0] = timeouts["Target Movement"][1]
|
||||
for sprite in bullet_group:
|
||||
if not sprite.at_top():
|
||||
sprite.update()
|
||||
if sprite.rect.y < 0:
|
||||
bullet_group.remove(sprite)
|
||||
|
||||
if timeouts["Powerup"][0] <= 0:
|
||||
timeouts["Powerup"][0] = timeouts["Powerup"][1]
|
||||
for bullet in bullet_group:
|
||||
hit_list = pygame.sprite.spritecollide(bullet, target_group, True)
|
||||
for target in hit_list:
|
||||
target_group.remove(target)
|
||||
bullet_group.remove(bullet)
|
||||
logging.info("Hit Target!")
|
||||
|
||||
if player.powerup == "SCORE":
|
||||
player.score += 10
|
||||
player.powerup = ""
|
||||
elif player.powerup == "LIVES":
|
||||
player.lives += 1
|
||||
player.powerup = ""
|
||||
player_group.update()
|
||||
bullet_group.draw(window)
|
||||
target_group.draw(window)
|
||||
player_group.draw(window)
|
||||
pygame.display.update()
|
||||
clock.tick(FPS)
|
||||
|
||||
for target in target_group:
|
||||
if target.type == "SHOOTER":
|
||||
if randint(0,600) > 1: continue
|
||||
temp = Bullet(target, player.options["Textures"], False)
|
||||
temp.type="TARGET"
|
||||
temp.image = pygame.transform.scale(player.options["Textures"].get_texture("TARGET_BULLET"), (temp.width, temp.height))
|
||||
x,y = temp.rect.x, temp.rect.y
|
||||
temp.rect = temp.image.get_rect()
|
||||
temp.set_position(x,y)
|
||||
temp.speed = -1 #So it shoots down!
|
||||
bullet_group.add(temp)
|
||||
|
||||
if len(target_group) == 0: #If all current players are gone.
|
||||
player.level += 1
|
||||
Sounds["main"].set_volume(0.5)
|
||||
target_group = generate_targets(player, WINDOW_SIZE, Levels)
|
||||
target_group.draw(window)
|
||||
bullet_group.empty()
|
||||
pygame.display.update()
|
||||
sleep(0.75)
|
||||
Sounds["main"].set_volume(1.0)
|
||||
|
||||
update_score(window, player.score)
|
||||
update_level(window, player.level)
|
||||
update_lives(window, player.lives)
|
||||
|
||||
target_group.draw(window)
|
||||
bullet_group.draw(window)
|
||||
player_group.draw(window)
|
||||
|
||||
for key, value in timeouts.items():
|
||||
value[0] -= 1
|
||||
|
||||
pygame.display.update()
|
||||
clock.tick(FPS)
|
||||
if __name__ == "__main__":
|
||||
initialise(None, None)
|
||||
|
|
37
player.py
|
@ -2,42 +2,19 @@ import pygame
|
|||
|
||||
|
||||
class Shooter(pygame.sprite.Sprite):
|
||||
def __init__(self, window, texture, colour=(255,255,255), width=55, height=25):
|
||||
def __init__(self, window, color=(30,0,150), width=50, height=25):
|
||||
super().__init__()
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.colour = colour
|
||||
self.texture = texture
|
||||
self.image = pygame.transform.scale(self.texture.get_texture("PLAYER"), (self.width, self.height))
|
||||
self.image = pygame.Surface((width, height))
|
||||
self.image.fill(color)
|
||||
self.rect = self.image.get_rect()
|
||||
self.speed = 3
|
||||
self.speed = 4
|
||||
self.window_rect = window.get_rect()
|
||||
|
||||
self.score = 0
|
||||
self.OP = False
|
||||
self.level = 0
|
||||
self.lives = 3
|
||||
self.powerup = ""
|
||||
|
||||
def set_position(self,x,y):
|
||||
self.rect.x, self.rect.y = x, y
|
||||
self.rect.x, self.rect.y = x,y
|
||||
|
||||
def move(self, value):
|
||||
self.rect.x += value
|
||||
self.rect.clamp_ip(self.window_rect)
|
||||
|
||||
def update(self):
|
||||
self.image.fill(self.colour)
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
def change_colour(self, colour):
|
||||
x,y = self.rect.x, self.rect.y
|
||||
self.image.fill(colour)
|
||||
self.rect = self.image.get_rect()
|
||||
self.set_position(x,y)
|
||||
|
||||
def reset_image(self):
|
||||
x,y = self.rect.x, self.rect.y
|
||||
self.image = pygame.transform.scale(self.texture.get_texture("PLAYER"), (self.width, self.height))
|
||||
self.rect = self.image.get_rect()
|
||||
self.set_position(x,y)
|
||||
self.rect.x += value
|
||||
self.rect.clamp_ip(self.window_rect)
|
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 48 KiB |
88
target.py
|
@ -1,85 +1,21 @@
|
|||
import pygame, logging
|
||||
from random import randint
|
||||
from game import generate_random_level
|
||||
|
||||
import pygame
|
||||
|
||||
class Target(pygame.sprite.Sprite):
|
||||
def __init__(self, x, y, textures, color=(30,0,150), width=23, height=23):
|
||||
def __init__(self, color=(30,0,150), width=16, height=16):
|
||||
super().__init__()
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.textures = textures
|
||||
self.default_texture = textures.get_target_texture()
|
||||
self.image = pygame.transform.scale(self.default_texture[0], (self.width, self.height))
|
||||
self.image = pygame.Surface((self.width, self.height))
|
||||
self.image.fill(color)
|
||||
self.rect = self.image.get_rect()
|
||||
self.speed = 5
|
||||
self.rect.x, self.rect.y = (x+(self.width/2)),(y+(self.width/2)) # centres co-ordinates
|
||||
self.type = "NORMAL"
|
||||
self.lives = 1
|
||||
self.speed = 4
|
||||
|
||||
def move(self):
|
||||
self.rect.x += self.speed
|
||||
def set_position(self,x,y):
|
||||
self.rect.x, self.rect.y = (x+(self.width/2)),(x+(self.width/2)) # centres co-ordinates
|
||||
|
||||
def drop(self):
|
||||
self.rect.y += 13
|
||||
self.speed *= -1
|
||||
|
||||
def set_position(self, x, y, center=False):
|
||||
if center:
|
||||
self.rect.x, self.rect.y = (x+(self.width/2)),(y+(self.width/2))
|
||||
def move(self, x,y):
|
||||
if ((self.rect.y + self.width) > window_rect.y) or((self.rect.y - self.width < 0)):
|
||||
movement = self.speed
|
||||
else:
|
||||
self.rect.x, self.rect.y = x, y
|
||||
|
||||
def generate_targets(player, window_size, Levels):
|
||||
sprite_list = []
|
||||
group = pygame.sprite.Group()
|
||||
if player.level > len(Levels)-1:
|
||||
level = generate_random_level()
|
||||
else: level = Levels[player.level]
|
||||
logging.debug("Generating Level: " + str(level))
|
||||
|
||||
for i in range(level.rows):
|
||||
i *= level.padding + 8
|
||||
for j in range(75, window_size[0] - 75, level.padding + 10):
|
||||
temp = Target(x=j,y=i, textures=player.options["Textures"])
|
||||
sprite_list.append(temp)
|
||||
del temp
|
||||
|
||||
if len(sprite_list) < level.firebacks:
|
||||
firebacks = len(sprite_list)
|
||||
else: firebacks = level.firebacks
|
||||
for i in range(firebacks):
|
||||
loop = 0
|
||||
changed = False
|
||||
while not changed:
|
||||
if loop == firebacks: changed = True
|
||||
index = randint(0, len(sprite_list)-1) if (len(sprite_list) - 1 != 0) else 0
|
||||
if sprite_list[index].type != "SHOOTER":
|
||||
sprite_list[index].type = "SHOOTER"
|
||||
sprite_list[index].lives = 2
|
||||
sprite_list[index].image = pygame.transform.scale(player.options["Textures"].get_texture("SHOOTER"), (sprite_list[index].width, sprite_list[index].height))
|
||||
x,y = sprite_list[index].rect.x, sprite_list[index].rect.y
|
||||
sprite_list[index].rect = sprite_list[index].image.get_rect()
|
||||
sprite_list[index].set_position(x,y, center=False) #Already Centered!
|
||||
changed = True
|
||||
loop += 1
|
||||
|
||||
if len(sprite_list) < level.powerups:
|
||||
powerups = len(sprite_list)
|
||||
else: powerups = level.powerups
|
||||
for i in range(powerups):
|
||||
changed = False
|
||||
while not changed:
|
||||
index = randint(0, len(sprite_list)-1) if (len(sprite_list) - 1 != 0) else 0
|
||||
if sprite_list[index].type != "POWERUP" and sprite_list[index].type != "SHOOTER" :
|
||||
sprite_list[index].type = "POWERUP"
|
||||
sprite_list[index].image = pygame.transform.scale(player.options["Textures"].get_texture("POWERUP"), (sprite_list[index].width, sprite_list[index].height))
|
||||
x,y = sprite_list[index].rect.x, sprite_list[index].rect.y
|
||||
sprite_list[index].rect = sprite_list[index].image.get_rect()
|
||||
sprite_list[index].set_position(x,y, center=False) #Already Centered!
|
||||
changed = True
|
||||
|
||||
for sprite in sprite_list: #Because sprite groups dont support indexing!
|
||||
group.add(sprite)
|
||||
return group
|
||||
|
||||
movement = -self.speed
|
||||
self.rect.y += movement
|
||||
|
|
28
textures.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
import os, pygame, glob, logging
|
||||
|
||||
|
||||
class Textures():
|
||||
def __init__(self):
|
||||
self.images = {
|
||||
"PLAYER":"player.png",
|
||||
"BULLET":"bullet.png",
|
||||
"TARGETS":[]
|
||||
}
|
||||
self.path=os.path.dirname(os.path.realpath(__file__)) + "\\resources\\texture_packs\\"
|
||||
self.pack = "default"
|
||||
|
||||
def loadTexturePack(self, packName):
|
||||
if os.path.exists(self.path + packName):
|
||||
self.images["TARGETS"] = []
|
||||
|
||||
targets = glob.glob(self.path+packName+"\\target*.png")
|
||||
logging.debug("Found {0} target files.".format(len(targets)))
|
||||
for file in targets:
|
||||
fileName = file.split("\\")[-1]
|
||||
self.images["TARGETS"].append(filename)
|
||||
|
||||
self.pack = packName
|
||||
|
||||
def getTexture(self, objectName):
|
||||
filename = self.path + self.pack + "\\{0}.png".format(self.images[objectName.upper()])
|
||||
return pygame.image.load(filename)
|