From 78bcd163196b70a47173c0185ed7fdc627fb6a9b Mon Sep 17 00:00:00 2001 From: Cooper Date: Sun, 5 Dec 2021 13:28:10 +0000 Subject: [PATCH 1/4] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20Plan?= =?UTF-8?q?ewar.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Planewar.py | 310 ---------------------------------------------------- 1 file changed, 310 deletions(-) delete mode 100644 Planewar.py diff --git a/Planewar.py b/Planewar.py deleted file mode 100644 index 1599c54..0000000 --- a/Planewar.py +++ /dev/null @@ -1,310 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Tue Nov 16 21:31:30 2021 - -@author: angelshare -""" - -import pygame -import time -import random - - - - -class Base(object): - """所有类的基类""" - def __init__(self, screen_temp, x, y, image_name): - self.x = x - self.y = y - self.screen = screen_temp - self.image = pygame.image.load(image_name) - -class BasePlane(Base): - """飞机基类""" - def __init__(self, plane_type, screen_temp, x, y, image_name, picture_num, HP_temp): - Base.__init__(self, screen_temp, x, y, image_name)#plane_type飞机类型 - self.bullet_list = [] #存储发射出去的子弹的引用 - self.plane_type = plane_type #飞机类型标示 - self.HP = HP_temp #飞机hp - self.fire_bullet_count = 0#飞机已发射子弹计数 - - def display(self): - """显示飞机""" - self.screen.blit(self.image, (self.x, self.y)) - - - #判断是否被击中 - def isHitted(self, plane, width, height): - {}# widht和height表示范围 - -class EnemyPlane(BasePlane): - def __init__(self, screen_temp): - random_num_x = random.randint(12, 418) - random_num_y = random.randint(-50, -40) - self.direction = "left" - BasePlane.__init__(self, 0, screen_temp, random_num_x, random_num_y, "image/plane/enemy.png", 4, 20) - - def move(self): - if self.direction == "right": - self.x += 5 - elif self.direction == "left": - self.x -= 5 - if self.x > 430: - self.direction = "left" - elif self.x < 0: - self.direction = "right" - - - -class PlayerPlane(BasePlane): - global supply_size - def __init__(self, screen_temp, player_no): - BasePlane.__init__(self, 3, screen_temp, 210, 728, "image/plane/plane.png", 4, 10) #super().__init__() - self.player_no = player_no - self.move_dict = {'horizontal' : 0, 'vertical' : 0, 'space' : 0} - self.bullet_list = [] - - def pos_check(self): - if self.x < 0: - self.x = 830 - elif self.x > 830: - self.x = 0 - if self.y < 0: - self.y = 0 - elif self.y > 800: - self.y = 800 - - def move(self): - self.pos_check() - if self.move_dict['horizontal'] != 0 and self.move_dict['vertical'] != 0: - self.x += 3 * self.move_dict['horizontal'] - self.y += 3 * self.move_dict['vertical'] - elif self.move_dict['horizontal'] != 0: - self.x += 5 * self.move_dict['horizontal'] - elif self.move_dict['vertical'] != 0: - self.y += 5 * self.move_dict['vertical'] - if self.move_dict['space'] == 1: - if len(self.bullet_list) != 0: - if self.y - 14 - 80 > self.bullet_list[-1].y: - self.bullet_list.append(Bullet(self.screen, self.x, self.y, 'player')) - else: - self.bullet_list.append(Bullet(self.screen, self.x, self.y, 'player')) - -class Bullet(Base): - def __init__(self, screen_temp, x, y, authority): - self.x = x+40 - self.y = y-20 - self.screen = screen_temp - self.image = pygame.image.load("image/bullet/bullet.png") - self.authority = authority - self.width = 9 - self.height = 21 - - def display(self): - self.screen.blit(self.image, (self.x, self.y)) - - def judge(self): - if self.y > 0 or self.y < 897: - return True - else: - return False - - def move(self): - self.y -= 10 - -class PlayerBullet(Bullet): - global bullet_type - -class EnemyBullet(Bullet): - global bullet_type - -class button(object): - def __init__(self, screen, x, y, w, h, text): - self.x = x - self.y = y - self.w = w - self.h = h - self.text = text - self.screen = screen - - def display(self): - mouse_pos = pygame.mouse.get_pos() - if mouse_pos[0] < self.x + self.w and mouse_pos[0] > self.x and mouse_pos[1] < self.y + self.h and mouse_pos[1] > self.y: - pygame.draw.rect(self.screen, (178, 178, 178), (self.x, self.y, self.w, self.h)) #鼠标进入按钮,颜色设置为(178,178,178) - else: - pygame.draw.rect(self.screen, (128, 128, 128), (self.x, self.y, self.w, self.h)) #鼠标离开按钮,颜色设置为(128,128,128) - font = pygame.font.SysFont('宋体', 32) #设置字体及大小 - textSurf = font.render(self.text, True, (0, 0, 0)) - textRect = textSurf.get_rect() - textRect.center = ((self.x + (self.w / 2)), (self.y + (self.h / 2))) - self.screen.blit(textSurf, textRect) #绘制按钮 - - def click(self): - mouse_pos = pygame.mouse.get_pos() - if mouse_pos[0] < self.x + self.w and mouse_pos[0] > self.x and mouse_pos[1] < self.y + self.h and mouse_pos[1] > self.y: - if self.text == 'Back': - pass - elif self.text == 'Restart': - pass - elif self.text == 'Settings': - pass - elif self.text == 'Restart': - pass - -def pause(player): - button_list = [button(player.screen, 160, 200, 160, 100, 'Back'), - button(player.screen, 160, 300, 160, 100, 'Restart'), - button(player.screen, 160, 400, 160, 100, 'Settings'), - button(player.screen, 160, 500, 160, 100, 'Exit')] - isPause = True - while isPause: - for item in button_list: - item.display() - for event in pygame.event.get(): - if event.type == pygame.QUIT: - pygame.quit() - elif event.type == pygame.MOUSEBUTTONDOWN: - isPause = False - break - elif event.type == event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: - isPause = False - break - controller = pygame.joystick.Joystick(0) - controller.init() - if controller.get_button(7): - isPause = False - pygame.display.update() - time.sleep(0.01) - -#键盘控制移动和开火 -#玩家一:WASD+空格 -#玩家二:方向键+小键盘回车键 -def key_control(player, event): - global isPause - if event.type == pygame.KEYDOWN: - if player: - if player.player_no == 0: - if event.key == pygame.K_a: - player.move_dict['horizontal'] = -1 - print(player.move_dict) - if event.key == pygame.K_d: - player.move_dict['horizontal'] = 1 - if event.key == pygame.K_w: - player.move_dict['vertical'] = -1 - if event.key == pygame.K_s: - player.move_dict['vertical'] = 1 - if event.key == pygame.K_SPACE: - player.move_dict['space'] = 1 - elif player.player_no == 1: - if event.key == pygame.K_LEFT: - player.move_dict['horizontal'] = -1 - if event.key == pygame.K_RIGHT: - player.move_dict['horizontal'] = 1 - if event.key == pygame.K_UP: - player.move_dict['vertical'] = -1 - if event.key == pygame.K_DOWN: - player.move_dict['vertical'] = 1 - if event.key == pygame.K_KP_ENTER: - player.move_dict['space'] = 1 - if event.key == pygame.K_ESCAPE: #按下ESC键暂停游戏 - pause(player) - - - elif event.type == pygame.KEYUP and player: - if player.player_no == 0: - if event.key == pygame.K_a: - player.move_dict['horizontal'] = 0 - if event.key == pygame.K_d: - player.move_dict['horizontal'] = 0 - if event.key == pygame.K_w: - player.move_dict['vertical'] = 0 - if event.key == pygame.K_s: - player.move_dict['vertical'] = 0 - if event.key == pygame.K_SPACE: - player.move_dict['space'] = 0 - elif player.player_no == 1: - if event.key == pygame.K_LEFT: - player.move_dict['horizontal'] = 0 - if event.key == pygame.K_RIGHT: - player.move_dict['horizontal'] = 0 - if event.key == pygame.K_UP: - player.move_dict['vertical'] = 0 - if event.key == pygame.K_DOWN: - player.move_dict['vertical'] = 0 - if event.key == pygame.K_KP_ENTER: - player.move_dict['space'] = 0 - -#手柄控制移动和开火 -#左摇杆+A(Xbox)/×(Playstation)/B(Nintendo) -def joystick_control(player, controller): - if abs(controller.get_axis(0)) > 0.1: - player.move_dict['horizontal'] = controller.get_axis(0) - else: - player.move_dict['horizontal'] = 0 - if abs(controller.get_axis(0)) > 0.1: - player.move_dict['vertical'] = controller.get_axis(1) - else: - player.move_dict['vertical'] = 0 - if controller.get_button(0): - player.move_dict['space'] = 1 - else: - player.move_dict['space'] = 0 - if controller.get_button(7): - pause(player) - -def main(): - pygame.init() # 初始化pygame - bg_size = width, height = 901,897 - screen = pygame.display.set_mode(bg_size) # 显示窗口 - pygame.display.set_caption("飞机大战") - - - #创建一个背景图片,路径需做出背景图片放入文件夹中填入路径,haven't finished - background = pygame.image.load("image/bg.png").convert() - - - screen.blit(background, (0,0)) - - #创建一个玩家飞机 - player = PlayerPlane(screen, player_no = 0) - - #创建一个敌机对象 - enemy = EnemyPlane(screen) - - pygame.joystick.init() - controller_num = pygame.joystick.get_count() - if(controller_num != 0): - controller = [] - for i in range(controller_num): - controller.append(pygame.joystick.Joystick(i)) - controller[i].init() - - while True: - screen.blit(background, (0,0)) - - player.display() - enemy.display() - enemy.move()#调用敌机移动 - - bullet_del_list = [] - for item in player.bullet_list: - if item.judge(): - item.display() - item.move() - else: - bullet_del_list.append(item) - for item in bullet_del_list: - player.bullet_list.remove(item) - for event in pygame.event.get(): - if event.type == pygame.QUIT: - pygame.quit() - key_control(player, event) - if(controller_num != 0): - joystick_control(player, controller[0]) - player.move() - pygame.display.update() - time.sleep(0.01) - -if __name__ == "__main__": - main() -- Gitee From 77fedc418708930ced4c9f9517c657e1aa8504d1 Mon Sep 17 00:00:00 2001 From: Cooper Date: Sun, 5 Dec 2021 13:28:16 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20Plan?= =?UTF-8?q?e.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Plane.py | 66 -------------------------------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 Plane.py diff --git a/Plane.py b/Plane.py deleted file mode 100644 index f613eb5..0000000 --- a/Plane.py +++ /dev/null @@ -1,66 +0,0 @@ -# coding: utf-8 -# 飞机的基类和敌方飞机 玩家飞机(缺乏玩家控制移动部分) - -import time -import random -import pygame -# 飞机基类的属性:基类+生命+飞机类型 方法:出现在窗口 被打中减少hp - -class Base(object): # 基类 - def __init__(self, screen_temp, x, y, image_name): - self.x = x - self.y = y - self.screen = screen_temp - self.image = pygame.image.load(image_name) - -class BasePlane(Base): # 飞机基类 - def __init__(self, screen_temp, x, y, image_name, plane_hp, plane_type_num, ): - Base.__init__(self, screen_temp, x, y,image_name) - self.bullet_list = [] - self.hp = plane_hp - self.plane_type = plane_type_num - - def display(self): # 加载飞机的图像和位置 待update后出现 - self.screen.blit(self.image, (self.x, self.y)) - - def isHitted(self, plane, width, height): # TODO:飞机和子弹“相遇”的判断函数 - {} - self.hp -= 1 - -class EnemyPlane(BasePlane): - def __init__(self, screen_temp, image_name, enemy_type_num, ): - random_x = random.randint(150, self.screen.get_width()-150) # 根据屏幕大小适当调整,这个是敌机的起始位置 - random_y = random.randint(-50, -20) - if enemy_type_num == 3: # 一类敌机最强 血条3, 三个类型血条和移动速度不同 - enemy_hp = 3 - elif enemy_type_num == 2: - enemy_hp = 2 - elif enemy_type_num == 1: - enemy_hp = 1 - else: - print("敌机目前只有三个类型") - BasePlane.__init__(self, screen_temp, random_x, random_y, image_name, enemy_hp, enemy_type_num) - - # 敌机的移动逻辑:在hp不为0的前提下,随着时间每过1s移动一次,遇到边界就换方向 - # TODO: 时间判断刷新次数较长 暂未想其他方法 待更改 - def enemy_move(self): - move_step = {"1": 50, "2": 80, "3": 120} # 不同类型飞机一秒移动步数不一样 - move_direction = {"0": -1, "1":1} # 随机判定起始的移动方向 结果为1/-1 - random_direction = move_direction[str(random.randint(0, 1))] - while self.hp != 0: # 判断有命才能动 - time_start = int(time.time()) # 获取个时间 暂定一秒一次 一次步数根据档次不同 - if time_start + 1 == int(time.time()): - self.x += move_step[str(self.plane_type)] * random_direction # 步数*1/-1 控制向左还是右 - self.y -= 50 - if self.x < 20 or self.x > self.screen.get_width() - 20: # 敌机移动到边界,就换方向 - random_direction *= -1 - - -class PlayerPlane(BasePlane): - def __init__(self, screen_temp, image_name, myplane_type_num): - x = self.screen.get_width()/2 # 默认玩家出现在最下面最中间 - y = self.screen.get_height() - BasePlane.__init__(self, screen_temp,x, y,image_name,3, myplane_type_num) - - def move(self): - {} # TODO: 玩家的移动控制 \ No newline at end of file -- Gitee From f2f45afadc464b36e1aeafde88d57d4b445161fc Mon Sep 17 00:00:00 2001 From: Cooper Date: Sun, 5 Dec 2021 13:30:18 +0000 Subject: [PATCH 3/4] Add several functions and neural network model --- Planewar.py | 514 ++++++++++++++++++++++++++++++++++++++++++++++++++++ cnn.py | 402 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 916 insertions(+) create mode 100644 Planewar.py create mode 100644 cnn.py diff --git a/Planewar.py b/Planewar.py new file mode 100644 index 0000000..02fad3f --- /dev/null +++ b/Planewar.py @@ -0,0 +1,514 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Nov 16 21:31:30 2021 + +@author: angelshare +""" + +import pygame +import time +import random +import pickle + +width = 901 +height = 897 +score = 0 +enemy_list = [] +bullet_list = [] +supply_list = [] + +class Base(object): + """所有类的基类""" + def __init__(self, screen_temp, x, y, image_name): + self.x = x + self.y = y + self.screen = screen_temp + self.image = pygame.image.load(image_name).convert_alpha() + self.w = self.image.get_rect().size[0] + self.h = self.image.get_rect().size[1] + +class BasePlane(Base): + """飞机基类""" + global bullet_list + global enemy_list + global width, height + def __init__(self, plane_type, screen_temp, x, y, image_name, picture_num, HP_temp, authority): + Base.__init__(self, screen_temp, x, y, image_name)#plane_type飞机类型 + self.bullet_list = [] #存储发射出去的子弹的引用 + self.plane_type = plane_type #飞机类型标示 + self.hp = HP_temp #飞机hp + self.authority = authority + self.time = 0 + #self.fire_bullet_count = 0#飞机已发射子弹计数 + + def display(self): + global score + if self.hp > 0: + self.screen.blit(self.image, (self.x, self.y)) + self.hit() + else: + if self.time < 100: + explode_image = pygame.image.load('image/explode.png').convert_alpha() + self.screen.blit(self.image, (self.x, self.y)) + self.screen.blit(explode_image, (self.x, self.y)) + self.time += 1 + else: + if self.authority == 'enemy' and self.hp <= 0: + enemy_list.remove(self) + score += 1 + for item in self.bullet_list: + if not item.judge(): + self.bullet_list.remove(item) + + def hit(self): + if bullet_list and self.hp: + for bullet in bullet_list: + if bullet.authority != self.authority: + if bullet.x < self.x + self.w and bullet.x > self.x and bullet.y < self.y + self.h and bullet.y > self.y: + self.hp -= bullet.damage + bullet.damage = 0 + bullet.visible = False + + + def pos_check(self): + if self.x < 0: + self.x = self.w + elif self.x > width: + self.x = 0 + if self.authority == 'player': + if self.y < 0: + self.y = 0 + elif self.y > height - self.h: + self.y = height - self.h + if self.authority == 'enemy' and self.y > height: + enemy_list.remove(self) + +class EnemyPlane(BasePlane): + def __init__(self, screen_temp): + random_num_x = random.randint(12, 418) + random_num_y = random.randint(-50, -40) + self.direction = "left" + BasePlane.__init__(self, 0, screen_temp, random_num_x, random_num_y, "image/plane/enemy.png", 4, 1, "enemy") + + def move(self): + self.pos_check() + self.fire() + if self.hp > 0: + if self.direction == 'right': + self.x += 1 + elif self.direction == 'left': + self.x -= 1 + if self.x > 430: + self.direction = 'left' + elif self.x < 0: + self.direction = 'right' + self.y += 3 + + def fire(self): + if len(self.bullet_list) != 0: + if self.y - 14 - 80 > self.bullet_list[-1].y: + self.bullet_list.append(Bullet(self.screen, self.x, self.y+60, 'enemy')) + else: + self.bullet_list.append(Bullet(self.screen, self.x, self.y+60, 'enemy')) + +class PlayerPlane(BasePlane): + global supply_size + def __init__(self, screen_temp, player_no): + #x = self.screen.get_width()/2 # 默认玩家出现在最下面最中间 + #y = self.screen.get_height() + x = 400 + y = 200 + BasePlane.__init__(self, 3, screen_temp, x, y, "image/plane/plane.png", 4, 10, "player") #super().__init__() + self.player_no = player_no + self.level = 1 + self.exp = 0 + self.hp_amount = 100 + self.move_dict = {'horizontal' : 0, 'vertical' : 0, 'space' : 0} + + + def levelup(self): + self.level += 1 + + def move(self): + self.pos_check() + if self.move_dict['horizontal'] != 0 and self.move_dict['vertical'] != 0: + self.x += 3 * self.move_dict['horizontal'] + self.y += 3 * self.move_dict['vertical'] + elif self.move_dict['horizontal'] != 0: + self.x += 5 * self.move_dict['horizontal'] + elif self.move_dict['vertical'] != 0: + self.y += 5 * self.move_dict['vertical'] + if self.move_dict['space'] == 1: + if len(self.bullet_list) != 0: + if self.y - 14 - 80 > self.bullet_list[-1].y: + self.bullet_list.append(Bullet(self.screen, self.x, self.y, 'player')) + else: + self.bullet_list.append(Bullet(self.screen, self.x, self.y, 'player')) + +class Bullet(Base): + def __init__(self, screen_temp, x, y, authority): + self.x = x+40 + self.y = y-20 + self.screen = screen_temp + self.image = pygame.image.load("image/bullet/bullet.png") + self.authority = authority + self.damage = 1 + self.visible = True + if self.authority == 'enemy': + self.image = pygame.transform.rotate(self.image, 180) + + def display(self): + if self.visible == True: + self.screen.blit(self.image, (self.x, self.y)) + + def judge(self): + if self.y > 0 and self.y < 897: + return True + else: + return False + + def move(self): + if self.authority == 'player': + self.y -= 8 + elif self.authority == 'enemy': + self.y += 8 + +class PlayerBullet(Bullet): + global bullet_type + +class EnemyBullet(Bullet): + global bullet_type + +class Game(object): + def __init__(self, screen, player_list, enemy_list): + self.player_list = player_list + self.enemy_list = enemy_list + + #保存游戏 + def save_game(self): + with open('save.dat', 'wb') as f: + pickle.dump(self, f) + + #读取游戏 + def load_game(self): + with open('save.dat', 'rb+') as f: + model = pickle.load(f) + return model + +#标签 +class Label(object): + def __init__(self, screen, x, y, w, h): + self.x = x + self.y = y + self.w = w + self.h = h + self.screen = screen + + def display(self, text, size = 32): + font = pygame.font.SysFont('Times New Romans', size) #设置字体及大小 + textSurf = font.render(text, True, (0, 0, 0)) + textRect = textSurf.get_rect() + textRect.center = ((self.x + (self.w / 2)), (self.y + (self.h / 2))) + self.screen.blit(textSurf, textRect) #绘制标签 + +#按钮 +class Button(object): + def __init__(self, screen, x, y, w, h, text): + self.x = x + self.y = y + self.w = w + self.h = h + self.text = text + self.screen = screen + + def display(self): + mouse_pos = pygame.mouse.get_pos() + if mouse_pos[0] < self.x + self.w and mouse_pos[0] > self.x and mouse_pos[1] < self.y + self.h and mouse_pos[1] > self.y: + pygame.draw.rect(self.screen, (178, 178, 178), (self.x, self.y, self.w, self.h)) #鼠标进入按钮,颜色设置为(178,178,178) + else: + pygame.draw.rect(self.screen, (128, 128, 128), (self.x, self.y, self.w, self.h)) #鼠标离开按钮,颜色设置为(128,128,128) + font = pygame.font.SysFont('宋体', 32) #设置字体及大小 + textSurf = font.render(self.text, True, (0, 0, 0)) + textRect = textSurf.get_rect() + textRect.center = ((self.x + (self.w / 2)), (self.y + (self.h / 2))) + self.screen.blit(textSurf, textRect) #绘制按钮 + + def click(self): + mouse_pos = pygame.mouse.get_pos() + if mouse_pos[0] < self.x + self.w and mouse_pos[0] > self.x and mouse_pos[1] < self.y + self.h and mouse_pos[1] > self.y: + return True + +class Supply(Base): + def __init__(self, screen_temp, x, y, image_name, supply_type): + super().__init__(screen_temp, x, y, image_name) + + def display(self): + self.screen.blit(self.image, (self.x, self.y)) + + def move(self): + self.y += 1 + +def sum_bullet(player_list, enemy_list): + global bullet_list + for item in player_list: + bullet_list.extend(item.bullet_list) + for item in enemy_list: + bullet_list.extend(item.bullet_list) + return bullet_list + +def create_enemy(screen): + global width + global enemy_list + if len(enemy_list) < 5: + enemy_list.append(EnemyPlane(screen)) + +def game_fail(): + pass + +def pause(player): + button_list = [Button(player.screen, 160, 200, 160, 100, 'Back'), + Button(player.screen, 160, 300, 160, 100, 'Restart'), + Button(player.screen, 160, 400, 160, 100, 'Save'), + Button(player.screen, 160, 500, 160, 100, 'Settings'), + Button(player.screen, 160, 600, 160, 100, 'Exit')] + isPause = True + while isPause: + for item in button_list: + item.display() + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + elif event.type == pygame.MOUSEBUTTONDOWN: + isPause = False + break + elif event.type == event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: + isPause = False + break + controller_num = pygame.joystick.get_count() + if(controller_num != 0): + controller = pygame.joystick.Joystick(0) + controller.init() + if controller.get_button(7): + isPause = False + pygame.display.update() + time.sleep(0.01) + +def ai_save_data(): + pass + +#自动游戏,ai控制移动和开火 +def ai_control(player, event): + '''model = load_model('lstm_300.h5', custom_objects={'r2': r2}) + player.move_dict['horizontal'] = model.predict(test_x)''' + pass + +#键盘控制移动和开火 +#玩家一:WASD+空格 +#玩家二:方向键+小键盘回车键 +def key_control(player, event): + global isPause + if event.type == pygame.KEYDOWN: + if player: + if player.player_no == 0: + if event.key == pygame.K_a: + player.move_dict['horizontal'] = -1 + if event.key == pygame.K_d: + player.move_dict['horizontal'] = 1 + if event.key == pygame.K_w: + player.move_dict['vertical'] = -1 + if event.key == pygame.K_s: + player.move_dict['vertical'] = 1 + if event.key == pygame.K_SPACE: + player.move_dict['space'] = 1 + elif player.player_no == 1: + if event.key == pygame.K_LEFT: + player.move_dict['horizontal'] = -1 + if event.key == pygame.K_RIGHT: + player.move_dict['horizontal'] = 1 + if event.key == pygame.K_UP: + player.move_dict['vertical'] = -1 + if event.key == pygame.K_DOWN: + player.move_dict['vertical'] = 1 + if event.key == pygame.K_KP_ENTER: + player.move_dict['space'] = 1 + if event.key == pygame.K_ESCAPE: #按下ESC键暂停游戏 + pause(player) + + elif event.type == pygame.KEYUP and player: + if player.player_no == 0: + if event.key == pygame.K_a: + player.move_dict['horizontal'] = 0 + if event.key == pygame.K_d: + player.move_dict['horizontal'] = 0 + if event.key == pygame.K_w: + player.move_dict['vertical'] = 0 + if event.key == pygame.K_s: + player.move_dict['vertical'] = 0 + if event.key == pygame.K_SPACE: + player.move_dict['space'] = 0 + elif player.player_no == 1: + if event.key == pygame.K_LEFT: + player.move_dict['horizontal'] = 0 + if event.key == pygame.K_RIGHT: + player.move_dict['horizontal'] = 0 + if event.key == pygame.K_UP: + player.move_dict['vertical'] = 0 + if event.key == pygame.K_DOWN: + player.move_dict['vertical'] = 0 + if event.key == pygame.K_KP_ENTER: + player.move_dict['space'] = 0 + + + +#手柄控制移动和开火 +#左摇杆+A(Xbox)/×(Playstation)/B(Nintendo) +def joystick_control(player, controller): + if abs(controller.get_axis(0)) > 0.1: + player.move_dict['horizontal'] = controller.get_axis(0) + else: + player.move_dict['horizontal'] = 0 + if abs(controller.get_axis(0)) > 0.1: + player.move_dict['vertical'] = controller.get_axis(1) + else: + player.move_dict['vertical'] = 0 + if controller.get_button(0): + player.move_dict['space'] = 1 + else: + player.move_dict['space'] = 0 + if controller.get_button(7): + pause(player) + +def main(): + global width, height + global score + global enemy_list + global bullet_list + global supply_list + + pygame.init() # 初始化pygame + bg_size = width, height = 901,897 + screen = pygame.display.set_mode(bg_size) # 显示窗口 + pygame.display.set_caption("飞机大战") + + + #创建一个背景图片,路径需做出背景图片放入文件夹中填入路径,haven't finished + background = pygame.image.load("image/bg.png").convert() + + + score_label = Label(screen, width - 120, 0, 120, 30) + pygame.joystick.init() + controller_num = pygame.joystick.get_count() + if(controller_num != 0): + controller = [] + for i in range(controller_num): + controller.append(pygame.joystick.Joystick(i)) + controller[i].init() + mode = 'single' + start = False + button_list = [Button(screen, width / 2 - 80, 350, 160, 100, 'New Game'), + Button(screen, width / 2 - 80, 450, 160, 100, 'Continue'), + Button(screen, width / 2 - 80, 550, 160, 100, 'Settings'), + Button(screen, width / 2 - 80, 650, 160, 100, 'Exit')] + + while not start: + operation = -1 + screen.blit(background, (0,0)) + label = Label(screen, width / 2 - 120, height / 2 - 200, 240, 120) + + label.display('Plane War', 72) + for button in button_list: + button.display() + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + elif event.type == pygame.MOUSEBUTTONDOWN: + if(len(button_list) == 4): + if button_list[0].click(): + button_list.clear() + button_list = [Button(screen, width / 2 - 80, 350, 160, 100, 'Single Player'), + Button(screen, width / 2 - 80, 650, 160, 100, 'Double Player')] + elif button_list[1].click(): + #game = Game.load_game() + pass + elif button_list[2].click(): + pass + elif button_list[3].click(): + pygame.quit() + else: + if button_list[0].click(): + start = True + break + elif button_list[1].click(): + mode = 'double' + start = True + break + + if operation == 0: + break + + time.sleep(0.01) + pygame.display.update() + + if mode == 'single': + player_list = [PlayerPlane(screen, player_no = 0)] + else: + player_list = [PlayerPlane(screen, player_no = 0), + PlayerPlane(screen, player_no = 1)] + + while True: + screen.blit(background, (0,0)) + for player in player_list: + player.display() + + create_enemy(screen) + for enemy in enemy_list: + enemy.display() + enemy.move() + bullet_list = [] + bullet_list = sum_bullet(player_list, enemy_list) + #bullet_del_list = [] + for item in bullet_list: + if item.judge(): + item.display() + item.move() + ''' else: + bullet_del_list.append(item) + for item in bullet_del_list: + bullet_list.remove(item)''' + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + for player in player_list: + key_control(player, event) + + if player_list[0].hp <= 0: + player_list.clear() + enemy_list.clear() + pygame.display.update() + label1 = Label(screen, width / 2 - 120, height / 2 - 200, 240, 120) + label2 = Label(screen, width / 2 - 60, height / 2 - 30, 120, 60) + button1 = Button(screen, width / 2 - 80, height / 2 + 100, 160, 100, 'Restart') + button2 = Button(screen, width / 2 - 80, height / 2 + 250, 160, 100, 'Back') + while True: + label1.display('Game Over!', 72) + label2.display('Your Score:' + str(score)) + button1.display() + button2.display() + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + pygame.display.update() + time.sleep(0.01) + + if(controller_num != 0): + joystick_control(player_list[0], controller[0]) + + for player in player_list: + player.move() + + score_label.display('Score:' + str(score)) + time.sleep(0.01) + pygame.display.update() + +if __name__ == "__main__": + main() diff --git a/cnn.py b/cnn.py new file mode 100644 index 0000000..e82c64e --- /dev/null +++ b/cnn.py @@ -0,0 +1,402 @@ +# -*- coding: utf-8 -*- +""" +Created on Sat Dec 4 20:50:49 2021 + +@author: admin +""" + +from keras.layers import LSTM, Dense +from keras.models import Sequential +from keras.models import load_model +import keras.backend as K +import matplotlib.pyplot as plt +from sklearn.metrics import r2_score +import pandas as pd +import numpy as np +import os + + +def cnn_load_data(stock_code): + data = pd.read_excel('data.xlsx') + train_data = [] + train_label = [] + for index,row in data.iterrows(): + train_cells = [] + train_cells.append(row['horizontal']) + train_cells.append(row['vertical']) + train_cells.append(row['space']) + train_cells = np.array(train_cells, dtype='float') + train_data.append(train_cells) + train_label.append(row['close']) + train_data = train_data[:len(train_data)-1] + train_label = train_label[1:] + length = len(train_data) + length = round(length * 0.8) + test_data = train_data[length:] + test_label = train_label[length:] + train_data = train_data[:length] + train_label = train_label[:length] + train_data = np.array(train_data, dtype='float') + train_label = np.array(train_label, dtype='float') + test_data = np.array(test_data, dtype='float') + test_label = np.array(test_label, dtype='float') + #label = to_categorical(label,num_classes=class_num) + return train_data,train_label,test_data,test_label + +def lstm_load_data(stock_code): + '''file = Path('./tdxstocks/day/' + finance.get_tdx_type(stock_code) + '.xlsx') + if not file.exists(): + tdxdata.get_tdx_day(finance.get_tdx_type(stock_code) + '.day') + data = pd.read_excel(file, index_col = 'date')''' + data = ts.get_hist_data(stock_code) + mf_data = trendline.mainforce_monitor_ml(data) + gs_data = trendline.golden_snipe_ml(data) + data = data[['open', 'high', 'close', 'low', 'ma5', 'ma10', 'ma20']] + data = data.iloc[:len(data) - 100] + data = pd.merge(data, mf_data, on='date') + data = pd.merge(data, gs_data, on='date') + data = data.iloc[::-1] + train_data = [] + train_label = [] + for index,row in data.iterrows(): + train_cells = [] + train_cells.append(row['horizontal']) + train_cells.append(row['vertical']) + train_cells.append(row['space']) + train_cells = np.array(train_cells, dtype='float') + train_data.append(train_cells) + train_label.append(row['close']) + train_data = train_data[:len(train_data)-1] + train_label = train_label[1:] + length = len(train_data) + length = round(length * 0.8) + test_data = train_data[length:] + test_label = train_label[length:] + train_data = train_data[:length] + train_label = train_label[:length] + train_data = np.array(train_data, dtype='float') + train_label = np.array(train_label, dtype='float') + test_data = np.array(test_data, dtype='float') + test_label = np.array(test_label, dtype='float') + train_data = train_data.reshape((train_data.shape[0], 1, train_data.shape[1])) + test_data = test_data.reshape((test_data.shape[0], 1, test_data.shape[1])) + #label = to_categorical(label,num_classes=class_num) + return train_data,train_label,test_data,test_label + +def r2(y_true, y_pred): + a = K.square(y_pred - y_true) + b = K.sum(a) + c = K.mean(y_true) + d = K.square(y_true - c) + e = K.sum(d) + f = 1 - b/e + return f + +class CNN: + def neural_model(): + #input_shape = (bin_n * 4, 1) + model = Sequential() + model.add(Dense(64, activation='relu', input_dim=17)) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(1)) + return model + +def cnn_train(stock_code): + batch_size = 32 + epochs = 1000 + model = CNN.neural_model() + train_x, train_y, test_x, test_y = cnn_load_data(stock_code) + + model.compile(loss='mse', optimizer='rmsprop', metrics=['mae',r2]) + model.fit(train_x, train_y, batch_size=batch_size, epochs=epochs, validation_split=0.2) + + pred_test_y = model.predict(test_x) + #print(pred_test_y) + + pred_acc = r2_score(test_y, pred_test_y) + print('pred_acc', pred_acc) + + plt.rcParams['font.sans-serif'] = ['SimHei'] + plt.rcParams['axes.unicode_minus'] = False + + plt.figure(figsize=(8, 4), dpi=80) + plt.plot(range(len(test_y)), test_y, ls='-.',lw=2,c='r',label='真实值') + plt.plot(range(len(pred_test_y)), pred_test_y, ls='-',lw=2,c='b',label='预测值') + + plt.grid(alpha=0.4, linestyle=':') + plt.legend() + plt.xlabel('number') + plt.ylabel('股价') + + plt.show() + +def cnn_predict(stock_code, length): + '''file = Path('./tdxstocks/day/' + finance.get_tdx_type(stock_code) + '.xlsx') + if not file.exists(): + tdxdata.get_tdx_day(finance.get_tdx_type(stock_code) + '.day') + data = pd.read_excel(file, index_col = 'date')''' + data = ts.get_hist_data(stock_code) + mf_data = trendline.mainforce_monitor_ml(data) + gs_data = trendline.golden_snipe_ml(data) + data = data[['open', 'high', 'close', 'low', 'ma5', 'ma10', 'ma20']] + data = data.iloc[:len(data) - 100] + data = pd.merge(data, mf_data, on='date') + data = pd.merge(data, gs_data, on='date') + data = data.iloc[::-1] + traindata = [] + label = [] + for index,row in data.iterrows(): + train_cells = [] + train_cells.append(row['horizontal']) + train_cells.append(row['vertical']) + train_cells.append(row['space']) + train_cells = np.array(train_cells, dtype='float') + traindata.append(train_cells) + label.append(row['close']) + traindata = traindata[:len(traindata)-1] + label = label[1:] + traindata = np.array(traindata, dtype='float') + #traindata = np.expand_dims(traindata, axis=2) + label = np.array(label, dtype='float') + #label = to_categorical(label,num_classes=class_num) + +class ml_LSTM: + def neural_model(): + model = Sequential() + model.add(LSTM(50, return_sequences=True, input_shape=(1, 18))) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(LSTM(50, return_sequences=True)) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(Dense(64, activation='relu')) + model.add(LSTM(50)) + model.add(Dense(1)) + return model + +def lstm_train(stock_code): + batch_size = 8 + epochs = 1000 + train_x, train_y, test_x, test_y = lstm_load_data(stock_code) + model = ml_LSTM.neural_model(train_x) + #model.compile(loss='mae', optimizer='adam') + model.compile(loss='mse', optimizer='rmsprop', metrics=['mae',r2]) + #model.fit(train_x, train_y, batch_size=batch_size, epochs=epochs, validation_split=0.2) + history = model.fit(train_x, train_y, batch_size=batch_size, epochs=epochs, validation_split=0.2) + + plt.figure() + plt.plot(history.history['loss'], label='train') + plt.plot(history.history['val_loss'], label='test') + plt.legend() + #plt.show() + + pred_test_y = model.predict(test_x) + #print(pred_test_y) + + pred_acc = r2_score(test_y, pred_test_y) + print(test_y) + print(pred_test_y) + print('pred_acc', pred_acc) + + plt.rcParams['font.sans-serif'] = ['SimHei'] + plt.rcParams['axes.unicode_minus'] = False + + plt.figure(figsize=(8, 4), dpi=80) + plt.plot(range(len(test_y)), test_y, ls='-.',lw=2,c='r',label='真实值') + plt.plot(range(len(pred_test_y)), pred_test_y, ls='-',lw=2,c='b',label='预测值') + + plt.grid(alpha=0.4, linestyle=':') + plt.legend() + plt.xlabel('number') + plt.ylabel('股价') + + plt.show() + +def lstm_train_all(): + listfile = os.listdir('./tdxstocks/day/') + batch_size = 32 + epochs = 1 + #model = ml_LSTM.neural_model() + #model.compile(loss='mse', optimizer='rmsprop', metrics=['mae',r2]) + model = load_model('lstm_model.h5', custom_objects={'r2': r2}) + for stock_code in listfile: + data = pd.read_excel('./tdxstocks/day/' + stock_code, index_col = 'date') + if len(data) < 250: + continue + data = data[:600] + + data = data.iloc[::-1] + train_data = [] + train_label = [] + for index,row in data.iterrows(): + train_cells = [] + train_cells.append(row['horizontal']) + train_cells.append(row['vertical']) + train_cells.append(row['space']) + train_cells = np.array(train_cells, dtype='float') + train_data.append(train_cells) + train_label.append(row['close']) + train_data = train_data[:len(train_data)-1] + train_label = train_label[1:] + train_data = np.array(train_data, dtype='float') + train_label = np.array(train_label, dtype='float') + train_data = train_data.reshape((train_data.shape[0], 1, train_data.shape[1])) + #label = to_categorical(label,num_classes=class_num) + + #model.compile(loss='mae', optimizer='adam') + + model.fit(train_data, train_label, batch_size=batch_size, epochs=epochs) + + stock_code = stock_code[2:8] + print(stock_code + ' finished') + model.save('lstm_model.h5') + +def lstm_train_300(): + df = pd.read_excel('./tdxstocks/hs300.xlsx', index_col = 0, converters = {'code':str}) + batch_size = 32 + epochs = 1 + model = ml_LSTM.neural_model() + model.compile(loss='mse', optimizer='rmsprop', metrics=['mae',r2]) + #model = load_model('lstm_model.h5', custom_objects={'r2': r2}) + for iters in range(0,30): + for index,row in df.iterrows(): + stock_code = finance.get_tdx_type(row[0]) + data = pd.read_excel('./tdxstocks/day/' + stock_code + '.xlsx', index_col = 'date') + if len(data) < 250: + continue + data = data[:600] + mf_data = trendline.mainforce_monitor_ml(data) + gs_data = trendline.golden_snipe_ml(data) + ma5_data = trendline.ma(data, 5) + ma10_data = trendline.ma(data, 10) + ma20_data = trendline.ma(data, 20) + ma30_data = trendline.ma(data, 30) + data = data[['open', 'high', 'close', 'low']] + data = data.iloc[:len(data) - 100] + data = pd.merge(data, ma5_data, on='date') + data = pd.merge(data, ma10_data, on='date') + data = pd.merge(data, ma20_data, on='date') + data = pd.merge(data, ma30_data, on='date') + data = pd.merge(data, mf_data, on='date') + data = pd.merge(data, gs_data, on='date') + data = data.iloc[::-1] + train_data = [] + train_label = [] + for index,row in data.iterrows(): + train_cells = [] + train_cells.append(row['horizontal']) + train_cells.append(row['vertical']) + train_cells.append(row['space']) + train_cells = np.array(train_cells, dtype='float') + train_data.append(train_cells) + train_label.append(row['close']) + train_data = train_data[:len(train_data)-1] + train_label = train_label[1:] + train_data = np.array(train_data, dtype='float') + train_label = np.array(train_label, dtype='float') + train_data = train_data.reshape((train_data.shape[0], 1, train_data.shape[1])) + #label = to_categorical(label,num_classes=class_num) + + #model.compile(loss='mae', optimizer='adam') + + model.fit(train_data, train_label, batch_size=batch_size, epochs=epochs) + + stock_code = stock_code[2:8] + print(stock_code + ' iter' + str(iters) + ' finished') + model.save('lstm_300.h5') + +def lstm_train_500(): + df = pd.read_excel('./tdxstocks/zz500.xlsx', index_col = 0, converters = {'code':str}) + batch_size = 32 + epochs = 1 + model = ml_LSTM.neural_model() + model.compile(loss='mse', optimizer='rmsprop', metrics=['mae',r2]) + #model = load_model('lstm_model.h5', custom_objects={'r2': r2}) + for iters in range(0,30): + for index,row in df.iterrows(): + data = data.iloc[::-1] + train_data = [] + train_label = [] + for index,row in data.iterrows(): + train_cells = [] + train_cells.append(row['horizontal']) + train_cells.append(row['vertical']) + train_cells.append(row['space']) + train_cells = np.array(train_cells, dtype='float') + train_data.append(train_cells) + train_label.append(row['close']) + train_data = train_data[:len(train_data)-1] + train_label = train_label[1:] + train_data = np.array(train_data, dtype='float') + train_label = np.array(train_label, dtype='float') + train_data = train_data.reshape((train_data.shape[0], 1, train_data.shape[1])) + #label = to_categorical(label,num_classes=class_num) + + #model.compile(loss='mae', optimizer='adam') + + model.fit(train_data, train_label, batch_size=batch_size, epochs=epochs) + + stock_code = stock_code[2:8] + print(stock_code + ' iter' + str(iters) + ' finished') + model.save('lstm_500.h5') + +def lstm_predict(stock_code): + train_data = [] + train_label = [] + for index,row in data.iterrows(): + train_cells = [] + train_cells.append(row['horizontal']) + train_cells.append(row['vertical']) + train_cells.append(row['space']) + train_cells = np.array(train_cells, dtype='float') + train_data.append(train_cells) + train_label.append(row['close']) + train_data = train_data[:len(train_data)-1] + train_label = train_label[1:] + test_x = np.array(train_data, dtype='float') + test_y = np.array(train_label, dtype='float') + test_x = test_x.reshape((test_x.shape[0], 1, test_x.shape[1])) + model = load_model('lstm_300.h5', custom_objects={'r2': r2}) + + pred_test_y = model.predict(test_x) + #print(pred_test_y) + + pred_acc = r2_score(test_y, pred_test_y) + print(pred_acc) + + plt.rcParams['font.sans-serif'] = ['SimHei'] + plt.rcParams['axes.unicode_minus'] = False + + plt.figure(figsize=(8, 4), dpi=80) + plt.plot(range(len(test_y)), test_y, ls='-.',lw=2,c='r',label='真实值') + plt.plot(range(len(pred_test_y)), pred_test_y, ls='-',lw=2,c='b',label='预测值') + + plt.grid(alpha=0.4, linestyle=':') + plt.legend() + plt.xlabel('number') + plt.ylabel('股价') + + plt.show() + + +if __name__ == '__main__': + #lstm_train('002221') + #cnn_train('002221') + #predict_nextday('002221') + #load_data('002221') + #lstm_train_all() + #lstm_train_300() + lstm_predict('002221') \ No newline at end of file -- Gitee From 5c0a8391df7806e1b458219906ee3861b9ecc3a3 Mon Sep 17 00:00:00 2001 From: Cooper Date: Sun, 5 Dec 2021 13:30:50 +0000 Subject: [PATCH 4/4] Add some images for test. --- image/explode.png | Bin 0 -> 5305 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 image/explode.png diff --git a/image/explode.png b/image/explode.png new file mode 100644 index 0000000000000000000000000000000000000000..1ea338e054611b3c3288cb969c4681f1cc04c9cf GIT binary patch literal 5305 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