1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > python 构建_通过构建互动游戏来教孩子Python

python 构建_通过构建互动游戏来教孩子Python

时间:2022-02-12 18:58:58

相关推荐

python 构建_通过构建互动游戏来教孩子Python

python 构建

Python已作为一种出色的初学者编程语言而享有盛誉。 但是,从哪里开始呢?

我最喜欢的使人们对编程感兴趣的方法之一就是编写游戏。

PursuedPyBear (ppb)是为教学而优化的游戏编程库,我最近使用它来向孩子们传授更多有关我最喜欢的编程语言的知识 。

Jupyter项目是一个基于浏览器的Python控制台,最初是为数据科学家设计的,用于处理数据。

我有一个Jupyter笔记本,旨在教您如何制作简单的互动游戏,您可以从此处下载。 为了打开文件,您将需要安装最新的Jupyter项目JupyterLab。

先决条件:

运行最新版本的Python( Linux , Mac和Windows的说明 ) 运行最新版本的Git( 此处的说明)

我们将简要配置一个虚拟环境,以为所需的库创建单独的空间。 (您可以在此处了解有关虚拟环境如何工作的更多信息。)

$ git clone https://github. com /moshez/penguin-bit-by-bit. git

$ cd penguin-bit-by-bit

$ python -m venv venv

$ source ./venv/bin/activate

$ pip install -r requirements. txt

$ jupyter lab .

最后一条命令应在默认浏览器中打开http:// localhost:8888 / lab的 JupyterLab。 在左侧栏中选择dynamic_penguin.ipynb文件,我们就可以开始!

将运行游戏的事件循环

asyncio和PursuedPyBear运行自己的事件循环。

我们可以使用另一个库Twisted集成这两个库,例如粘胶。 这听起来很复杂,但值得庆幸的是,复杂性隐藏在库中,这将为我们完成所有艰苦的工作。

Jupyter中的以下单元格负责上半部分-将Twisted与asyncio事件循环集成。

__file__ = None不需要将PursuedPyBear与Jupyter集成。

from twisted. internet import asyncioreactor

asyncioreactor. install ( )

__file__ = None

接下来,我们需要一个“设置”功能。 设置功能是关键游戏元素配置的常用术语。 但是,我们的功能只会将游戏“场景”放在全局变量中。 就像我们定义要玩游戏的桌子一样。

Jupyter Notebook中的以下单元将完成此操作。

def setup ( scene ) :

global SCENE

SCENE = scene

现在,我们需要将PursuedPyBear的事件循环与Twisted集成。 我们txppb使用txppb模块:

import txppb

d = txppb. run ( setup )

d. addBoth ( print )

如果游戏由于错误而崩溃,最后的print将为我们提供帮助-它将打印出对Jupyter输出的追溯。

这将显示一个空窗口,准备好游戏元素。

这就是我们开始利用Jupyter的地方-传统上,在开始玩游戏之前,需要先编写整个游戏。 但是,我们违反约定,立即开始玩游戏!

通过互动使游戏变得有趣

但是,这不是一个非常有趣的游戏。 它什么都没有,只坐在那里。 如果我们想要一些东西,我们最好添加它。

在视频游戏编程中,屏幕上移动的东西称为“精灵”。 在PursuedPyBear中,子画面由类表示。 精灵会自动使用与该类相同名称的图像。 我从Kenney那里得到了一张小企鹅图片,这是免费和开源视频游戏资产的集合。

import ppb

class Penguin ( ppb. Sprite ) :

pass

现在让我们把企鹅的权利放到中间。

SCENE. add ( Penguin ( pos = ( 0 , 0 ) ) )

它小心地坐在中间。 这比什么都不是要有趣得多。 很好-这正是我们想要的。 在渐进式游戏开发中,每一步都只会稍微有趣一点。

使用ppb为我们的企鹅游戏增添动感

但是企鹅并不能坐以待!! 企鹅应该四处走动。 我们将让玩家使用箭头键控制企鹅。 首先,让我们将键映射到向量:

from ppb import keycodes

DIRECTIONS = {keycodes. Left : ppb. Vector ( - 1 , 0 ) , keycodes. Right : ppb. Vector ( 1 , 0 ) ,

keycodes. Up : ppb. Vector ( 0 , 1 ) , keycodes. Down : ppb. Vector ( 0 , - 1 ) }

