IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 推箱子---小游戏 -> 正文阅读

[游戏开发]推箱子---小游戏

一、?环境搭建?

环境需求:

工作系统环境:windows /linux /macos

Python3.9.x

Anaconda

Pycharm 2021.3

二、Pycharm及Anaconda安装

在官网下载Pycharm对应的版本及Anaconda

三、使用Pycharm创建项目

1、打开pycharm,第一次创建项目,我们就选择create new project

2、按图上的顺序配置好,LocationApplication name可以根据自己需要自定义,项目解析器笔者此处选择了系统环境路径。全部设置好之后创建项目。

3.创建好的项目长得是这个样子的,

在输入框输入print(hello)点击运行,这时候打印hello,项目就可以正常跑起来了

四、 游戏原理

经典的推箱子是一个来自日本的古老游戏,目的是在训练你的逻辑思考能力。在一个狭小的仓库中,要求把木箱放到指定的位置,稍不小心就会出现箱子无法移动或者通道被堵住的情况,所以需要巧妙的利用有限的空间和通道,合理安排移动的次序和位置,才能顺利的完成任务通关。

推箱子功能如下:游戏运行时载入相应的地图,屏幕中出现一个推箱子的工人,其他都是围墙,通过移动把相应的箱子推到目的地点,全部推完即算通过,选择相应的关卡也可以重新开始或者其他关卡。

??

控制方式:

↑↓←→键控制人物行动,可以选择相应的关卡重新开始本关。

五、 逐步实现

1.设计游戏地图

地图,想象成一个网格,每个格子就是工人每次移动的步长,首先,我们设计一个7x7的二维列表myArray,对于x,y的坐标可以按二维列表计算。

格子的状态子常量 Wall=0代表墙,Worker=1 代表人,Box=2 代表箱子,Passageway=3 代表路,Destination=4 代表目的地,WorkerIndDest=5 代表人的目的地,RedBox=6 代表放到目的地的箱子。

这里我把地图信息储存到了map.txt文件里,运用了pickle模块及读写操作,需要时直接从文件中读取下一关的数据即可,使用了imgs列表储存图像,按照图像代号的顺序存储

map.txt里的代码

gamearray=[
[[0,3,1,4,3,3,3,0],
           [0,3,3,3,2,3,0,0],
           [0,0,3,0,3,3,0,0],
           [3,3,2,3,0,0,0,0],
           [3,4,3,3,3,0,0,0],
           [0,0,3,3,3,3,0,0],
           [0,0,0,0,0,0,0,0]],
[[0,3,1,4,3,3,3,0],
           [0,3,3,2,3,3,0,0],
           [0,0,3,0,3,3,0,0],
           [3,3,2,3,3,0,0,0],
           [3,4,3,3,3,0,0,0],
           [0,0,3,3,2,3,0,0],
           [0,0,4,3,3,3,0,0]],
[[0,3,1,4,3,3,3,0],
           [0,3,3,3,2,3,0,0],
           [0,0,3,0,3,3,0,0],
           [3,3,3,3,3,0,0,0],
           [3,4,3,2,0,0,0,0],
           [0,0,3,3,2,3,0,0],
           [0,0,4,3,3,3,0,0]],
[[0,3,1,4,3,3,3,0],
           [0,3,3,3,3,2,3,0],
           [0,0,3,0,3,3,0,0],
           [3,3,3,3,3,0,0,0],
           [3,4,3,3,2,0,0,0],
           [0,0,3,3,2,3,0,0],
           [0,0,4,3,3,3,0,0]]
]
import pickle
pickle_file=open('gamearray_data.pkl','wb')
pickle.dump(gamearray,pickle_file)
pickle_file.close()

?

?2.绘制游戏区块图形

绘制游戏图像按照地图从map.txt存储的图像代号,从imgs获得相应的图像,显示到Canvas。全局变量x,y代表工人当前的位置(x,y),从地图,myArray读取时,如果是0,记录当前位置信息

