【EDA】基于pygame的方块移动案例

import pygame
import random

# 初始化 Pygame
pygame.init()

# 游戏常量
SCREEN_SIZEX = 800
SCREEN_SIZEY = 800
GRID_SIZE = 40
FPS = 60
MACRO_COLORS = [
    (255, 102, 102),  # 红色 (尺寸1)
    (102, 178, 255),  # 蓝色 (尺寸2)
    (255, 178, 102),  # 橙色 (尺寸3)
    (102, 255, 178),  # 绿色 (尺寸4)
    (178, 102, 255)   # 紫色 (尺寸5)
]
MACRO_SIZES = [  # 五种基础尺寸(宽x高,单位:网格数)
    (3, 4),   # 尺寸1
    (2, 3),   # 尺寸2
    (1, 3),   # 尺寸3
    (1, 2),   # 尺寸4
    (2, 2)    # 尺寸5
]
MACRO_NUMS = [
    4, # 尺寸1
    8,  # 尺寸2
    6,  # 尺寸3
    8,  # 尺寸4
    8   # 尺寸5
]

class MacroUnit:
    existing_rects = []
    
    def __init__(self, size_type, color):
        self.size_type = size_type
        self.width = MACRO_SIZES[size_type][0] * GRID_SIZE
        self.height = MACRO_SIZES[size_type][1] * GRID_SIZE
        self.color = color
        self.x, self.y = self.generate_valid_position()
        self.selected = False
        self.offset_x = 0
        self.offset_y = 0

    def generate_valid_position(self, max_attempts=500):
        """生成不与其他宏单元重叠的位置"""
        for _ in range(max_attempts):
            x = random.randint(0, SCREEN_SIZEX - self.width)
            y = random.randint(0, SCREEN_SIZEY - self.height)
            new_rect = pygame.Rect(x, y, self.width, self.height)
            
            # 检查是否与已有位置重叠
            overlap = False
            for rect in MacroUnit.existing_rects:
                if new_rect.colliderect(rect):
                    overlap = True
                    break
            
            if not overlap:
                MacroUnit.existing_rects.append(new_rect)
                return x, y
        
        # 如果无法找到合适位置,返回随机位置
        return (random.randint(0, SCREEN_SIZEX - self.width),
                random.randint(0, SCREEN_SIZEY - self.height))

    def draw(self, surface):
        pygame.draw.rect(surface, self.color, 
                        (self.x, self.y, self.width, self.height))
        if self.selected:
            pygame.draw.rect(surface, (0,0,0), 
                            (self.x-2, self.y-2, self.width+4, self.height+4), 3)

    def check_click(self, mouse_pos):
        return (self.x <= mouse_pos[0] <= self.x + self.width and
                self.y <= mouse_pos[1] <= self.y + self.height)

    def move(self, dx, dy, macros):
        new_x = self.x + dx
        new_y = self.y + dy
        
        # 临时计算新位置
        temp_rect = pygame.Rect(new_x, new_y, self.width, self.height)
        
        # 边界检查
        if temp_rect.left < 0 or temp_rect.right > SCREEN_SIZEX:
            return
        if temp_rect.top < 0 or temp_rect.bottom > SCREEN_SIZEY:
            return
        
        # 碰撞检测
        for macro in macros:
            if macro is not self and temp_rect.colliderect(
                pygame.Rect(macro.x, macro.y, macro.width, macro.height)):
                return
        
        # 执行移动
        self.x = new_x
        self.y = new_y
     
    # 添加自动对齐功能
    def snap_to_grid(self):
        self.x = round(self.x / GRID_SIZE) * GRID_SIZE
        self.y = round(self.y / GRID_SIZE) * GRID_SIZE

class LayoutGame:
    def __init__(self):
        # 创建35个宏单元(每种尺寸7个)
        self.macros = []
        for size_type in range(5):
            color = MACRO_COLORS[size_type]
            for _ in range(MACRO_NUMS[size_type]):
                macro = MacroUnit(size_type, color)
                self.macros.append(macro)
        
        self.selected_macro = None
        self.running = True
        self.show_grid = True
        self.font = pygame.font.Font(None, 24)
        self.screen = pygame.display.set_mode((SCREEN_SIZEX+200, SCREEN_SIZEY))
        pygame.display.set_caption("宏单元布局游戏(35单元版)")

    def draw_grid(self):
        for x in range(0, SCREEN_SIZEX, GRID_SIZE):
            pygame.draw.line(self.screen, (200,200,200), (x,0), (x,SCREEN_SIZEX))
        for y in range(0, SCREEN_SIZEY, GRID_SIZE):
            pygame.draw.line(self.screen, (200,200,200), (0,y), (SCREEN_SIZEY,y))

    def draw_info_panel(self):
        # 绘制右侧信息面板
        pygame.draw.rect(self.screen, (220,220,220), 
                        (SCREEN_SIZEX, 0, SCREEN_SIZEX+200, SCREEN_SIZEY))
        
        # 统计各尺寸数量
        size_counts = {i:0 for i in range(5)}
        for macro in self.macros:
            size_counts[macro.size_type] += 1
        
        y = 20
        for size_type in range(5):
            text = self.font.render(
                f"size {size_type+1}: {size_counts[size_type]}",
                True, MACRO_COLORS[size_type])
            self.screen.blit(text, (SCREEN_SIZEX+10, y))
            y += 30

    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_q:
                    self.running = False
                elif event.key == pygame.K_g:
                    self.show_grid = not self.show_grid
                elif event.key == pygame.K_r:
                    self.reset_layout()

            if event.type == pygame.MOUSEBUTTONDOWN:
                for macro in reversed(self.macros):  # 优先选择上层元素
                    if macro.check_click(event.pos):
                        self.selected_macro = macro
                        macro.selected = True
                        macro.offset_x = event.pos[0] - macro.x
                        macro.offset_y = event.pos[1] - macro.y
                        # 将被选中的宏单元移到列表最后(显示在最上层)
                        self.macros.remove(macro)
                        self.macros.append(macro)
                        break

            if event.type == pygame.MOUSEBUTTONUP:
                if self.selected_macro:
                    self.selected_macro.selected = False
                    self.selected_macro = None

            if event.type == pygame.MOUSEMOTION and self.selected_macro:
                dx = (event.pos[0] - self.selected_macro.offset_x - 
                     self.selected_macro.x) * 0.5
                dy = (event.pos[1] - self.selected_macro.offset_y - 
                     self.selected_macro.y) * 0.5
                self.selected_macro.move(dx, dy, self.macros)
                
            # 在handle_events中添加快捷键
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_s:  # 按S键对齐到网格
                    for macro in self.macros:
                        macro.snap_to_grid()
                    
                    
                    

    def reset_layout(self):
        """重置所有宏单元位置"""
        self.macros = []
        for size_type in range(5):
            color = MACRO_COLORS[size_type]
            for _ in range(MACRO_NUMS[size_type]):
                macro = MacroUnit(size_type, color)
                self.macros.append(macro)

    def run(self):
        clock = pygame.time.Clock()
        while self.running:
            self.screen.fill((240, 240, 240))
            
            if self.show_grid:
                self.draw_grid()
            
            for macro in self.macros:
                macro.draw(self.screen)
            
            self.draw_info_panel()
            self.handle_events()
            
            pygame.display.flip()
            clock.tick(FPS)

if __name__ == "__main__":
    game = LayoutGame()
    game.run()
    pygame.quit()

运行示例:
在这里插入图片描述
按下s键后:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值