当前位置:首页 > 乒乓球资讯 > 正文内容

Python语言难学吗?第15讲实操小游戏项目

杏彩体育2年前 (2022-12-01)乒乓球资讯36

想谈谈一个项目一般是怎么完成的。更具体的说,程序员是如何思考和解决问题的呢?

我认为其中一个很重要的能力是【问题拆解】。问题拆解,指的是在做一件事或面对一个问题的时候,将其拆解成多个步骤或多个层次,逐步执行和解决问题,直至达到最终效果。

举个例子,在上一关的末尾,我们就将一个猜数字游戏拆解成四个目标:

当然这种拆解问题的思维并不少见。不过可能是出于长期编写代码的习惯,程序员会将问题拆得更细致一些,即拆到无法再拆为止。

像这样,我会将完成一个项目的流程总结为以下三步:

明确项目目标,是指我们希望程序达成什么目的,实现什么功能,从而帮我们将项目拆解成不同的单元;而一个妥当的拆解方案,难度适度递增,能帮我们逐步顺利执行,最终完成项目。这三个步骤可以说是环环相扣的。

明确项目目标

在互联网公司,一般情况下是由产品经理提出明确的项目需求,由程序员来实现,他们之间是“相爱相杀”的关系。:)

今天且让我扮演一下产品经理的角色。我们此次要实现的需求是:人机PK小游戏。具体效果请参照下面的示意动图。

简单来说,这个游戏中,会随机生成玩家和敌人的属性,同时互相攻击,直至一方血量小于零。

另外,这样的战斗会持续三局,采取三局两胜制,最后输出战斗结果,公布获胜方。

确了项目要实现什么效果后,就可以对项目进行拆解了。

分析过程,拆解项目

编写代码,我们无须苛求一步到位。尤其对于刚接触编程的学习者来说,层层递进、逐渐提升难度才能达到更好的练习效果。

了让你暖暖身,同时照顾大部分同学的学习节奏,我从“功能叠加、难度递增”这个角度考虑,将我们要实现的小游戏拆分成了三个版本。

版本1.0,主要是帮我们理清战斗逻辑。而版本2.0和3.0,会涉及到一些新的知识点,到时遇到了再和大家介绍。

当项目被清晰地拆解后,剩下的就是去逐步执行,也就是重复“执行→遇到问题→解决问题→继续执行”这个循环的过程。

下面,开始正式写代码咯

逐步执行,代码实现

版本1.0:自定属性,人工PK

第一阶段的代码,主要任务是理清战斗的逻辑,再用print()函数将战斗过程打印在终端。

先来思考一下,一个人机PK游戏最基础的元素是什么,可以拿最经典的拳皇游戏来脑补一下。

根据这一版本的设定,我们要做的主要有三步:1.规定并显示出玩家和敌人的属性 2.双方同时互相攻击,血量根据对方的攻击力扣除 3.若有一方血量小于等于0,游戏结束。

为了让我们的思路保持清晰,画成流程图就是这样子的:

这个版本的所有步骤,都还很不“智能”,只用到了唯一一个函数Print()。也就是说,我们只要把步骤一个一个打印上去,就算成功啦。

好,我们从第1步开始:设定【玩家】和【敌人】的属性,即【血量】和【攻击】。

第2步:手动计算攻击一次,双方各自所剩的血量。

第3步:继续做人工计算:算一算,玩家攻击2次敌人,敌人的血量就等于0了,这时候可以结束战斗,打印游戏结果。

很简单吧!现在我们要做的,就是把这三段代码拼起来,然后我会加一些修饰视觉的换行符和分割线,让运行结果看得更清楚一点。

现在,请你直接运行一下代码,看看结果是不是如我们所愿。

唔...虽然看起来还有点儿意思,但所有信息一下子都蹦跶出来,一点都没有体现游戏的进程感。

所以,为了让打印出的东西能有时间间隔地依次出现,我们需要设置一个类似“计时器”的东西。在Python里,我们需要用到两行代码来实现:(敲黑板,很简单的新知识)

这里有个新名词——模块,它是Python里一个重要的概念,会在之后的课程详细介绍。

你可以把模块想象成是一个装着许多神奇函数的百宝箱,不过想要使用这个百宝箱里的函数,得先用import 模块名这样一句代码来打开它。

