mini-ai/day2/main.py

459 lines
18 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# coding = utf-8
import pygame
import sys
import math
import random
from pygame.sprite import Sprite
from pygame.sprite import Group
from Shield import Shield
class Map:
def __init__(self, width, height, tile_size=40):
self.width = width
self.height = height
self.tile_size = tile_size
self.tiles = []
self.circle = [0, 0, 0, 0]
self.circle_r = 200
def render(self, screen):
colors = {
0: (242, 234, 211), # 浅色
1: (255, 0, 0), # 红色
2: (0, 0, 255) # 蓝色
}
for y in range(self.height):
for x in range(self.width):
tile_type = self.tiles[y][x]
tile_color = colors.get(tile_type, (255, 255, 255)) # 默认为白色
rect = pygame.Rect(x * self.tile_size, y *
self.tile_size, self.tile_size, self.tile_size)
pygame.draw.rect(screen, tile_color, rect)
# 画圆
# 如果全部为1
if self.circle[0] == 1 and self.circle[1] == 1 and self.circle[2] == 1 and self.circle[3] == 1:
pygame.draw.circle(screen, (0, 255, 0), (400, 300), self.circle_r)
else:
for i in range(4):
if self.circle[i] == 1:
# 从 90*i 开始画,画 90 度
pygame.draw.arc(screen, (255, 255, 255), (400 - self.circle_r, 300 - self.circle_r, self.circle_r * 2, self.circle_r * 2),
math.radians(90 * i), math.radians(90 * (i + 1)), 4)
# 画两个边
pygame.draw.line(screen, (255, 255, 255), (400, 300), (400 + self.circle_r * math.cos(math.radians(90 * i)),
300 - self.circle_r * math.sin(math.radians(90 * i))), 4)
pygame.draw.line(screen, (255, 255, 255), (400, 300), (400 + self.circle_r * math.cos(math.radians(90 * (i + 1))),
300 - self.circle_r * math.sin(math.radians(90 * (i + 1)))), 4)
def generate_map(self):
# 先生成一个空的二维数组
self.tiles = []
for y in range(self.height):
row = []
for x in range(self.width):
row.append(random.randint(-1, 1))
self.tiles.append(row)
for y in range(self.height):
for x in range(self.width):
self.tiles[y][x] = self.map_func(x, y)
def map_func(self, x, y):
neighbors_weights = [
self.get_tile_weight(x-1, y),
self.get_tile_weight(x+1, y),
self.get_tile_weight(x, y-1),
self.get_tile_weight(x, y+1)
]
weight_sum = sum(neighbors_weights)/4 + random.uniform(-0.3, 0.3)
tile_type = 0 # 默认为绿色
# 最外面一圈默认为红色
if x == 0 or y == 0 or x == self.width - 1 or y == self.height - 1:
tile_type = 1
# 每隔4个格子随机出现一个蓝色格子
elif random.random() < 0.01:
tile_type = 2
return tile_type
def get_tile_weight(self, x, y):
if x < 0 or y < 0 or x >= self.width or y >= self.height:
return 0 # 超出地图边界默认权重为0
return self.tiles[y][x]
class Bullet(pygame.sprite.Sprite):
def __init__(self, position, direction, color, owner, speed=8):
super().__init__()
# 使用SRCALPHA色彩格式创建Surface对象
self.image = pygame.Surface((16, 16), pygame.SRCALPHA)
self.image.fill(color)
# pygame.draw.line(self.image, (255, 255, 255), (0, 15), (32, 15), 4)
# pygame.draw.line(self.image, (255, 255, 255), (15, 0), (15, 32), 4)
self.rect = self.image.get_rect()
self.rect.center = position
self.direction = direction
self.speed = speed
self.owner = owner
self.collision_rect = pygame.Rect(
self.rect.x, self.rect.y, self.rect.width, self.rect.height)
def update(self):
dx = math.cos(math.radians(self.direction)) * self.speed
dy = -math.sin(math.radians(self.direction)) * self.speed
self.rect.x += dx
self.rect.y += dy
self.collision_rect.x = self.rect.x
self.collision_rect.y = self.rect.y
class Mysprite(Sprite):
def __init__(self, id, bot=False):
super().__init__()
if(bot):
self.mast_image = pygame.image.load('./assets/enemy.png')
else :
self.mast_image = pygame.image.load('./assets/cat.png') # 读取图像
self.original_image = self.mast_image.copy()
self.rect = self.mast_image.get_rect(height=32, width=32) # 获取图像矩形参数
self.frame_rect = self.rect.copy() # 声明框架参数
self.rect.x, self.rect.y = 400, 300
# self.frame_rect.width /= 1
# self.frame_rect.height /= 4
self.id = id
self.frame = 0
self.last_frame = (self.rect.height // self.frame_rect.height) - 1
self.old_frame = 1
self.last_time = 0
self.speed = 4
self.direction = 1
self.toword_angle = 0
self.hp = 10
self.move_directions = []
self.collision_rect = pygame.Rect(
self.rect.x, self.rect.y, self.rect.width, self.rect.height)
self.last_use_time = 0
self.click_move = False
self.click_move_x = 0
self.click_move_y = 0
self.bot = bot
self.cool_down = 500
self.hurt_time = 0
def update(self, current_time, rate=100):
if current_time >= self.last_time + rate:
self.frame += 1
if self.frame > self.last_frame:
self.frame = 0
self.last_time = current_time
if self.bot:
self.bot_update()
current_time = pygame.time.get_ticks()
if current_time - self.hurt_time < 100:
overlay = pygame.Surface(self.image.get_size())
overlay.fill((255, 0, 0, 25))
self.image.blit(overlay, (0, 0),
special_flags=pygame.BLEND_MULT)
else:
self.image = self.original_image.copy()
if self.old_frame != self.frame:
self.frame_rect.x = (self.frame // 4) * self.frame_rect.width
self.frame_rect.y = (self.frame % 4) * self.frame_rect.height
self.old_frame = self.frame
if self.direction == 1:
self.frame_rect.y = 0 # 向上
elif self.direction == 2:
self.frame_rect.y = self.frame_rect.height # 向下
elif self.direction == 3:
self.frame_rect.y = self.frame_rect.height * 2 # 向左
elif self.direction == 4:
self.frame_rect.y = self.frame_rect.height * 3 # 向右
self.updatemove()
self.image = self.mast_image.subsurface(self.frame_rect) # 这里就是在生成子表面
self.collision_rect.x = self.rect.x
self.collision_rect.y = self.rect.y
def attack(self):
# 发射子弹
# 随机生成一个颜色
color = (random.randint(0, 255), random.randint(
0, 255), random.randint(0, 255))
bullet = Bullet(self.rect.center, self.toword_angle, color, self)
bullet_group.add(bullet)
def bot_update(self):
# bot 的更新逻辑
# 随机移动
if random.random() < 0.05:
self.startmove(random.choice(['left', 'right', 'up', 'down']))
if random.random() < 0.1:
self.stopmove(random.choice(['left', 'right', 'up', 'down']))
if random.random() < 0.01:
self.attack()
if random.random() < 0.01:
self.flash()
def be_hit(self, attacker=None):
self.hp -= 1
self.hurt_time = pygame.time.get_ticks()
if self.hp <= 0:
if(attacker != None):
if(attacker.bot == False):
attacker.hp += 10
attacker.cool_down = max(0, attacker.cool_down - 25)
self.kill()
def updatemove(self):
dx = 0
dy = 0
if(self.click_move):
# 判断是否到达目标点
if(abs(self.rect.centerx - self.click_move_x) < 3 and abs(self.rect.centery - self.click_move_y) < 3):
self.click_move = False
else:
self.move(self.click_move_x - self.rect.centerx,
self.click_move_y - self.rect.centery)
return
if 'left' in self.move_directions:
dx -= 1
if 'right' in self.move_directions:
dx += 1
if 'up' in self.move_directions:
dy -= 1
if 'down' in self.move_directions:
dy += 1
self.move(dx, dy)
# 三角函数
def clickmove(self, x, y):
self.click_move = True
self.click_move_x = x
self.click_move_y = y
def move(self, dx, dy):
if dx != 0 or dy != 0:
angle = math.atan2(-dy, dx)
self.rect.x += self.speed * math.cos(angle)
if(self.rect.x < 0):
self.rect.x = 0
elif(self.rect.x + self.rect.width > 800):
self.rect.x = 800 - self.rect.width
self.rect.y -= self.speed * math.sin(angle)
if(self.rect.y < 0):
self.rect.y = 0
elif(self.rect.y + self.rect.height > 600):
self.rect.y = 600 - self.rect.height
# 判断是否和其他玩家碰撞
for player in group.sprites():
if player.id != self.id:
if self.collision_rect.colliderect(player.collision_rect):
self.rect.x -= self.speed * math.cos(angle)
self.rect.y += self.speed * math.sin(angle)
self.resetmove()
break
for enemy in enemy_group.sprites():
if self.collision_rect.colliderect(enemy.collision_rect):
self.rect.x -= self.speed * math.cos(angle)
self.rect.y += self.speed * math.sin(angle)
self.resetmove()
break
self.toword_angle = math.degrees(angle)
if(dy < 0):
self.direction = 4
elif(dy > 0):
self.direction = 1
if(dx < 0):
self.direction = 2
elif(dx > 0):
self.direction = 3
def resetmove(self):
self.move_directions = []
def startmove(self, direction):
self.click_move = False
self.move_directions.append(direction)
def stopmove(self, direction):
if direction in self.move_directions:
self.move_directions.remove(direction)
def flash(self):
if pygame.time.get_ticks() - self.last_use_time < self.cool_down:
return
self.last_use_time = pygame.time.get_ticks()
for i in range(4):
color = (random.randint(0, 255), random.randint(
0, 255), random.randint(0, 255))
bullet = Bullet(self.rect.center,
self.toword_angle + i * 30 - 45, color, self, 16)
bullet_group.add(bullet)
pygame.init()
font = pygame.font.Font("./assets/MineCraft.ttf", 24)
screen = pygame.display.set_mode((800, 600))
color = (255, 255, 255)
tick = pygame.time.Clock() # 第一行初始化了一个Clock对象
player1 = Mysprite(1)
player2 = Mysprite(2)
group = Group()
bullet_group = Group()
shields = pygame.sprite.Group()
shield1 = Shield(player1)
shield2 = Shield(player2)
shields.add(shield1)
shields.add(shield2)
group.add(player1)
group.add(player2)
player1.rect.center = (200, 300)
player2.rect.center = (600, 300)
enemy_group = pygame.sprite.Group()
enemy_timer_interval = 5000
enemy_timer_event = pygame.USEREVENT + 1
pygame.time.set_timer(enemy_timer_event, enemy_timer_interval)
map_tile_size = 8
map_width = screen.get_width() // map_tile_size
map_height = screen.get_height() // map_tile_size
map_obj = Map(map_width, map_height, map_tile_size)
map_obj.generate_map()
while True:
tick.tick(60) # 给tick方法加上的参数就成为了游戏绘制的最大帧率
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN: # 键盘事件
if player1 in group:
if event.key == pygame.K_a:
player1.startmove('left')
elif event.key == pygame.K_d:
player1.startmove('right')
elif event.key == pygame.K_w:
player1.startmove('up')
elif event.key == pygame.K_s:
player1.startmove('down')
elif event.key == pygame.K_v:
player1.attack()
elif event.key == pygame.K_b:
player1.flash()
if player2 in group:
if event.key == pygame.K_LEFT:
player2.startmove('left')
elif event.key == pygame.K_RIGHT:
player2.startmove('right')
elif event.key == pygame.K_UP:
player2.startmove('up')
elif event.key == pygame.K_DOWN:
player2.startmove('down')
elif event.key == pygame.K_COMMA:
player2.attack()
elif event.key == pygame.K_PERIOD:
player2.flash()
elif event.key == pygame.K_1:
map_obj.circle[0] = 1 - map_obj.circle[0]
elif event.key == pygame.K_2:
map_obj.circle[1] = 1 - map_obj.circle[1]
elif event.key == pygame.K_3:
map_obj.circle[2] = 1 - map_obj.circle[2]
elif event.key == pygame.K_4:
map_obj.circle[3] = 1 - map_obj.circle[3]
elif event.type == pygame.KEYUP:
if player1 in group:
if event.key == pygame.K_a:
player1.stopmove('left')
elif event.key == pygame.K_d:
player1.stopmove('right')
elif event.key == pygame.K_w:
player1.stopmove('up')
elif event.key == pygame.K_s:
player1.stopmove('down')
if player2 in group:
if event.key == pygame.K_LEFT:
player2.stopmove('left')
elif event.key == pygame.K_RIGHT:
player2.stopmove('right')
elif event.key == pygame.K_UP:
player2.stopmove('up')
elif event.key == pygame.K_DOWN:
player2.stopmove('down')
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
player1.clickmove(event.pos[0], event.pos[1])
elif event.button == 3:
player2.clickmove(event.pos[0], event.pos[1])
if event.type == enemy_timer_event:
enemy = Mysprite(len(enemy_group.sprites()) + 3, True)
enemy.rect.center = (random.randint(0, 800),
random.randint(0, 600))
enemy_group.add(enemy)
screen.fill(color)
ticks = pygame.time.get_ticks()
map_obj.render(screen)
group.update(ticks)
bullet_group.update()
enemy_group.update(ticks)
# shields.update()
group.draw(screen)
bullet_group.draw(screen)
enemy_group.draw(screen)
# shields.draw(screen)
if player1 in group:
if player1.hp > 0:
# 左上角血量显示
player1_hp_text = font.render(
"HP " + str(player1.hp), True, (0, 0, 0))
screen.blit(player1_hp_text, (10, 10))
# 下面是技能冷却时间显示,显示一个条形,总宽度 100px
if pygame.time.get_ticks() - player1.last_use_time < 500:
pygame.draw.rect(screen, (255, 255, 0), (10, 30, 100, 10))
# 从左向右
pygame.draw.rect(screen, (0, 128, 255), (10, 30, (pygame.time.get_ticks() -
player1.last_use_time) / 5, 10))
else:
pygame.draw.rect(screen, (0, 128, 255), (10, 30, 100, 10))
if player2 in group:
if player2.hp > 0:
# 右上角血量显示
player2_hp_text = font.render(
"HP " + str(player2.hp), True, (0, 0, 0))
hp_text_width = player2_hp_text.get_width()
screen.blit(player2_hp_text,
(screen.get_width() - hp_text_width - 10, 10))
# 下面是技能冷却时间显示,显示一个条形,总宽度 100px
if pygame.time.get_ticks() - player2.last_use_time < 500:
pygame.draw.rect(screen, (255, 255, 0),
(screen.get_width() - 110, 30, 100, 10))
# 从右向左
pygame.draw.rect(screen, (0, 128, 255), (screen.get_width() - 110 + 100 - (pygame.time.get_ticks() -
player2.last_use_time) / 5, 30, (pygame.time.get_ticks() - player2.last_use_time) / 5, 10))
else:
pygame.draw.rect(screen, (0, 128, 255),
(screen.get_width() - 110, 30, 100, 10))
for bullet in bullet_group.sprites():
for player in group.sprites():
if bullet.collision_rect.colliderect(player.collision_rect) and bullet.owner.id != player.id:
player.be_hit()
bullet.kill()
for enemy in enemy_group.sprites():
if bullet.collision_rect.colliderect(enemy.collision_rect) and bullet.owner.bot != True:
enemy.be_hit(bullet.owner)
bullet.kill()
pygame.display.update()
pygame.event.pump()