Python 旋转立方体

news2024/11/26 4:24:07

文章目录

  • 效果图
  • 运行环境
  • 完整代码
  • 实现思路
    • 1. 导入库和定义常量
    • 2. 创建Cube类
    • 3. 实现Cube类的draw方法
    • 4. 实现主函数


效果图

请添加图片描述

运行环境

python版本:python3.x

依赖包:

$ pip install pygame
$ pip install numpy

完整代码

import numpy as np  # 导入 NumPy 库,用于数值计算和处理多维数组
import pygame  # 导入 Pygame 库,用于游戏开发和图形界面设计

# 定义屏幕的宽度和高度
WIDTH = 800
HEIGHT = 800

# 定义颜色常量
BLACK = (0, 0, 0)  # 黑色
WHITE = (255, 255, 255)  # 白色


class Cube:
    """
    表示一个立方体。
    """

    def __init__(self, pos: np.ndarray, a: float) -> None:
        """
        初始化立方体。
        :param pos: 立方体的中心位置,是一个包含三个元素的 NumPy 数组。
        :param a: 立方体的边长。
        """
        self.pos = pos  # 立方体的中心位置
        self.angle = np.pi / 4  # 立方体的旋转角度,初始化为 45 度
        self.center_offset = np.array([-a / 2, -a / 2, -a / 2])  # 立方体顶点到中心的偏移量
        self.edges = np.array([  # 立方体的边,是一个包含 12 条边的数组
            # 前脸的四条边
            np.array([np.array([0, 0, 0]), np.array([a, 0, 0])]),
            np.array([np.array([a, 0, 0]), np.array([a, a, 0])]),
            np.array([np.array([a, a, 0]), np.array([0, a, 0])]),
            np.array([np.array([0, a, 0]), np.array([0, 0, 0])]),
            # 右脸的四条边
            np.array([np.array([0, 0, 0]), np.array([0, 0, a])]),
            np.array([np.array([a, a, 0]), np.array([a, a, a])]),
            np.array([np.array([a, 0, 0]), np.array([a, 0, a])]),
            np.array([np.array([0, a, 0]), np.array([0, a, a])]),
            # 上脸的四条边
            np.array([np.array([0, 0, a]), np.array([a, 0, a])]),
            np.array([np.array([a, 0, a]), np.array([a, a, a])]),
            np.array([np.array([a, a, a]), np.array([0, a, a])]),
            np.array([np.array([0, a, a]), np.array([0, 0, a])]),
        ])

    def draw(self, screen: pygame.surface.Surface, rotation_rate: float) -> None:
        """
        在屏幕上绘制立方体。
        :param screen: 要绘制立方体的 Pygame 屏幕对象。
        :param rotation_rate: 立方体的旋转速率,用于控制立方体旋转的速度。
        """
        # 将立方体的边加上中心偏移量,得到实际的顶点位置
        rotated_cube = np.add(self.edges, self.center_offset)

        # 计算绕 X、Y、Z 轴旋转的矩阵
        rotation_matrix_x = np.array([
            [1, 0, 0],
            [0, np.cos(self.angle), -np.sin(self.angle)],
            [0, np.sin(self.angle), np.cos(self.angle)]
        ])
        rotation_matrix_y = np.array([
            [np.cos(self.angle), 0, np.sin(self.angle)],
            [0, 1, 0],
            [-np.sin(self.angle), 0, np.cos(self.angle)]
        ])
        rotation_matrix_z = np.array([
            [np.cos(self.angle), -np.sin(self.angle), 0],
            [np.sin(self.angle), np.cos(self.angle), 0],
            [0, 0, 1],
        ])

        # 对立方体进行旋转
        rotated_cube = np.matmul(rotated_cube, rotation_matrix_x)
        rotated_cube = np.matmul(rotated_cube, rotation_matrix_y)
        rotated_cube = np.matmul(rotated_cube, rotation_matrix_z)

        # 将旋转后的立方体移动到正确的位置
        moved_cube = np.add(self.pos, rotated_cube)

        # 在屏幕上绘制立方体的边
        for edge in moved_cube:
            # 获取边的两个端点的屏幕坐标
            start_pos = edge[0][0:2]
            end_pos = edge[1][0:2]
            # 绘制边
            pygame.draw.line(screen, WHITE, start_pos, end_pos)

        # 更新立方体的旋转角度
        self.angle += rotation_rate