drawGameImage():
    global x,y
    for i in range(0,7):
        for j in range(0,7):
            if myArray[i][j]==Worker:
                x=i #工人当前的位置(x,y)
                y=j
                print("工人当前位置:",x,y)
            img1=imgs[myArray[i][j]]  #从imgs列表获取相对应的图像
            cv.create_image((i * 32 + 20, j * 32 + 20), image=img1)
            #显示到Canvas上
            cv.pack()

3.对于按键事件的处理

对游戏中玩家的按键操作采用的Canvas对象的KeyPress按键事件处理。KeyPress按键处理函数callback()根据用户按键信息,计算出工人移动的位置坐标(x1,y1)?、(x2,y2),将所有的位置作为参数调用MoveTo(x1,y1,x2,y2)判断对地图的更新。如果用户想恢复游戏只需按相应关卡对应的键1,例如1代表第一关,或者通过选择关卡进行重玩和选择其他关卡进行游玩。

def callback(event): #按键处理
    #(x1,y1)、(x2,y2)分别代表工人移动的两个方格
    global x,y,myArray
    print("按下键:")
    print("按下键:",event.char)
    KeyCode=event.keysym
    if KeyCode=="Up":#分析按键信息
    #向上
        x1=x;
        y1=y-1;
        x2=x;
        y2=y-2;
        #将所有位置输入以判断并作地图更新
        MoveTo(x1,y1,x2,y2);
    elif KeyCode=="Down":
    #向下
        x1=x
        y1=y+1
        x2=x
        y2=y+2
        MoveTo(x1,y1,x2,y2);
    elif KeyCode=="Left":
    #向左
        x1=x-1;
        y1=y;
        x2=x-2;
        y2=y;
        MoveTo(x1,y1,x2,y2);
    elif KeyCode=="Right":
    #向右
        x1=x+1;
        y1=y;
        x2=x+2;
        y2=y;
        MoveTo(x1,y1,x2,y2);

    elif KeyCode == "1":#1
        print("按下键:第1关", event.char)
        myArray = copy.deepcopy(gamearray[0])#恢复第1关地图
        drawGameImage()
    elif KeyCode == "2":#2
        print("按下键:第2关", event.char)
        myArray = copy.deepcopy(gamearray[1])#恢复第2关地图
        drawGameImage()
    elif KeyCode == "3":#3
        print("按下键:第1关", event.char)
        myArray = copy.deepcopy(gamearray[2])#恢复第3关地图
        drawGameImage()
    elif KeyCode == "4":#4
        print("按下键:第4关", event.char)
        myArray = copy.deepcopy(gamearray[3])#恢复第4关地图
        drawGameImage()

#判断是否在游戏区域中
def IsInGameArea(row,col):
    return (row>=0 and row<7 and col>=0 and col<7)
def MoveTo(x1,y1,x2,y2):
    global x,y
    p1=None                                  #p1,p2是移动方向的前两个格子
    p2=None
    if IsInGameArea(x1,y1):                  #判断是否在游戏区域中
        p1=myArray[x1][y1];
    if IsInGameArea(x2,y2):
        p2=myArray[x2][y2];
    if p1==Passageway:                        #p1为通道
        MoveMan(x,y);
        x=x1;
        y=y1;
        myArray[x1][y1]=Worker;
    if p1==Destination:                       #p1为目的地
        MoveMan(x,y);
        x=x1;
        y=y1;
        myArray[x1][y1]=WorkerInDest;
    if p1==Wall or not IsInGameArea(x1,y1):   #p1处为墙或者出界
            return;
    if p1==Box:                               #p1处为箱子
        if p2==Wall or not IsInGameArea(x1,y1) or p2==Box:#p2处为墙或者出界
            return;
    if p1==Box and p2==Passageway:            #p1处为箱子,p2为通道
        MoveMan(x,y);
        x=x1;
        y=y1;
        myArray[x2][y2]=Box;
        myArray[x1][y1]=Worker;
    if p1==Box and p2==Destination:#p1处为箱子,p2为目的地
        MoveMan(x,y);
        x=x1;
        y=y1;
        myArray[x2][y2]=RedBox;
        myArray[x1][y1]=Worker;
    if p1==RedBox and p2==Passageway:#p1处为放到目的箱子,p2为通道
        MoveMan(x,y)
        x=x1;
        y=y1
        myArray[x2][y2]=Box;
        myArray[x1][y1]=WorkerInDest;
    if p1==RedBox and p2==Destination:#p1处为放到目的箱子,p2为目的地
        MoveMan(x,y)
        x=x1;
        y=y1;
        myArray[x2][y2]=RedBox;
        myArray[x1][y1]=WorkerInDest;
    drawGameImage()
    #这里验证玩家是否通关
    if IsFinish():
        showinfo(title="提示",message="真棒通关了")

        print("下一关")
    drawGameImage()
    cv.bind("<KeyPress>", callback)
    cv.pack()
    cv.focus_set()

