andy大宝 发表于 2026-6-23 22:57:50

Pygame经典i wanna跑酷引擎

本帖最后由 andy大宝 于 2026-9-26 20:17 编辑

统一回复【直接复制能跑吗】
这个引擎程序不能直接跑,需要下载附件后运行附件内的py文件

首先,感谢Pygame纯画笔弹幕游戏(复制即玩)中鱼油们的鼓励和支持,看到各位热情捧场,我真的成就感满满{:10_257:}
在这之后呢,萌新信心爆棚,猛啃碰撞检测,计划写一个无爬墙跑酷引擎
刚思考完框架,准备动手{:10_256:}
结果……紧接着就在论坛上发现了这个:用Python做一个跑酷游戏{:10_277:}
兴致全无{:10_266:}(本来想整一个震撼首发)
美好的想法搁置了近10个月

现在正好放超长暑假(我26年高考),待在家里实在无聊,然后就想到了这个计划。
毕竟,这个帖子里Twilight6的话触动了我:
很棒,论坛就需要这种学习良性竞争的氛围!!!
既然有人已经实现,那就超越

我把目光投向了我最喜欢的跑酷游戏之一 ——i wanna
要实现 i wanna 跑酷引擎,有几个额外的问题必须攻克:


1.i wanna 的地图刷新模式以单个角色(如block, killer, save)为单位,将不同单位放置在棋盘格上,这就需要用到二维数组。然而(据我所知)Python 并没有现成的二维数组
解决方式:在文本文档内模拟二维数组,既满足地图刷新模式,又提高了关卡编辑的自由度


2.i wanna 跑酷引擎中跳跃时按住跳跃键可以增大跳跃高度,但有一定限度
解决方式:用一个变量对按住跳跃键的帧数计数,达到一定值时取消高度增加


3.i wanna 跑酷引擎支持二段跳,但空中只能多跳一次
解决方式:分类讨论,结合 player 是否碰到 block,讨论过程较复杂,详见代码


好了,下面是代码预览,作品文件和作品介绍{:10_287:}

import pygame as pg
import sys

#pygame初始化
pg.init()
clock = pg.time.Clock()

#加载角色图片
player_image = pg.image.load('player.png')

#设置窗口(长25×32=800,宽15×32=480)
window = pg.display.set_mode((800,480))
pg.display.set_caption("i wanna引擎")

#与跑酷算法相关的变量初始化
vy = 0                      #垂直方向移速
jump_num = 2                #跳跃段数
jump_hold = False         #是否按住跳跃键
hold_time = 0               #跳跃键按住时间

#与游戏控制相关的变量初始化
change_level = True         #是否进入下一关
level_num = 0               #关卡数

#读取关卡(0代表空气,1代表墙,2代表岩浆)
level = []
level_code = ''
with open('level.txt') as f:
    for each_line in f:
      if each_line == '=\n':
            level.append(level_code)   
            level_code = ''
      else:
            level_code = '{0}{1}'.format(level_code, each_line[:25])
      
#获得字体
font = pg.font.Font(None,35)

#定义方块类
class Obj(pg.sprite.Sprite):
    def __init__(self, sprite_num, position):
      pg.sprite.Sprite.__init__(self)
      self.num = sprite_num
      if sprite_num == '1':
            self.image = pg.image.load('block.png').convert_alpha()
      elif sprite_num == '2':
            self.image = pg.image.load('killer.png').convert_alpha()
      self.rect = self.image.get_rect()
      self.rect.left, self.rect.top = position

#定义玩家类
class Player(pg.sprite.Sprite):
    def __init__(self, postiton, image):
      pg.sprite.Sprite.__init__(self)
      self.image = image
      self.rect = self.image.get_rect()
      self.rect.left, self.rect.top = position
    def move(self,vx,vy):
      self.rect = self.rect.move()

