Ursina制作我的世界跑酷游戏(附源码)

本文介绍了如何使用Python的Ursina库制作一个类似我的世界的跑酷游戏。通过安装Ursina模块,利用其3D功能创建方块纹理和场景。游戏包括方块的生成、销毁、碰撞检测以及玩家交互,同时还有天空和地面的渲染。文章还提到了声音效果和重力系统的实现,并提供了部分源码。
摘要由CSDN通过智能技术生成

ursina是Python的一个强大的3d模块。用了它,我们可以在里面“复刻“我的世界,并制作跑酷赛道。

第一步:pip安装ursina模块:

pip install ursina

因为模块有点大(实际包含Panda3d等几个模块),为提升下载速度,我们可以设置国内镜像源:

pip install ursina -i https://pypi.tuna.tsinghua.edu.cn/simple

这里用的是清华大学的,可自己选择源

然后写代码:

第一步:引用ursina模块和第一人称

from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController

第二步,创建Ursina程序并赋值纹理(图在后面),为下面代码做铺垫

grass_texture = load_texture('texture\grass')
stone_texture = load_texture('texture\stone')
brick_texture = load_texture(r'texture\brick')
dirt_texture  = load_texture('texture\dirt')
sky_texture   = load_texture('sky')
arm_texture   = load_texture('white_cube')
bedrock_texture=load_texture(r"texture\bedrock")
punch_sound   = Audio('sine',loop = False, autoplay = False)
block_pick = 1
block_texture_dict={
1:grass_texture,2:stone_texture,3:brick_texture,4:dirt_texture,5:'white_cube'}
diction={}

grass,stone,brick,dirt和bedrock_texture是方块的纹理,load_texture(r'texture\brick')表示打开ursina模块中textures文件夹中texture文件夹中的brick图片(格式jpg和png都行),而sky和arm的纹理图片是ursina自带的,不用下载。Audio('sine',loop=False,autoplay=False)表示打开ursina自带的音频sine.wav,因其声音像挖放方块的声音,为后面的代码做铺垫。loop=False即循环为假,autoplay=False即自动播放为假。block_texture_dict,diction是为方便下文的字典。

接下来是定义方块的类,继承Button类,因为Entity是没有碰撞体积的

class Voxel(Button):
    def __init__(self, position = (0,0,0), texture = grass_texture,scale_y=1):
        super().__init__(
            parent = scene,
            position = position,
            model = 'cube',
            origin_y = 0.5,
            texture = texture,
            color = color.color(0,0,random.uniform(0.9,1)),
            scale_y = scale_y)

    def update(self):
        sx=self.x
        sy=self.y
        sz=self.z
        if ((self.x - player.x) ** 2 + (self.y - player.y) ** 2 + (self.z - player.z) ** 2) ** 0.5>=10:    #远离玩家10格以外的方块将被破坏
            destroy(self)
            try:
                del diction[(sx,sy,sz)] #not exist any more
            except KeyError:
                pass

    def input(self,key):
        if self.hovered:
            if ((self.x - player.x) ** 2 + (self.y - player.y) ** 2 + (self.z - player.z) ** 2) ** 0.5 <= 7: #distance    #7格的手长
                if key == 'right mouse down':
                    if block_pick!=5: punch_sound.play()
                    if block_pick == 1: voxel = Voxel(position = self.position + mouse.normal, texture = grass_texture)
                    if block_pick == 2: voxel = Voxel(position = self.position + mouse.normal, texture = stone_texture)
                    if block_pick == 3: voxel = Voxel(position = self.position + mouse.normal, texture = brick_texture)
                    if block_pick == 4: voxel = Voxel(position = self.position + mouse.normal, texture = dirt_texture)

            if key == 'left mouse down':
                if ((self.x-player.x)**2+(self.y-player.y)**2+(self.z-player.z)**2)**0.5<=7:
                    punch_sound.play()
                    if self.texture!=bedrock_texture:    #基岩不能破坏
                        destroy(self)

因为是跑酷,赛道肯定很长,方块数量多了,电脑就危险了,所以我在update()中规定:离玩家距离超过10格的方块(if ((self.x - player.x) ** 2 + (self.y - player.y) ** 2 + (self.z - player.z) ** 2) ** 0.5>=10,后面我把玩家起名为plyer)会被自动清除(destory(self)),并把字典中此方块的位置清除。是的,diction是用于放置已存在的方块的位置的,具体如下:

diction={已存在方块位置:True}。为什么要这样呢?

离玩家距离超过10格的方块自动清除,那么10格以内的方块就要重新放置。但ursina中一个位置是允许有多个方块的,这会导致同位置有无数的方块,电脑同样很卡。所以每当生成一个方块,就把当前位置标记为True,当前位置不再生成方块。同样,当方块被清除,那么此位置的字典就被删除。为什么用True呢?便于后面的if语句。

还有,这里讲一下update()和input()的区别。update(self)用于数据的更新,每一帧都会运行;而input(self,key)函数只有在键盘、鼠标活动时才运行。他们两个会被ursina自动调用,我们只用定义就好了。并且由于我糟糕的跑酷技术,我设置了可以放置(input(self)函数中的if key == 'right mouse down':下的内容)和破坏方块(destory(self)),且加了if ((self.x - player.x) ** 2 + (self.y - player.y) ** 2 + (self.z - player.z) ** 2) ** 0.5 <= 7的限制,我们只够得着7格以内的方块。在左\右键时,播放sine.wav(punch_sound.play())模拟方块破坏声。 if self.texture!=bedrock_texture:是指不能破坏基岩

接下来便是定义天和手的类了:

class Sky(Entity):
    def __init__(self):
        super().__init__(
            parent = scene,
            model = 'sphere',
            texture = sky_texture,
            scale = 150,
            double_sided = True)

class Hand(Entity):
    def __init__(self,texture=grass_texture,scale_x=0.5,scale_y=0.5):
        super().__init__(
            parent = camera.ui,
            model = 'cube',
            texture = texture,
            scale_x = scale_x,
            scale_y = scale_y,
            rotation = Vec3(150,-10,0),
            position = Vec2(0.4,-0.6))

    def update(self):
        if block_pick==5:
            self.scale_x=0.2
            self.scale_y=0.2    #空手时
        else:
            self.scale_x=self.scale_y=0.5
        self.texture=block_texture_dict[block_pick]    #手持方块时


    def active(self):
        self.position = Vec2(0.2,-0.4)

    def passive(self):
        self.position = Vec2(0.4,-0.6)

这里sky的double_sidede一定要设成True,不然就是黑乎乎一片,其他的非常简单,就不用我讲了

然后便是一些设置和实例:

def input(key):
    if key == 'q':
        player.y+=100    #作弊键
    if key == 'escape':
        quit()
window.fullscreen = True
player=FirstPersonController()
text=Text(text=f"Position:({player.x},{player.y},{player.z})",position=(-0.85,0.5))
text2=Text(text='Die-times:',color=color.red,position=(-0.85,0.45))
sky = Sky()
hand = Hand()    #创造一系列实例

zhi_music = Audio(r"zhi.mp3", autoplay=False, loop=False)
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值