MoveMan(x,y)移动(x,y)工人,修改格子状态值

def MoveMan(x,y)  :
    if myArray[x][y]==Worker:
        myArray[x][y]=Passageway;
    elif myArray[x][y]==WorkerInDest:
        myArray[x][y]=Destination;

IsFinsh()验证是否通关,只要格子状态存在的目的地(Destination),或者人在目的地(WorkerInDest)则表明没有放好箱子,游戏未成功;否则,游戏成功。

def IsFinish():#验证是否通过
     bFinish=True;
     for i in range(0,7):
         for j in range(0,7):
             if (myArray[i][j]==Destination
                  or myArray[i][j]==WorkerInDest):
                bFinish=False;
     return bFinish

4.菜单及选项,设置菜单

menu1=Menu(win)#设置菜单
win.geometry('250x250')
menu2_1=Menu(menu1,tearoff=False)
menu1.add_cascade(label="点击",menu=menu2_1)
menu2_1.add_command(label="开始",command=new_game)

menu2_2=Menu(menu1,tearoff=False)
menu1.add_cascade(label="选择",menu=menu2_2)
menu2_2.add_command(label="第1关",command=new1_game)
menu2_2.add_command(label="第2关",command=new2_game)
menu2_2.add_command(label="第3关",command=new3_game)
menu2_2.add_command(label="第4关",command=new4_game)
menu1.add_command(label=" 退出",command=win.quit)
win.config(menu=menu1)
win.mainloop()

5.主程序

def new_game():
 drawGameImage()
 cv.bind("<KeyPress>", callback)
 cv.pack()
 cv.focus_set()

def new1_game():
    global myArray
    myArray = copy.deepcopy(gamearray[0])
    drawGameImage()
    cv.bind("<KeyPress>", callback)
    cv.pack()
    cv.focus_set()
def new2_game():
    global myArray
    myArray = copy.deepcopy(gamearray[1])
    drawGameImage()
    cv.bind("<KeyPress>", callback)
    cv.pack()
    cv.focus_set()
def new3_game():
    global myArray
    myArray = copy.deepcopy(gamearray[2])
    drawGameImage()
    cv.bind("<KeyPress>", callback)
    cv.pack()
    cv.focus_set()
def new4_game():
    global myArray
    myArray = copy.deepcopy(gamearray[3])
    drawGameImage()
    cv.bind("<KeyPress>", callback)
    cv.pack()
    cv.focus_set()

6.运行效果

?点击开始?

?选择第1关卡

?成功通关

7.全部代码

from tkinter import *
import copy
from tkinter.messagebox  import *
win=Tk()
win.title("推箱子--ly")
global num
global myArray
import random
import pickle
pickle_file=open('gamearray_data.pkl','rb') #把地图存储在map.txt里
gamearray=pickle.load(pickle_file)
imgs= [PhotoImage(file='D:\pythonProject01\\bmp\\Wall.gif'),
       PhotoImage(file='D:\pythonProject01\\bmp\\Worker.gif'),
       PhotoImage(file='D:\pythonProject01\\bmp\\Box.gif'),
       PhotoImage(file='D:\pythonProject01\\bmp\\Passageway.gif'),
       PhotoImage(file='D:\pythonProject01\\bmp\\Destination.gif'),
       PhotoImage(file='D:\pythonProject01\\bmp\\WorkerInDest.gif'),
       PhotoImage(file='D:\pythonProject01\\bmp\\RedBox.gif') ]