def main():
    """
    主函数,启动 Pygame 并创建旋转的立方体。
    """
    # 初始化 Pygame
    pygame.init()
    # 创建屏幕对象
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    # 设置窗口标题
    pygame.display.set_caption("旋转立方体 By stormsha")
    # 创建立方体对象,中心位于 (400, 400, 200),边长为 200
    cube = Cube(np.array([400, 400, 200]), 200)

    # 主循环
    running = True
    while running:
        # 处理 Pygame 事件,如关闭窗口等
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

        # 清空屏幕
        screen.fill(BLACK)
        # 绘制立方体
        cube.draw(screen, 0.001)
        # 更新屏幕
        pygame.display.flip()


if __name__ == "__main__":
    # 如果脚本被直接运行,则执行主函数
    main()

实现思路

使用Pygame和NumPy创建旋转立方体

在这篇文章中,我们将详细介绍如何使用Python的Pygame库和NumPy库创建一个旋转的立方体。我们将逐步讲解代码的实现思路,并解释关键部分的作用。

1. 导入库和定义常量

首先,我们需要导入所需的库,包括NumPy和Pygame。NumPy库用于数值计算和处理多维数组,而Pygame库用于游戏开发和图形界面设计。

import numpy as np  # 导入 NumPy 库,用于数值计算和处理多维数组
import pygame  # 导入 Pygame 库,用于游戏开发和图形界面设计

# 定义屏幕的宽度和高度
WIDTH = 800
HEIGHT = 800

# 定义颜色常量
BLACK = (0, 0, 0)  # 黑色
WHITE = (255, 255, 255)  # 白色

2. 创建Cube类

接下来,我们创建一个名为Cube的类,用于表示立方体。在Cube类的构造函数中,我们初始化立方体的中心位置、旋转角度和边长。

class Cube:
    """
    表示一个立方体。
    """

    def __init__(self, pos: np.ndarray, a: float) -> None:
        """
        初始化立方体。
        :param pos: 立方体的中心位置,是一个包含三个元素的 NumPy 数组。
        :param a: 立方体的边长。
        """
        self.pos = pos  # 立方体的中心位置
        self.angle = np.pi / 4  # 立方体的旋转角度,初始化为 45 度
        self.center_offset = np.array([-a / 2, -a / 2, -a / 2])  # 立方体顶点到中心的偏移量
        self.edges = np.array([  # 立方体的边,是一个包含 12 条边的数组
            # 前脸的四条边
            np.array([np.array([0, 0, 0]), np.array([a, 0, 0])]),
            np.array([np.array([a, 0, 0]), np.array([a, a, 0])]),
            np.array([np.array([a, a, 0]), np.array([0, a, 0])]),
            np.array([np.array([0, a, 0]), np.array([0, 0, 0])]),
            # 右脸的四条边
            np.array([np.array([0, 0, 0]), np.array([0, 0, a])]),
            np.array([np.array([a, a, 0]), np.array([a, a, a])]),
            np.array([np.array([a, 0, 0]), np.array([a, 0, a])]),
            np.array([np.array([0, a, 0]), np.array([0, a, a])]),
            # 上脸的四条边
            np.array([np.array([0, 0, a]), np.array([a, 0, a])]),
            np.array([np.array([a, 0, a]), np.array([a, a, a])]),
            np.array([np.array([a, a, a]), np.array([0, a, a])]),
            np.array([np.array([0, a, a]), np.array([0, 0, a])]),
        ])

在上面的代码中,我们定义了立方体的12条边,包括前脸、右脸和上脸的边。每条边由两个顶点组成,使用NumPy的数组表示。

3. 实现Cube类的draw方法

接下来,我们实现Cube类的draw方法,用于在屏幕上绘制立方体。在draw方法中,我们首先将立方体的边加上中心偏移量,得到实际的顶点位置。然后,我们计算绕X、Y、Z轴旋转的矩阵,并对立方体进行旋转。最后,我们将旋转后的立方体移动到正确的位置,并在屏幕上绘制立方体的边。

