鱼C论坛

 找回密码
 立即注册
查看: 1736|回复: 0

[作品展示] 非常无聊的作品:怎么把pygame的过程录制到mp4

[复制链接]
发表于 2020-6-23 12:03:51 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
首先,用的是cv2模块,也就是没有音频,只是动画,不过mp4压缩比大,体积小,windows支持自动播放(比如flash格式flv是不支持的)。
所谓录制,就是一帧一帧图像写入video,想想很简单,不过有个数据接口问题,代码如下(插入到pygame的刷新一帧函数的结束部分即可):
    def printAll(self):
        #。。。。。。。pygame表示各种物体代码块
        if CMG.step == 1:
            fps = 12
            size = (800,570)
            file_path = r"C:\Users\Administrator\Desktop\aa1" + str(int(time.time())) + ".mp4v"#导出路径
            fourcc = cv2.VideoWriter_fourcc('I','4','2','0')#不同视频编码对应不同视频格式(例:'I','4','2','0' 对应avi格式)
            CMG.video = cv2.VideoWriter( file_path, fourcc, fps, size )
        else:
            imagestring = pygame.image.tostring(CMG.screen.subsurface(0,0,800,570),"RGB")
            pilImage = Image.frombytes("RGB", (800,570), imagestring)
            img = cv2.cvtColor(numpy.asarray(pilImage),cv2.COLOR_RGB2BGR)
            
            CMG.video.write(img)        #把图片写进视频
            if CMG.step == len(CMG.gameAnswer)+1:
                CMG.video.release() #释放

完整例子代码(解迷宫过程录制成mp4)
import pygame
import sys
import os
import random
import time
from pygame.locals import *
import tkinter as tk
from tkinter import *
import tkinter.messagebox  # 要使用messagebox先要导入模块
import cv2
import numpy
from PIL import Image, ImageDraw
from PIL import ImageFont