Wall=0
Worker=1
Box=2
Passageway=3
Destination=4
WorkerInDest=5
RedBox=6

word=random.choice(gamearray)
cv = Canvas(win, bg = 'green', width = 226, height = 226)
myArray=copy.deepcopy(word)



def drawGameImage():
    global x,y
    for i in range(0,7):
        for j in range(0,7):
            if myArray[i][j]==Worker:
                x=i #工人当前的位置(x,y)
                y=j
                print("工人当前位置:",x,y)
            img1=imgs[myArray[i][j]]  #从imgs列表获取相对应的图像
            cv.create_image((i * 32 + 20, j * 32 + 20), image=img1)
            #显示到Canvas上
            cv.pack()




def callback(event): #按键处理
    #(x1,y1)、(x2,y2)分别代表工人移动的两个方格
    global x,y,myArray
    print("按下键:")
    print("按下键:",event.char)
    KeyCode=event.keysym
    if KeyCode=="Up":#分析按键信息
    #向上
        x1=x;
        y1=y-1;
        x2=x;
        y2=y-2;
        #将所有位置输入以判断并作地图更新
        MoveTo(x1,y1,x2,y2);
    elif KeyCode=="Down":
    #向下
        x1=x
        y1=y+1
        x2=x
        y2=y+2
        MoveTo(x1,y1,x2,y2);
    elif KeyCode=="Left":
    #向左
        x1=x-1;
        y1=y;
        x2=x-2;
        y2=y;
        MoveTo(x1,y1,x2,y2);
    elif KeyCode=="Right":
    #向右
        x1=x+1;
        y1=y;
        x2=x+2;
        y2=y;
        MoveTo(x1,y1,x2,y2);

    elif KeyCode == "1":#1
        print("按下键:第1关", event.char)
        myArray = copy.deepcopy(gamearray[0])#恢复第1关地图
        drawGameImage()
    elif KeyCode == "2":#2
        print("按下键:第2关", event.char)
        myArray = copy.deepcopy(gamearray[1])#恢复第2关地图
        drawGameImage()
    elif KeyCode == "3":#3
        print("按下键:第1关", event.char)
        myArray = copy.deepcopy(gamearray[2])#恢复第3关地图
        drawGameImage()
    elif KeyCode == "4":#4
        print("按下键:第4关", event.char)
        myArray = copy.deepcopy(gamearray[3])#恢复第4关地图
        drawGameImage()

#判断是否在游戏区域中
def IsInGameArea(row,col):
    return (row>=0 and row<7 and col>=0 and col<7)
