欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python利用3D引擎制作一個3D迷宮游戲

 更新時間:2023年01月06日 09:30:30   作者:Leleprogrammer  
Python有一個不錯的3D引擎——Ursina。本文就來利用Ursina這一引擎制作一個簡單的3D迷宮游戲,感興趣的小伙伴可以跟隨小編一起學習一下

Ursina是一個3D引擎,初步使用方法,見文章:詳解Python 3D引擎Ursina如何繪制立體圖形

了解完Ursina的初步用法,接下來,我們就開始設(shè)計這個3D迷宮游戲啦!

效果:

墻面、地板、起始塊、終點塊所需要的圖像資源我放在下面供大家下載

↓↓

brick.png

redstoneblock.jpg

greendiamondblock.jpg 

plank.jpg

代碼詳解:

首先,要用Prim最小生成樹的方法生成迷宮,原理就是不斷遍歷還未遍歷過的墻,并不斷地刪除不需要的墻塊,代碼見文章:Python Prim算法通過遍歷墻實現(xiàn)迷宮的生成

這里,還有用遍歷網(wǎng)格生成迷宮的方法,不過在編輯這個3D迷宮時,我們最好選用上方遍歷墻的方式,順便送上遍歷網(wǎng)格的文章:Python利用Prim算法生成迷宮

把生成迷宮的代碼命名為create.py

在主程序main.py中導入相關(guān)模塊,其中ursina是整個3D引擎,ursina中有一個prefabs模塊,prefabs中有一些可以直接拿出來用的東西,比如first_person_controller中的FirstPersonController,是用于設(shè)置第一人稱的,sky中的Sky可以直接生成天空

然后,create模塊中createMaze模塊就是我們的Prim生成迷宮的算法

from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
from ursina.prefabs.sky import Sky
from create import createMaze

接下來,創(chuàng)建Ursina主程序

app=Ursina()

把剛剛提供給大家的圖片存到同目錄下的texture文件夾,作為材質(zhì)包

在程序中引入這些材質(zhì)

wall_texture=load_texture("texture/brick.png")
start_texture=load_texture("texture/redstoneblock.jpg")
end_texture=load_texture("texture/greendiamondblock.jpg")
ground_texture=load_texture("texture/plank.jpg")

創(chuàng)建Wall類,墻壁方塊,繼承于Button類,注意,這里不要用Entity,Entity是沒有碰撞體積的,所以要判斷玩家是否落地,需要寫更多代碼,這里用Button類,后面使用第一人稱時可以更方便,這里parent是場景,也就是Ursina里默認的scene,系統(tǒng)已經(jīng)自動定義好了,model是cube,也就是正方體,texture即材質(zhì),position是坐標,坐標現(xiàn)在還未確定,所以在__init__中添加為參數(shù),color設(shè)置為白色,這樣貼材質(zhì)的時候才不會讓材質(zhì)變色,設(shè)置為白色,可以讓材質(zhì)顯示自己本身的顏色,Ursina中有color變量,一些常用的顏色可以這樣使用:color.顏色名,或者用rgb的形式

class Wall(Button):
    def __init__(self,position):
        super().__init__(
            parent=scene,
            model="cube",
            texture=wall_texture,
            color=color.white,
            position=position,
            origin_y=0.5
        )

再創(chuàng)建一個類Start,用作起始方塊,這里參數(shù)都差不多,只改了材質(zhì)

class Start(Button):
    def __init__(self,position):
        super().__init__(
            parent=scene,
            model="cube",
            texture=start_texture,
            color=color.white,
            position=position,
            origin_y=0.5
        )

然后Ground(地板)和End(結(jié)束點)的類也差不多,都只改了個材質(zhì)

class End(Button):
    def __init__(self,position):
        super().__init__(
            parent=scene,
            model="cube",
            texture=end_texture,
            color=color.white,
            position=position,
            origin_y=0.5
        )
 
class Ground(Button):
    def __init__(self,position):
        super().__init__(
            parent=scene,
            model="cube",
            texture=ground_texture,
            color=color.white,
            position=position,
            origin_y=0.5
        )

接下來是Player,我們這里不直接使用Ursina的FirstPersonController,因為它系統(tǒng)已經(jīng)幫你設(shè)置好了行走速度、重力加速度、跳躍等等,這里在Pycharm編輯器里,ctrl+鼠標點FirstPersonController即可看到對應(yīng)的FirstPersonController的系統(tǒng)代碼,系統(tǒng)代碼如下:

class FirstPersonController(Entity):
    def __init__(self, **kwargs):
        self.cursor = Entity(parent=camera.ui, model='quad', color=color.pink, scale=.008, rotation_z=45)
        super().__init__()
        self.speed = 5
        self.height = 2
        self.camera_pivot = Entity(parent=self, y=self.height)
 
        camera.parent = self.camera_pivot
        camera.position = (0,0,0)
        camera.rotation = (0,0,0)
        camera.fov = 90
        mouse.locked = True
        self.mouse_sensitivity = Vec2(40, 40)
 
        self.gravity = 1
        self.grounded = False
        self.jump_height = 2
        self.jump_up_duration = .5
        self.fall_after = .35 # will interrupt jump up
        self.jumping = False
        self.air_time = 0
 
        for key, value in kwargs.items():
            setattr(self, key ,value)
 
        # make sure we don't fall through the ground if we start inside it
        if self.gravity:
            ray = raycast(self.world_position+(0,self.height,0), self.down, ignore=(self,))
            if ray.hit:
                self.y = ray.world_point.y
 
 
    def update(self):
        self.rotation_y += mouse.velocity[0] * self.mouse_sensitivity[1]
 
        self.camera_pivot.rotation_x -= mouse.velocity[1] * self.mouse_sensitivity[0]
        self.camera_pivot.rotation_x= clamp(self.camera_pivot.rotation_x, -90, 90)
 
        self.direction = Vec3(
            self.forward * (held_keys['w'] - held_keys['s'])
            + self.right * (held_keys['d'] - held_keys['a'])
            ).normalized()
 
        feet_ray = raycast(self.position+Vec3(0,0.5,0), self.direction, ignore=(self,), distance=.5, debug=False)
        head_ray = raycast(self.position+Vec3(0,self.height-.1,0), self.direction, ignore=(self,), distance=.5, debug=False)
        if not feet_ray.hit and not head_ray.hit:
            self.position += self.direction * self.speed * time.dt
 
 
        if self.gravity:
            # gravity
            ray = raycast(self.world_position+(0,self.height,0), self.down, ignore=(self,))
            # ray = boxcast(self.world_position+(0,2,0), self.down, ignore=(self,))
 
            if ray.distance <= self.height+.1:
                if not self.grounded:
                    self.land()
                self.grounded = True
                # make sure it's not a wall and that the point is not too far up
                if ray.world_normal.y > .7 and ray.world_point.y - self.world_y < .5: # walk up slope
                    self.y = ray.world_point[1]
                return
            else:
                self.grounded = False
 
            # if not on ground and not on way up in jump, fall
            self.y -= min(self.air_time, ray.distance-.05) * time.dt * 100
            self.air_time += time.dt * .25 * self.gravity
 
 
    def input(self, key):
        if key == 'space':
            self.jump()
 
 
    def jump(self):
        if not self.grounded:
            return
 
        self.grounded = False
        self.animate_y(self.y+self.jump_height, self.jump_up_duration, resolution=int(1//time.dt), curve=curve.out_expo)
        invoke(self.start_fall, delay=self.fall_after)
 
 
    def start_fall(self):
        self.y_animator.pause()
        self.jumping = False
 
    def land(self):
        # print('land')
        self.air_time = 0
        self.grounded = True
 
 
    def on_enable(self):
        mouse.locked = True
        self.cursor.enabled = True
 
 
    def on_disable(self):
        mouse.locked = False
        self.cursor.enabled = False

我們只需要修改里面一些參數(shù),__init__是一定要被修改的,跳躍的時候有時候會卡墻,然后跳到迷宮頂端,所以咱們這里禁用跳躍,重寫jump函數(shù),用pass代替即可。

gravity是重力,我們準備這樣設(shè)計:一開始,我們是在半空中,然后緩緩下降,進入迷宮初始點,所以要緩緩下降就需要改到重力,將self.gravity改為0.01,也就是默認的1%,然后將玩家移動速度設(shè)置為6,也就是將self.speed設(shè)置為6,self.position是坐標,暫時未知,用全局變量代替,camera像scene和color一樣,也是Ursina系統(tǒng)代碼中已經(jīng)幫我們定義好的了,我們無需重新定義,直接使用即可,camera中的fov是視角,咱們設(shè)置大一點,改為140,也差不多算廣角了,然后設(shè)置self.mouse_sensitivity(鼠標敏感度),這個要像系統(tǒng)代碼一樣用Vec2,而且要傳兩個參數(shù),我也不知道為啥這樣,反正系統(tǒng)怎么寫,咱們格式就盡量跟系統(tǒng)一樣。其實這個靈敏度,就是鼠標移動視角的時候的速度,原來是40,40,這里我們設(shè)置為原來的4倍,160,160。

別忘了要執(zhí)行父類的初始化函數(shù)哦?。╯uper().__init__())

class Player(FirstPersonController):
    def __init__(self):
        global startPosition
        super().__init__()
        camera.fov=140
        self.position=startPosition
        self.gravity=0.01
        self.speed=6
        self.mouse_sensitivity=Vec2(160,160)
 
    def jump(self):
        pass

接下來,生成迷宮,然后定義參數(shù),banPositions存儲起始塊和結(jié)束塊的坐標,生成地板的時候要跳過,因為在這兩個塊的地板是與其他不同的

maze=createMaze(15,15)
startPosition=None
endPosition=None
banPostions=[]

這里,因為一個格寬度的路很窄,顯得不寬敞,而且有時候行走也有些不方便,這里,我們把每個塊放大為2x2,然后再創(chuàng)建場景

for y in range(1,4):
    for x,row in enumerate(maze):
        for z,value in enumerate(row):
            if str(value)=="s":
                Start((x*2,0,z*2))
                Start((x*2,0,z*2+1))
                Start((x*2+1,0,z*2))
                Start((x*2+1,0,z*2+1))
                startPosition=(x*2,3,z*2)
                banPostions.append([x*2,z*2])
                banPostions.append([x*2,z*2+1])
                banPostions.append([x*2+1,z*2])
                banPostions.append([x*2+1,z*2+1])
            elif str(value)=="e":
                End((x*2,0,z*2))
                End((x*2,0,z*2+1))
                End((x*2+1,0,z*2))
                End((x*2+1,0,z*2+1))
                endPosition=(x*2,3,z*2)
                banPostions.append([x*2,z*2])
                banPostions.append([x*2,z*2+1])
                banPostions.append([x*2+1,z*2])
                banPostions.append([x*2+1,z*2+1])
            elif str(value)=="0":
                Wall((x*2,y,z*2))
                Wall((x*2,y,z*2+1))
                Wall((x*2+1,y,z*2))
                Wall((x*2+1,y,z*2+1))

生成地板

y2=0
for x2 in range(x*2+1):
    for z2 in range(z*2+1):
        if not ([x2,z2] in banPostions):
            Ground((x2,y2,z2))

然后實例化player和sky,最后運行程序

player=Player()
sky=Sky()
 
app.run()

這樣就可以實現(xiàn)文章一開始圖片中的效果啦!

不過我們走到終點也沒有啥效果,這個就留給大家自己嘗試和拓展啦!在這里就不再講解~

最后,附上main.py的參考代碼(迷宮生成的代碼到我文章開頭給出的鏈接中查看復(fù)制):

from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
from ursina.prefabs.sky import Sky
from create import createMaze
 
app=Ursina()
 
wall_texture=load_texture("texture/brick.png")
start_texture=load_texture("texture/redstoneblock.jpg")
end_texture=load_texture("texture/greendiamondblock.jpg")
ground_texture=load_texture("texture/plank.jpg")
 
class Wall(Button):
    def __init__(self,position):
        super().__init__(
            parent=scene,
            model="cube",
            texture=wall_texture,
            color=color.white,
            position=position,
            origin_y=0.5
        )
 
class Start(Button):
    def __init__(self,position):
        super().__init__(
            parent=scene,
            model="cube",
            texture=start_texture,
            color=color.white,
            position=position,
            origin_y=0.5
        )
 
class End(Button):
    def __init__(self,position):
        super().__init__(
            parent=scene,
            model="cube",
            texture=end_texture,
            color=color.white,
            position=position,
            origin_y=0.5
        )
 
class Ground(Button):
    def __init__(self,position):
        super().__init__(
            parent=scene,
            model="cube",
            texture=ground_texture,
            color=color.white,
            position=position,
            origin_y=0.5
        )
 
class Player(FirstPersonController):
    def __init__(self):
        global startPosition
        super().__init__()
        camera.fov=140
        self.position=startPosition
        self.gravity=0.01
        self.speed=6
        self.mouse_sensitivity=Vec2(160,160)
 
    def jump(self):
        pass
 
maze=createMaze(15,15)
startPosition=None
endPosition=None
banPostions=[]
for y in range(1,4):
    for x,row in enumerate(maze):
        for z,value in enumerate(row):
            if str(value)=="s":
                Start((x*2,0,z*2))
                Start((x*2,0,z*2+1))
                Start((x*2+1,0,z*2))
                Start((x*2+1,0,z*2+1))
                startPosition=(x*2,3,z*2)
                banPostions.append([x*2,z*2])
                banPostions.append([x*2,z*2+1])
                banPostions.append([x*2+1,z*2])
                banPostions.append([x*2+1,z*2+1])
            elif str(value)=="e":
                End((x*2,0,z*2))
                End((x*2,0,z*2+1))
                End((x*2+1,0,z*2))
                End((x*2+1,0,z*2+1))
                endPosition=(x*2,3,z*2)
                banPostions.append([x*2,z*2])
                banPostions.append([x*2,z*2+1])
                banPostions.append([x*2+1,z*2])
                banPostions.append([x*2+1,z*2+1])
            elif str(value)=="0":
                Wall((x*2,y,z*2))
                Wall((x*2,y,z*2+1))
                Wall((x*2+1,y,z*2))
                Wall((x*2+1,y,z*2+1))
 
y2=0
for x2 in range(x*2+1):
    for z2 in range(z*2+1):
        if not ([x2,z2] in banPostions):
            Ground((x2,y2,z2))
 
player=Player()
sky=Sky()
 
app.run()

以上就是Python利用3D引擎制作一個3D迷宮游戲的詳細內(nèi)容,更多關(guān)于Python 3D迷宮游戲的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論