class Maze:
    size = None
    print_str=(('##','  '),('#',' '))
    map = None
    direct = ((-2,0),(2,0),(0,2),(0,-2),(-2,0),(2,0),(0,2))

    @staticmethod
    def check_move(map,yx):
        for d in range(0,4):
            if(map[yx[0]+Maze.direct[d][0]][yx[1]+Maze.direct[d][1]] == 0):
                return True
        return False
    @staticmethod
    def create_maze(size_para):
        WAY = 1
        size=[size_para[0]*2+3,size_para[1]*2+3]
        Maze.size = size
        direct = Maze.direct
        center=[random.randint(1,size[0]-1)//2*2,random.randint(1,size[1]-1)//2*2]
        map= [[100]*size[1] for i in range(size[0])]
        for y in range(size_para[0]):
            for x in range(size_para[1]):
                map[2*y+2][2*x+2] = 0
        step0_nodes = [center]
        map[center[0]][center[1]] = WAY
        step1_nodes = []

        while len(step0_nodes) > 0:
            node_no = random.randint(0,len(step0_nodes)-1)
            yx= step0_nodes[node_no]
            if not Maze.check_move(map,yx):
                step0_nodes.pop(node_no)
                continue
            direct_start = random.randint(0,3)
            for d in range(direct_start,direct_start+4):
                y=yx[0]+direct[d][0]
                x=yx[1]+direct[d][1]
                if(map[y][x] == 0):
                    step1_nodes.append((y,x))
                    map[yx[0]+direct[d][0]//2][yx[1]+direct[d][1]//2] = WAY
                    map[y][x] = WAY
                    break
            step0_nodes.extend(step1_nodes)
            step1_nodes.clear()
        Maze.map = map

    @staticmethod
    def solve_maze(startY,endYX):
        WAY = 1
        direct = Maze.direct
        center=(startY*2+2,2,-1)
        map = Maze.map
        steps_nodes = []
        step0_nodes = [center]
        map[center[0]][center[1]] = 0
        step1_nodes = []

        while len(step0_nodes) > 0:
            steps_nodes.append(step0_nodes)
            for n in range(0,len(step0_nodes)):
                yx= step0_nodes[n]
                for d in range(0,4):
                    y=yx[0]+direct[d][0]
                    x=yx[1]+direct[d][1]
                    y3=yx[0]+direct[d][0]//2
                    x3=yx[1]+direct[d][1]//2
                    if(map[y3][x3] != 100 and map[y][x] == WAY ):
                        step1_nodes.append((y,x,n))
                        map[yx[0]+direct[d][0]][yx[1]+direct[d][1]] = 0
                        if y == endYX[0]*2 and x== endYX[1]*2:
                            steps_nodes.append(step1_nodes)
                            return steps_nodes
            step0_nodes = step1_nodes[:]
            step1_nodes.clear()
        return None

class CMG: #画面显示管理
    screen = None
    map = None
    gameAnswer = None
    WHITE = (255, 255, 255)
    GREEN = (0, 255, 0)
    RED = (255, 0, 0)
    BLUE = (0, 0, 255)
    blocksize = 0
    step = 0
    back_ground = None

    def __init__(self,screen,map,gameAnswer):
        if CMG.screen == None:
            #print("#############OS.PATH=%s"% os.path.dirname(os.path.abspath(__file__)))
            CMG.screen = screen
            CMG.map = map
            CMG.gameAnswer = gameAnswer
            if 800//len(map[0]) > 570//len(map):
                CMG.blocksize = 570//len(map)
            else:
                CMG.blocksize = 800//len(map[0])
        #如果存在对象成员
        self.init_game_info()

    def init_game_info(self):
        pass

    def printAll(self):
        if CMG.step > len(CMG.gameAnswer):
            return
        CMG.screen.fill((0, 0, 0))
        size = Maze.size
        if CMG.back_ground == None:
            for y in range(1,size[0]-1):
                for x in range(1,size[1]-1):
                    val = CMG.map[y][x]
                    if y%2==1 and x%2==0 and val == 100:
                        #start_pos = [(y*CMG.blocksize,x*CMG.blocksize)]
                        end_pos = [((x-1)*CMG.blocksize,y*CMG.blocksize),((x+1)*CMG.blocksize,y*CMG.blocksize)]
                        pygame.draw.lines(CMG.screen, CMG.GREEN,0 , end_pos, 2)
                    elif y%2==0 and x%2==1 and val == 100:
                        end_pos = [(x*CMG.blocksize,(y-1)*CMG.blocksize),(x*CMG.blocksize,(y+1)*CMG.blocksize)]
                        pygame.draw.lines(CMG.screen, CMG.GREEN,0 , end_pos, 2)
            select_rect = CMG.screen.subsurface(0,0,800,570)
            CMG.back_ground = select_rect.copy()
        else:
            self.screen.blit(CMG.back_ground,(0,0))
        if CMG.step == len(CMG.gameAnswer):
            step = CMG.step - 1
            step_node = CMG.gameAnswer[step]
            yx = step_node[len(step_node)-1]
            while(yx[2]!=-1):
                y = yx[0]
                x = yx[1]
                step -= 1
                step_node = CMG.gameAnswer[step]
                yx = step_node[yx[2]]
                pygame.draw.rect(CMG.screen, CMG.WHITE, (((x-1)*CMG.blocksize+2,(y-1)*CMG.blocksize+2), (CMG.blocksize*2-4, CMG.blocksize*2-4)), 0)
        else:
            step_node = CMG.gameAnswer[CMG.step]
            for s in range(0,len(step_node)):
                yx = step_node[s]
                y = yx[0]
                x = yx[1]
                #pygame.draw.rect(background, (0, 255, 0), ((200, 5), (100, 100)), 3)
                pygame.draw.rect(CMG.screen, CMG.WHITE, (((x-1)*CMG.blocksize+2,(y-1)*CMG.blocksize+2), (CMG.blocksize*2-4, CMG.blocksize*2-4)), 0)

        CMG.step += 1
        
        if CMG.step == 1:
            fps = 12
            size = (800,570)
            file_path = r"C:\Users\Administrator\Desktop\aa1" + str(int(time.time())) + ".mp4v"#导出路径
            fourcc = cv2.VideoWriter_fourcc('I','4','2','0')#不同视频编码对应不同视频格式(例:'I','4','2','0' 对应avi格式)
            CMG.video = cv2.VideoWriter( file_path, fourcc, fps, size )
        else:
            imagestring = pygame.image.tostring(CMG.screen.subsurface(0,0,800,570),"RGB")
            pilImage = Image.frombytes("RGB", (800,570), imagestring)
            img = cv2.cvtColor(numpy.asarray(pilImage),cv2.COLOR_RGB2BGR)
            
            CMG.video.write(img)        #把图片写进视频
            if CMG.step == len(CMG.gameAnswer)+1:
                CMG.video.release() #释放
        

    def moveAll(self):
        pass

#------------------------------------------------
#tkinter,pygame混合区 START
#------------------------------------------------
root = tk.Tk()
root.resizable(0,0)

embed = tk.Frame(root, width = 800, height = 570) #creates embed frame for pygame window
embed.grid(columnspan = (800), rowspan = 730) # Adds grid
embed.pack(side = TOP) #packs window to the left

buttonwin = tk.Frame(root, width = 800, height = 150)
buttonwin.pack(side = BOTTOM)

os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
os.environ['SDL_VIDEODRIVER'] = 'windib'

screen = pygame.display.set_mode((800,570))

#pygame.init()
pygame.display.init()
pygame.mixer.init()
#------------------------------------------------
#tkinter,pygame混合区 END
#------------------------------------------------

#参数,因为函数内要使用之外的变量,需要globe,因此全部打包
class PARAM:
    STATUS = 0
    TICK_NORMAL = 5

#按钮动作区 =====================================
def exit_game():
    global param
    param.STATUS = 100
#控件定义区 =====================================
button_exit_b = Button(buttonwin,text = '退出画面', width=7, command=exit_game)
button_exit_b.place(x=740,y=100)


#状态,参数,循环中使用,比如STATUS=0:初次进入,1:...100:退出
param = PARAM()
Maze.create_maze([50,70])
steps_nodes = Maze.solve_maze(0,(49,69))
param.cmg = CMG(screen,Maze.map,steps_nodes)
#------------------------------------------------
#主函数,使用pygame框架,无限LOOP对各种事件然后相应处理
#------------------------------------------------
def main():
    global param
    #pygame.mixer.music.play(-1)
    clock = pygame.time.Clock()

    while True:
        #这段event代码是必须的,哪怕在这个程序中不需要,不执行的话整个框架转不动
        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit()

        #画面按钮按下后,修改param.STATUS,实际动作这里实现
        if  param.STATUS == 100:
            #退出按钮
            if tk.messagebox.askokcancel('提示', '要退出画面吗'):
                break
            param.STATUS = 0
        elif param.STATUS == 10:
            pass
            
        param.cmg.printAll()

        #显示游戏画面
        pygame.display.flip()
        #设置帧率:长期画面不操作,设置成最闲
        clock.tick(param.TICK_NORMAL)
            
        root.update()

main()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-20 13:20

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表