def draw(self, screen: pygame.surface.Surface, rotation_rate: float) -> None:
        """
        在屏幕上绘制立方体。
        :param screen: 要绘制立方体的 Pygame 屏幕对象。
        :param rotation_rate: 立方体的旋转速率,用于控制立方体旋转的速度。
        """
        # 将立方体的边加上中心偏移量,得到实际的顶点位置
        rotated_cube = np.add(self.edges, self.center_offset)

        # 计算绕 X、Y、Z 轴旋转的矩阵
        rotation_matrix_x = np.array([
            [1, 0, 0],
            [0, np.cos(self.angle), -np.sin(self.angle)],
            [0, np.sin(self.angle), np.cos(self.angle)]
        ])
        rotation_matrix_y = np.array([
            [np.cos(self.angle), 0, np.sin(self.angle)],
            [0, 1, 0],
            [-np.sin(self.angle), 0, np.cos(self.angle)]
        ])
        rotation_matrix_z = np.array([
            [np.cos(self.angle), -np.sin(self.angle), 0],
            [np.sin(self.angle), np.cos(self.angle), 0],
            [0, 0, 1],
        ])

        # 对立方体进行旋转
        rotated_cube = np.matmul(rotated_cube, rotation_matrix_x)
        rotated_cube = np.matmul(rotated_cube, rotation_matrix_y)
        rotated_cube = np.matmul(rotated_cube, rotation_matrix_z)

        # 将旋转后的立方体移动到正确的位置
        moved_cube = np.add(self.pos, rotated_cube)

        # 在屏幕上绘制立方体的边
        for edge in moved_cube:
            # 获取边的两个端点的屏幕坐标
            start_pos = edge[0][0:2]
            end_pos = edge[1][0:2]
            # 绘制边
            pygame.draw.line(screen, WHITE, start_pos, end_pos)

        # 更新立方体的旋转角度
        self.angle += rotation_rate

在上面的代码中,我们使用NumPy的matmul函数进行矩阵乘法,以实现立方体的旋转。然后,我们使用pygame的draw.line函数在屏幕上绘制立方体的边。

4. 实现主函数

最后,我们实现主函数main,用于启动Pygame并创建旋转的立方体。在主函数中,我们首先初始化Pygame,并创建屏幕对象。然后,我们创建一个Cube对象,并进入主循环。在主循环中,我们处理Pygame事件,清空屏幕,绘制立方体,并更新屏幕。

def main():
    """
    主函数,启动 Pygame 并创建旋转的立方体。
    """
    # 初始化 Pygame
    pygame.init()
    # 创建屏幕对象
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    # 设置窗口标题
    pygame.display.set_caption("旋转立方体 By stormsha")
    # 创建立方体对象,中心位于 (400, 400, 200),边长为 200
    cube = Cube(np.array([400, 400, 200]), 200)

    # 主循环
    running = True
    while running:
        # 处理 Pygame 事件,如关闭窗口等
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

        # 清空屏幕
        screen.fill(BLACK)
        # 绘制立方体
        cube.draw(screen, 0.001)
        # 更新屏幕
        pygame.display.flip()

if __name__ == "__main__":
    # 如果脚本被直接运行,则执行主函数
    main()

在上面的代码中,我们使用pygame的event.get函数获取事件,并判断是否为关闭窗口事件。如果是关闭窗口事件,则退出主循环。然后,我们使用screen.fill函数清空屏幕,并使用cube.draw函数绘制立方体。最后,我们使用pygame的display.flip函数更新屏幕。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1669390.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【YOLOv8模型网络结构图理解】

YOLOv8模型网络结构图理解 1 YOLOv8的yaml配置文件2 YOLOv8网络结构2.1 Conv2.2 C3与C2f2.3 SPPF2.4 Upsample2.5 Detect层 1 YOLOv8的yaml配置文件 YOLOv8的配置文件定义了模型的关键参数和结构,包括类别数、模型尺寸、骨干(backbone)和头部…

单调栈问题

原理 单调栈的核心原理是:在栈内保持元素的单调性(递增或递减) 单调递增栈: 用于处理“下一个更小的元素”问题。当新元素比栈顶元素小或等于时,直接入栈;否则,一直从栈顶弹出元素&#xff0c…

会声会影2024中文汉化补丁器附免费激活码序列号

会声会影是一款由加拿大Corel公司发布的视频编辑软件,它以其功能丰富和用户友好的界面而闻名。会声会影2024是该系列的最新版本,它不仅继承了之前版本的强大功能,还引入了一系列新的特性和工具,使得视频编辑更加简单、高效且富有创…

【简单讲解下Fine-tuning BERT】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…

【图解计算机网络】TCP 重传、滑动窗口、流量控制、拥塞控制

TCP 重传、滑动窗口、流量控制、拥塞控制 TCP 重传超时重传快速重传 滑动窗口流量控制拥塞控制慢启动拥塞避免拥塞发生快速恢复 TCP 重传 TCP重传是当发送的报文发生丢失的时候,重新发送丢失报文的一种机制,它是保证TCP协议可靠性的一种机制。 TCP重传…

【Oracle篇】rman物理备份工具的基础理论概述(第一篇,总共八篇)

☘️博主介绍☘️: ✨又是一天没白过,我是奈斯,DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux,也在扩展大数据方向的知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&am…

试衣不再有界:Tunnel Try-on开启视频试衣应用新纪元