def MoveTo(x1,y1,x2,y2):
    global x,y
    p1=None                                  #p1,p2是移动方向的前两个格子
    p2=None
    if IsInGameArea(x1,y1):                  #判断是否在游戏区域中
        p1=myArray[x1][y1];
    if IsInGameArea(x2,y2):
        p2=myArray[x2][y2];
    if p1==Passageway:                        #p1为通道
        MoveMan(x,y);
        x=x1;
        y=y1;
        myArray[x1][y1]=Worker;
    if p1==Destination:                       #p1为目的地
        MoveMan(x,y);
        x=x1;
        y=y1;
        myArray[x1][y1]=WorkerInDest;
    if p1==Wall or not IsInGameArea(x1,y1):   #p1处为墙或者出界
            return;
    if p1==Box:                               #p1处为箱子
        if p2==Wall or not IsInGameArea(x1,y1) or p2==Box:#p2处为墙或者出界
            return;
    if p1==Box and p2==Passageway:            #p1处为箱子,p2为通道
        MoveMan(x,y);
        x=x1;
        y=y1;
        myArray[x2][y2]=Box;
        myArray[x1][y1]=Worker;
    if p1==Box and p2==Destination:#p1处为箱子,p2为目的地
        MoveMan(x,y);
        x=x1;
        y=y1;
        myArray[x2][y2]=RedBox;
        myArray[x1][y1]=Worker;
    if p1==RedBox and p2==Passageway:#p1处为放到目的箱子,p2为通道
        MoveMan(x,y)
        x=x1;
        y=y1
        myArray[x2][y2]=Box;
        myArray[x1][y1]=WorkerInDest;
    if p1==RedBox and p2==Destination:#p1处为放到目的箱子,p2为目的地
        MoveMan(x,y)
        x=x1;
        y=y1;
        myArray[x2][y2]=RedBox;
        myArray[x1][y1]=WorkerInDest;
    drawGameImage()
    #这里验证玩家是否通关
    if IsFinish():
        showinfo(title="提示",message="真棒通关了")

        print("下一关")
    drawGameImage()
    cv.bind("<KeyPress>", callback)
    cv.pack()
    cv.focus_set()



def MoveMan(x,y)  :
    if myArray[x][y]==Worker:
        myArray[x][y]=Passageway;
    elif myArray[x][y]==WorkerInDest:
        myArray[x][y]=Destination;
def IsFinish():#验证是否通过
     bFinish=True;
     for i in range(0,7):
         for j in range(0,7):
             if (myArray[i][j]==Destination
                  or myArray[i][j]==WorkerInDest):
                bFinish=False;
     return bFinish

def drawQiPan( ) :
    for i in range(0,15) :
        cv.create_line(20,20+40*i,580,20+40*i,width=2)
    for i in range(0,15) :
        cv.create_line(20+40*i,20,20+40*i,580,width=2)
    cv.pack()

def print_map( ) :
    for i in range(0,15) :
       for j in range(0,15) :
           print (map[i][j],end=' ')
       print ('w')

def new_game():
 drawGameImage()
 cv.bind("<KeyPress>", callback)
 cv.pack()
 cv.focus_set()

def new1_game():
    global myArray
    myArray = copy.deepcopy(gamearray[0])
    drawGameImage()
    cv.bind("<KeyPress>", callback)
    cv.pack()
    cv.focus_set()
def new2_game():
    global myArray
    myArray = copy.deepcopy(gamearray[1])
    drawGameImage()
    cv.bind("<KeyPress>", callback)
    cv.pack()
    cv.focus_set()
def new3_game():
    global myArray
    myArray = copy.deepcopy(gamearray[2])
    drawGameImage()
    cv.bind("<KeyPress>", callback)
    cv.pack()
    cv.focus_set()
def new4_game():
    global myArray
    myArray = copy.deepcopy(gamearray[3])
    drawGameImage()
    cv.bind("<KeyPress>", callback)
    cv.pack()
    cv.focus_set()


menu1=Menu(win)#设置菜单
win.geometry('250x250')
menu2_1=Menu(menu1,tearoff=False)
menu1.add_cascade(label="点击",menu=menu2_1)
menu2_1.add_command(label="开始",command=new_game)

menu2_2=Menu(menu1,tearoff=False)
menu1.add_cascade(label="选择",menu=menu2_2)
menu2_2.add_command(label="第1关",command=new1_game)
menu2_2.add_command(label="第2关",command=new2_game)
menu2_2.add_command(label="第3关",command=new3_game)
menu2_2.add_command(label="第4关",command=new4_game)
menu1.add_command(label=" 退出",command=win.quit)
win.config(menu=menu1)
win.mainloop()

六、 相关素材

链接:https://pan.baidu.com/s/1HJ45qGt8t0IhJGUtod-eNg 提取码:70u3


  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章           查看所有文章
加:2021-08-22 13:49:17  更:2021-08-22 13:49:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 21:31:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码