zoukankan      html  css  js  c++  java
  • Python第07周:一个小游戏

    本篇严重参考Julian Meyer发表的文章:Beginning Game Programming for Teens with Python

    本次作业将创建一个简单的游戏叫做英雄兔ver0.1版;

    游戏背景:


    在这里作为英雄的兔子要保卫城堡,它必须能够移动和射击反击敌人
    (关于敌人我们在后续章再添加,那时你已经能看懂大部分代码了)。

    # 设计步骤

    # 第一步:Hello Bunny(嘿,兔子)
    # 第二步:添加布景
    # 第三步:让兔子动起来
    # 第四步: 旋转兔子
    # 第五步:射击吧,兔子!
    # V0.1 Over!

    # 第一步:(编写简单的)Hello Bunny(嘿,兔子)

    # 1 - 导入PyGame库
    import pygame
    from pygame.locals import * #导入命名空间
     
    # 2 - 初始化PyGame并设置显示窗口
    pygame.init()
    width, height = 640, 480
    screen=pygame.display.set_mode((width, height))
     
    # 3 - 加载你想要给bunny使用的图片
    player = pygame.image.load("resources/images/dude.png")
     
    # 4 - 循环执行以下缩进的代码
    while 1:
        # 5 - 每次绘图前,将屏幕填充成黑色
        screen.fill(0)
        # 6 - 以100*100的大小显示图片
        screen.blit(player, (100,100))
        # 7 - 更新屏幕
        pygame.display.flip()
        # 8 - 检查是否有新事件
        for event in pygame.event.get():
            if event.type==pygame.QUIT:
                pygame.quit()
                exit(0)

    把它保存到你的游戏目录下(即资源子目录)并命名为itgame.py。让我们逐段分析以上代码:
    1. 导入PyGame库。这一步让你在你的程序中使用来自库中的函数。
    2. 初始化PyGame并设置显示窗口。
    3. 加载你想要给bunny使用的图片。
    4. 循环执行以下缩进的代码。
    5. 在绘图前,将屏幕填充成黑色。
    6. 将之前加载进来的bunny图片以100*100的大小显示在屏幕上。
    7. 更新屏幕。
    8. 检查是否有新事件,如果有的话,否则转到退出命令,退出程序。
    注意:根据PyGame的文档,你不需要调用pygame.quit()因为解析器关闭时会自动调用它。
    如果现在运行这段代码(在Idle菜单栏点击 “RunRun Module"),你应该可以看到一个如下所示的屏幕:
     
    耶,兔子就显示在屏幕上了,并准备做动作!
    但是只有一只兔子显示在一个黑漆漆的屏幕上,这个游戏看起来很吓人且很孤单。接下来要做的就是稍微美化一下咯。

    # 第二步:添加布景

    我们首先给游戏场景添加背景图片,可以通过调用一组screen.blit()来完成背景添加。
    在代码的#3 小节,载入角色图像之后添加下面的代码
    # 3 - 加载你想要给bunny使用的图片
    player = pygame.image.load("resources/images/dude.png")
    grass = pygame.image.load("resources/images/grass.png")
    castle = pygame.image.load("resources/images/castle.png")
    这些代码载入图片然后赋给指定的变量,然后把它们画到屏幕上。但如果你检查草地的图片,你会发现它没有覆盖整个640 x 480的屏幕,所以你必须平铺使草地的图片完全覆盖屏幕。
    在#6小节的开始(把兔子画在屏幕上之前),添加以下代码到game.py:
        # 6 - 以100*100的大小显示图片
        for x in range(width/grass.get_width()+1):
            for y in range(height/grass.get_height()+1):
        screen.blit(grass,(x*100,y*100))
        screen.blit(castle,(0,30))
        screen.blit(castle,(0,135))
        screen.blit(castle,(0,240))
        screen.blit(castle,(0,345 ))
        screen.blit(player, (100,100))

    正如你所见,首先把x坐标通过for循环递增,在这个循环中再把y坐标循环递增,并且将草地画在使用循环生成的x、y坐标上。紧接着的一组代码只是将城堡画在屏幕上。从现在开始,变得好看点了!
    你现在运行这个程序,你会看到像如下的结果:

    # 第三步:让兔子动起来

    下面需要添加一些真正的游戏元素,比如让兔子响应键盘的按键。
    要做到这一点,需要一个方法记录哪一个键在某一时刻被按下。
    可以简单的使用一个数组保存在游戏需要使用的键的按下状态。
    添加如下代码到game.py的#2小节结束(在你设了屏幕高和宽度之后) :
    # 2 - 初始化PyGame并设置显示窗口
    ...
    screen=pygame.display.set_mode((width, height))
    keys = [False, False, False, False]
    playerpos=[100,100] #游戏角色的位置

    这段代码是非常明了。数组keys按WASD的顺序记录它们的状态。
    数组的每个元素对应一个键,第一个是上W,下S,左A右D。
    playerpos变量定义程序开始绘制游戏角色的起始位置。因为这个游戏将移动游戏角色到不同的位置,设置一个储存角色位置的变量,然后便可以简单地将角色绘制到这个位置。
    现在你需要修改现有的代码来绘制角色,使用新的playerpos变量,将# 6的程序:
    screen.blit(player, (100,100))
    改为:
    screen.blit(player, playerpos)
    接下来,基于哪些按键被按下更新键数组,PyGame通过添加event.key事件使检测按键很容易实现。
    在# 8检测event.type==pygame.QUIT之后,添加这些代码
    (如果有块缩进的话使用与pygame.QUIT相同的缩进级):
        # 8 - 循环游戏、检查是否有新事件

            if event.type == pygame.KEYDOWN:
                if event.key == K_w:
                    keys[0] = True
                elif event.key == K_a:
                    keys[1] = True
                elif event.key == K_s:
                    keys[2] = True
                elif event.key == K_d:
                    keys[3] = True
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_w:
                    keys[0] = False
                elif event.key == pygame.K_a:
                    keys[1] = False
                elif event.key == pygame.K_s:
                    keys[2] = False
                elif event.key == pygame.K_d:
                    keys[3] = False
    哇!这里有很多行代码,如果你把它按If语句拆分也不是很复杂的。
    首先你要检测一是否有键被按下或释放,然后你需要检测哪个键被按下或者释放,如果被按下或者释放的键是你要使用的键,根据键值更新相应的键变量。
    最后,你需要更新playerpos变量作为键按下的响应,这太简单了。
    将下附代码添加到game.py的末尾(使用和for循环相同的缩进级)
        # 9 - Move player
        if keys[0]:
            playerpos[1] -= 5
        elif keys[2]:
            playerpos[1] += 5
        if keys[1]:
            playerpos[0] -= 5
        elif keys[3]:
            playerpos[0] += 5
    这段代码只是检查哪个键被按下,然后添加或减去游戏角色的x或y位置(取决于按下的键)来移动游戏角色。

    # 第四步: 旋转兔子

    是的,你的兔子现在可以随着你的按键移动,但用鼠标来旋转兔子朝向到你选择的方向岂不更酷,所以它不是所有时间都朝向一个方向。使用三角函数来实现:
    应用atan2三角函数获得旋转角度(z)。记住,Z值是弧度。
    atan2函数在Python的math库总,所有先在#1结尾处增加:
    import math

    然后,将#6最后一行(screen.blit...这行)替换成下面的代码:
    # 6.1 - Set player position and rotation
    position = pygame.mouse.get_pos()
    angle = math.atan2(position[1]-(playerpos[1]+32),position[0]-(playerpos[0]+26))
    playerrot = pygame.transform.rotate(player, 360-angle*57.29)
    playerpos1 = (playerpos[0]-playerrot.get_rect().width/2, playerpos[1]-playerrot.get_rect().height/2)
    screen.blit(playerrot, playerpos1)

    让我们梳理一下上面代码的基本流程。首先获取鼠标和游戏角色的位置,然后你对两个位置应用atan2函数,之后,你将atan2返回的弧度转化成度数(将弧度乘以近似57.29或360/2π)。
    因为兔子会旋转,它的位置也将会改变。所以现在计算兔子的新位置并把它显示在屏幕。
    再次运行这个游戏。如果你只按了“WASD”键,那么这个游戏应该和之前完全一样,但如果你移动你的鼠标兔子也会随之旋转!

    # 第五步:射击吧,兔子!

    现在你的兔子已经可以自由活动了,是时候给它添加更多的动作了。让兔子可以用弓箭射击敌人!
    这一步稍微有点复杂,因为你必须记录所有射出的剑,更新它们的位置、旋转并且在它们飞出屏幕后删除它们。
    首先,在初始化小节(#2小节)的结束添加必要的变量:
    acc=[0,0] #记录玩家的射击精度
    arrows=[] # 记录所有的箭

    精度变量acc实际上是一个包含射击数量和命中獾次数的列表。
    最后我们可以使用这些信息来计算精度的百分比。
    接下来,在section #3的末尾加载弓箭图像:
    arrow = pygame.image.load("resources/images/bullet.png")

    现在当玩家点击鼠标,弓箭就要射出。
    在section #8的末尾加入以下代码作为新的事件句柄
    if event.type == pygame.MOUSEBUTTONDOWN:
                position = pygame.mouse.get_pos()
                acc[1] += 1   
                arrows.append(
                    [math.atan2(position[1] - (playerpos1[1] + 32), position[0] - (playerpos1[0] + 26)), playerpos1[0] + 32,
                     playerpos1[1] + 32])

    这些代码检查是否有鼠标点击,如果有它会读取鼠标位置,并根据玩家的旋转和指针的位置计算出弓箭的旋转。这个旋转储存在arrows数组里。
    接下来你需要真正在屏幕上画出弓箭了。在section #6.1之后插入以下代码:
    # 6.2 - Draw arrows
    for bullet in arrows:
        index=0
        velx=math.cos(bullet[0])*10
        vely=math.sin(bullet[0])*10
        bullet[1]+=velx
        bullet[2]+=vely
        if bullet[1]<-64 or bullet[1]>640 or bullet[2]<-64 or bullet[2]>480:
            arrows.pop(index)
        index+=1
        for projectile in arrows:
            arrow1 = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
            screen.blit(arrow1, (projectile[1], projectile[2]))
    运用基本的三角函数可以计算出vely和velx。10是弓箭的速度。if语句检查弓箭是否飞出边界,如果是则删除该弓箭。第二个for语句循环过arrows数组并画出相应旋转的弓箭。
    试试运行程序。你应该有一只兔兔在你点击鼠标时发射弓箭了。

    祝你好运!

  • 相关阅读:
    Attach Files to Objects 将文件附加到对象
    Provide Several View Variants for End-Users 为最终用户提供多个视图变体
    Audit Object Changes 审核对象更改
    Toggle the WinForms Ribbon Interface 切换 WinForms 功能区界面
    Change Style of Navigation Items 更改导航项的样式
    Apply Grouping to List View Data 将分组应用于列表视图数据
    Choose the WinForms UI Type 选择 WinForms UI 类型
    Filter List Views 筛选器列表视图
    Make a List View Editable 使列表视图可编辑
    Add a Preview to a List View将预览添加到列表视图
  • 原文地址:https://www.cnblogs.com/jlxuqiang/p/4051495.html
Copyright © 2011-2022 走看看