论文:https://arxiv.org/pdf/2404.17571 主页:https://mengtingchen.github.io/tunnel-try-on-page/ 一、摘要总结 随着虚拟试衣技术的发展,消费者和时尚行业对于能够在视频中实现高质量虚拟试衣的需求日益增长。这项技术允许用户在不实际穿…

云计算十三课

centos安装 点击左上角文件 点击新建虚拟机 点击下一步 点击稍后安装操作系统,下一步 选择Linux(l)下一步 设置虚拟机名称 点击浏览选择安装位置 新建文件夹设置名称不能为中文,点击确定 点击下一步 设置磁盘大小点击下一步…

修改MTU值解决Linux下运行top命令卡死问题

上周明月的Linux服务器上运行top命令总是莫名的出现卡死现象,甚至是CtrlC都无法终止进程,今天终于抽空找到了解决办法,原来是需要修改Linux的MTU值,将服务器操作系统数据包调小,加上VxLAN数据包小于1500即可。 top命令…

HCIP【BGP综合实验】

目录 一、实验拓扑图: 二、实验要求: 三、实验思路: 四、实验步骤: 1、进行网段的子网划分(整个实验总共有19条网段): (1)首先,根据实验要求,将172.16.0.0/16全部划…

英伟达发布AM-RADIO高效视觉基础模型,推理速度提升6倍,性能超CLIP、DINOv2、SAM

前言 近年来,视觉基础模型 (VFM) 在众多下游任务中取得了巨大成功,例如图像分类、目标检测和图像生成等。然而,现有的 VFM 通常专注于特定领域,例如 CLIP 擅长零样本视觉语言理解,DINOv2 擅长语义分割,SAM…

C控制语句:分支和跳转

1.1if语句 //colddays.c --找出0摄氏度以下的天数占总天数的百分比 #include <stdio.h>int main(void) {const int FREEZING 0;float temperature;int cold_days 0;int all_days 0;printf("Enter the list of daily low temperature.\n");printf("Use…

C++内存管理new/delete和new[ ]/delete[ ]

1.c/c内存分布 首先看一段代码 int globalVar 1; static int staticGlobalVar 1; void Test() { static int staticVar 1; int localVar 1; int num1[10] { 1, 2, 3, 4 }; char char2[] "abcd";const char* pChar3 "abcd"; //这里不加const会导致…

整理好的宁夏光伏发电数据集(2007-2020年)

1、包含指标&#xff1a;采样结束时刻、采样起始时刻、时间间隔、气温、方位角、云层不透明度、露点温度、DHI&#xff08;太阳散射辐射指数&#xff09;、DNI&#xff08;太阳直接辐射指数&#xff09;、GHI&#xff08;太阳总水平辐射&#xff09;、GTI&#xff08;固定倾角辐…

06-Fortran基础--Fortran模块化编程

06-Fortran基础--Fortran模块化编程 1 模块的定义和使用2 接口和模块间通信3 模块化编程的优势&#xff1a;4 模块使用示例5 结语 Fortran的模块化编程是一种组织和管理代码的方法&#xff0c;它包括模块的定义和使用、接口和模块间通信以及模块化编程的优势。 1 模块的定义和…

外网如何访问内网?快解析

由于公网IP资源短缺&#xff0c;我们的电脑大多处于内网环境&#xff0c;如何在外网访问内网电脑&#xff0c;成为一个令人头疼的问题&#xff0c;下面我给大家推荐一个非常实用的方法。 1&#xff1a;访问快解析下载安装快解析服务器 2&#xff1a;运行软件&#xff0c;点击“…

匿名管道及其应用

目录 一、什么是匿名管道&#xff1f; 三、创建与使用匿名管道 三、匿名管道的特点 匿名管道的四种情况 匿名管道的五种特性 四、匿名管道的实践应用---进程池 在编程的世界中&#xff0c;匿名管道是一种非常重要的通信机制。今天&#xff0c;让我们一起来深入探讨一下匿…

Spring WebFlux-响应式编程-019

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace The Nex…

Redis-发布与订阅

发布与订阅 什么是发布与订阅 Redis 发布订阅 (pub/sub) 是一种消息通信模式&#xff1a;发送者 (pub) 发送消息&#xff0c;订阅者 (sub) 接收消息。 Redis 客户端可以订阅任意数量的频道。 Redis的发布与订阅 客户端订阅频道 当给这个频道发送消息后&#xff0c;消息就会…

Java | Leetcode Java题解之第86题分隔链表

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode partition(ListNode head, int x) {ListNode small new ListNode(0);ListNode smallHead small;ListNode large new ListNode(0);ListNode largeHead large;while (head ! null) {if (head.val < x…