然后这里我们想使用time模块里的sleep()函数,也就是让代码运行结果不要一次性全部出现,而是分批分批的出现。就要写成time.sleep(secs)的形式。

如果我想设置成打印的信息间隔1.5秒出现,代码就可以这么写:

呼~总算完成了版本1.0,不过我想你一定在心里默默吐槽,一句句用print()写也太蠢太弱鸡了吧。

没错,不过代码嘛,总得一步步实现。就先当作是小小的热身。

而且,这个版本的代码还有两个明显的缺陷:一是玩家和敌人的属性(血量&攻击)是我自己说了算,那胜负早已没有悬念;二是战斗过程中血量的变化要自己手动算,那要计算机有何用?

放心,这些都是我们会在版本2.0解决的问题。

版本2.0:随机属性,自动PK

如前所述,这个阶段,我们主要新增【随机属性】和【自动战斗】两个功能,画成流程图是这样子的:

想一想:自己来定义双方角色的属性,那简直是黑箱操作,胜负早已注定。所以,为了游戏公平,我们要让属性由自己说了算变成随机生成。

现在问题来了,要随机生成属性(数字),这课堂里又没教。怎么办?

百度一下你就知道~

遇到卡点后上网搜索,其实就能解决目前你绝大多数的问题。“不懂就查”也是程序员的工作习惯之一。

要随机生成整数,就要用到random模块里的randint()函数,括号里放的是两个整数,划定随机生成整数的范围。

好,可以动手敲代码了!

请听题:1.定义两个变量,来存储玩家血量和玩家攻击力的数值 2.血量是100-150的随机数,攻击力是30-50的随机数 3.将两个变量打印出来

标准的变量名最好是用英文来表达含义,如果是多个单词组成,需要用英文下划线_来隔开。

对于取英文变量名,很多英语水平在高考即巅峰的同学会感到头疼,这里我推荐大家一个网站:CODELF,输入中文就可以看到别人是怎么命名的。

好,我们已经知道如何生成随机属性,下面我们就要将属性展示打印出来,请阅读下列代码,弄懂每一行的含义:

那截至目前,我们已经完成了随机生成属性和展示属性,接下来我们就来实现"自动战斗"。

要怎么实现自动战斗呢?如果一头雾水的话,可以先尝试从版本1.0的人为战斗来寻找规律:

我们可以发现,4-6行这3行是重复出现的结构,除了数字是灵活变动之外,其余是一毛一样的。

根据我们已学知识,用循环来解决重复劳动!

说到循环,我们就要思考是要使用for循环还是while循环了。

因为现在双方的血量和攻击是随机生成,不是固定的。所以我们不知道具体要战斗多少回合才能分出胜负,也就是循环次数不明确,那自然要用while循环。

所以我们现在确定了让循环执行需要满足的条件就是——双方血量均大于零,也就是不死不休。

可见while后面要同时满足两个条件,即这两个条件要同时为真,所以我们要用and来连接,用代码来表示就是:

现在我们确定了执行while循环的条件,接下来就是要填充循环内部的内容。

根据刚才的分析,我们希望循环的内容是双方互相攻击,掉血的过程。

其中【敌人】剩余血量=敌人当前血量-玩家攻击,【玩家】剩余血量=玩家当前血量-敌人攻击。

事实上我们之前已经定义好了这四个变量,每一次互相伤害后,player_life(玩家血量)和enemy_life(敌人血量)都会被重新赋值,所以转换为代码逻辑就是:

好,自动攻击的基础逻辑也已经理清楚了。我们先合并一下这之前写过的代码。

接下来,只需要补充完成while循环语句,让双方自动战斗、扣血的过程循环起来

应该能感受到,版本2.0总算像模像样了,慢慢逼近我们的项目目标。

不过它还没有实现:打印出每局结果,三局两胜,并打印最终战果的功能。这就是我们在版本3.0要增加的功能。

版本3.0:打印战果,三局两胜

对比版本2.0,在版本3.0中,我们想要增加的功能是:1.打印战果:每局战斗后,根据胜负平的结果打印出不同的提示;2.三局两胜:双方战斗三局,胜率高的为最终赢家。

反复解释新增功能,是因为这样不断地明确项目的阶段性目标,可以让自己持续专注地推进项目。

好啦,我们继续前进。版本3.0也只剩最后的“三局两胜”了!

同样的,我们可以将其拆分成两个部分:先来个三局,再判断最终胜负。