现在,我们将使用一个实用程序库。set_in_class函数设置类中的方法。 Python能够向类追溯添加功能的功能真的派上用场了!

from mzutil import set_in_class

Penguin. direction = ppb. Vector ( 0 , 0 )

@ set_in_class ( Penguin )

def on_update ( self , update_event , signal ) :

self . position + = update_event. time_delta * self . direction

set_in_class的代码set_in_class不长,但是确实使用了一些不平凡的Python技巧。 我们将完整的实用程序库放在文章的末尾以进行回顾,并且为了顺畅起见,我们暂时将其跳过。

回到企鹅!

哦,嗯。

企鹅正在努力地以……零速运动,正好无处可走。 让我们手动设置方向以查看会发生什么。

Penguin. direction = DIRECTIONS [ keycodes. Up ] / 4

方向是向上,但是有点慢。 这给了足够的时间来手动设置企鹅的方向为零。 现在就开始吧!

Penguin. direction = ppb. Vector ( 0 , 0 )

为我们的企鹅游戏增添互动性

哎呀,那很令人兴奋-但不是我们想要的。 我们希望企鹅对按键进行响应。 通过代码控制它是游戏玩家所称的“作弊”。

我们将其设置为将方向设置为按键,并在释放键时将其设置回零。

@ set_in_class ( Penguin )

def on_key_pressed ( self , key_event , signal ) :

self . direction = DIRECTIONS. get ( key_event. key , ppb. Vector ( 0 , 0 ) )

@ set_in_class ( Penguin )

def on_key_released ( self , key_event , signal ) :

if key_event. key in DIRECTIONS:

self . direction = ppb. Vector ( 0 , 0 )

企鹅有点无聊,不是吗? 也许我们应该给它一个橙色的球来玩。

class OrangeBall ( ppb. Sprite ) :

pass

同样,我确保有一个名为orangeball.png的图像。 现在,让我们将球放在屏幕的左侧。

SCENE. add ( OrangeBall ( pos = ( - 4 , 0 ) ) )

尽可能尝试,企鹅不能踢球。 让我们在球接近时将球从企鹅上移开。

首先,让我们定义“踢”球的含义。 踢球意味着决定一秒钟内它将在哪里,然后将其状态设置为“移动”。

首先,我们将通过第一次更新将其移动到目标位置来移动它。

OrangeBall. is_moving = False

@ set_in_class ( OrangeBall )

def kick ( self , direction ) :

self . target_position = self . position + direction

self . original_position = self . position

self . time_passed = 0

self . is_moving = True

@ set_in_class ( OrangeBall )

def on_update ( self , update_event , signal ) :

if self . is_moving :

self . position = self . target_position

self . is_moving = False

现在,让我们踢吧!

ball , = SCENE. get ( kind = OrangeBall )

ball. kick ( ppb. Vector ( 1 , 1 ) )

但这只是传送球。 它立即改变位置。 在现实生活中,球在中间点之间移动。 移动时,它将在其位置和需要移动的位置之间进行插值。

天真的,我们将使用线性插值 。 但是,很酷的视频游戏技巧是使用“缓动”功能。 在这里,我们使用常见的“平滑步骤”。

from mzutil import smooth_step

@ set_in_class ( OrangeBall )

def maybe_move ( self , update_event , signal ) :

if not self . is_moving :

return False

self . time_passed + = update_event. time_delta

if self . time_passed >= 1 :

self . position = self . target_position

self . is_moving = False

return False

t = smooth_step ( self . time_passed )

self . position = ( 1 -t ) * self . original_position + t * self . target_position

return True

OrangeBall. on_update = OrangeBall. maybe_move

现在,让我们尝试再次踢它。

ball , = SCENE. get ( kind = OrangeBall )

ball. kick ( ppb. Vector ( 1 , - 1 ) )

但实际上,企鹅应该踢球了。 当球看到它与企鹅碰撞时,它将向相反的方向踢。 如果企鹅正好位于其顶部,则球将选择一个随机方向。

现在,更新函数将调用maybe_move并且仅在我们当前不移动时才检查碰撞。

