459 lines
18 KiB
Python
459 lines
18 KiB
Python
# 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()
|