while True:
    #加载关卡
    if change_level == True:
      change_level = False
      level_num += 1
      objs = []
      group_block = pg.sprite.Group()
      group_killer = pg.sprite.Group()
      w = -1
      h = 0
      for i in level:
            w += 1
            if w == 25:
                w = 0
                h += 1
            if i != '0':
                position = w*32, h*32
                obj = Obj(i,position)
                objs.append(obj)
                if i == '1':
                  group_block.add(obj)
                elif i == '2':
                  group_killer.add(obj)
      position = 50, 400
      player = Player(position, player_image)   

    #处理按键事件
    for ev in pg.event.get():
      if ev.type == pg.QUIT:
            pg.quit()
            sys.exit()
      
    keys = pg.key.get_pressed()
    #跳跃
    if keys:
      hold_time += 1
      if jump_num > 0:
            if jump_hold == False:
                jump_hold = True
                vy = -4
                jump_num -= 1
            elif hold_time <= 15:
                vy = -4
      elif jump_hold == True and hold_time <= 12:
            vy = -4
    else:
      hold_time = 0
      jump_hold = False
    #左右移动
    if keys:
      player.move(-3,0)
      while pg.sprite.spritecollide(player, group_block, False):
            player.move(1,0)
    if keys:
      player.move(3,0)
      while pg.sprite.spritecollide(player, group_block, False):
            player.move(-1,0)

    #玩家运动处理(垂直方向)
    player.move(0,vy)
    if vy < 8:
      vy += 0.5
    if pg.sprite.spritecollide(player, group_block, False):
      if vy >= 0:
            while pg.sprite.spritecollide(player, group_block, False):
                player.move(0,-1)
            jump_num = 2
      else:
            while pg.sprite.spritecollide(player, group_block, False):
                player.move(0,1)
      vy = 0
    #空中仅一段跳
    if vy > 1 and jump_num == 2:
      jump_num = 1

    #死亡判定
    if pg.sprite.spritecollide(player, group_killer, False) or player.rect.left < 0:
      player = Player(position, player_image)

    #通关判定
    if player.rect.right > 800:
      change_level = True

    #绘制窗口
    window.fill("white")

    #绘制角色
    for each in objs:
      window.blit(each.image, each.rect)
    window.blit(player_image, player.rect)

    #画面更新
    pg.display.update()

    #设置帧率
    clock.tick(60)    文件:
规则:
AD移动,W跳跃(跳跃高度与按住时长有关),可二段跳,碰到红色或玩家出左边界时死亡,玩家出右边界时进入下一关
作为一个跑酷引擎,游戏内没有提供完整的关卡包,仅对游戏机制作介绍用
游戏截图:



关于bug与可玩性:
在我电脑上运行的时候,游戏一开始总是会出现轻微卡顿,随后就好了,不知道是什么原因
附件里面有一个文本文档,打开后可以自己编辑关卡,编辑方式很简单,你读完代码秒懂(不懂的话也欢迎来问{:10_330:})


顺便说,代码的37行有一个设置字体,这是我调试变量时留下的,你可以用下面这行代码将变量实时显示在屏幕上:window.blit(font.render("变量名:%s" % 变量名,True,"black"),(20,20))之后时间我的作品可能会更新(如建立严谨的关卡包),感兴趣的鱼油可以时常关注一下







andy大宝 发表于 2026-6-23 23:04:08

有人能提供关卡包吗,我突然有点想玩自己写的游戏了{:10_328:}

小甲鱼的二师兄 发表于 2026-6-26 19:02:27

嘿嘿,就喜欢这种有点抽象的游戏~

Pioneer. 发表于 2026-6-26 19:09:59

学到了

神荼Q 发表于 2026-6-26 19:10:16

复制直接跑吗?

qiuhan1987 发表于 2026-6-26 19:10:36

强

疯狗马德森 发表于 2026-6-26 19:10:55

我来打卡学习啦

我也不想学编程 发表于 2026-6-26 19:11:05

啊?

我不是熊大 发表于 2026-6-26 19:11:15

能复制直接跑吗

xcchuanqi 发表于 2026-6-26 19:11:16

学到了

想个好名字@ 发表于 2026-6-26 19:11:32

有时间玩一下

Fidodido 发表于 2026-6-26 19:11:35

学习学习

终极菠萝冲击 发表于 2026-6-26 19:11:45

有点抽象

katedaisy-2024 发表于 2026-6-26 19:11:53

强得可怕,我什么时候能这么强啊!

a308627301 发表于 2026-6-26 19:13:17

这个是不是画面改一下,就更高大上了

lu10086 发表于 2026-6-26 19:13:21

学到了

stacymeowmeow 发表于 2026-6-26 19:13:33

好强啊!!

iHobe 发表于 2026-6-26 19:14:15

完蛋了,每次分享的都是看不懂,要加紧学习了

gaming1990 发表于 2026-6-26 19:14:16

加油,好好干,万丈高楼平地起

clollipops 发表于 2026-6-26 19:14:50

还有这种引擎
页: [1] 2 3 4
查看完整版本: Pygame经典i wanna跑酷引擎