diff --git a/alien.py b/alien.py new file mode 100644 index 0000000..ca9fe9b --- /dev/null +++ b/alien.py @@ -0,0 +1,39 @@ +import pygame + +from pygame.sprite import Sprite + + +class Alien(Sprite): + """A class to represent a single alien in the fleet.""" + + def __init__(self, ai_game): + """Initialize the alien and set its starting position.""" + super().__init__() + self.screen = ai_game.screen + self.settings = ai_game.settings + + # Load the alien image and set its rect attribute. + self.original_image = pygame.image.load('images\外星人2.png') + alien_width = 75 + alien_height = 50 + + # 调整图片大小 + self.image = pygame.transform.scale(self.original_image, (alien_width, alien_height)) + self.rect = self.image.get_rect() + + # Start each new alien near the top left of the screen. + self.rect.x = self.rect.width + self.rect.y = self.rect.height + + # Store the alien's exact horizontal position. + self.x = float(self.rect.x) + + def check_edges(self): + """Return True if alien is at edge of screen.""" + screen_rect = self.screen.get_rect() + return (self.rect.right >= screen_rect.right) or (self.rect.left <= 0) + + def update(self): + """Move the alien right or left.""" + self.x += self.settings.alien_speed * self.settings.fleet_direction + self.rect.x = self.x \ No newline at end of file diff --git a/alien_invasion.py b/alien_invasion.py new file mode 100644 index 0000000..7991b72 --- /dev/null +++ b/alien_invasion.py @@ -0,0 +1,253 @@ +import sys +from time import sleep + +import pygame +from settings import Settings +from game_stats import GameStats +from scoreboard import Scoreboard +from button import Button +from ship import Ship +from bullet import Bullet +from alien import Alien + +class AlienInvasion: + """Overall class to manage game assets and behavior.""" + + def __init__(self,index): + """Initialize the game, and create game resources.""" + pygame.init() + self.clock = pygame.time.Clock() + self.settings = Settings() + self.screen = pygame.display.set_mode( + (self.settings.screen_width, self.settings.screen_height)) + + pygame.display.set_caption("外星人入侵") + # self.screen.blit(self.background_image, (0, 0)) + # pygame.display.flip() + self.stats = GameStats(self) + self.sb = Scoreboard(self,index) + + self.ship = Ship(self,index) + + self.bullets = pygame.sprite.Group() + self.aliens = pygame.sprite.Group() + + self._create_fleet() + + # Start Alien Invasion in an inactive state. + self.game_active = False + + # Make the Play button. + self.play_button = Button(self, "Play") + + + def run_game(self,selected_image_path): + """Start the main loop for the game.""" + while True: + self._check_events(selected_image_path) + + if self.game_active: + self.ship.update() + self._update_bullets() + self._update_aliens(selected_image_path) + + self._update_screen() + self.clock.tick(60) + + def _check_events(self,selected_image_path): + """Respond to keypresses and mouse events.""" + for event in pygame.event.get(): + if event.type == pygame.QUIT: + sys.exit() + elif event.type == pygame.KEYDOWN: + self._check_keydown_events(event) + elif event.type == pygame.KEYUP: + self._check_keyup_events(event) + elif event.type == pygame.MOUSEBUTTONDOWN: + mouse_pos = pygame.mouse.get_pos() + self._check_play_button(mouse_pos,selected_image_path) + + def _check_play_button(self, mouse_pos,selected_image_path): + """Start a new game when the player clicks Play.""" + button_clicked = self.play_button.rect.collidepoint(mouse_pos) + if button_clicked and not self.game_active: + # Reset the game settings. + self.settings.initialize_dynamic_settings() + + # Reset the game statistics. + self.stats.reset_stats() + self.sb.prep_score() + self.sb.prep_level() + self.sb.prep_ships(selected_image_path) + self.game_active = True + + # Get rid of any remaining bullets and aliens. + self.bullets.empty() + self.aliens.empty() + + # Create a new fleet and center the ship. + self._create_fleet() + self.ship.center_ship() + + # Hide the mouse cursor. + pygame.mouse.set_visible(False) + + def _check_keydown_events(self, event): + """Respond to keypresses.""" + if event.key == pygame.K_RIGHT: + self.ship.moving_right = True + elif event.key == pygame.K_LEFT: + self.ship.moving_left = True + elif event.key == pygame.K_q: + sys.exit() + elif event.key == pygame.K_SPACE: + self._fire_bullet() + + def _check_keyup_events(self, event): + """Respond to key releases.""" + if event.key == pygame.K_RIGHT: + self.ship.moving_right = False + elif event.key == pygame.K_LEFT: + self.ship.moving_left = False + + def _fire_bullet(self): + """Create a new bullet and add it to the bullets group.""" + if len(self.bullets) < self.settings.bullets_allowed: + new_bullet = Bullet(self) + self.bullets.add(new_bullet) + + def _update_bullets(self): + """Update position of bullets and get rid of old bullets.""" + # Update bullet positions. + self.bullets.update() + + # Get rid of bullets that have disappeared. + for bullet in self.bullets.copy(): + if bullet.rect.bottom <= 0: + self.bullets.remove(bullet) + + self._check_bullet_alien_collisions() + + def _check_bullet_alien_collisions(self): + """Respond to bullet-alien collisions.""" + # Remove any bullets and aliens that have collided. + collisions = pygame.sprite.groupcollide( + self.bullets, self.aliens, True, True) + + if collisions: + for aliens in collisions.values(): + self.stats.score += self.settings.alien_points * len(aliens) + self.sb.prep_score() + self.sb.check_high_score() + + if not self.aliens: + # Destroy existing bullets and create new fleet. + self.bullets.empty() + self._create_fleet() + self.settings.increase_speed() + + # Increase level. + self.stats.level += 1 + self.sb.prep_level() + + def _ship_hit(self,selected_image_path): + """Respond to the ship being hit by an alien.""" + if self.stats.ships_left > 0: + # Decrement ships_left, and update scoreboard. + self.stats.ships_left -= 1 + self.sb.prep_ships(selected_image_path) + + # Get rid of any remaining bullets and aliens. + self.bullets.empty() + self.aliens.empty() + + # Create a new fleet and center the ship. + self._create_fleet() + self.ship.center_ship() + + # Pause. + sleep(0.5) + else: + self.game_active = False + pygame.mouse.set_visible(True) + + def _update_aliens(self,selected_image_path): + """Check if the fleet is at an edge, then update positions.""" + self._check_fleet_edges() + self.aliens.update() + + # Look for alien-ship collisions. + if pygame.sprite.spritecollideany(self.ship, self.aliens): + self._ship_hit(selected_image_path) + + # Look for aliens hitting the bottom of the screen. + self._check_aliens_bottom(selected_image_path) + + def _check_aliens_bottom(self,selected_image_path): + """Check if any aliens have reached the bottom of the screen.""" + for alien in self.aliens.sprites(): + if alien.rect.bottom >= self.settings.screen_height: + # Treat this the same as if the ship got hit. + self._ship_hit(selected_image_path) + break + + def _create_fleet(self): + """Create the fleet of aliens.""" + # Create an alien and keep adding aliens until there's no room left. + # Spacing between aliens is one alien width and one alien height. + alien = Alien(self) + alien_width, alien_height = alien.rect.size + + current_x, current_y = alien_width, alien_height + while current_y < (self.settings.screen_height - 3 * alien_height): + while current_x < (self.settings.screen_width - 2 * alien_width): + self._create_alien(current_x, current_y) + current_x += 2 * alien_width + + # Finished a row; reset x value, and increment y value. + current_x = alien_width + current_y += 2 * alien_height + + def _create_alien(self, x_position, y_position): + """Create an alien and place it in the fleet.""" + new_alien = Alien(self) + new_alien.x = x_position + new_alien.rect.x = x_position + new_alien.rect.y = y_position + self.aliens.add(new_alien) + + def _check_fleet_edges(self): + """Respond appropriately if any aliens have reached an edge.""" + for alien in self.aliens.sprites(): + if alien.check_edges(): + self._change_fleet_direction() + break + + def _change_fleet_direction(self): + """Drop the entire fleet and change the fleet's direction.""" + for alien in self.aliens.sprites(): + alien.rect.y += self.settings.fleet_drop_speed + self.settings.fleet_direction *= -1 + + def _update_screen(self): + """Update images on the screen, and flip to the new screen.""" + self.screen.fill(self.settings.bg_color) + for bullet in self.bullets.sprites(): + bullet.draw_bullet() + self.ship.blitme() + self.aliens.draw(self.screen) + + # Draw the score information. + self.sb.show_score() + + # Draw the play button if the game is inactive. + if not self.game_active: + self.play_button.draw_button() + + pygame.display.flip() + + +# if __name__ == '__main__': +# # Make a game instance, and run the game. +# ai = AlienInvasion() +# ai.run_game() \ No newline at end of file diff --git a/bullet.py b/bullet.py new file mode 100644 index 0000000..2625e1b --- /dev/null +++ b/bullet.py @@ -0,0 +1,31 @@ +import pygame +from pygame.sprite import Sprite + +class Bullet(Sprite): + """A class to manage bullets fired from the ship.""" + + def __init__(self, ai_game): + """Create a bullet object at the ship's current position.""" + super().__init__() + self.screen = ai_game.screen + self.settings = ai_game.settings + self.color = (255, 0,0) + + # Create a bullet rect at (0, 0) and then set correct position. + self.rect = pygame.Rect(0, 0, self.settings.bullet_width, + self.settings.bullet_height) + self.rect.midtop = ai_game.ship.rect.midtop + + # Store the bullet's position as a float. + self.y = float(self.rect.y) + + def update(self): + """Move the bullet up the screen.""" + # Update the exact position of the bullet. + self.y -= self.settings.bullet_speed + # Update the rect position. + self.rect.y = self.y + + def draw_bullet(self): + """Draw the bullet to the screen.""" + pygame.draw.rect(self.screen, self.color, self.rect) \ No newline at end of file diff --git a/button.py b/button.py new file mode 100644 index 0000000..1a726e2 --- /dev/null +++ b/button.py @@ -0,0 +1,35 @@ +import pygame.font + + +class Button: + """A class to build buttons for the game.""" + + def __init__(self, ai_game, msg): + """Initialize button attributes.""" + self.screen = ai_game.screen + self.screen_rect = self.screen.get_rect() + + # Set the dimensions and properties of the button. + self.width, self.height = 200, 50 + self.button_color = (0, 135, 0) + self.text_color = (255, 255, 255) + self.font = pygame.font.SysFont(None, 48) + + # Build the button's rect object and center it. + self.rect = pygame.Rect(0, 0, self.width, self.height) + self.rect.center = self.screen_rect.center + + # The button message needs to be prepped only once. + self._prep_msg(msg) + + def _prep_msg(self, msg): + """Turn msg into a rendered image and center text on the button.""" + self.msg_image = self.font.render(msg, True, self.text_color, + self.button_color) + self.msg_image_rect = self.msg_image.get_rect() + self.msg_image_rect.center = self.rect.center + + def draw_button(self): + """Draw blank button and then draw message.""" + self.screen.fill(self.button_color, self.rect) + self.screen.blit(self.msg_image, self.msg_image_rect) \ No newline at end of file diff --git a/category.py b/category.py new file mode 100644 index 0000000..918bfa0 --- /dev/null +++ b/category.py @@ -0,0 +1,65 @@ +import tkinter as tk +from PIL import Image, ImageTk +from alien_invasion import AlienInvasion +class ImageSwitcher: + def __init__(self, master, images_paths): + self.master = master + self.master.title("选择你想要的飞机") + self.images = [] + self.image_frames = [] + self.current_image_index = 0 + rows = (len(images_paths) - 1) // 3 + 1 + column = 0 + row = 0 + + for i, path in enumerate(images_paths): + frame = tk.Frame(master) + img = Image.open(path) + img = img.resize((400, 260), Image.BICUBIC) + img_tk = ImageTk.PhotoImage(img) + self.images.append(img_tk) + image_label = tk.Label(frame, image=img_tk) + image_label.grid(row=0, column=0, padx=5, pady=5) # 在frame内部使用grid + + button = tk.Button(frame, text=f"选择飞机 {i+1}", command=lambda index=i: self.switch_image(index), + font=("Arial", 18), padx=10, pady=5) + button.grid(row=0, column=1, padx=5, pady=5) # 在frame内部与图片并排 + + # 将frame添加到master中,但注意使用grid而不是pack + frame.grid(row=row, column=column, padx=10, pady=10) + + # 更新行列索引以进行下一组图片和按钮的放置 + column += 2 # 因为每个frame包含1个图片和1个按钮,所以column增加2 + if column >= 3: # 假设每行3个组合 + column = 0 + row += 1 + + # 添加"确定"按钮到master的底部 + button_show = tk.Button(master, text="确定", command=self.on_button_click, + font=("Arial", 18), padx=10, pady=5) + button_show.grid(row=rows, column=0, columnspan=3, pady=10) # 使其横跨3列 + def show_current_image(self): + for frame in self.image_frames: + frame.pack_forget() + current_frame = self.image_frames[self.current_image_index] + current_frame.pack(pady=10) + + def switch_image(self, index): + if 0 <= index < len(self.images): + self.current_image_index = index + self.show_current_image() + + def on_button_click(self): + selected_image_path = images_paths[self.current_image_index] + alien_invasion = AlienInvasion(selected_image_path) + alien_invasion.run_game(selected_image_path) + self.master.destroy() + print(f"用户选择了图片: {selected_image_path}") +images_paths = ["images\火箭1.png", "images\火箭2.png", "images\火箭3.png","images\火箭4.png"] + +def category(): + root = tk.Tk() + root.geometry("1200x700") + root.configure(background='#666666') # 白色背景 + app = ImageSwitcher(root, images_paths) + root.mainloop() diff --git a/game_stats.py b/game_stats.py new file mode 100644 index 0000000..ed0971b --- /dev/null +++ b/game_stats.py @@ -0,0 +1,16 @@ +class GameStats: + """Track statistics for Alien Invasion.""" + + def __init__(self, ai_game): + """Initialize statistics.""" + self.settings = ai_game.settings + self.reset_stats() + + # High score should never be reset. + self.high_score = 0 + + def reset_stats(self): + """Initialize statistics that can change during the game.""" + self.ships_left = self.settings.ship_limit + self.score = 0 + self.level = 1 \ No newline at end of file diff --git a/images/background.jpg b/images/background.jpg new file mode 100644 index 0000000..c910dc8 Binary files /dev/null and b/images/background.jpg differ diff --git a/images/外星人2.png b/images/外星人2.png new file mode 100644 index 0000000..9d2cb0b Binary files /dev/null and b/images/外星人2.png differ diff --git a/images/火箭1.png b/images/火箭1.png new file mode 100644 index 0000000..91947d7 Binary files /dev/null and b/images/火箭1.png differ diff --git a/images/火箭2.png b/images/火箭2.png new file mode 100644 index 0000000..c3b7dab Binary files /dev/null and b/images/火箭2.png differ diff --git a/images/火箭3.png b/images/火箭3.png new file mode 100644 index 0000000..8bf82ab Binary files /dev/null and b/images/火箭3.png differ diff --git a/images/火箭4.png b/images/火箭4.png new file mode 100644 index 0000000..3b08789 Binary files /dev/null and b/images/火箭4.png differ diff --git a/images/背景图.jpg b/images/背景图.jpg new file mode 100644 index 0000000..3a66ee0 Binary files /dev/null and b/images/背景图.jpg differ diff --git a/scoreboard.py b/scoreboard.py new file mode 100644 index 0000000..28c03e6 --- /dev/null +++ b/scoreboard.py @@ -0,0 +1,83 @@ +import pygame.font +from pygame.sprite import Group + +from ship import Ship + + +class Scoreboard: + """A class to report scoring information.""" + + def __init__(self, ai_game,index): + """Initialize scorekeeping attributes.""" + self.ai_game = ai_game + self.screen = ai_game.screen + self.screen_rect = self.screen.get_rect() + self.settings = ai_game.settings + self.stats = ai_game.stats + + # Font settings for scoring information. + self.text_color = (30, 30, 30) + self.font = pygame.font.SysFont(None, 48) + + # Prepare the initial score images. + self.prep_score() + self.prep_high_score() + self.prep_level() + self.prep_ships(index) + + def prep_score(self): + """Turn the score into a rendered image.""" + rounded_score = round(self.stats.score, -1) + score_str = f"{rounded_score:,}" + self.score_image = self.font.render(score_str, True, + self.text_color, self.settings.bg_color) + + # Display the score at the top right of the screen. + self.score_rect = self.score_image.get_rect() + self.score_rect.right = self.screen_rect.right - 20 + self.score_rect.top = 20 + + def prep_high_score(self): + """Turn the high score into a rendered image.""" + high_score = round(self.stats.high_score, -1) + high_score_str = f"{high_score:,}" + self.high_score_image = self.font.render(high_score_str, True, + self.text_color, self.settings.bg_color) + + # Center the high score at the top of the screen. + self.high_score_rect = self.high_score_image.get_rect() + self.high_score_rect.centerx = self.screen_rect.centerx + self.high_score_rect.top = self.score_rect.top + + def prep_level(self): + """Turn the level into a rendered image.""" + level_str = str(self.stats.level) + self.level_image = self.font.render(level_str, True, + self.text_color, self.settings.bg_color) + + # Position the level below the score. + self.level_rect = self.level_image.get_rect() + self.level_rect.right = self.score_rect.right + self.level_rect.top = self.score_rect.bottom + 10 + + def prep_ships(self,index): + """Show how many ships are left.""" + self.ships = Group() + for ship_number in range(self.stats.ships_left): + ship = Ship(self.ai_game,index) + ship.rect.x = 10 + ship_number * ship.rect.width + ship.rect.y = 10 + self.ships.add(ship) + + def check_high_score(self): + """Check to see if there's a new high score.""" + if self.stats.score > self.stats.high_score: + self.stats.high_score = self.stats.score + self.prep_high_score() + + def show_score(self): + """Draw scores, level, and ships to the screen.""" + self.screen.blit(self.score_image, self.score_rect) + self.screen.blit(self.high_score_image, self.high_score_rect) + self.screen.blit(self.level_image, self.level_rect) + self.ships.draw(self.screen) diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..b926d04 --- /dev/null +++ b/settings.py @@ -0,0 +1,50 @@ +import pygame +class Settings: + """A class to store all settings for Alien Invasion.""" + + def __init__(self): + """Initialize the game's static settings.""" + # Screen settings + self.screen_width = 1200 + self.screen_height = 650 + self.bg_color = (255, 255, 255) + # background = pygame.image.load('scoring\\images\\background.jpg') + # alien_invasion.screen.blit(background,(0,0)) + # Ship settings + self.ship_limit = 3 + + # Bullet settings + self.bullet_width = 3 + self.bullet_height = 15 + self.bullet_color = (60, 60, 60) + self.bullets_allowed = 5 + + # Alien settings + self.fleet_drop_speed = 10 + + # How quickly the game speeds up + self.speedup_scale = 1.1 + # How quickly the alien point values increase + self.score_scale = 1.5 + + self.initialize_dynamic_settings() + + def initialize_dynamic_settings(self): + """Initialize settings that change throughout the game.""" + self.ship_speed = 1.5 + self.bullet_speed = 2.5 + self.alien_speed = 1.0 + + # fleet_direction of 1 represents right; -1 represents left. + self.fleet_direction = 1 + + # Scoring settings + self.alien_points = 50 + + def increase_speed(self): + """Increase speed settings and alien point values.""" + self.ship_speed *= self.speedup_scale + self.bullet_speed *= self.speedup_scale + self.alien_speed *= self.speedup_scale + + self.alien_points = int(self.alien_points * self.score_scale) \ No newline at end of file diff --git a/ship.py b/ship.py new file mode 100644 index 0000000..2cba01b --- /dev/null +++ b/ship.py @@ -0,0 +1,54 @@ +import pygame +from pygame.sprite import Sprite + + +class Ship(Sprite): + """A class to manage the ship.""" + + def __init__(self, ai_game,index): + """Initialize the ship and set its starting position.""" + super().__init__() + self.screen = ai_game.screen + self.settings = ai_game.settings + self.screen_rect = ai_game.screen.get_rect() + # 现在你可以通过实例访问image_path + # images = ImageSwitcher.j + print(index) + # Load the ship image and get its rect. + self.original_image = pygame.image.load(index) + alien_width = 90 + alien_height = 90 + + # 调整图片大小 + self.image = pygame.transform.scale(self.original_image, (alien_width, alien_height)) + self.rect = self.image.get_rect() + + # Start each new ship at the bottom center of the screen. + self.rect.midbottom = self.screen_rect.midbottom + + # Store a float for the ship's exact horizontal position. + self.x = float(self.rect.x) + + # Movement flags; start with a ship that's not moving. + self.moving_right = False + self.moving_left = False + + def center_ship(self): + """Center the ship on the screen.""" + self.rect.midbottom = self.screen_rect.midbottom + self.x = float(self.rect.x) + + def update(self): + """Update the ship's position based on movement flags.""" + # Update the ship's x value, not the rect. + if self.moving_right and self.rect.right < self.screen_rect.right: + self.x += self.settings.ship_speed + if self.moving_left and self.rect.left > 0: + self.x -= self.settings.ship_speed + + # Update rect object from self.x. + self.rect.x = self.x + + def blitme(self): + """Draw the ship at its current location.""" + self.screen.blit(self.image, self.rect) \ No newline at end of file diff --git a/welcome.py b/welcome.py new file mode 100644 index 0000000..057b357 --- /dev/null +++ b/welcome.py @@ -0,0 +1,59 @@ +import tkinter as tk +# 这个就属于第三方库 tkinter,还有pygame,像这样的import引入时报错的,一般就是你的第三方库没有引入 +from tkinter import messagebox +# 然后你输入命令下载第三方库,我这里已经下载了,所以它会提示已存在gaiku +# 像这样下载完之后,就可以找到代码中对应的主函数运行了,记得每个python文件都要引入(如果有的话就要引入), +# 不然代码会报错,我这里的主程序设置成welcome.py了,我直接运行该文件就可以,内如比较简陋,但是基本 +# 的功能都有,这个都可以自己改的 +import category +def welcome_screen(): + # 创建主窗口 + root = tk.Tk() + root.title("欢迎界面") + root.geometry("1200x700") + root.configure(bg='lightblue') + + # 创建欢迎标签 + welcome_label = tk.Label(root, text="欢迎使用外星人大战!", font=("Arial", 50, "bold")) + welcome_label.pack(pady=50) + + # 倒计时变量 + countdown = 7 + + # 更新倒计时标签的函数 + def update_countdown_label(): + nonlocal countdown + countdown -= 1 + if countdown >= 0: + # 更新标签文本并再次调用自己(使用root.after实现递归) + message_label.config(text=f"{countdown}秒后自动进入游戏") + root.after(1000, update_countdown_label) # 每隔1秒调用一次 + else: + # 倒计时结束,弹出消息框并关闭窗口 + root.destroy() + category.category() + + + # 创建倒计时标签 + message_label = tk.Label(root, text="7秒后自动进入游戏", font=("Arial", 10, "bold")) + message_label.pack(pady=10) + + # 创建开始游戏按钮(可选,用于手动开始游戏) + def simulate_page_jump(): + root.destroy() + category.category() + + jump_button = tk.Button(root, text="开始游戏", font=("Arial", 24, "bold"), command=simulate_page_jump) + jump_button.pack(pady=20) + + # 开始倒计时 + update_countdown_label() + + # 进入Tkinter事件循环 + root.mainloop() +if __name__ == '__main__': + welcome_screen() + + # ai = AlienInvasion() + # ai.run_game() + \ No newline at end of file