from mzutil import collide

import random

OrangeBall. x_offset = OrangeBall. y_offset = 0.25

@ set_in_class ( OrangeBall )

def on_update ( self , update_event , signal ) :

if self . maybe_move ( update_event , signal ) :

return

penguin , = update_event. scene . get ( kind = Penguin )

if not collide ( penguin , self ) :

return

try :

direction = ( self . position - penguin. position ) . normalize ( )

except ZeroDivisionError :

direction = ppb. Vector ( random . uniform ( - 1 , 1 ) , random . uniform ( - 1 , 1 ) ) . normalize ( )

self . kick ( direction )

但是,只是踢球并没有那么有趣。 让我们添加一个目标。

class Target ( ppb. Sprite ) :

pass

让我们将目标放在屏幕的右侧。

SCENE. add ( Target ( pos = ( 4 , 0 ) ) )

奖励我们的企鹅

现在,当企鹅将球踢入目标时,我们将希望获得奖励。 一条鱼怎么样?

class Fish ( ppb. Sprite ) :

pass

当目标拿到球时,它应该将其删除并在屏幕的另一端创建一个新球。 然后,它将导致一条鱼出现。

@ set_in_class ( Target )

def on_update ( self , update_event , signal ) :

for ball in update_event. scene . get ( kind = OrangeBall ) :

if not collide ( ball , self ) :

continue

update_event. scene . remove ( ball )

update_event. scene . add ( OrangeBall ( pos = ( - 4 , random . uniform ( - 3 , 3 ) ) ) )

update_event. scene . add ( Fish ( pos = ( random . uniform ( - 4 , - 3 ) ,

random . uniform ( - 3 , 3 ) ) ) )

我们想让企鹅吃鱼。 当鱼看见企鹅时,它应该消失。

Fish. x_offset = 0.05

Fish. y_offset = 0.2

@ set_in_class ( Fish )

def on_update ( self , update_event , signal ) :

penguin , = update_event. scene . get ( kind = Penguin )

if collide ( penguin , self ) :

update_event. scene . remove ( self )

有用!

迭代游戏设计对企鹅和其他人来说都很有趣!

这具有游戏的所有功能:由玩家控制的企鹅将球踢入目标,获得鱼,吃鱼并踢出新球。 这可以作为游戏的“磨削级别”部分,或者我们可以添加障碍来使企鹅的生活更加艰难。

无论您是经验丰富的程序员,还是刚开始使用,对视频游戏进行编程都是很有趣的。 具有Jupyter的PursuedPyBear通过经典环境(如Logo和Smalltalk)的交互编程功能,带来了经典2D游戏的所有乐趣。 是时候享受复古80年代了!

附录

这是实用程序库的完整源代码。 它提供了一些有趣的概念来使游戏板正常工作。 有关如何执行此操作的更多信息,请阅读冲突检测 setattr 。 和__name__属性 。

def set_in_class ( klass ) :

def retval ( func ) :

setattr ( klass , func.__name__ , func )

return func

return retval

def smooth_step ( t ) :

return t * t * ( 3 - 2 * t )

_WHICH_OFFSET = dict (

top = 'y_offset' ,

bottom = 'y_offset' ,

left = 'x_offset' ,

right = 'x_offset'

)

_WHICH_SIGN = dict ( top = 1 , bottom = - 1 , left = - 1 , right = 1 )

def _effective_side ( sprite , direction ) :

return ( getattr ( sprite , direction ) -

_WHICH_SIGN [ direction ] *

getattr ( sprite , _WHICH_OFFSET [ direction ] , 0 ) )

def _extreme_side ( sprite1 , sprite2 , direction ) :

sign = -_WHICH_SIGN [ direction ]

return sign * max ( sign * _effective_side ( sprite1 , direction ) ,

sign * _effective_side ( sprite2 , direction ) )

def collide ( sprite1 , sprite2 ) :

return ( _extreme_side ( sprite1 , sprite2 , 'bottom' ) <

_extreme_side ( sprite1 , sprite2 , 'top' )

and

_extreme_side ( sprite1 , sprite2 , 'left' ) <

_extreme_side ( sprite1 , sprite2 , 'right' ) )

翻译自: /article/20/5/python-games

python 构建

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。