首先我们来看,三局战斗也是一个可以循环的结构,且循环次数是固定的,所以要用到for循环。

在这里我们可以使用for i in range( )的结构,我们先来回顾一下之前学过的range()函数:

现在,你有思路了吗?尝试把代码打出来吧,让战斗循环三局。

给两个提示:1.想清楚哪些代码要嵌套到for循环里,即一局战斗里包括什么信息。确定了for写在哪里之后,一局战斗包含的所有信息都要缩进;2.细节也需要留意,如局与局之间要怎么区分开来(时间间隔&打印局数信息)

如果做起来有些障碍,检查一下是否存在上面提示的这几个问题:

1. for循环语句的位置放的对不对?这个关键在于,你想让哪些信息被循环展示。例如:如果你错将for循环语句放在了【随机属性】 和【自动战斗】之间,那每一局的战斗信息会是一样的,也就不存在什么三局两胜了。

2.你写完for循环语句后,需要缩进的信息【整体】缩进了吗?如果没有缩进,可能存在报错,或者只有部分战斗信息循环的情况。

3.细节注意到了吗?局与局之间要有明显间隔,那我们可以同时使用time.sleep()和print(现在是第x局)来完美解决这个问题。此外,遇到各种报错的话,记得去搜索一下,看看报的是什么错,先自己尝试解决看看。

OK,打三局这个需求也成功了。现在我们距离最后的终点只剩一步之遥,只有“统计三局两胜的结果”这个功能还没实现了。

我们可以想一想,平常我们是怎么统计比赛结果呢?

好比乒乓球比赛,有一方赢了一局就翻一下计分牌,让数字+1,最后看哪边的数字大就是哪边获胜。

对于计算机也是如此:它靠数据思考,比如拿数据做计算、做条件判断、做循环等。所以这里的关键就在于,要给计算机数据。

那么仿照计分牌的做法,我们的解决方法也就出来了:采取计分的方式,赢一局记一分,平局不计分。

所以,我们要给计算机一个空白的“计分板”,用于存放【玩家】和【敌人】每一局的得分。

那什么情况下,这两个变量会变动(+1)呢?自然是要与具体每一局的结果挂钩,这时候可以回看我们计算输赢的条件判断语句。

然后,我们将敌人和玩家各自赢的局数给算出来:

这样三局过后,player_victory和enemy_victory会被赋上新的值。给你一个小技巧:player_victory = player_victory + 1,总是这样写有点烦人,我们可以写作player_victory += 1,这两个代码是等价的,都代表"如果if后的条件满足,变量就+1"。

这也是程序员是追求“极简”的体现。好,我们把这段代码替换一下:

现在,我们只需要再用一次条件判断,比较两个变量的大小就能知道谁输谁赢了。

将条件判断的思维逻辑转换成代码逻辑的话是这样子的:

需要注意的是最终判断结果要放在for循环外面,也就是不用缩进。

完整代码:

不过,这还没完呢。作为一个程序员,代码是我们的名片,我们会追求更加优雅的,方便他人阅读的代码,所以上述代码还有一些优化空间。

所以,以下是彩蛋时间,我会教大家一个新的知识点——【格式化字符串】,作为这一关的收尾。

什么意思呢,上面有这么两行代码,是用来展示双方角色的属性的:

我们在用+拼接字符串和变量的时候,常常需要考虑变量是什么类型的数据,如果不是字符串类型,还先需要str()函数转换。

并且一句话常常要拼接成好几个部分,然后我们要考虑每一对引号的起始位置,好麻烦,相信你多少会有点体会。

所以,为了更方便地实现不同数据类型的拼接,用【格式符%】是更常用更便利的一种方式。

我们可以把%想象成:图书馆里用来占位的一本书。先占一个位置,之后再填上实际的变量。举个例子:下面这两种写法是相同的,请你着重研究下第二行的语法。

我们看到格式符%后面有一个字母s,这是一个类型码,用来控制数据显示的类型。%s就表示先占一个字符串类型的位置。

还有其他常见的类型码如下图所示:

占完位置之后,我们要以%的形式在后面补上要填充的内容,如此一来我们就免去了转换类型的烦恼。如果是多个数据,就要把它们放进括号,按顺序填充,用逗号隔开。

举个例子,你可以运行一下,对比下列输出的结果:

一个小小的提示:%后面的类型码用什么,取决于你希望这个%占住的这个位置的数据以什么类型展示出来,如果你希望它以字符串形式展示,那就写%s,如果你希望它以整数形式展示,那就写%d。

这就出现了一些容易混淆的地方,比如,请运行以下的代码:

选用了不同的类型码,打印出的结果却是一样,原因也已经在代码注释中写清楚了:因为整数8与字符串8的打印结果是一样的,所以选两种类型码都OK。但这种“都OK”的情况仅限于整数,对文字是行不通的:

会报错,对吧?好啦,现在你应该更懂这个格式化字符串该怎么用了。

那就看回我们之前的代码,如果把一开始用+拼接的字符串都替换成%格式符表示,我们先替换一部分试试

你也许想问我,这里的%s是不是都能换成%d,答案是“YES!”,因为这里的变量i,player_life,player_attack统统都是整数。

是不是看起来清爽了些?如果还不习惯这种表示方法没有关系,多写几次就习惯啦。

以上就是第一节项目实操课的全部内容了!

----------------------------------------------------------------------------------------------

更多课程请关注:

扫描二维码推送至手机访问。

版权声明:本文由财神资讯-领先的体育资讯互动媒体转载发布,如需删除请联系。

本文链接:http://www.tengj.cn/?id=8933

分享给朋友:

“Python语言难学吗?第15讲实操小游戏项目” 的相关文章

乒乓球女单5月世界排名,中国继续包揽前5,朱雨玲与队友差距拉大

乒乓球女单5月世界排名,中国继续包揽前5,朱雨玲与队友差距拉大

随着4月份的世乒赛大幕落下,国际乒联也随后发布了五月份最新女单世界排名。中国队再次包揽世界排名前5位,显示出强大的统治力。世乒赛刘诗雯、陈梦、丁宁、王曼昱胜利包揽前四名,她们也是最新女单世界排名的前四位。...

体育风采||2022乒乓世界排名公布,国乒稳坐第一!

体育风采||2022乒乓世界排名公布,国乒稳坐第一!

体育风采   2022.03.08 音频: 进度条 00:00 06:17 后退15秒 倍速 快进15秒 ▲点击上方绿色按钮 收听节目/《体育风采》 主播/施怡晴 苏雅欣 剪辑/高莹莹...

梅西进球,阿根廷赢了!卡塔尔世界杯最新战报→

梅西进球,阿根廷赢了!卡塔尔世界杯最新战报→

  26日晚,世界杯小组赛D组第二轮,突尼斯迎战澳大利亚。第23分钟,杜克头球破门,澳大利亚1比0领先。此后,突尼斯一直试图扳平比分,但始终没能进球。最终,突尼斯0比1不敌澳大利亚。两轮过后,突尼斯一平一负,澳大利亚一胜一负。    26日晚,世界杯小组赛C组第二轮,波兰...

世界杯最新排名!法国提前晋级,阿根廷赢下生死战,3队错失良机

世界杯最新排名!法国提前晋级,阿根廷赢下生死战,3队错失良机

  11月27日,世界杯小组赛第二轮进行了一半,有人欢喜有人愁,法国队在姆巴佩的带领下打破卫冕冠军小组出局的魔咒,成为第一支晋级16强的队伍。东道主卡塔尔队出局,英格兰、荷兰和沙特均错失两连胜提前晋级的良机。梅西传射,率领阿根廷队在生死战中击败墨西哥,避免提前出局。   ...

原创 乒乓球世界最新排名出炉!张本智、王曼昱是大赢家!

原标题:乒乓球世界最新排名出炉!张本智、王曼昱是大赢家! 7月25日深夜,最新乒乓球世界10强排行榜出炉:王曼昱加1350积分第一冠和前四,王艺迪加1300分第一冠和一个子,前2和前2的差距逐渐缩小。 孙颖莎要小心了。排名女单如下:第一名中国孙颖莎:5770分,第二名中...

常识 | “乒乓球”起源于...中国吗?

常识 | “乒乓球”起源于...中国吗?

常识 | “乒乓球”起源于...中国吗?​mp.weixin.qq.com/s/zrCJYxkIUWjNFMiqFpw0Lg 乒乓球的起源 乒乓球(table tennis),素来被称为中国的“国球”,是一种世界流行的球类体育项目,包括进攻、对抗和防守。 虽然咱打得...